1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/system/gonk/nsVolume.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,385 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "nsVolume.h" 1.9 + 1.10 +#include "base/message_loop.h" 1.11 +#include "nsIPowerManagerService.h" 1.12 +#include "nsISupportsUtils.h" 1.13 +#include "nsIVolume.h" 1.14 +#include "nsServiceManagerUtils.h" 1.15 +#include "nsThreadUtils.h" 1.16 +#include "nsVolumeStat.h" 1.17 +#include "nsXULAppAPI.h" 1.18 +#include "Volume.h" 1.19 +#include "AutoMounter.h" 1.20 +#include "VolumeManager.h" 1.21 + 1.22 +#define VOLUME_MANAGER_LOG_TAG "nsVolume" 1.23 +#include "VolumeManagerLog.h" 1.24 + 1.25 +namespace mozilla { 1.26 +namespace system { 1.27 + 1.28 +const char * 1.29 +NS_VolumeStateStr(int32_t aState) 1.30 +{ 1.31 + switch (aState) { 1.32 + case nsIVolume::STATE_INIT: return "Init"; 1.33 + case nsIVolume::STATE_NOMEDIA: return "NoMedia"; 1.34 + case nsIVolume::STATE_IDLE: return "Idle"; 1.35 + case nsIVolume::STATE_PENDING: return "Pending"; 1.36 + case nsIVolume::STATE_CHECKING: return "Checking"; 1.37 + case nsIVolume::STATE_MOUNTED: return "Mounted"; 1.38 + case nsIVolume::STATE_UNMOUNTING: return "Unmounting"; 1.39 + case nsIVolume::STATE_FORMATTING: return "Formatting"; 1.40 + case nsIVolume::STATE_SHARED: return "Shared"; 1.41 + case nsIVolume::STATE_SHAREDMNT: return "Shared-Mounted"; 1.42 + } 1.43 + return "???"; 1.44 +} 1.45 + 1.46 +// While nsVolumes can only be used on the main thread, in the 1.47 +// UpdateVolumeRunnable constructor (which is called from IOThread) we 1.48 +// allocate an nsVolume which is then passed to MainThread. Since we 1.49 +// have a situation where we allocate on one thread and free on another 1.50 +// we use a thread safe AddRef implementation. 1.51 +NS_IMPL_ISUPPORTS(nsVolume, nsIVolume) 1.52 + 1.53 +nsVolume::nsVolume(const Volume* aVolume) 1.54 + : mName(NS_ConvertUTF8toUTF16(aVolume->Name())), 1.55 + mMountPoint(NS_ConvertUTF8toUTF16(aVolume->MountPoint())), 1.56 + mState(aVolume->State()), 1.57 + mMountGeneration(aVolume->MountGeneration()), 1.58 + mMountLocked(aVolume->IsMountLocked()), 1.59 + mIsFake(false), 1.60 + mIsMediaPresent(aVolume->MediaPresent()), 1.61 + mIsSharing(aVolume->IsSharing()), 1.62 + mIsFormatting(aVolume->IsFormatting()) 1.63 +{ 1.64 +} 1.65 + 1.66 +bool nsVolume::Equals(nsIVolume* aVolume) 1.67 +{ 1.68 + nsString volName; 1.69 + aVolume->GetName(volName); 1.70 + if (!mName.Equals(volName)) { 1.71 + return false; 1.72 + } 1.73 + 1.74 + nsString volMountPoint; 1.75 + aVolume->GetMountPoint(volMountPoint); 1.76 + if (!mMountPoint.Equals(volMountPoint)) { 1.77 + return false; 1.78 + } 1.79 + 1.80 + int32_t volState; 1.81 + aVolume->GetState(&volState); 1.82 + if (mState != volState){ 1.83 + return false; 1.84 + } 1.85 + 1.86 + int32_t volMountGeneration; 1.87 + aVolume->GetMountGeneration(&volMountGeneration); 1.88 + if (mMountGeneration != volMountGeneration) { 1.89 + return false; 1.90 + } 1.91 + 1.92 + bool volIsMountLocked; 1.93 + aVolume->GetIsMountLocked(&volIsMountLocked); 1.94 + if (mMountLocked != volIsMountLocked) { 1.95 + return false; 1.96 + } 1.97 + 1.98 + bool isFake; 1.99 + aVolume->GetIsFake(&isFake); 1.100 + if (mIsFake != isFake) { 1.101 + return false; 1.102 + } 1.103 + 1.104 + bool isSharing; 1.105 + aVolume->GetIsSharing(&isSharing); 1.106 + if (mIsSharing != isSharing) { 1.107 + return false; 1.108 + } 1.109 + 1.110 + bool isFormatting; 1.111 + aVolume->GetIsFormatting(&isFormatting); 1.112 + if (mIsFormatting != isFormatting) { 1.113 + return false; 1.114 + } 1.115 + 1.116 + return true; 1.117 +} 1.118 + 1.119 +NS_IMETHODIMP nsVolume::GetIsMediaPresent(bool *aIsMediaPresent) 1.120 +{ 1.121 + *aIsMediaPresent = mIsMediaPresent; 1.122 + return NS_OK; 1.123 +} 1.124 + 1.125 +NS_IMETHODIMP nsVolume::GetIsMountLocked(bool *aIsMountLocked) 1.126 +{ 1.127 + *aIsMountLocked = mMountLocked; 1.128 + return NS_OK; 1.129 +} 1.130 + 1.131 +NS_IMETHODIMP nsVolume::GetIsSharing(bool *aIsSharing) 1.132 +{ 1.133 + *aIsSharing = mIsSharing; 1.134 + return NS_OK; 1.135 +} 1.136 + 1.137 +NS_IMETHODIMP nsVolume::GetIsFormatting(bool *aIsFormatting) 1.138 +{ 1.139 + *aIsFormatting = mIsFormatting; 1.140 + return NS_OK; 1.141 +} 1.142 + 1.143 +NS_IMETHODIMP nsVolume::GetName(nsAString& aName) 1.144 +{ 1.145 + aName = mName; 1.146 + return NS_OK; 1.147 +} 1.148 + 1.149 +NS_IMETHODIMP nsVolume::GetMountGeneration(int32_t* aMountGeneration) 1.150 +{ 1.151 + *aMountGeneration = mMountGeneration; 1.152 + return NS_OK; 1.153 +} 1.154 + 1.155 +NS_IMETHODIMP nsVolume::GetMountLockName(nsAString& aMountLockName) 1.156 +{ 1.157 + aMountLockName = NS_LITERAL_STRING("volume-") + Name(); 1.158 + aMountLockName.AppendPrintf("-%d", mMountGeneration); 1.159 + 1.160 + return NS_OK; 1.161 +} 1.162 + 1.163 +NS_IMETHODIMP nsVolume::GetMountPoint(nsAString& aMountPoint) 1.164 +{ 1.165 + aMountPoint = mMountPoint; 1.166 + return NS_OK; 1.167 +} 1.168 + 1.169 +NS_IMETHODIMP nsVolume::GetState(int32_t* aState) 1.170 +{ 1.171 + *aState = mState; 1.172 + return NS_OK; 1.173 +} 1.174 + 1.175 +NS_IMETHODIMP nsVolume::GetStats(nsIVolumeStat **aResult) 1.176 +{ 1.177 + if (mState != STATE_MOUNTED) { 1.178 + return NS_ERROR_NOT_AVAILABLE; 1.179 + } 1.180 + 1.181 + NS_IF_ADDREF(*aResult = new nsVolumeStat(mMountPoint)); 1.182 + return NS_OK; 1.183 +} 1.184 + 1.185 +NS_IMETHODIMP nsVolume::GetIsFake(bool *aIsFake) 1.186 +{ 1.187 + *aIsFake = mIsFake; 1.188 + return NS_OK; 1.189 +} 1.190 + 1.191 +NS_IMETHODIMP nsVolume::Format() 1.192 +{ 1.193 + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); 1.194 + 1.195 + XRE_GetIOMessageLoop()->PostTask( 1.196 + FROM_HERE, 1.197 + NewRunnableFunction(FormatVolumeIOThread, NameStr())); 1.198 + 1.199 + return NS_OK; 1.200 +} 1.201 + 1.202 +/* static */ 1.203 +void nsVolume::FormatVolumeIOThread(const nsCString& aVolume) 1.204 +{ 1.205 + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); 1.206 + 1.207 + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); 1.208 + if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { 1.209 + return; 1.210 + } 1.211 + 1.212 + AutoMounterFormatVolume(aVolume); 1.213 +} 1.214 + 1.215 +NS_IMETHODIMP nsVolume::Mount() 1.216 +{ 1.217 + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); 1.218 + 1.219 + XRE_GetIOMessageLoop()->PostTask( 1.220 + FROM_HERE, 1.221 + NewRunnableFunction(MountVolumeIOThread, NameStr())); 1.222 + 1.223 + return NS_OK; 1.224 +} 1.225 + 1.226 +/* static */ 1.227 +void nsVolume::MountVolumeIOThread(const nsCString& aVolume) 1.228 +{ 1.229 + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); 1.230 + 1.231 + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); 1.232 + if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { 1.233 + return; 1.234 + } 1.235 + 1.236 + AutoMounterMountVolume(aVolume); 1.237 +} 1.238 + 1.239 +NS_IMETHODIMP nsVolume::Unmount() 1.240 +{ 1.241 + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); 1.242 + 1.243 + XRE_GetIOMessageLoop()->PostTask( 1.244 + FROM_HERE, 1.245 + NewRunnableFunction(UnmountVolumeIOThread, NameStr())); 1.246 + 1.247 + return NS_OK; 1.248 +} 1.249 + 1.250 +/* static */ 1.251 +void nsVolume::UnmountVolumeIOThread(const nsCString& aVolume) 1.252 +{ 1.253 + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); 1.254 + 1.255 + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); 1.256 + if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { 1.257 + return; 1.258 + } 1.259 + 1.260 + AutoMounterUnmountVolume(aVolume); 1.261 +} 1.262 + 1.263 +void 1.264 +nsVolume::LogState() const 1.265 +{ 1.266 + if (mState == nsIVolume::STATE_MOUNTED) { 1.267 + LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d " 1.268 + "media %d sharing %d formatting %d", 1.269 + NameStr().get(), StateStr(), MountPointStr().get(), 1.270 + MountGeneration(), (int)IsMountLocked(), (int)IsFake(), 1.271 + (int)IsMediaPresent(), (int)IsSharing(), 1.272 + (int)IsFormatting()); 1.273 + return; 1.274 + } 1.275 + 1.276 + LOG("nsVolume: %s state %s", NameStr().get(), StateStr()); 1.277 +} 1.278 + 1.279 +void nsVolume::Set(nsIVolume* aVolume) 1.280 +{ 1.281 + MOZ_ASSERT(NS_IsMainThread()); 1.282 + 1.283 + aVolume->GetName(mName); 1.284 + aVolume->GetMountPoint(mMountPoint); 1.285 + aVolume->GetState(&mState); 1.286 + aVolume->GetIsFake(&mIsFake); 1.287 + aVolume->GetIsMediaPresent(&mIsMediaPresent); 1.288 + aVolume->GetIsSharing(&mIsSharing); 1.289 + aVolume->GetIsFormatting(&mIsFormatting); 1.290 + 1.291 + int32_t volMountGeneration; 1.292 + aVolume->GetMountGeneration(&volMountGeneration); 1.293 + 1.294 + if (mState != nsIVolume::STATE_MOUNTED) { 1.295 + // Since we're not in the mounted state, we need to 1.296 + // forgot whatever mount generation we may have had. 1.297 + mMountGeneration = -1; 1.298 + return; 1.299 + } 1.300 + if (mMountGeneration == volMountGeneration) { 1.301 + // No change in mount generation, nothing else to do 1.302 + return; 1.303 + } 1.304 + 1.305 + mMountGeneration = volMountGeneration; 1.306 + 1.307 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.308 + // Child processes just track the state, not maintain it. 1.309 + aVolume->GetIsMountLocked(&mMountLocked); 1.310 + return; 1.311 + } 1.312 + 1.313 + // Notify the Volume on IOThread whether the volume is locked or not. 1.314 + nsCOMPtr<nsIPowerManagerService> pmService = 1.315 + do_GetService(POWERMANAGERSERVICE_CONTRACTID); 1.316 + if (!pmService) { 1.317 + return; 1.318 + } 1.319 + nsString mountLockName; 1.320 + GetMountLockName(mountLockName); 1.321 + nsString mountLockState; 1.322 + pmService->GetWakeLockState(mountLockName, mountLockState); 1.323 + UpdateMountLock(mountLockState); 1.324 +} 1.325 + 1.326 +void 1.327 +nsVolume::UpdateMountLock(const nsAString& aMountLockState) 1.328 +{ 1.329 + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); 1.330 + MOZ_ASSERT(NS_IsMainThread()); 1.331 + 1.332 + // There are 3 states, unlocked, locked-background, and locked-foreground 1.333 + // I figured it was easier to use negtive logic and compare for unlocked. 1.334 + UpdateMountLock(!aMountLockState.EqualsLiteral("unlocked")); 1.335 +} 1.336 + 1.337 +void 1.338 +nsVolume::UpdateMountLock(bool aMountLocked) 1.339 +{ 1.340 + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); 1.341 + MOZ_ASSERT(NS_IsMainThread()); 1.342 + 1.343 + if (aMountLocked == mMountLocked) { 1.344 + return; 1.345 + } 1.346 + // The locked/unlocked state changed. Tell IOThread about it. 1.347 + mMountLocked = aMountLocked; 1.348 + LogState(); 1.349 + XRE_GetIOMessageLoop()->PostTask( 1.350 + FROM_HERE, 1.351 + NewRunnableFunction(Volume::UpdateMountLock, 1.352 + NS_LossyConvertUTF16toASCII(Name()), 1.353 + MountGeneration(), aMountLocked)); 1.354 +} 1.355 + 1.356 +void 1.357 +nsVolume::SetIsFake(bool aIsFake) 1.358 +{ 1.359 + mIsFake = aIsFake; 1.360 + if (mIsFake) { 1.361 + // The media is always present for fake volumes. 1.362 + mIsMediaPresent = true; 1.363 + MOZ_ASSERT(!mIsSharing); 1.364 + } 1.365 +} 1.366 + 1.367 +void 1.368 +nsVolume::SetState(int32_t aState) 1.369 +{ 1.370 + static int32_t sMountGeneration = 0; 1.371 + 1.372 + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); 1.373 + MOZ_ASSERT(NS_IsMainThread()); 1.374 + MOZ_ASSERT(IsFake()); 1.375 + 1.376 + if (aState == mState) { 1.377 + return; 1.378 + } 1.379 + 1.380 + if (aState == nsIVolume::STATE_MOUNTED) { 1.381 + mMountGeneration = ++sMountGeneration; 1.382 + } 1.383 + 1.384 + mState = aState; 1.385 +} 1.386 + 1.387 +} // system 1.388 +} // mozilla