mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
7edec4880a
- Bug 859764 - Part 5: Changes in Test Cases. r=echen (f1a5cd4fd3) - Bug 859764 - Part 6: Changes in Payment. r=ferjm, r=smaug (2b47641375) - Bug 1010756 - Helpful errors for using nsCOMPtr on non-XPCOM types; r=froydnj (6b1521c482) - leftover (e1a24351e9) - Bug 1192102 - Remove unused file embedded/android/GeckoSmsManager.java. r=blassey (ac05ae649d) - var-let (8ddb529f96) - Bug 1181466 - Fix observe function in SmsService/MmsService. r=btseng (ca93122404) - Bug 733331 - Part 2: Update enabledGsmTableTuples when MCC changes in SmsService.js and fix segmentChars in SmsSegmentHelper.jsm. r=btseng (24fa23e4be) - Bug 1173156 - Fix typo and add a Marionette test case. r=btseng (e7199eb55a) - Bug 1132774 - [B2G][SMS] Enable DEBUG Flag in SmsService if the default value of "ril.debugging.enabled" is true. r=btseng (7300d24fb7) - Bug 1169160 - [MobileConnection] Support more call barring program: all service, outgoing service and incoming service. r=hsinyi,aknow (872c2cc056) - Bug 1169225 - [MobileConnectionService] Support setting/getting call waiting on all serviceClass. r=aknow (14c546a9ca) - Bug 1110619 - Part 1: IDL Interface Changes. r=echen (beae2b4b77) - Bug 1168064 - B2G RIL: filter out cell info with unknown values. r=echen (11dfc5a7e8) - Bug 1159591 - Part 2: Move MMI logic from ril_worker to telephonyService (Call Forwarding). r=aknow (b4edb76863) - Bug 1159591 - Part 3: Move MMI logic from ril_worker to telephonyService (Icc Lock). r=aknow (3faba76808) - Bug 1138263 - Make TelephonyService.js JSHint friendly. r=hsinyi (454bd4c765) - Bug 1159591 - Part 4: Move MMI logic from ril_worker to telephonyService (IMEI). r=aknow (57f423ecdd) - Bug 1159591 - Part 5: Move MMI logic from ril_worker to telephonyService (CLIP). r=aknow (c6611dbcb8) - Bug 1159591 - Part 6: Move MMI logic from ril_worker to telephonyService (CLIR). r=aknow (8c1fc03edb) - Bug 1159591 - Part 7: Move MMI logic from ril_worker to telephonyService (Call Barring Password). r=aknow (5d8bcbf177) - Bug 1159591 - Part 8: Move MMI logic from ril_worker to telephonyService (Call Barring). r=aknow (aa0b89aea1) - Bug 1159591 - Part 9: Move MMI logic from ril_worker to telephonyService (Call Waiting). r=aknow (1d14d2b864) - Bug 1159591 - Part 10: Move MMI logic from ril_worker to telephonyService (USSD). r=aknow (c92130b5b2) - Bug 1159591 - Part 11: Move MMI consts from ril_consts to telephonyService. r=aknow (0e7b3fea9a) - Bug 1159591 - Part 12: Move radio check for MMI to a common place. r=aknow (dcdc3178ad) - Bug 1110619 - Part 2: Implementation Changes. r=echen (6d8e78d684) - Bug 1110619 - Part 3: Bluetooth Changes. r=btian (9787727be0) - Bug 1147736 - Part 1: Extend TelephonyCallInfo. r=aknow (2a426cc99f) - Bug 1147736 - Part 2: Bypass NotifyError. r=aknow (6cd6fd6867) - Bug 1147736 - Part 3: Deprecate NotifyError. r=aknow (e41c719442) - Bug 1147736 - Part 4: Deprecate NotifyError(Bluetooth). r=btian (9c8f97bb22) - Bug 1204817 - Delete the child property of a parent call only when the parent call exists. r=btseng (d35dc6b08f) - Bug 1191205 - Cancel USSD sessions only when needed. r=edgar (01a72dbacb) - Bug 1200134 - Control USSD Sessions with State-Transitions instead of Boolean. r=echen (a4e55b3d9d) - Bug 1163511 - Use defineLazyModuleGetter. r=hsinyi (8a97a4912c) - Bug 991582 - Part 2: Handle the result of RIL request in a consistent way. r=aknow (914ecc2bbb) - Bug 1164248 - Handling of session/sessionEnded for notifyUssdReceived. r=edgar (a79df75d38) - Bug 1223662 - Part 1: Check mmiServiceCode with correct constant. r=echen (abeb286050) - Bug 1174673 - Part 1: Automatically resume the held call. r=hsinyi (280543af7d) - Bug 1174673 - Part 2: Update test case. r=hsinyi (cfe19f1a52) - Bug 1185156 - Fix bug in resuming held call. r=hsinyi (b96346d319) - Bug 1162426 - Part 1: Provide TelephonyUtils. r=hsinyi (62b71e6e83) - Bug 1162426 - Part 2: Test case. r=hsniyi (13a0b3c6f5) - Bug 1171807 - Part 1: Add enums for TelephonyCall::State and TelephonyCallGroup::State (WebIDL). r=hsinyi (0b698eecc4) - Bug 1145551 - DTMF should be sent using the active SIM, the given or the default one (in that order). r=aknow (6157636493) - Bug 1171807 - Part 2: Move to enums and deprecate TelephonyCall.mCallState and TelephonyCallGroup.mCallState (DOM). r=btseng (5faef22d91) - Bug 1168515 - do not block incall MMI requests on alerting state. r=aknow (b1f85c5789) - Bug 1155072 - Part 1: Deprecate nsITelephonyListener.conferenceCallStateChanged (Telephony). r=btseng (e41d1a4bc9) - Bug 1155072 - Part 2: Deprecate nsITelephonyListener.conferenceCallStateChanged (Bluetooth). r=btian (27e69fa89b) - Bug 1166936 - JS Warning in TelephonyService.js r=aknow (3559d3ad3d) - Bug 1191237 - Part 1: Enhance |TelephonyService.js|. r=aknow (86576a6d32) - Bug 1202902 - Fix the world. (0dc256d67d) - Bug 1161438 - Part 1 - Exporting contact to SIM should also return updated contact. r=echen (505d7d7f83) - Bug 1159622 - Split test_icc_contact.js into read contact and add contact. r=echen (fec0c428df) - Bug 1122376 - Support read SIM contact dialling number exceed 20 digits. r=echen (5d0599e93c) - Bug 1161438 - Part 2 - marionette testcase. r=echen (1f0d18a479) - Bug 1114937 - Part 5: Fix Test Case to Remove Contact with Correct Contact Id. r=echen (8d746fdbd2) - Bug 1194149 - Continue importing contacts when there is no sufficient Type 2 USIM contact fields record. r=echen (e9be40dbf2) - Bug 962995 - xpcshell tests for write ICC UCS2 characters for 0x81 and 0x82 encoding. r=echen (9500afaa4d) - Bug 1161438 - Part 3 - xpcshell testcase. r=echen (01f7fb4514) - Bug 1122376 - Support write SIM contact dialling number exceed 20 digits. r=echen (91133e286d) - Bug 999300 - Part 1: Removed the Ril v5 legacy support. r=edgar (ded77fcb6f) - Bug 999300 - Part 2: Update the related testcases. r=edgar (f77a8b96cc) - Bug 1177146 - [Aries][RIL] Reply from QUERY_AVAILABLE_NETWORKS has extra strings. r=hsinyi (a6816cbbab) - Bug 1043250 - Part 1: Update ril_worker and xpcshell test. r=btseng (8b9b25b5cf) - Bug 1185406 - B2G RIL: Read 'pcscf' and expose it in nsIRilNetworkInfo. r=hsinyi (ce707ecb83) - Bug 1174998 - Part 3: Read data call's MTU from network/apn settings. r=echen (bfa08d8380) - Bug 1166320 - Make volume service safer to use off main thread. r=dhylands (b3976622ad) - Bug 1177374 - Call realpath on volume mount points so thatVolumeService::GetVolumeByPath works properly. r=achen (aea97080eb) - Bug 1195166 - AutoMounter: add ignore command to allow volumes to be ignored. r=alchen (f265d832c8) - Bug 1196724 - Refactoring of AudioManager r=alwu (e5b896b7ce) - Bug 1222564 - Save audio volume to database r=alwu (1303d01ae7) - Bug 1164049 - Fix some mode lines in embedding/. r=smaug (79ddce4871)
597 lines
18 KiB
C++
597 lines
18 KiB
C++
/* 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) recieves 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
|