1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=8 et ft=cpp : */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "Hal.h"
8 : #include "HalImpl.h"
9 : #include "HalSandbox.h"
10 : #include "mozilla/Util.h"
11 : #include "nsThreadUtils.h"
12 : #include "nsXULAppAPI.h"
13 : #include "mozilla/Observer.h"
14 : #include "nsIDOMDocument.h"
15 : #include "nsIDOMWindow.h"
16 : #include "mozilla/Services.h"
17 : #include "nsIWebNavigation.h"
18 : #include "nsITabChild.h"
19 : #include "nsIDocShell.h"
20 : #include "mozilla/ClearOnShutdown.h"
21 : #include "WindowIdentifier.h"
22 :
23 : using namespace mozilla::services;
24 :
25 : #define PROXY_IF_SANDBOXED(_call) \
26 : do { \
27 : if (InSandbox()) { \
28 : hal_sandbox::_call; \
29 : } else { \
30 : hal_impl::_call; \
31 : } \
32 : } while (0)
33 :
34 : #define RETURN_PROXY_IF_SANDBOXED(_call) \
35 : do { \
36 : if (InSandbox()) { \
37 : return hal_sandbox::_call; \
38 : } else { \
39 : return hal_impl::_call; \
40 : } \
41 : } while (0)
42 :
43 : namespace mozilla {
44 : namespace hal {
45 :
46 1464 : PRLogModuleInfo *sHalLog = PR_LOG_DEFINE("hal");
47 :
48 : namespace {
49 :
50 : void
51 0 : AssertMainThread()
52 : {
53 0 : MOZ_ASSERT(NS_IsMainThread());
54 0 : }
55 :
56 : bool
57 0 : InSandbox()
58 : {
59 0 : return GeckoProcessType_Content == XRE_GetProcessType();
60 : }
61 :
62 : bool
63 0 : WindowIsActive(nsIDOMWindow *window)
64 : {
65 0 : NS_ENSURE_TRUE(window, false);
66 :
67 0 : nsCOMPtr<nsIDOMDocument> doc;
68 0 : window->GetDocument(getter_AddRefs(doc));
69 0 : NS_ENSURE_TRUE(doc, false);
70 :
71 0 : bool hidden = true;
72 0 : doc->GetMozHidden(&hidden);
73 0 : return !hidden;
74 : }
75 :
76 1464 : nsAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
77 :
78 0 : void InitLastIDToVibrate()
79 : {
80 0 : gLastIDToVibrate = new WindowIdentifier::IDArrayType();
81 0 : ClearOnShutdown(&gLastIDToVibrate);
82 0 : }
83 :
84 : } // anonymous namespace
85 :
86 : void
87 0 : Vibrate(const nsTArray<uint32>& pattern, nsIDOMWindow* window)
88 : {
89 0 : Vibrate(pattern, WindowIdentifier(window));
90 0 : }
91 :
92 : void
93 0 : Vibrate(const nsTArray<uint32>& pattern, const WindowIdentifier &id)
94 : {
95 0 : AssertMainThread();
96 :
97 : // Only active windows may start vibrations. If |id| hasn't gone
98 : // through the IPC layer -- that is, if our caller is the outside
99 : // world, not hal_proxy -- check whether the window is active. If
100 : // |id| has gone through IPC, don't check the window's visibility;
101 : // only the window corresponding to the bottommost process has its
102 : // visibility state set correctly.
103 0 : if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
104 0 : HAL_LOG(("Vibrate: Window is inactive, dropping vibrate."));
105 0 : return;
106 : }
107 :
108 0 : if (InSandbox()) {
109 0 : hal_sandbox::Vibrate(pattern, id);
110 : }
111 : else {
112 0 : if (!gLastIDToVibrate)
113 0 : InitLastIDToVibrate();
114 0 : *gLastIDToVibrate = id.AsArray();
115 :
116 0 : HAL_LOG(("Vibrate: Forwarding to hal_impl."));
117 :
118 : // hal_impl doesn't need |id|. Send it an empty id, which will
119 : // assert if it's used.
120 0 : hal_impl::Vibrate(pattern, WindowIdentifier());
121 : }
122 : }
123 :
124 : void
125 0 : CancelVibrate(nsIDOMWindow* window)
126 : {
127 0 : CancelVibrate(WindowIdentifier(window));
128 0 : }
129 :
130 : void
131 0 : CancelVibrate(const WindowIdentifier &id)
132 : {
133 0 : AssertMainThread();
134 :
135 : // Although only active windows may start vibrations, a window may
136 : // cancel its own vibration even if it's no longer active.
137 : //
138 : // After a window is marked as inactive, it sends a CancelVibrate
139 : // request. We want this request to cancel a playing vibration
140 : // started by that window, so we certainly don't want to reject the
141 : // cancellation request because the window is now inactive.
142 : //
143 : // But it could be the case that, after this window became inactive,
144 : // some other window came along and started a vibration. We don't
145 : // want this window's cancellation request to cancel that window's
146 : // actively-playing vibration!
147 : //
148 : // To solve this problem, we keep track of the id of the last window
149 : // to start a vibration, and only accepts cancellation requests from
150 : // the same window. All other cancellation requests are ignored.
151 :
152 0 : if (InSandbox()) {
153 0 : hal_sandbox::CancelVibrate(id);
154 : }
155 0 : else if (*gLastIDToVibrate == id.AsArray()) {
156 : // Don't forward our ID to hal_impl. It doesn't need it, and we
157 : // don't want it to be tempted to read it. The empty identifier
158 : // will assert if it's used.
159 0 : HAL_LOG(("CancelVibrate: Forwarding to hal_impl."));
160 0 : hal_impl::CancelVibrate(WindowIdentifier());
161 : }
162 0 : }
163 :
164 : template <class InfoType>
165 : class ObserversManager
166 4392 : {
167 : public:
168 0 : void AddObserver(Observer<InfoType>* aObserver) {
169 0 : if (!mObservers) {
170 0 : mObservers = new mozilla::ObserverList<InfoType>();
171 : }
172 :
173 0 : mObservers->AddObserver(aObserver);
174 :
175 0 : if (mObservers->Length() == 1) {
176 0 : EnableNotifications();
177 : }
178 0 : }
179 :
180 0 : void RemoveObserver(Observer<InfoType>* aObserver) {
181 0 : MOZ_ASSERT(mObservers);
182 0 : mObservers->RemoveObserver(aObserver);
183 :
184 0 : if (mObservers->Length() == 0) {
185 0 : DisableNotifications();
186 :
187 0 : OnNotificationsDisabled();
188 :
189 0 : delete mObservers;
190 0 : mObservers = 0;
191 : }
192 0 : }
193 :
194 0 : void BroadcastInformation(const InfoType& aInfo) {
195 0 : MOZ_ASSERT(mObservers);
196 0 : mObservers->Broadcast(aInfo);
197 0 : }
198 :
199 : protected:
200 : virtual void EnableNotifications() = 0;
201 : virtual void DisableNotifications() = 0;
202 0 : virtual void OnNotificationsDisabled() {}
203 :
204 : private:
205 : mozilla::ObserverList<InfoType>* mObservers;
206 : };
207 :
208 : template <class InfoType>
209 : class CachingObserversManager : public ObserversManager<InfoType>
210 5902 : {
211 : public:
212 0 : InfoType GetCurrentInformation() {
213 0 : if (mHasValidCache) {
214 0 : return mInfo;
215 : }
216 :
217 0 : GetCurrentInformationInternal(&mInfo);
218 0 : return mInfo;
219 : }
220 :
221 0 : void CacheInformation(const InfoType& aInfo) {
222 0 : mHasValidCache = true;
223 0 : mInfo = aInfo;
224 0 : }
225 :
226 0 : void BroadcastCachedInformation() {
227 0 : this->BroadcastInformation(mInfo);
228 0 : }
229 :
230 : protected:
231 : virtual void GetCurrentInformationInternal(InfoType*) = 0;
232 :
233 0 : virtual void OnNotificationsDisabled() {
234 0 : mHasValidCache = false;
235 0 : }
236 :
237 : private:
238 : InfoType mInfo;
239 : bool mHasValidCache;
240 : };
241 :
242 : class BatteryObserversManager : public CachingObserversManager<BatteryInformation>
243 2951 : {
244 : protected:
245 0 : void EnableNotifications() {
246 0 : PROXY_IF_SANDBOXED(EnableBatteryNotifications());
247 0 : }
248 :
249 0 : void DisableNotifications() {
250 0 : PROXY_IF_SANDBOXED(DisableBatteryNotifications());
251 0 : }
252 :
253 0 : void GetCurrentInformationInternal(BatteryInformation* aInfo) {
254 0 : PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
255 0 : }
256 : };
257 :
258 1464 : static BatteryObserversManager sBatteryObservers;
259 :
260 : class NetworkObserversManager : public CachingObserversManager<NetworkInformation>
261 2951 : {
262 : protected:
263 0 : void EnableNotifications() {
264 0 : PROXY_IF_SANDBOXED(EnableNetworkNotifications());
265 0 : }
266 :
267 0 : void DisableNotifications() {
268 0 : PROXY_IF_SANDBOXED(DisableNetworkNotifications());
269 0 : }
270 :
271 0 : void GetCurrentInformationInternal(NetworkInformation* aInfo) {
272 0 : PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
273 0 : }
274 : };
275 :
276 1464 : static NetworkObserversManager sNetworkObservers;
277 :
278 : class WakeLockObserversManager : public ObserversManager<WakeLockInformation>
279 1464 : {
280 : protected:
281 0 : void EnableNotifications() {
282 0 : PROXY_IF_SANDBOXED(EnableWakeLockNotifications());
283 0 : }
284 :
285 0 : void DisableNotifications() {
286 0 : PROXY_IF_SANDBOXED(DisableWakeLockNotifications());
287 0 : }
288 : };
289 :
290 1464 : static WakeLockObserversManager sWakeLockObservers;
291 :
292 : void
293 0 : RegisterBatteryObserver(BatteryObserver* aObserver)
294 : {
295 0 : AssertMainThread();
296 0 : sBatteryObservers.AddObserver(aObserver);
297 0 : }
298 :
299 : void
300 0 : UnregisterBatteryObserver(BatteryObserver* aObserver)
301 : {
302 0 : AssertMainThread();
303 0 : sBatteryObservers.RemoveObserver(aObserver);
304 0 : }
305 :
306 : void
307 0 : GetCurrentBatteryInformation(BatteryInformation* aInfo)
308 : {
309 0 : AssertMainThread();
310 0 : *aInfo = sBatteryObservers.GetCurrentInformation();
311 0 : }
312 :
313 : void
314 0 : NotifyBatteryChange(const BatteryInformation& aInfo)
315 : {
316 0 : AssertMainThread();
317 0 : sBatteryObservers.CacheInformation(aInfo);
318 0 : sBatteryObservers.BroadcastCachedInformation();
319 0 : }
320 :
321 0 : bool GetScreenEnabled()
322 : {
323 0 : AssertMainThread();
324 0 : RETURN_PROXY_IF_SANDBOXED(GetScreenEnabled());
325 : }
326 :
327 0 : void SetScreenEnabled(bool enabled)
328 : {
329 0 : AssertMainThread();
330 0 : PROXY_IF_SANDBOXED(SetScreenEnabled(enabled));
331 0 : }
332 :
333 0 : double GetScreenBrightness()
334 : {
335 0 : AssertMainThread();
336 0 : RETURN_PROXY_IF_SANDBOXED(GetScreenBrightness());
337 : }
338 :
339 0 : void SetScreenBrightness(double brightness)
340 : {
341 0 : AssertMainThread();
342 0 : PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness, 0.0, 1.0)));
343 0 : }
344 :
345 0 : bool SetLight(LightType light, const hal::LightConfiguration& aConfig)
346 : {
347 0 : AssertMainThread();
348 0 : RETURN_PROXY_IF_SANDBOXED(SetLight(light, aConfig));
349 : }
350 :
351 0 : bool GetLight(LightType light, hal::LightConfiguration* aConfig)
352 : {
353 0 : AssertMainThread();
354 0 : RETURN_PROXY_IF_SANDBOXED(GetLight(light, aConfig));
355 : }
356 :
357 :
358 : void
359 0 : AdjustSystemClock(int32_t aDeltaMilliseconds)
360 : {
361 0 : AssertMainThread();
362 0 : PROXY_IF_SANDBOXED(AdjustSystemClock(aDeltaMilliseconds));
363 0 : }
364 :
365 : void
366 0 : SetTimezone(const nsCString& aTimezoneSpec)
367 : {
368 0 : AssertMainThread();
369 0 : PROXY_IF_SANDBOXED(SetTimezone(aTimezoneSpec));
370 0 : }
371 :
372 : void
373 0 : EnableSensorNotifications(SensorType aSensor) {
374 0 : AssertMainThread();
375 0 : PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
376 0 : }
377 :
378 : void
379 0 : DisableSensorNotifications(SensorType aSensor) {
380 0 : AssertMainThread();
381 0 : PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor));
382 0 : }
383 :
384 : typedef mozilla::ObserverList<SensorData> SensorObserverList;
385 : static SensorObserverList *gSensorObservers = NULL;
386 :
387 : static SensorObserverList &
388 0 : GetSensorObservers(SensorType sensor_type) {
389 0 : MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
390 :
391 0 : if(gSensorObservers == NULL)
392 0 : gSensorObservers = new SensorObserverList[NUM_SENSOR_TYPE];
393 0 : return gSensorObservers[sensor_type];
394 : }
395 :
396 : void
397 0 : RegisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) {
398 0 : SensorObserverList &observers = GetSensorObservers(aSensor);
399 :
400 0 : AssertMainThread();
401 :
402 0 : observers.AddObserver(aObserver);
403 0 : if(observers.Length() == 1) {
404 0 : EnableSensorNotifications(aSensor);
405 : }
406 0 : }
407 :
408 : void
409 0 : UnregisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) {
410 0 : SensorObserverList &observers = GetSensorObservers(aSensor);
411 :
412 0 : AssertMainThread();
413 :
414 0 : observers.RemoveObserver(aObserver);
415 0 : if(observers.Length() == 0) {
416 0 : DisableSensorNotifications(aSensor);
417 : }
418 0 : }
419 :
420 : void
421 0 : NotifySensorChange(const SensorData &aSensorData) {
422 0 : SensorObserverList &observers = GetSensorObservers(aSensorData.sensor());
423 :
424 0 : AssertMainThread();
425 :
426 0 : observers.Broadcast(aSensorData);
427 0 : }
428 :
429 : void
430 0 : RegisterNetworkObserver(NetworkObserver* aObserver)
431 : {
432 0 : AssertMainThread();
433 0 : sNetworkObservers.AddObserver(aObserver);
434 0 : }
435 :
436 : void
437 0 : UnregisterNetworkObserver(NetworkObserver* aObserver)
438 : {
439 0 : AssertMainThread();
440 0 : sNetworkObservers.RemoveObserver(aObserver);
441 0 : }
442 :
443 : void
444 0 : GetCurrentNetworkInformation(NetworkInformation* aInfo)
445 : {
446 0 : AssertMainThread();
447 0 : *aInfo = sNetworkObservers.GetCurrentInformation();
448 0 : }
449 :
450 : void
451 0 : NotifyNetworkChange(const NetworkInformation& aInfo)
452 : {
453 0 : sNetworkObservers.CacheInformation(aInfo);
454 0 : sNetworkObservers.BroadcastCachedInformation();
455 0 : }
456 :
457 0 : void Reboot()
458 : {
459 0 : AssertMainThread();
460 0 : PROXY_IF_SANDBOXED(Reboot());
461 0 : }
462 :
463 0 : void PowerOff()
464 : {
465 0 : AssertMainThread();
466 0 : PROXY_IF_SANDBOXED(PowerOff());
467 0 : }
468 :
469 : void
470 0 : RegisterWakeLockObserver(WakeLockObserver* aObserver)
471 : {
472 0 : AssertMainThread();
473 0 : sWakeLockObservers.AddObserver(aObserver);
474 0 : }
475 :
476 : void
477 0 : UnregisterWakeLockObserver(WakeLockObserver* aObserver)
478 : {
479 0 : AssertMainThread();
480 0 : sWakeLockObservers.RemoveObserver(aObserver);
481 0 : }
482 :
483 : void
484 0 : ModifyWakeLock(const nsAString &aTopic,
485 : hal::WakeLockControl aLockAdjust,
486 : hal::WakeLockControl aHiddenAdjust)
487 : {
488 0 : AssertMainThread();
489 0 : PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust));
490 0 : }
491 :
492 : void
493 0 : GetWakeLockInfo(const nsAString &aTopic, WakeLockInformation *aWakeLockInfo)
494 : {
495 0 : AssertMainThread();
496 0 : PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));
497 0 : }
498 :
499 : void
500 0 : NotifyWakeLockChange(const WakeLockInformation& aInfo)
501 : {
502 0 : AssertMainThread();
503 0 : sWakeLockObservers.BroadcastInformation(aInfo);
504 0 : }
505 :
506 : } // namespace hal
507 4392 : } // namespace mozilla
|