summaryrefslogtreecommitdiffstats
path: root/dom/system/gonk/Volume.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/system/gonk/Volume.cpp')
-rw-r--r--dom/system/gonk/Volume.cpp596
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