|
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/. */ |
|
4 |
|
5 #include "nsVolumeMountLock.h" |
|
6 |
|
7 #include "mozilla/dom/ContentChild.h" |
|
8 #include "mozilla/Services.h" |
|
9 |
|
10 #include "nsIObserverService.h" |
|
11 #include "nsIPowerManagerService.h" |
|
12 #include "nsIVolume.h" |
|
13 #include "nsIVolumeService.h" |
|
14 #include "nsString.h" |
|
15 #include "nsXULAppAPI.h" |
|
16 |
|
17 #define VOLUME_MANAGER_LOG_TAG "nsVolumeMountLock" |
|
18 #include "VolumeManagerLog.h" |
|
19 #include "nsServiceManagerUtils.h" |
|
20 #include "mozilla/dom/power/PowerManagerService.h" |
|
21 |
|
22 using namespace mozilla::dom; |
|
23 using namespace mozilla::services; |
|
24 |
|
25 namespace mozilla { |
|
26 namespace system { |
|
27 |
|
28 NS_IMPL_ISUPPORTS(nsVolumeMountLock, nsIVolumeMountLock, |
|
29 nsIObserver, nsISupportsWeakReference) |
|
30 |
|
31 // static |
|
32 already_AddRefed<nsVolumeMountLock> |
|
33 nsVolumeMountLock::Create(const nsAString& aVolumeName) |
|
34 { |
|
35 DBG("nsVolumeMountLock::Create called"); |
|
36 |
|
37 nsRefPtr<nsVolumeMountLock> mountLock = new nsVolumeMountLock(aVolumeName); |
|
38 nsresult rv = mountLock->Init(); |
|
39 NS_ENSURE_SUCCESS(rv, nullptr); |
|
40 |
|
41 return mountLock.forget(); |
|
42 } |
|
43 |
|
44 nsVolumeMountLock::nsVolumeMountLock(const nsAString& aVolumeName) |
|
45 : mVolumeName(aVolumeName), |
|
46 mVolumeGeneration(-1), |
|
47 mUnlocked(false) |
|
48 { |
|
49 } |
|
50 |
|
51 //virtual |
|
52 nsVolumeMountLock::~nsVolumeMountLock() |
|
53 { |
|
54 Unlock(); |
|
55 } |
|
56 |
|
57 nsresult nsVolumeMountLock::Init() |
|
58 { |
|
59 LOG("nsVolumeMountLock created for '%s'", |
|
60 NS_LossyConvertUTF16toASCII(mVolumeName).get()); |
|
61 |
|
62 // Add ourselves as an Observer. It's important that we use a weak |
|
63 // reference here. If we used a strong reference, then that reference |
|
64 // would prevent this object from being destructed. |
|
65 nsCOMPtr<nsIObserverService> obs = GetObserverService(); |
|
66 obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, true /*weak*/); |
|
67 |
|
68 // Request the sdcard info, so we know the state/generation without having |
|
69 // to wait for a state change. |
|
70 if (XRE_GetProcessType() == GeckoProcessType_Content) { |
|
71 ContentChild::GetSingleton()->SendBroadcastVolume(mVolumeName); |
|
72 return NS_OK; |
|
73 } |
|
74 nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); |
|
75 NS_ENSURE_TRUE(vs, NS_ERROR_FAILURE); |
|
76 |
|
77 vs->BroadcastVolume(mVolumeName); |
|
78 |
|
79 return NS_OK; |
|
80 } |
|
81 |
|
82 /* void unlock (); */ |
|
83 NS_IMETHODIMP nsVolumeMountLock::Unlock() |
|
84 { |
|
85 LOG("nsVolumeMountLock released for '%s'", |
|
86 NS_LossyConvertUTF16toASCII(mVolumeName).get()); |
|
87 |
|
88 mUnlocked = true; |
|
89 mWakeLock = nullptr; |
|
90 |
|
91 // While we don't really need to remove weak observers, we do so anyways |
|
92 // since it will reduce the number of times Observe gets called. |
|
93 nsCOMPtr<nsIObserverService> obs = GetObserverService(); |
|
94 obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED); |
|
95 return NS_OK; |
|
96 } |
|
97 |
|
98 NS_IMETHODIMP nsVolumeMountLock::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) |
|
99 { |
|
100 if (strcmp(aTopic, NS_VOLUME_STATE_CHANGED) != 0) { |
|
101 return NS_OK; |
|
102 } |
|
103 if (mUnlocked) { |
|
104 // We're not locked anymore, so we don't need to look at the notifications. |
|
105 return NS_OK; |
|
106 } |
|
107 |
|
108 nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject); |
|
109 if (!vol) { |
|
110 return NS_OK; |
|
111 } |
|
112 nsString volName; |
|
113 vol->GetName(volName); |
|
114 if (!volName.Equals(mVolumeName)) { |
|
115 return NS_OK; |
|
116 } |
|
117 int32_t state; |
|
118 nsresult rv = vol->GetState(&state); |
|
119 NS_ENSURE_SUCCESS(rv, rv); |
|
120 |
|
121 if (state != nsIVolume::STATE_MOUNTED) { |
|
122 mWakeLock = nullptr; |
|
123 mVolumeGeneration = -1; |
|
124 return NS_OK; |
|
125 } |
|
126 |
|
127 int32_t mountGeneration; |
|
128 rv = vol->GetMountGeneration(&mountGeneration); |
|
129 NS_ENSURE_SUCCESS(rv, rv); |
|
130 |
|
131 DBG("nsVolumeMountLock::Observe mountGeneration = %d mVolumeGeneration = %d", |
|
132 mountGeneration, mVolumeGeneration); |
|
133 |
|
134 if (mVolumeGeneration == mountGeneration) { |
|
135 return NS_OK; |
|
136 } |
|
137 |
|
138 // The generation changed, which means that any wakelock we may have |
|
139 // been holding is now invalid. Grab a new wakelock for the new generation |
|
140 // number. |
|
141 |
|
142 mWakeLock = nullptr; |
|
143 mVolumeGeneration = mountGeneration; |
|
144 |
|
145 nsRefPtr<power::PowerManagerService> pmService = |
|
146 power::PowerManagerService::GetInstance(); |
|
147 NS_ENSURE_TRUE(pmService, NS_ERROR_FAILURE); |
|
148 |
|
149 nsString mountLockName; |
|
150 vol->GetMountLockName(mountLockName); |
|
151 |
|
152 ErrorResult err; |
|
153 mWakeLock = pmService->NewWakeLock(mountLockName, nullptr, err); |
|
154 if (err.Failed()) { |
|
155 return err.ErrorCode(); |
|
156 } |
|
157 |
|
158 LOG("nsVolumeMountLock acquired for '%s' gen %d", |
|
159 NS_LossyConvertUTF16toASCII(mVolumeName).get(), mVolumeGeneration); |
|
160 return NS_OK; |
|
161 } |
|
162 |
|
163 } // namespace system |
|
164 } // namespace mozilla |