diff -r 000000000000 -r 6474c204b198 dom/system/gonk/nsVolumeMountLock.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/system/gonk/nsVolumeMountLock.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,164 @@ +/* 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" + +#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::Create(const nsAString& aVolumeName) +{ + DBG("nsVolumeMountLock::Create called"); + + nsRefPtr 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 obs = GetObserverService(); + obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, true /*weak*/); + + // Request the sdcard info, so we know the state/generation without having + // to wait for a state change. + if (XRE_GetProcessType() == GeckoProcessType_Content) { + ContentChild::GetSingleton()->SendBroadcastVolume(mVolumeName); + return NS_OK; + } + nsCOMPtr vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); + NS_ENSURE_TRUE(vs, NS_ERROR_FAILURE); + + vs->BroadcastVolume(mVolumeName); + + return NS_OK; +} + +/* void unlock (); */ +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 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 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; + + nsRefPtr pmService = + power::PowerManagerService::GetInstance(); + NS_ENSURE_TRUE(pmService, NS_ERROR_FAILURE); + + nsString mountLockName; + vol->GetMountLockName(mountLockName); + + ErrorResult err; + mWakeLock = pmService->NewWakeLock(mountLockName, nullptr, err); + if (err.Failed()) { + return err.ErrorCode(); + } + + LOG("nsVolumeMountLock acquired for '%s' gen %d", + NS_LossyConvertUTF16toASCII(mVolumeName).get(), mVolumeGeneration); + return NS_OK; +} + +} // namespace system +} // namespace mozilla