From b43c0867f506fce56475b3e42a518f1dc98234dc Mon Sep 17 00:00:00 2001 From: CHUANG CHENYU Date: Mon, 22 Dec 2014 10:33:33 +0800 Subject: [PATCH] Bug 1033952 - Implement "Removable" and "HotSwappable" APIs for device storage. r=dhylands, r=bzbarsky --- dom/devicestorage/DeviceStorage.h | 2 + dom/devicestorage/nsDeviceStorage.cpp | 13 +++++ dom/ipc/ContentChild.cpp | 8 ++- dom/ipc/ContentChild.h | 4 +- dom/ipc/ContentParent.cpp | 6 +- dom/ipc/PContent.ipdl | 5 +- dom/system/gonk/Volume.cpp | 74 ++++++++++++++++++++++++ dom/system/gonk/Volume.h | 9 +++ dom/system/gonk/VolumeManager.cpp | 83 +++++++++++++++++++++++---- dom/system/gonk/VolumeManager.h | 2 + dom/system/gonk/nsIVolume.idl | 9 ++- dom/system/gonk/nsVolume.cpp | 53 ++++++++++++++++- dom/system/gonk/nsVolume.h | 17 +++++- dom/system/gonk/nsVolumeService.cpp | 24 +++++--- dom/webidl/DeviceStorage.webidl | 3 + 15 files changed, 282 insertions(+), 30 deletions(-) diff --git a/dom/devicestorage/DeviceStorage.h b/dom/devicestorage/DeviceStorage.h index 75d8f39a013..05436a9d888 100644 --- a/dom/devicestorage/DeviceStorage.h +++ b/dom/devicestorage/DeviceStorage.h @@ -272,6 +272,7 @@ public: bool CanBeMounted(); bool CanBeFormatted(); bool CanBeShared(); + bool IsRemovable(); bool Default(); // Uses XPCOM GetStorageName @@ -322,6 +323,7 @@ private: nsCOMPtr mRootDirectory; nsString mStorageName; bool mIsShareable; + bool mIsRemovable; already_AddRefed GetStorage(const nsAString& aFullPath, nsAString& aOutStoragePath); diff --git a/dom/devicestorage/nsDeviceStorage.cpp b/dom/devicestorage/nsDeviceStorage.cpp index 20b1efeffba..41534479c66 100644 --- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -3337,6 +3337,7 @@ NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorage, DOMEventTargetHelper) nsDOMDeviceStorage::nsDOMDeviceStorage(nsPIDOMWindow* aWindow) : DOMEventTargetHelper(aWindow) , mIsShareable(false) + , mIsRemovable(false) , mIsWatchingFile(false) , mAllowedToWatchFile(false) { @@ -3383,6 +3384,12 @@ nsDOMDeviceStorage::Init(nsPIDOMWindow* aWindow, const nsAString &aType, return rv; } mIsShareable = !isFake; + bool isRemovable; + rv = vol->GetIsHotSwappable(&isRemovable); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + mIsRemovable = isRemovable; } #endif } @@ -4226,6 +4233,12 @@ nsDOMDeviceStorage::CanBeShared() return mIsShareable; } +bool +nsDOMDeviceStorage::IsRemovable() +{ + return mIsRemovable; +} + already_AddRefed nsDOMDeviceStorage::GetRoot(ErrorResult& aRv) { diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index b0f9ae79eb3..d98def2487c 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -2153,13 +2153,15 @@ ContentChild::RecvFileSystemUpdate(const nsString& aFsName, const bool& aIsSharing, const bool& aIsFormatting, const bool& aIsFake, - const bool& aIsUnmounting) + const bool& aIsUnmounting, + const bool& aIsRemovable, + const bool& aIsHotSwappable) { #ifdef MOZ_WIDGET_GONK nsRefPtr volume = new nsVolume(aFsName, aVolumeName, aState, aMountGeneration, aIsMediaPresent, aIsSharing, aIsFormatting, aIsFake, - aIsUnmounting); + aIsUnmounting, aIsRemovable, aIsHotSwappable); nsRefPtr vs = nsVolumeService::GetSingleton(); if (vs) { @@ -2176,6 +2178,8 @@ ContentChild::RecvFileSystemUpdate(const nsString& aFsName, unused << aIsFormatting; unused << aIsFake; unused << aIsUnmounting; + unused << aIsRemovable; + unused << aIsHotSwappable; #endif return true; } diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 8315b6f180f..d38478b92bd 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -336,7 +336,9 @@ public: const bool& aIsSharing, const bool& aIsFormatting, const bool& aIsFake, - const bool& aIsUnmounting) MOZ_OVERRIDE; + const bool& aIsUnmounting, + const bool& aIsRemovable, + const bool& aIsHotSwappable) MOZ_OVERRIDE; virtual bool RecvNuwaFork() MOZ_OVERRIDE; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index bc492c210e9..1f4e837c6c3 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -2829,6 +2829,8 @@ ContentParent::Observe(nsISupports* aSubject, bool isFormatting; bool isFake; bool isUnmounting; + bool isRemovable; + bool isHotSwappable; vol->GetName(volName); vol->GetMountPoint(mountPoint); @@ -2839,6 +2841,8 @@ ContentParent::Observe(nsISupports* aSubject, vol->GetIsFormatting(&isFormatting); vol->GetIsFake(&isFake); vol->GetIsUnmounting(&isUnmounting); + vol->GetIsRemovable(&isRemovable); + vol->GetIsHotSwappable(&isHotSwappable); #ifdef MOZ_NUWA_PROCESS if (!(IsNuwaReady() && IsNuwaProcess())) @@ -2847,7 +2851,7 @@ ContentParent::Observe(nsISupports* aSubject, unused << SendFileSystemUpdate(volName, mountPoint, state, mountGeneration, isMediaPresent, isSharing, isFormatting, isFake, - isUnmounting); + isUnmounting, isRemovable, isHotSwappable); } } else if (!strcmp(aTopic, "phone-state-changed")) { nsString state(aData); diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index cd49ba90321..5c370b9d0ce 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -319,6 +319,8 @@ struct VolumeInfo { bool isFormatting; bool isFake; bool isUnmounting; + bool isRemovable; + bool isHotSwappable; }; struct ClipboardCapabilities { @@ -489,7 +491,8 @@ child: // VolumeInfo above. FileSystemUpdate(nsString fsName, nsString mountPoint, int32_t fsState, int32_t mountGeneration, bool isMediaPresent, - bool isSharing, bool isFormatting, bool isFake, bool isUnmounting); + bool isSharing, bool isFormatting, bool isFake, + bool isUnmounting, bool isRemovable, bool isHotSwappable); // Ask the Nuwa process to create a new child process. NuwaFork(); diff --git a/dom/system/gonk/Volume.cpp b/dom/system/gonk/Volume.cpp index f9c8ccf924c..6ea8a40a7cc 100644 --- a/dom/system/gonk/Volume.cpp +++ b/dom/system/gonk/Volume.cpp @@ -81,6 +81,8 @@ Volume::Volume(const nsCSubstring& aName) mIsSharing(false), mIsFormatting(false), mIsUnmounting(false), + mIsRemovable(false), + mIsHotSwappable(false), mId(sNextId++) { DBG("Volume %s: created", NameStr()); @@ -156,6 +158,78 @@ Volume::SetIsUnmounting(bool aIsUnmounting) 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) { diff --git a/dom/system/gonk/Volume.h b/dom/system/gonk/Volume.h index cb47a2e53da..733d9f748e6 100644 --- a/dom/system/gonk/Volume.h +++ b/dom/system/gonk/Volume.h @@ -75,6 +75,8 @@ public: bool IsSharing() const { return mIsSharing; } bool IsFormatting() const { return mIsFormatting; } bool IsUnmounting() const { return mIsUnmounting; } + bool IsRemovable() const { return mIsRemovable; } + bool IsHotSwappable() const { return mIsHotSwappable; } void SetFakeVolume(const nsACString& aMountPoint); @@ -107,11 +109,16 @@ private: void SetIsSharing(bool aIsSharing); void SetIsFormatting(bool aIsFormatting); void SetIsUnmounting(bool aIsUnmounting); + void SetIsRemovable(bool aIsRemovable); + void SetIsHotSwappable(bool aIsHotSwappable); void SetState(STATE aNewState); void SetMediaPresent(bool aMediaPresent); void SetMountPoint(const nsCSubstring& aMountPoint); void StartCommand(VolumeCommand* aCommand); + bool BoolConfigValue(const nsCString& aConfigValue, bool& aBoolValue); + void SetConfig(const nsCString& aConfigName, const nsCString& aConfigValue); + void HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer& aTokenizer); static void UpdateMountLock(const nsACString& aVolumeName, @@ -132,6 +139,8 @@ private: bool mIsSharing; bool mIsFormatting; bool mIsUnmounting; + bool mIsRemovable; + bool mIsHotSwappable; uint32_t mId; // Unique ID (used by MTP) static VolumeObserverList sEventObserverList; diff --git a/dom/system/gonk/VolumeManager.cpp b/dom/system/gonk/VolumeManager.cpp index 66d2ae943ad..68ba0f8245b 100644 --- a/dom/system/gonk/VolumeManager.cpp +++ b/dom/system/gonk/VolumeManager.cpp @@ -168,12 +168,12 @@ void VolumeManager::InitConfig() // // The format of the volume.cfg file is as follows: // create volume-name mount-point + // configure volume-name preference preference-value // Blank lines and lines starting with the hash character "#" will be ignored. ScopedCloseFile fp; int n = 0; char line[255]; - char *command, *volNamePtr, *mountPointPtr, *save_ptr; const char *filename = "/system/etc/volume.cfg"; if (!(fp = fopen(filename, "r"))) { LOG("Unable to open volume configuration file '%s' - ignoring", filename); @@ -185,27 +185,87 @@ void VolumeManager::InitConfig() if (line[0] == '#') continue; - if (!(command = strtok_r(line, delim, &save_ptr))) { + + nsCString commandline(line); + nsCWhitespaceTokenizer tokenizer(commandline); + if (!tokenizer.hasMoreTokens()) { // Blank line - ignore continue; } - if (!strcmp(command, "create")) { - if (!(volNamePtr = strtok_r(nullptr, delim, &save_ptr))) { + + nsCString command(tokenizer.nextToken()); + if (command.EqualsLiteral("create")) { + if (!tokenizer.hasMoreTokens()) { ERR("No vol_name in %s line %d", filename, n); continue; } - if (!(mountPointPtr = strtok_r(nullptr, delim, &save_ptr))) { - ERR("No mount point for volume '%s'. %s line %d", volNamePtr, filename, n); + nsCString volName(tokenizer.nextToken()); + if (!tokenizer.hasMoreTokens()) { + ERR("No mount point for volume '%s'. %s line %d", + volName.get(), filename, n); continue; } - nsCString mountPoint(mountPointPtr); - nsCString volName(volNamePtr); - + nsCString mountPoint(tokenizer.nextToken()); RefPtr vol = FindAddVolumeByName(volName); vol->SetFakeVolume(mountPoint); + continue; } - else { - ERR("Unrecognized command: '%s'", command); + if (command.EqualsLiteral("configure")) { + if (!tokenizer.hasMoreTokens()) { + ERR("No vol_name in %s line %d", filename, n); + continue; + } + nsCString volName(tokenizer.nextToken()); + if (!tokenizer.hasMoreTokens()) { + ERR("No configuration name specified for volume '%s'. %s line %d", + volName.get(), filename, n); + continue; + } + nsCString configName(tokenizer.nextToken()); + if (!tokenizer.hasMoreTokens()) { + ERR("No value for configuration name '%s'. %s line %d", + configName.get(), filename, n); + continue; + } + nsCString configValue(tokenizer.nextToken()); + RefPtr vol = FindVolumeByName(volName); + if (vol) { + vol->SetConfig(configName, configValue); + } else { + ERR("Invalid volume name '%s'.", volName.get()); + } + continue; + } + ERR("Unrecognized command: '%s'", command.get()); + } +} + +void +VolumeManager::DefaultConfig() +{ + + VolumeManager::VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); + if (numVolumes == 0) { + return; + } + if (numVolumes == 1) { + // This is to cover early shipping phones like the Buri, + // which had no internal storage, and only external sdcard. + // + // Phones line the nexus-4 which only have an internal + // storage area will need to have a volume.cfg file with + // removable set to false. + RefPtr vol = VolumeManager::GetVolume(0); + vol->SetIsRemovable(true); + vol->SetIsHotSwappable(true); + return; + } + VolumeManager::VolumeArray::index_type volIndex; + for (volIndex = 0; volIndex < numVolumes; volIndex++) { + RefPtr vol = VolumeManager::GetVolume(volIndex); + if (!vol->Name().EqualsLiteral("sdcard")) { + vol->SetIsRemovable(true); + vol->SetIsHotSwappable(true); } } } @@ -233,6 +293,7 @@ class VolumeListCallback : public VolumeResponseCallback // We've received the list of volumes. Now read the Volume.cfg // file to perform customizations, and then tell everybody // that we're ready for business. + VolumeManager::DefaultConfig(); VolumeManager::InitConfig(); VolumeManager::Dump("READY"); VolumeManager::SetState(VolumeManager::VOLUMES_READY); diff --git a/dom/system/gonk/VolumeManager.h b/dom/system/gonk/VolumeManager.h index 1b97393b10c..b5ba082d218 100644 --- a/dom/system/gonk/VolumeManager.h +++ b/dom/system/gonk/VolumeManager.h @@ -138,6 +138,8 @@ protected: virtual void OnFileCanWriteWithoutBlocking(int aFd); virtual void OnError(); + static void DefaultConfig(); + private: bool OpenSocket(); diff --git a/dom/system/gonk/nsIVolume.idl b/dom/system/gonk/nsIVolume.idl index b7327436e15..01e2c5227fd 100644 --- a/dom/system/gonk/nsIVolume.idl +++ b/dom/system/gonk/nsIVolume.idl @@ -5,7 +5,7 @@ #include "nsISupports.idl" #include "nsIVolumeStat.idl" -[scriptable, uuid(9B5E27F4-601C-11E4-B541-3E2D1D5D46B0)] +[scriptable, uuid(946B5334-6EC9-11E4-8689-F3061E5D46B0)] interface nsIVolume : nsISupports { // These MUST match the states from android's system/vold/Volume.h header @@ -86,6 +86,13 @@ interface nsIVolume : nsISupports // Whether this is a fake volume. readonly attribute boolean isFake; + + // Whether this is a removable volume + readonly attribute boolean isRemovable; + + // Whether this is a hot-swappable volume + readonly attribute boolean isHotSwappable; + }; %{C++ diff --git a/dom/system/gonk/nsVolume.cpp b/dom/system/gonk/nsVolume.cpp index 25848b916da..6f005001387 100644 --- a/dom/system/gonk/nsVolume.cpp +++ b/dom/system/gonk/nsVolume.cpp @@ -59,7 +59,9 @@ nsVolume::nsVolume(const Volume* aVolume) mIsMediaPresent(aVolume->MediaPresent()), mIsSharing(aVolume->IsSharing()), mIsFormatting(aVolume->IsFormatting()), - mIsUnmounting(aVolume->IsUnmounting()) + mIsUnmounting(aVolume->IsUnmounting()), + mIsRemovable(aVolume->IsRemovable()), + mIsHotSwappable(aVolume->IsHotSwappable()) { } @@ -119,6 +121,18 @@ bool nsVolume::Equals(nsIVolume* aVolume) return false; } + bool isRemovable; + aVolume->GetIsRemovable(&isRemovable); + if (mIsRemovable != isRemovable) { + return false; + } + + bool isHotSwappable; + aVolume->GetIsHotSwappable(&isHotSwappable); + if (mIsHotSwappable != isHotSwappable) { + return false; + } + return true; } @@ -200,6 +214,18 @@ NS_IMETHODIMP nsVolume::GetIsFake(bool *aIsFake) 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_GetProcessType() == GeckoProcessType_Default); @@ -277,11 +303,12 @@ 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", + "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)IsFormatting(), (int)IsUnmounting(), + (int)IsRemovable(), (int)IsHotSwappable()); return; } @@ -300,6 +327,8 @@ void nsVolume::Set(nsIVolume* aVolume) aVolume->GetIsSharing(&mIsSharing); aVolume->GetIsFormatting(&mIsFormatting); aVolume->GetIsUnmounting(&mIsUnmounting); + aVolume->GetIsRemovable(&mIsRemovable); + aVolume->GetIsHotSwappable(&mIsHotSwappable); int32_t volMountGeneration; aVolume->GetMountGeneration(&volMountGeneration); @@ -377,6 +406,24 @@ nsVolume::SetIsFake(bool aIsFake) } } +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) { diff --git a/dom/system/gonk/nsVolume.h b/dom/system/gonk/nsVolume.h index 049ccea5542..a902fe83b8c 100644 --- a/dom/system/gonk/nsVolume.h +++ b/dom/system/gonk/nsVolume.h @@ -31,7 +31,8 @@ public: const int32_t& aState, const int32_t& aMountGeneration, const bool& aIsMediaPresent, const bool& aIsSharing, const bool& aIsFormatting, const bool& aIsFake, - const bool& aIsUnmounting) + const bool& aIsUnmounting, const bool& aIsRemovable, + const bool& aIsHotSwappable) : mName(aName), mMountPoint(aMountPoint), mState(aState), @@ -41,7 +42,9 @@ public: mIsMediaPresent(aIsMediaPresent), mIsSharing(aIsSharing), mIsFormatting(aIsFormatting), - mIsUnmounting(aIsUnmounting) + mIsUnmounting(aIsUnmounting), + mIsRemovable(aIsRemovable), + mIsHotSwappable(aIsHotSwappable) { } @@ -56,7 +59,9 @@ public: mIsMediaPresent(false), mIsSharing(false), mIsFormatting(false), - mIsUnmounting(false) + mIsUnmounting(false), + mIsRemovable(false), + mIsHotSwappable(false) { } @@ -82,6 +87,8 @@ public: bool IsSharing() const { return mIsSharing; } bool IsFormatting() const { return mIsFormatting; } bool IsUnmounting() const { return mIsUnmounting; } + bool IsRemovable() const { return mIsRemovable; } + bool IsHotSwappable() const { return mIsHotSwappable; } typedef nsTArray > Array; @@ -93,6 +100,8 @@ private: void UpdateMountLock(bool aMountLocked); void SetIsFake(bool aIsFake); + void SetIsRemovable(bool aIsRemovable); + void SetIsHotSwappable(bool aIsHotSwappble); void SetState(int32_t aState); static void FormatVolumeIOThread(const nsCString& aVolume); static void MountVolumeIOThread(const nsCString& aVolume); @@ -108,6 +117,8 @@ private: bool mIsSharing; bool mIsFormatting; bool mIsUnmounting; + bool mIsRemovable; + bool mIsHotSwappable; }; } // system diff --git a/dom/system/gonk/nsVolumeService.cpp b/dom/system/gonk/nsVolumeService.cpp index bf1fa8e79cd..ca85a384690 100644 --- a/dom/system/gonk/nsVolumeService.cpp +++ b/dom/system/gonk/nsVolumeService.cpp @@ -210,7 +210,9 @@ nsVolumeService::CreateOrGetVolumeByPath(const nsAString& aPath, nsIVolume** aRe false /* isSharing */, false /* isFormatting */, true /* isFake */, - false /* isUnmounting*/); + false /* isUnmounting */, + false /* isRemovable */, + false /* isHotSwappable*/); vol.forget(aResult); return NS_OK; } @@ -272,6 +274,8 @@ nsVolumeService::GetVolumesForIPC(nsTArray* aResult) volInfo->isFormatting() = vol->mIsFormatting; volInfo->isFake() = vol->mIsFake; volInfo->isUnmounting() = vol->mIsUnmounting; + volInfo->isRemovable() = vol->mIsRemovable; + volInfo->isHotSwappable() = vol->mIsHotSwappable; } } @@ -300,7 +304,9 @@ nsVolumeService::GetVolumesFromParent() volInfo.isSharing(), volInfo.isFormatting(), volInfo.isFake(), - volInfo.isUnmounting()); + volInfo.isUnmounting(), + volInfo.isRemovable(), + volInfo.isHotSwappable()); UpdateVolume(vol, false); } } @@ -425,7 +431,9 @@ nsVolumeService::CreateFakeVolume(const nsAString& name, const nsAString& path) false /* isSharing */, false /* isFormatting */, true /* isFake */, - false /* isUnmounting */); + false /* isUnmounting */, + false /* isRemovable */, + false /* isHotSwappable */); vol->LogState(); UpdateVolume(vol.get()); return NS_OK; @@ -475,11 +483,12 @@ public: { MOZ_ASSERT(NS_IsMainThread()); DBG("UpdateVolumeRunnable::Run '%s' state %s gen %d locked %d " - "media %d sharing %d formatting %d unmounting %d", + "media %d sharing %d formatting %d unmounting %d removable %d hotswappable %d", mVolume->NameStr().get(), mVolume->StateStr(), mVolume->MountGeneration(), (int)mVolume->IsMountLocked(), (int)mVolume->IsMediaPresent(), mVolume->IsSharing(), - mVolume->IsFormatting(), mVolume->IsUnmounting()); + mVolume->IsFormatting(), mVolume->IsUnmounting(), + (int)mVolume->IsRemovable(), (int)mVolume->IsHotSwappable()); mVolumeService->UpdateVolume(mVolume); mVolumeService = nullptr; @@ -496,11 +505,12 @@ void nsVolumeService::UpdateVolumeIOThread(const Volume* aVolume) { DBG("UpdateVolumeIOThread: Volume '%s' state %s mount '%s' gen %d locked %d " - "media %d sharing %d formatting %d unmounting %d", + "media %d sharing %d formatting %d unmounting %d removable %d hotswappable %d", aVolume->NameStr(), aVolume->StateStr(), aVolume->MountPoint().get(), aVolume->MountGeneration(), (int)aVolume->IsMountLocked(), (int)aVolume->MediaPresent(), (int)aVolume->IsSharing(), - (int)aVolume->IsFormatting(), (int)mVolume->IsUnmounting()); + (int)aVolume->IsFormatting(), (int)mVolume->IsUnmounting(), + (int)aVolume->IsRemovable(), (int)mVolume->IsHotSwappable()); MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); NS_DispatchToMainThread(new UpdateVolumeRunnable(this, aVolume)); } diff --git a/dom/webidl/DeviceStorage.webidl b/dom/webidl/DeviceStorage.webidl index 4c4c32afa61..9016b02def1 100644 --- a/dom/webidl/DeviceStorage.webidl +++ b/dom/webidl/DeviceStorage.webidl @@ -82,6 +82,9 @@ interface DeviceStorage : EventTarget { // for storing new files. readonly attribute boolean default; + // Indicates if the storage area denoted by storageName is removable + readonly attribute boolean isRemovable; + [NewObject, Throws] // XXXbz what type does this really return? Promise getRoot();