diff -r 000000000000 -r 6474c204b198 dom/system/gonk/nsVolume.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/system/gonk/nsVolume.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,385 @@ +/* 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 "nsVolume.h" + +#include "base/message_loop.h" +#include "nsIPowerManagerService.h" +#include "nsISupportsUtils.h" +#include "nsIVolume.h" +#include "nsServiceManagerUtils.h" +#include "nsThreadUtils.h" +#include "nsVolumeStat.h" +#include "nsXULAppAPI.h" +#include "Volume.h" +#include "AutoMounter.h" +#include "VolumeManager.h" + +#define VOLUME_MANAGER_LOG_TAG "nsVolume" +#include "VolumeManagerLog.h" + +namespace mozilla { +namespace system { + +const char * +NS_VolumeStateStr(int32_t aState) +{ + switch (aState) { + case nsIVolume::STATE_INIT: return "Init"; + case nsIVolume::STATE_NOMEDIA: return "NoMedia"; + case nsIVolume::STATE_IDLE: return "Idle"; + case nsIVolume::STATE_PENDING: return "Pending"; + case nsIVolume::STATE_CHECKING: return "Checking"; + case nsIVolume::STATE_MOUNTED: return "Mounted"; + case nsIVolume::STATE_UNMOUNTING: return "Unmounting"; + case nsIVolume::STATE_FORMATTING: return "Formatting"; + case nsIVolume::STATE_SHARED: return "Shared"; + case nsIVolume::STATE_SHAREDMNT: return "Shared-Mounted"; + } + return "???"; +} + +// While nsVolumes can only be used on the main thread, in the +// UpdateVolumeRunnable constructor (which is called from IOThread) we +// allocate an nsVolume which is then passed to MainThread. Since we +// have a situation where we allocate on one thread and free on another +// we use a thread safe AddRef implementation. +NS_IMPL_ISUPPORTS(nsVolume, nsIVolume) + +nsVolume::nsVolume(const Volume* aVolume) + : mName(NS_ConvertUTF8toUTF16(aVolume->Name())), + mMountPoint(NS_ConvertUTF8toUTF16(aVolume->MountPoint())), + mState(aVolume->State()), + mMountGeneration(aVolume->MountGeneration()), + mMountLocked(aVolume->IsMountLocked()), + mIsFake(false), + mIsMediaPresent(aVolume->MediaPresent()), + mIsSharing(aVolume->IsSharing()), + mIsFormatting(aVolume->IsFormatting()) +{ +} + +bool nsVolume::Equals(nsIVolume* aVolume) +{ + nsString volName; + aVolume->GetName(volName); + if (!mName.Equals(volName)) { + return false; + } + + nsString volMountPoint; + aVolume->GetMountPoint(volMountPoint); + if (!mMountPoint.Equals(volMountPoint)) { + return false; + } + + int32_t volState; + aVolume->GetState(&volState); + if (mState != volState){ + return false; + } + + int32_t volMountGeneration; + aVolume->GetMountGeneration(&volMountGeneration); + if (mMountGeneration != volMountGeneration) { + return false; + } + + bool volIsMountLocked; + aVolume->GetIsMountLocked(&volIsMountLocked); + if (mMountLocked != volIsMountLocked) { + return false; + } + + bool isFake; + aVolume->GetIsFake(&isFake); + if (mIsFake != isFake) { + return false; + } + + bool isSharing; + aVolume->GetIsSharing(&isSharing); + if (mIsSharing != isSharing) { + return false; + } + + bool isFormatting; + aVolume->GetIsFormatting(&isFormatting); + if (mIsFormatting != isFormatting) { + return false; + } + + return true; +} + +NS_IMETHODIMP nsVolume::GetIsMediaPresent(bool *aIsMediaPresent) +{ + *aIsMediaPresent = mIsMediaPresent; + return NS_OK; +} + +NS_IMETHODIMP nsVolume::GetIsMountLocked(bool *aIsMountLocked) +{ + *aIsMountLocked = mMountLocked; + return NS_OK; +} + +NS_IMETHODIMP nsVolume::GetIsSharing(bool *aIsSharing) +{ + *aIsSharing = mIsSharing; + return NS_OK; +} + +NS_IMETHODIMP nsVolume::GetIsFormatting(bool *aIsFormatting) +{ + *aIsFormatting = mIsFormatting; + return NS_OK; +} + +NS_IMETHODIMP nsVolume::GetName(nsAString& aName) +{ + aName = mName; + return NS_OK; +} + +NS_IMETHODIMP nsVolume::GetMountGeneration(int32_t* aMountGeneration) +{ + *aMountGeneration = mMountGeneration; + return NS_OK; +} + +NS_IMETHODIMP nsVolume::GetMountLockName(nsAString& aMountLockName) +{ + aMountLockName = NS_LITERAL_STRING("volume-") + Name(); + aMountLockName.AppendPrintf("-%d", mMountGeneration); + + return NS_OK; +} + +NS_IMETHODIMP nsVolume::GetMountPoint(nsAString& aMountPoint) +{ + aMountPoint = mMountPoint; + return NS_OK; +} + +NS_IMETHODIMP nsVolume::GetState(int32_t* aState) +{ + *aState = mState; + return NS_OK; +} + +NS_IMETHODIMP nsVolume::GetStats(nsIVolumeStat **aResult) +{ + if (mState != STATE_MOUNTED) { + return NS_ERROR_NOT_AVAILABLE; + } + + NS_IF_ADDREF(*aResult = new nsVolumeStat(mMountPoint)); + return NS_OK; +} + +NS_IMETHODIMP nsVolume::GetIsFake(bool *aIsFake) +{ + *aIsFake = mIsFake; + return NS_OK; +} + +NS_IMETHODIMP nsVolume::Format() +{ + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + + XRE_GetIOMessageLoop()->PostTask( + FROM_HERE, + NewRunnableFunction(FormatVolumeIOThread, NameStr())); + + return NS_OK; +} + +/* static */ +void nsVolume::FormatVolumeIOThread(const nsCString& aVolume) +{ + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); + if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { + return; + } + + AutoMounterFormatVolume(aVolume); +} + +NS_IMETHODIMP nsVolume::Mount() +{ + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + + XRE_GetIOMessageLoop()->PostTask( + FROM_HERE, + NewRunnableFunction(MountVolumeIOThread, NameStr())); + + return NS_OK; +} + +/* static */ +void nsVolume::MountVolumeIOThread(const nsCString& aVolume) +{ + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); + if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { + return; + } + + AutoMounterMountVolume(aVolume); +} + +NS_IMETHODIMP nsVolume::Unmount() +{ + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + + XRE_GetIOMessageLoop()->PostTask( + FROM_HERE, + NewRunnableFunction(UnmountVolumeIOThread, NameStr())); + + return NS_OK; +} + +/* static */ +void nsVolume::UnmountVolumeIOThread(const nsCString& aVolume) +{ + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); + if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { + return; + } + + AutoMounterUnmountVolume(aVolume); +} + +void +nsVolume::LogState() const +{ + if (mState == nsIVolume::STATE_MOUNTED) { + LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d " + "media %d sharing %d formatting %d", + NameStr().get(), StateStr(), MountPointStr().get(), + MountGeneration(), (int)IsMountLocked(), (int)IsFake(), + (int)IsMediaPresent(), (int)IsSharing(), + (int)IsFormatting()); + return; + } + + LOG("nsVolume: %s state %s", NameStr().get(), StateStr()); +} + +void nsVolume::Set(nsIVolume* aVolume) +{ + MOZ_ASSERT(NS_IsMainThread()); + + aVolume->GetName(mName); + aVolume->GetMountPoint(mMountPoint); + aVolume->GetState(&mState); + aVolume->GetIsFake(&mIsFake); + aVolume->GetIsMediaPresent(&mIsMediaPresent); + aVolume->GetIsSharing(&mIsSharing); + aVolume->GetIsFormatting(&mIsFormatting); + + int32_t volMountGeneration; + aVolume->GetMountGeneration(&volMountGeneration); + + if (mState != nsIVolume::STATE_MOUNTED) { + // Since we're not in the mounted state, we need to + // forgot whatever mount generation we may have had. + mMountGeneration = -1; + return; + } + if (mMountGeneration == volMountGeneration) { + // No change in mount generation, nothing else to do + return; + } + + mMountGeneration = volMountGeneration; + + if (XRE_GetProcessType() != GeckoProcessType_Default) { + // Child processes just track the state, not maintain it. + aVolume->GetIsMountLocked(&mMountLocked); + return; + } + + // Notify the Volume on IOThread whether the volume is locked or not. + nsCOMPtr pmService = + do_GetService(POWERMANAGERSERVICE_CONTRACTID); + if (!pmService) { + return; + } + nsString mountLockName; + GetMountLockName(mountLockName); + nsString mountLockState; + pmService->GetWakeLockState(mountLockName, mountLockState); + UpdateMountLock(mountLockState); +} + +void +nsVolume::UpdateMountLock(const nsAString& aMountLockState) +{ + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + MOZ_ASSERT(NS_IsMainThread()); + + // There are 3 states, unlocked, locked-background, and locked-foreground + // I figured it was easier to use negtive logic and compare for unlocked. + UpdateMountLock(!aMountLockState.EqualsLiteral("unlocked")); +} + +void +nsVolume::UpdateMountLock(bool aMountLocked) +{ + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + MOZ_ASSERT(NS_IsMainThread()); + + if (aMountLocked == mMountLocked) { + return; + } + // The locked/unlocked state changed. Tell IOThread about it. + mMountLocked = aMountLocked; + LogState(); + XRE_GetIOMessageLoop()->PostTask( + FROM_HERE, + NewRunnableFunction(Volume::UpdateMountLock, + NS_LossyConvertUTF16toASCII(Name()), + MountGeneration(), aMountLocked)); +} + +void +nsVolume::SetIsFake(bool aIsFake) +{ + mIsFake = aIsFake; + if (mIsFake) { + // The media is always present for fake volumes. + mIsMediaPresent = true; + MOZ_ASSERT(!mIsSharing); + } +} + +void +nsVolume::SetState(int32_t aState) +{ + static int32_t sMountGeneration = 0; + + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(IsFake()); + + if (aState == mState) { + return; + } + + if (aState == nsIVolume::STATE_MOUNTED) { + mMountGeneration = ++sMountGeneration; + } + + mState = aState; +} + +} // system +} // mozilla