diff options
Diffstat (limited to 'dom/system/gonk/nsVolumeMountLock.cpp')
-rw-r--r-- | dom/system/gonk/nsVolumeMountLock.cpp | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/dom/system/gonk/nsVolumeMountLock.cpp b/dom/system/gonk/nsVolumeMountLock.cpp new file mode 100644 index 000000000..288c0f689 --- /dev/null +++ b/dom/system/gonk/nsVolumeMountLock.cpp @@ -0,0 +1,171 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsVolumeMountLock.h" + +#include "mozilla/dom/ContentChild.h" +#include "mozilla/Services.h" + +#include "nsIObserverService.h" +#include "nsIPowerManagerService.h" +#include "nsIVolume.h" +#include "nsIVolumeService.h" +#include "nsString.h" +#include "nsXULAppAPI.h" + +#undef VOLUME_MANAGER_LOG_TAG +#define VOLUME_MANAGER_LOG_TAG "nsVolumeMountLock" +#include "VolumeManagerLog.h" +#include "nsServiceManagerUtils.h" +#include "mozilla/dom/power/PowerManagerService.h" + +using namespace mozilla::dom; +using namespace mozilla::services; + +namespace mozilla { +namespace system { + +NS_IMPL_ISUPPORTS(nsVolumeMountLock, nsIVolumeMountLock, + nsIObserver, nsISupportsWeakReference) + +// static +already_AddRefed<nsVolumeMountLock> +nsVolumeMountLock::Create(const nsAString& aVolumeName) +{ + DBG("nsVolumeMountLock::Create called"); + + RefPtr<nsVolumeMountLock> mountLock = new nsVolumeMountLock(aVolumeName); + nsresult rv = mountLock->Init(); + NS_ENSURE_SUCCESS(rv, nullptr); + + return mountLock.forget(); +} + +nsVolumeMountLock::nsVolumeMountLock(const nsAString& aVolumeName) + : mVolumeName(aVolumeName), + mVolumeGeneration(-1), + mUnlocked(false) +{ +} + +//virtual +nsVolumeMountLock::~nsVolumeMountLock() +{ + Unlock(); +} + +nsresult nsVolumeMountLock::Init() +{ + LOG("nsVolumeMountLock created for '%s'", + NS_LossyConvertUTF16toASCII(mVolumeName).get()); + + // Add ourselves as an Observer. It's important that we use a weak + // reference here. If we used a strong reference, then that reference + // would prevent this object from being destructed. + nsCOMPtr<nsIObserverService> obs = GetObserverService(); + obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, true /*weak*/); + + // Get the initial mountGeneration and grab a lock. + nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); + NS_ENSURE_TRUE(vs, NS_ERROR_FAILURE); + + nsCOMPtr<nsIVolume> vol; + nsresult rv = vs->GetVolumeByName(mVolumeName, getter_AddRefs(vol)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + rv = vol->GetMountGeneration(&mVolumeGeneration); + NS_ENSURE_SUCCESS(rv, rv); + + return Lock(vol); +} + +NS_IMETHODIMP nsVolumeMountLock::Unlock() +{ + LOG("nsVolumeMountLock released for '%s'", + NS_LossyConvertUTF16toASCII(mVolumeName).get()); + + mUnlocked = true; + mWakeLock = nullptr; + + // While we don't really need to remove weak observers, we do so anyways + // since it will reduce the number of times Observe gets called. + nsCOMPtr<nsIObserverService> obs = GetObserverService(); + obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED); + return NS_OK; +} + +NS_IMETHODIMP nsVolumeMountLock::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) +{ + if (strcmp(aTopic, NS_VOLUME_STATE_CHANGED) != 0) { + return NS_OK; + } + if (mUnlocked) { + // We're not locked anymore, so we don't need to look at the notifications. + return NS_OK; + } + + nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject); + if (!vol) { + return NS_OK; + } + nsString volName; + vol->GetName(volName); + if (!volName.Equals(mVolumeName)) { + return NS_OK; + } + int32_t state; + nsresult rv = vol->GetState(&state); + NS_ENSURE_SUCCESS(rv, rv); + + if (state != nsIVolume::STATE_MOUNTED) { + mWakeLock = nullptr; + mVolumeGeneration = -1; + return NS_OK; + } + + int32_t mountGeneration; + rv = vol->GetMountGeneration(&mountGeneration); + NS_ENSURE_SUCCESS(rv, rv); + + DBG("nsVolumeMountLock::Observe mountGeneration = %d mVolumeGeneration = %d", + mountGeneration, mVolumeGeneration); + + if (mVolumeGeneration == mountGeneration) { + return NS_OK; + } + + // The generation changed, which means that any wakelock we may have + // been holding is now invalid. Grab a new wakelock for the new generation + // number. + + mWakeLock = nullptr; + mVolumeGeneration = mountGeneration; + + return Lock(vol); +} + +nsresult +nsVolumeMountLock::Lock(nsIVolume* aVolume) +{ + RefPtr<power::PowerManagerService> pmService = + power::PowerManagerService::GetInstance(); + NS_ENSURE_TRUE(pmService, NS_ERROR_FAILURE); + + nsString mountLockName; + aVolume->GetMountLockName(mountLockName); + + ErrorResult err; + mWakeLock = pmService->NewWakeLock(mountLockName, nullptr, err); + if (err.Failed()) { + return err.StealNSResult(); + } + + LOG("nsVolumeMountLock acquired for '%s' gen %d", + NS_LossyConvertUTF16toASCII(mVolumeName).get(), mVolumeGeneration); + return NS_OK; +} + +} // namespace system +} // namespace mozilla |