diff options
Diffstat (limited to 'dom/system/gonk/nsVolume.cpp')
-rw-r--r-- | dom/system/gonk/nsVolume.cpp | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/dom/system/gonk/nsVolume.cpp b/dom/system/gonk/nsVolume.cpp new file mode 100644 index 000000000..77a1628e4 --- /dev/null +++ b/dom/system/gonk/nsVolume.cpp @@ -0,0 +1,467 @@ +/* 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 "base/task.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" + +#undef VOLUME_MANAGER_LOG_TAG +#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"; + case nsIVolume::STATE_CHECKMNT: return "Check-Mounted"; + case nsIVolume::STATE_MOUNT_FAIL: return "Mount-Fail"; + } + 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(!aVolume->CanBeShared()), + mIsMediaPresent(aVolume->MediaPresent()), + mIsSharing(aVolume->IsSharing()), + mIsFormatting(aVolume->IsFormatting()), + mIsUnmounting(aVolume->IsUnmounting()), + mIsRemovable(aVolume->IsRemovable()), + mIsHotSwappable(aVolume->IsHotSwappable()) +{ +} + +nsVolume::nsVolume(const nsVolume* aVolume) + : mName(aVolume->mName), + mMountPoint(aVolume->mMountPoint), + mState(aVolume->mState), + mMountGeneration(aVolume->mMountGeneration), + mMountLocked(aVolume->mMountLocked), + mIsFake(aVolume->mIsFake), + mIsMediaPresent(aVolume->mIsMediaPresent), + mIsSharing(aVolume->mIsSharing), + mIsFormatting(aVolume->mIsFormatting), + mIsUnmounting(aVolume->mIsUnmounting), + mIsRemovable(aVolume->mIsRemovable), + mIsHotSwappable(aVolume->mIsHotSwappable) +{ +} + +void nsVolume::Dump(const char* aLabel) const +{ + LOG("%s: Volume: %s is %s and %s @ %s gen %d locked %d", + aLabel, + NameStr().get(), + StateStr(), + IsMediaPresent() ? "inserted" : "missing", + MountPointStr().get(), + MountGeneration(), + (int)IsMountLocked()); + LOG("%s: IsSharing %s IsFormating %s IsUnmounting %s", + aLabel, + (IsSharing() ? "y" : "n"), + (IsFormatting() ? "y" : "n"), + (IsUnmounting() ? "y" : "n")); +} + +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; + } + + bool isUnmounting; + aVolume->GetIsUnmounting(&isUnmounting); + if (mIsUnmounting != isUnmounting) { + return false; + } + + bool isRemovable; + aVolume->GetIsRemovable(&isRemovable); + if (mIsRemovable != isRemovable) { + return false; + } + + bool isHotSwappable; + aVolume->GetIsHotSwappable(&isHotSwappable); + if (mIsHotSwappable != isHotSwappable) { + 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::GetIsUnmounting(bool* aIsUnmounting) +{ + *aIsUnmounting = mIsUnmounting; + 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::GetIsRemovable(bool *aIsRemovable) +{ + *aIsRemovable = mIsRemovable; + return NS_OK; +} + +NS_IMETHODIMP nsVolume::GetIsHotSwappable(bool *aIsHotSwappable) +{ + *aIsHotSwappable = mIsHotSwappable; + return NS_OK; +} + +NS_IMETHODIMP nsVolume::Format() +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + XRE_GetIOMessageLoop()->PostTask( + NewRunnableFunction(FormatVolumeIOThread, NameStr())); + + return NS_OK; +} + +/* static */ +void nsVolume::FormatVolumeIOThread(const nsCString& aVolume) +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); + if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { + return; + } + + AutoMounterFormatVolume(aVolume); +} + +NS_IMETHODIMP nsVolume::Mount() +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + XRE_GetIOMessageLoop()->PostTask( + NewRunnableFunction(MountVolumeIOThread, NameStr())); + + return NS_OK; +} + +/* static */ +void nsVolume::MountVolumeIOThread(const nsCString& aVolume) +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); + if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { + return; + } + + AutoMounterMountVolume(aVolume); +} + +NS_IMETHODIMP nsVolume::Unmount() +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + XRE_GetIOMessageLoop()->PostTask( + NewRunnableFunction(UnmountVolumeIOThread, NameStr())); + + return NS_OK; +} + +/* static */ +void nsVolume::UnmountVolumeIOThread(const nsCString& aVolume) +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + 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 unmounting %d removable %d hotswappable %d", + NameStr().get(), StateStr(), MountPointStr().get(), + MountGeneration(), (int)IsMountLocked(), (int)IsFake(), + (int)IsMediaPresent(), (int)IsSharing(), + (int)IsFormatting(), (int)IsUnmounting(), + (int)IsRemovable(), (int)IsHotSwappable()); + return; + } + + LOG("nsVolume: %s state %s", NameStr().get(), StateStr()); +} + +void nsVolume::UpdateMountLock(nsVolume* aOldVolume) +{ + MOZ_ASSERT(NS_IsMainThread()); + + bool oldMountLocked = aOldVolume ? aOldVolume->mMountLocked : false; + 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; + mMountLocked = oldMountLocked; + return; + } + + int32_t oldMountGeneration = aOldVolume ? aOldVolume->mMountGeneration : -1; + if (mMountGeneration == oldMountGeneration) { + // No change in mount generation, nothing else to do + mMountLocked = oldMountLocked; + return; + } + + if (!XRE_IsParentProcess()) { + // Child processes just track the state, not maintain it. + return; + } + + // Notify the Volume on IOThread whether the volume is locked or not. + nsCOMPtr<nsIPowerManagerService> 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_IsParentProcess()); + 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_IsParentProcess()); + MOZ_ASSERT(NS_IsMainThread()); + + if (aMountLocked == mMountLocked) { + return; + } + // The locked/unlocked state changed. Tell IOThread about it. + mMountLocked = aMountLocked; + LogState(); + XRE_GetIOMessageLoop()->PostTask( + 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::SetIsRemovable(bool aIsRemovable) +{ + mIsRemovable = aIsRemovable; + if (!mIsRemovable) { + mIsHotSwappable = false; + } +} + +void +nsVolume::SetIsHotSwappable(bool aIsHotSwappable) +{ + mIsHotSwappable = aIsHotSwappable; + if (mIsHotSwappable) { + mIsRemovable = true; + } +} + +void +nsVolume::SetState(int32_t aState) +{ + static int32_t sMountGeneration = 0; + + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(IsFake()); + + if (aState == mState) { + return; + } + + if (aState == nsIVolume::STATE_MOUNTED) { + mMountGeneration = ++sMountGeneration; + } + + mState = aState; +} + +} // system +} // mozilla |