diff options
Diffstat (limited to 'dom/system/gonk/Volume.cpp')
-rw-r--r-- | dom/system/gonk/Volume.cpp | 596 |
1 files changed, 0 insertions, 596 deletions
diff --git a/dom/system/gonk/Volume.cpp b/dom/system/gonk/Volume.cpp deleted file mode 100644 index f90c7b693..000000000 --- a/dom/system/gonk/Volume.cpp +++ /dev/null @@ -1,596 +0,0 @@ -/* 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 "Volume.h" -#include "VolumeCommand.h" -#include "VolumeManager.h" -#include "VolumeManagerLog.h" -#include "nsIVolume.h" -#include "nsXULAppAPI.h" - -#include <vold/ResponseCode.h> - -namespace mozilla { -namespace system { - -#if DEBUG_VOLUME_OBSERVER -void -VolumeObserverList::Broadcast(Volume* const& aVolume) -{ - uint32_t size = mObservers.Length(); - for (uint32_t i = 0; i < size; ++i) { - LOG("VolumeObserverList::Broadcast to [%u] %p volume '%s'", - i, mObservers[i], aVolume->NameStr()); - mObservers[i]->Notify(aVolume); - } -} -#endif - -VolumeObserverList Volume::sEventObserverList; - -// We have a feature where volumes can be locked when mounted. This -// is used to prevent a volume from being shared with the PC while -// it is actively being used (say for storing an update image) -// -// We use WakeLocks (a poor choice of name, but it does what we want) -// from the PowerManagerService to determine when we're locked. -// In particular we'll create a wakelock called volume-NAME-GENERATION -// (where NAME is the volume name, and GENERATION is its generation -// number), and if this wakelock is locked, then we'll prevent a volume -// from being shared. -// -// Implementation Details: -// -// Since the AutoMounter can only control when something gets mounted -// and not when it gets unmounted (for example: a user pulls the SDCard) -// and because Volume and nsVolume data structures are maintained on -// separate threads, we have the potential for some race conditions. -// We eliminate the race conditions by introducing the concept of a -// generation number. Every time a volume transitions to the Mounted -// state, it gets assigned a new generation number. Whenever the state -// of a Volume changes, we send the updated state and current generation -// number to the main thread where it gets updated in the nsVolume. -// -// Since WakeLocks can only be queried from the main-thread, the -// nsVolumeService looks for WakeLock status changes, and forwards -// the results to the IOThread. -// -// If the Volume (IOThread) receives a volume update where the generation -// number mismatches, then the update is simply ignored. -// -// When a Volume (IOThread) initially becomes mounted, we assume it to -// be locked until we get our first update from nsVolume (MainThread). -static int32_t sMountGeneration = 0; - -static uint32_t sNextId = 1; - -// We don't get media inserted/removed events at startup. So we -// assume it's present, and we'll be told that it's missing. -Volume::Volume(const nsCSubstring& aName) - : mMediaPresent(true), - mState(nsIVolume::STATE_INIT), - mName(aName), - mMountGeneration(-1), - mMountLocked(true), // Needs to agree with nsVolume::nsVolume - mSharingEnabled(false), - mFormatRequested(false), - mMountRequested(false), - mUnmountRequested(false), - mCanBeShared(true), - mIsSharing(false), - mIsFormatting(false), - mIsUnmounting(false), - mIsRemovable(false), - mIsHotSwappable(false), - mId(sNextId++) -{ - DBG("Volume %s: created", NameStr()); -} - -void -Volume::Dump(const char* aLabel) const -{ - LOG("%s: Volume: %s (%d) is %s and %s @ %s gen %d locked %d", - aLabel, - NameStr(), - Id(), - StateStr(), - MediaPresent() ? "inserted" : "missing", - MountPoint().get(), - MountGeneration(), - (int)IsMountLocked()); - LOG("%s: Sharing %s Mounting %s Formating %s Unmounting %s", - aLabel, - CanBeShared() ? (IsSharingEnabled() ? (IsSharing() ? "en-y" : "en-n") - : "dis") - : "x", - IsMountRequested() ? "req" : "n", - IsFormatRequested() ? (IsFormatting() ? "req-y" : "req-n") - : (IsFormatting() ? "y" : "n"), - IsUnmountRequested() ? (IsUnmounting() ? "req-y" : "req-n") - : (IsUnmounting() ? "y" : "n")); -} - -void -Volume::ResolveAndSetMountPoint(const nsCSubstring& aMountPoint) -{ - nsCString mountPoint(aMountPoint); - char realPathBuf[PATH_MAX]; - - // Call realpath so that we wind up with a path which is compatible with - // functions like nsVolumeService::GetVolumeByPath. - - if (realpath(mountPoint.get(), realPathBuf) < 0) { - // The path we were handed doesn't exist. Warn about it, but use it - // anyways assuming that the user knows what they're doing. - - ERR("ResolveAndSetMountPoint: realpath on '%s' failed: %d", - mountPoint.get(), errno); - mMountPoint = mountPoint; - } else { - mMountPoint = realPathBuf; - } - DBG("Volume %s: Setting mountpoint to '%s'", NameStr(), mMountPoint.get()); -} - -void Volume::SetFakeVolume(const nsACString& aMountPoint) -{ - this->mMountLocked = false; - this->mCanBeShared = false; - ResolveAndSetMountPoint(aMountPoint); - SetState(nsIVolume::STATE_MOUNTED); -} - -void -Volume::SetIsSharing(bool aIsSharing) -{ - if (aIsSharing == mIsSharing) { - return; - } - mIsSharing = aIsSharing; - LOG("Volume %s: IsSharing set to %d state %s", - NameStr(), (int)mIsSharing, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetIsFormatting(bool aIsFormatting) -{ - if (aIsFormatting == mIsFormatting) { - return; - } - mIsFormatting = aIsFormatting; - LOG("Volume %s: IsFormatting set to %d state %s", - NameStr(), (int)mIsFormatting, StateStr(mState)); - if (mIsFormatting) { - sEventObserverList.Broadcast(this); - } -} - -void -Volume::SetIsUnmounting(bool aIsUnmounting) -{ - if (aIsUnmounting == mIsUnmounting) { - return; - } - mIsUnmounting = aIsUnmounting; - LOG("Volume %s: IsUnmounting set to %d state %s", - NameStr(), (int)mIsUnmounting, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetIsRemovable(bool aIsRemovable) -{ - if (aIsRemovable == mIsRemovable) { - return; - } - mIsRemovable = aIsRemovable; - if (!mIsRemovable) { - mIsHotSwappable = false; - } - LOG("Volume %s: IsRemovable set to %d state %s", - NameStr(), (int)mIsRemovable, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetIsHotSwappable(bool aIsHotSwappable) -{ - if (aIsHotSwappable == mIsHotSwappable) { - return; - } - mIsHotSwappable = aIsHotSwappable; - if (mIsHotSwappable) { - mIsRemovable = true; - } - LOG("Volume %s: IsHotSwappable set to %d state %s", - NameStr(), (int)mIsHotSwappable, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -bool -Volume::BoolConfigValue(const nsCString& aConfigValue, bool& aBoolValue) -{ - if (aConfigValue.EqualsLiteral("1") || - aConfigValue.LowerCaseEqualsLiteral("true")) { - aBoolValue = true; - return true; - } - if (aConfigValue.EqualsLiteral("0") || - aConfigValue.LowerCaseEqualsLiteral("false")) { - aBoolValue = false; - return true; - } - return false; -} - -void -Volume::SetConfig(const nsCString& aConfigName, const nsCString& aConfigValue) -{ - if (aConfigName.LowerCaseEqualsLiteral("removable")) { - bool value = false; - if (BoolConfigValue(aConfigValue, value)) { - SetIsRemovable(value); - } else { - ERR("Volume %s: invalid value '%s' for configuration '%s'", - NameStr(), aConfigValue.get(), aConfigName.get()); - } - return; - } - if (aConfigName.LowerCaseEqualsLiteral("hotswappable")) { - bool value = false; - if (BoolConfigValue(aConfigValue, value)) { - SetIsHotSwappable(value); - } else { - ERR("Volume %s: invalid value '%s' for configuration '%s'", - NameStr(), aConfigValue.get(), aConfigName.get()); - } - return; - } - ERR("Volume %s: invalid config '%s'", NameStr(), aConfigName.get()); -} - -void -Volume::SetMediaPresent(bool aMediaPresent) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // mMediaPresent is slightly redunant to the state, however - // when media is removed (while Idle), we get the following: - // 631 Volume sdcard /mnt/sdcard disk removed (179:0) - // 605 Volume sdcard /mnt/sdcard state changed from 1 (Idle-Unmounted) to 0 (No-Media) - // - // And on media insertion, we get: - // 630 Volume sdcard /mnt/sdcard disk inserted (179:0) - // 605 Volume sdcard /mnt/sdcard state changed from 0 (No-Media) to 2 (Pending) - // 605 Volume sdcard /mnt/sdcard state changed from 2 (Pending) to 1 (Idle-Unmounted) - // - // On media removal while the media is mounted: - // 632 Volume sdcard /mnt/sdcard bad removal (179:1) - // 605 Volume sdcard /mnt/sdcard state changed from 4 (Mounted) to 5 (Unmounting) - // 605 Volume sdcard /mnt/sdcard state changed from 5 (Unmounting) to 1 (Idle-Unmounted) - // 631 Volume sdcard /mnt/sdcard disk removed (179:0) - // 605 Volume sdcard /mnt/sdcard state changed from 1 (Idle-Unmounted) to 0 (No-Media) - // - // When sharing with a PC, it goes Mounted -> Idle -> Shared - // When unsharing with a PC, it goes Shared -> Idle -> Mounted - // - // The AutoMounter needs to know whether the media is present or not when - // processing the Idle state. - - if (mMediaPresent == aMediaPresent) { - return; - } - - LOG("Volume: %s media %s", NameStr(), aMediaPresent ? "inserted" : "removed"); - mMediaPresent = aMediaPresent; - sEventObserverList.Broadcast(this); -} - -void -Volume::SetSharingEnabled(bool aSharingEnabled) -{ - mSharingEnabled = aSharingEnabled; - - LOG("SetSharingMode for volume %s to %d canBeShared = %d", - NameStr(), (int)mSharingEnabled, (int)mCanBeShared); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetFormatRequested(bool aFormatRequested) -{ - mFormatRequested = aFormatRequested; - - LOG("SetFormatRequested for volume %s to %d CanBeFormatted = %d", - NameStr(), (int)mFormatRequested, (int)CanBeFormatted()); -} - -void -Volume::SetMountRequested(bool aMountRequested) -{ - mMountRequested = aMountRequested; - - LOG("SetMountRequested for volume %s to %d CanBeMounted = %d", - NameStr(), (int)mMountRequested, (int)CanBeMounted()); -} - -void -Volume::SetUnmountRequested(bool aUnmountRequested) -{ - mUnmountRequested = aUnmountRequested; - - LOG("SetUnmountRequested for volume %s to %d CanBeMounted = %d", - NameStr(), (int)mUnmountRequested, (int)CanBeMounted()); -} - -void -Volume::SetState(Volume::STATE aNewState) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (aNewState == mState) { - return; - } - if (aNewState == nsIVolume::STATE_MOUNTED) { - mMountGeneration = ++sMountGeneration; - LOG("Volume %s (%u): changing state from %s to %s @ '%s' (%d observers) " - "mountGeneration = %d, locked = %d", - NameStr(), mId, StateStr(mState), - StateStr(aNewState), mMountPoint.get(), sEventObserverList.Length(), - mMountGeneration, (int)mMountLocked); - } else { - LOG("Volume %s (%u): changing state from %s to %s (%d observers)", - NameStr(), mId, StateStr(mState), - StateStr(aNewState), sEventObserverList.Length()); - } - - switch (aNewState) { - case nsIVolume::STATE_NOMEDIA: - // Cover the startup case where we don't get insertion/removal events - mMediaPresent = false; - mIsSharing = false; - mUnmountRequested = false; - mMountRequested = false; - mIsUnmounting = false; - break; - - case nsIVolume::STATE_MOUNTED: - case nsIVolume::STATE_MOUNT_FAIL: - mMountRequested = false; - mIsFormatting = false; - mIsSharing = false; - mIsUnmounting = false; - break; - - case nsIVolume::STATE_FORMATTING: - mFormatRequested = false; - mIsFormatting = true; - mIsSharing = false; - mIsUnmounting = false; - break; - - case nsIVolume::STATE_SHARED: - case nsIVolume::STATE_SHAREDMNT: - // Covers startup cases. Normally, mIsSharing would be set to true - // when we issue the command to initiate the sharing process, but - // it's conceivable that a volume could already be in a shared state - // when b2g starts. - mIsSharing = true; - mIsUnmounting = false; - mIsFormatting = false; - break; - - case nsIVolume::STATE_UNMOUNTING: - mIsUnmounting = true; - mIsFormatting = false; - mIsSharing = false; - break; - - case nsIVolume::STATE_IDLE: // Fall through - case nsIVolume::STATE_CHECKMNT: // Fall through - default: - break; - } - mState = aNewState; - sEventObserverList.Broadcast(this); -} - -void -Volume::SetMountPoint(const nsCSubstring& aMountPoint) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - if (mMountPoint.Equals(aMountPoint)) { - return; - } - ResolveAndSetMountPoint(aMountPoint); -} - -void -Volume::StartMount(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "mount", "", aCallback)); -} - -void -Volume::StartUnmount(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "unmount", "force", aCallback)); -} - -void -Volume::StartFormat(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "format", "", aCallback)); -} - -void -Volume::StartShare(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "share", "ums", aCallback)); -} - -void -Volume::StartUnshare(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "unshare", "ums", aCallback)); -} - -void -Volume::StartCommand(VolumeCommand* aCommand) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - VolumeManager::PostCommand(aCommand); -} - -//static -void -Volume::RegisterVolumeObserver(Volume::EventObserver* aObserver, const char* aName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - sEventObserverList.AddObserver(aObserver); - - DBG("Added Volume Observer '%s' @%p, length = %u", - aName, aObserver, sEventObserverList.Length()); - - // Send an initial event to the observer (for each volume) - size_t numVolumes = VolumeManager::NumVolumes(); - for (size_t volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex); - aObserver->Notify(vol); - } -} - -//static -void -Volume::UnregisterVolumeObserver(Volume::EventObserver* aObserver, const char* aName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - sEventObserverList.RemoveObserver(aObserver); - - DBG("Removed Volume Observer '%s' @%p, length = %u", - aName, aObserver, sEventObserverList.Length()); -} - -//static -void -Volume::UpdateMountLock(const nsACString& aVolumeName, - const int32_t& aMountGeneration, - const bool& aMountLocked) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - RefPtr<Volume> vol = VolumeManager::FindVolumeByName(aVolumeName); - if (!vol || (vol->mMountGeneration != aMountGeneration)) { - return; - } - if (vol->mMountLocked != aMountLocked) { - vol->mMountLocked = aMountLocked; - DBG("Volume::UpdateMountLock for '%s' to %d\n", vol->NameStr(), (int)aMountLocked); - sEventObserverList.Broadcast(vol); - } -} - -void -Volume::HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer& aTokenizer) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // The volume name will have already been parsed, and the tokenizer will point - // to the token after the volume name - switch (aResponseCode) { - case ::ResponseCode::VolumeListResult: { - // Each line will look something like: - // - // sdcard /mnt/sdcard 1 - // - nsDependentCSubstring mntPoint(aTokenizer.nextToken()); - SetMountPoint(mntPoint); - nsresult errCode; - nsCString state(aTokenizer.nextToken()); - if (state.EqualsLiteral("X")) { - // Special state for creating fake volumes which can't be shared. - mCanBeShared = false; - SetState(nsIVolume::STATE_MOUNTED); - } else { - SetState((STATE)state.ToInteger(&errCode)); - } - break; - } - - case ::ResponseCode::VolumeStateChange: { - // Format of the line looks something like: - // - // Volume sdcard /mnt/sdcard state changed from 7 (Shared-Unmounted) to 1 (Idle-Unmounted) - // - // So we parse out the state after the string " to " - while (aTokenizer.hasMoreTokens()) { - nsAutoCString token(aTokenizer.nextToken()); - if (token.EqualsLiteral("to")) { - nsresult errCode; - token = aTokenizer.nextToken(); - STATE newState = (STATE)(token.ToInteger(&errCode)); - if (newState == nsIVolume::STATE_MOUNTED) { - // We set the state to STATE_CHECKMNT here, and the once the - // AutoMounter detects that the volume is actually accessible - // then the AutoMounter will set the volume as STATE_MOUNTED. - SetState(nsIVolume::STATE_CHECKMNT); - } else { - if (State() == nsIVolume::STATE_CHECKING && newState == nsIVolume::STATE_IDLE) { - LOG("Mount of volume '%s' failed", NameStr()); - SetState(nsIVolume::STATE_MOUNT_FAIL); - } else { - SetState(newState); - } - } - break; - } - } - break; - } - - case ::ResponseCode::VolumeDiskInserted: - SetMediaPresent(true); - break; - - case ::ResponseCode::VolumeDiskRemoved: // fall-thru - case ::ResponseCode::VolumeBadRemoval: - SetMediaPresent(false); - break; - - default: - LOG("Volume: %s unrecognized reponse code (ignored)", NameStr()); - break; - } -} - -} // namespace system -} // namespace mozilla |