Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsVolume.h"
7 #include "base/message_loop.h"
8 #include "nsIPowerManagerService.h"
9 #include "nsISupportsUtils.h"
10 #include "nsIVolume.h"
11 #include "nsServiceManagerUtils.h"
12 #include "nsThreadUtils.h"
13 #include "nsVolumeStat.h"
14 #include "nsXULAppAPI.h"
15 #include "Volume.h"
16 #include "AutoMounter.h"
17 #include "VolumeManager.h"
19 #define VOLUME_MANAGER_LOG_TAG "nsVolume"
20 #include "VolumeManagerLog.h"
22 namespace mozilla {
23 namespace system {
25 const char *
26 NS_VolumeStateStr(int32_t aState)
27 {
28 switch (aState) {
29 case nsIVolume::STATE_INIT: return "Init";
30 case nsIVolume::STATE_NOMEDIA: return "NoMedia";
31 case nsIVolume::STATE_IDLE: return "Idle";
32 case nsIVolume::STATE_PENDING: return "Pending";
33 case nsIVolume::STATE_CHECKING: return "Checking";
34 case nsIVolume::STATE_MOUNTED: return "Mounted";
35 case nsIVolume::STATE_UNMOUNTING: return "Unmounting";
36 case nsIVolume::STATE_FORMATTING: return "Formatting";
37 case nsIVolume::STATE_SHARED: return "Shared";
38 case nsIVolume::STATE_SHAREDMNT: return "Shared-Mounted";
39 }
40 return "???";
41 }
43 // While nsVolumes can only be used on the main thread, in the
44 // UpdateVolumeRunnable constructor (which is called from IOThread) we
45 // allocate an nsVolume which is then passed to MainThread. Since we
46 // have a situation where we allocate on one thread and free on another
47 // we use a thread safe AddRef implementation.
48 NS_IMPL_ISUPPORTS(nsVolume, nsIVolume)
50 nsVolume::nsVolume(const Volume* aVolume)
51 : mName(NS_ConvertUTF8toUTF16(aVolume->Name())),
52 mMountPoint(NS_ConvertUTF8toUTF16(aVolume->MountPoint())),
53 mState(aVolume->State()),
54 mMountGeneration(aVolume->MountGeneration()),
55 mMountLocked(aVolume->IsMountLocked()),
56 mIsFake(false),
57 mIsMediaPresent(aVolume->MediaPresent()),
58 mIsSharing(aVolume->IsSharing()),
59 mIsFormatting(aVolume->IsFormatting())
60 {
61 }
63 bool nsVolume::Equals(nsIVolume* aVolume)
64 {
65 nsString volName;
66 aVolume->GetName(volName);
67 if (!mName.Equals(volName)) {
68 return false;
69 }
71 nsString volMountPoint;
72 aVolume->GetMountPoint(volMountPoint);
73 if (!mMountPoint.Equals(volMountPoint)) {
74 return false;
75 }
77 int32_t volState;
78 aVolume->GetState(&volState);
79 if (mState != volState){
80 return false;
81 }
83 int32_t volMountGeneration;
84 aVolume->GetMountGeneration(&volMountGeneration);
85 if (mMountGeneration != volMountGeneration) {
86 return false;
87 }
89 bool volIsMountLocked;
90 aVolume->GetIsMountLocked(&volIsMountLocked);
91 if (mMountLocked != volIsMountLocked) {
92 return false;
93 }
95 bool isFake;
96 aVolume->GetIsFake(&isFake);
97 if (mIsFake != isFake) {
98 return false;
99 }
101 bool isSharing;
102 aVolume->GetIsSharing(&isSharing);
103 if (mIsSharing != isSharing) {
104 return false;
105 }
107 bool isFormatting;
108 aVolume->GetIsFormatting(&isFormatting);
109 if (mIsFormatting != isFormatting) {
110 return false;
111 }
113 return true;
114 }
116 NS_IMETHODIMP nsVolume::GetIsMediaPresent(bool *aIsMediaPresent)
117 {
118 *aIsMediaPresent = mIsMediaPresent;
119 return NS_OK;
120 }
122 NS_IMETHODIMP nsVolume::GetIsMountLocked(bool *aIsMountLocked)
123 {
124 *aIsMountLocked = mMountLocked;
125 return NS_OK;
126 }
128 NS_IMETHODIMP nsVolume::GetIsSharing(bool *aIsSharing)
129 {
130 *aIsSharing = mIsSharing;
131 return NS_OK;
132 }
134 NS_IMETHODIMP nsVolume::GetIsFormatting(bool *aIsFormatting)
135 {
136 *aIsFormatting = mIsFormatting;
137 return NS_OK;
138 }
140 NS_IMETHODIMP nsVolume::GetName(nsAString& aName)
141 {
142 aName = mName;
143 return NS_OK;
144 }
146 NS_IMETHODIMP nsVolume::GetMountGeneration(int32_t* aMountGeneration)
147 {
148 *aMountGeneration = mMountGeneration;
149 return NS_OK;
150 }
152 NS_IMETHODIMP nsVolume::GetMountLockName(nsAString& aMountLockName)
153 {
154 aMountLockName = NS_LITERAL_STRING("volume-") + Name();
155 aMountLockName.AppendPrintf("-%d", mMountGeneration);
157 return NS_OK;
158 }
160 NS_IMETHODIMP nsVolume::GetMountPoint(nsAString& aMountPoint)
161 {
162 aMountPoint = mMountPoint;
163 return NS_OK;
164 }
166 NS_IMETHODIMP nsVolume::GetState(int32_t* aState)
167 {
168 *aState = mState;
169 return NS_OK;
170 }
172 NS_IMETHODIMP nsVolume::GetStats(nsIVolumeStat **aResult)
173 {
174 if (mState != STATE_MOUNTED) {
175 return NS_ERROR_NOT_AVAILABLE;
176 }
178 NS_IF_ADDREF(*aResult = new nsVolumeStat(mMountPoint));
179 return NS_OK;
180 }
182 NS_IMETHODIMP nsVolume::GetIsFake(bool *aIsFake)
183 {
184 *aIsFake = mIsFake;
185 return NS_OK;
186 }
188 NS_IMETHODIMP nsVolume::Format()
189 {
190 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
192 XRE_GetIOMessageLoop()->PostTask(
193 FROM_HERE,
194 NewRunnableFunction(FormatVolumeIOThread, NameStr()));
196 return NS_OK;
197 }
199 /* static */
200 void nsVolume::FormatVolumeIOThread(const nsCString& aVolume)
201 {
202 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
204 MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
205 if (VolumeManager::State() != VolumeManager::VOLUMES_READY) {
206 return;
207 }
209 AutoMounterFormatVolume(aVolume);
210 }
212 NS_IMETHODIMP nsVolume::Mount()
213 {
214 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
216 XRE_GetIOMessageLoop()->PostTask(
217 FROM_HERE,
218 NewRunnableFunction(MountVolumeIOThread, NameStr()));
220 return NS_OK;
221 }
223 /* static */
224 void nsVolume::MountVolumeIOThread(const nsCString& aVolume)
225 {
226 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
228 MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
229 if (VolumeManager::State() != VolumeManager::VOLUMES_READY) {
230 return;
231 }
233 AutoMounterMountVolume(aVolume);
234 }
236 NS_IMETHODIMP nsVolume::Unmount()
237 {
238 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
240 XRE_GetIOMessageLoop()->PostTask(
241 FROM_HERE,
242 NewRunnableFunction(UnmountVolumeIOThread, NameStr()));
244 return NS_OK;
245 }
247 /* static */
248 void nsVolume::UnmountVolumeIOThread(const nsCString& aVolume)
249 {
250 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
252 MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
253 if (VolumeManager::State() != VolumeManager::VOLUMES_READY) {
254 return;
255 }
257 AutoMounterUnmountVolume(aVolume);
258 }
260 void
261 nsVolume::LogState() const
262 {
263 if (mState == nsIVolume::STATE_MOUNTED) {
264 LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d "
265 "media %d sharing %d formatting %d",
266 NameStr().get(), StateStr(), MountPointStr().get(),
267 MountGeneration(), (int)IsMountLocked(), (int)IsFake(),
268 (int)IsMediaPresent(), (int)IsSharing(),
269 (int)IsFormatting());
270 return;
271 }
273 LOG("nsVolume: %s state %s", NameStr().get(), StateStr());
274 }
276 void nsVolume::Set(nsIVolume* aVolume)
277 {
278 MOZ_ASSERT(NS_IsMainThread());
280 aVolume->GetName(mName);
281 aVolume->GetMountPoint(mMountPoint);
282 aVolume->GetState(&mState);
283 aVolume->GetIsFake(&mIsFake);
284 aVolume->GetIsMediaPresent(&mIsMediaPresent);
285 aVolume->GetIsSharing(&mIsSharing);
286 aVolume->GetIsFormatting(&mIsFormatting);
288 int32_t volMountGeneration;
289 aVolume->GetMountGeneration(&volMountGeneration);
291 if (mState != nsIVolume::STATE_MOUNTED) {
292 // Since we're not in the mounted state, we need to
293 // forgot whatever mount generation we may have had.
294 mMountGeneration = -1;
295 return;
296 }
297 if (mMountGeneration == volMountGeneration) {
298 // No change in mount generation, nothing else to do
299 return;
300 }
302 mMountGeneration = volMountGeneration;
304 if (XRE_GetProcessType() != GeckoProcessType_Default) {
305 // Child processes just track the state, not maintain it.
306 aVolume->GetIsMountLocked(&mMountLocked);
307 return;
308 }
310 // Notify the Volume on IOThread whether the volume is locked or not.
311 nsCOMPtr<nsIPowerManagerService> pmService =
312 do_GetService(POWERMANAGERSERVICE_CONTRACTID);
313 if (!pmService) {
314 return;
315 }
316 nsString mountLockName;
317 GetMountLockName(mountLockName);
318 nsString mountLockState;
319 pmService->GetWakeLockState(mountLockName, mountLockState);
320 UpdateMountLock(mountLockState);
321 }
323 void
324 nsVolume::UpdateMountLock(const nsAString& aMountLockState)
325 {
326 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
327 MOZ_ASSERT(NS_IsMainThread());
329 // There are 3 states, unlocked, locked-background, and locked-foreground
330 // I figured it was easier to use negtive logic and compare for unlocked.
331 UpdateMountLock(!aMountLockState.EqualsLiteral("unlocked"));
332 }
334 void
335 nsVolume::UpdateMountLock(bool aMountLocked)
336 {
337 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
338 MOZ_ASSERT(NS_IsMainThread());
340 if (aMountLocked == mMountLocked) {
341 return;
342 }
343 // The locked/unlocked state changed. Tell IOThread about it.
344 mMountLocked = aMountLocked;
345 LogState();
346 XRE_GetIOMessageLoop()->PostTask(
347 FROM_HERE,
348 NewRunnableFunction(Volume::UpdateMountLock,
349 NS_LossyConvertUTF16toASCII(Name()),
350 MountGeneration(), aMountLocked));
351 }
353 void
354 nsVolume::SetIsFake(bool aIsFake)
355 {
356 mIsFake = aIsFake;
357 if (mIsFake) {
358 // The media is always present for fake volumes.
359 mIsMediaPresent = true;
360 MOZ_ASSERT(!mIsSharing);
361 }
362 }
364 void
365 nsVolume::SetState(int32_t aState)
366 {
367 static int32_t sMountGeneration = 0;
369 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
370 MOZ_ASSERT(NS_IsMainThread());
371 MOZ_ASSERT(IsFake());
373 if (aState == mState) {
374 return;
375 }
377 if (aState == nsIVolume::STATE_MOUNTED) {
378 mMountGeneration = ++sMountGeneration;
379 }
381 mState = aState;
382 }
384 } // system
385 } // mozilla