Bug 783551 - Get tooltool running on the b2g on OS X builds. r=respindola
[gecko.git] / hal / Hal.cpp
bloba5b6d732b142f8fec19704908796144a80589e45
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/. */
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/StaticPtr.h"
21 #include "mozilla/ClearOnShutdown.h"
22 #include "WindowIdentifier.h"
23 #include "mozilla/dom/ScreenOrientation.h"
25 #ifdef XP_WIN
26 #include <process.h>
27 #define getpid _getpid
28 #endif
30 using namespace mozilla::services;
32 #define PROXY_IF_SANDBOXED(_call) \
33 do { \
34 if (InSandbox()) { \
35 hal_sandbox::_call; \
36 } else { \
37 hal_impl::_call; \
38 } \
39 } while (0)
41 #define RETURN_PROXY_IF_SANDBOXED(_call) \
42 do { \
43 if (InSandbox()) { \
44 return hal_sandbox::_call; \
45 } else { \
46 return hal_impl::_call; \
47 } \
48 } while (0)
50 namespace mozilla {
51 namespace hal {
53 PRLogModuleInfo *sHalLog = PR_LOG_DEFINE("hal");
55 namespace {
57 void
58 AssertMainThread()
60 MOZ_ASSERT(NS_IsMainThread());
63 bool
64 InSandbox()
66 return GeckoProcessType_Content == XRE_GetProcessType();
69 bool
70 WindowIsActive(nsIDOMWindow *window)
72 NS_ENSURE_TRUE(window, false);
74 nsCOMPtr<nsIDOMDocument> doc;
75 window->GetDocument(getter_AddRefs(doc));
76 NS_ENSURE_TRUE(doc, false);
78 bool hidden = true;
79 doc->GetMozHidden(&hidden);
80 return !hidden;
83 StaticAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
85 void InitLastIDToVibrate()
87 gLastIDToVibrate = new WindowIdentifier::IDArrayType();
88 ClearOnShutdown(&gLastIDToVibrate);
91 } // anonymous namespace
93 void
94 Vibrate(const nsTArray<uint32_t>& pattern, nsIDOMWindow* window)
96 Vibrate(pattern, WindowIdentifier(window));
99 void
100 Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier &id)
102 AssertMainThread();
104 // Only active windows may start vibrations. If |id| hasn't gone
105 // through the IPC layer -- that is, if our caller is the outside
106 // world, not hal_proxy -- check whether the window is active. If
107 // |id| has gone through IPC, don't check the window's visibility;
108 // only the window corresponding to the bottommost process has its
109 // visibility state set correctly.
110 if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
111 HAL_LOG(("Vibrate: Window is inactive, dropping vibrate."));
112 return;
115 if (InSandbox()) {
116 hal_sandbox::Vibrate(pattern, id);
118 else {
119 if (!gLastIDToVibrate)
120 InitLastIDToVibrate();
121 *gLastIDToVibrate = id.AsArray();
123 HAL_LOG(("Vibrate: Forwarding to hal_impl."));
125 // hal_impl doesn't need |id|. Send it an empty id, which will
126 // assert if it's used.
127 hal_impl::Vibrate(pattern, WindowIdentifier());
131 void
132 CancelVibrate(nsIDOMWindow* window)
134 CancelVibrate(WindowIdentifier(window));
137 void
138 CancelVibrate(const WindowIdentifier &id)
140 AssertMainThread();
142 // Although only active windows may start vibrations, a window may
143 // cancel its own vibration even if it's no longer active.
145 // After a window is marked as inactive, it sends a CancelVibrate
146 // request. We want this request to cancel a playing vibration
147 // started by that window, so we certainly don't want to reject the
148 // cancellation request because the window is now inactive.
150 // But it could be the case that, after this window became inactive,
151 // some other window came along and started a vibration. We don't
152 // want this window's cancellation request to cancel that window's
153 // actively-playing vibration!
155 // To solve this problem, we keep track of the id of the last window
156 // to start a vibration, and only accepts cancellation requests from
157 // the same window. All other cancellation requests are ignored.
159 if (InSandbox()) {
160 hal_sandbox::CancelVibrate(id);
162 else if (*gLastIDToVibrate == id.AsArray()) {
163 // Don't forward our ID to hal_impl. It doesn't need it, and we
164 // don't want it to be tempted to read it. The empty identifier
165 // will assert if it's used.
166 HAL_LOG(("CancelVibrate: Forwarding to hal_impl."));
167 hal_impl::CancelVibrate(WindowIdentifier());
171 template <class InfoType>
172 class ObserversManager
174 public:
175 void AddObserver(Observer<InfoType>* aObserver) {
176 if (!mObservers) {
177 mObservers = new mozilla::ObserverList<InfoType>();
180 mObservers->AddObserver(aObserver);
182 if (mObservers->Length() == 1) {
183 EnableNotifications();
187 void RemoveObserver(Observer<InfoType>* aObserver) {
188 // If mObservers is null, that means there are no observers.
189 // In addition, if RemoveObserver() returns false, that means we didn't
190 // find the observer.
191 // In both cases, that is a logical error we want to make sure the developer
192 // notices.
194 MOZ_ASSERT(mObservers);
196 #ifndef DEBUG
197 if (!mObservers) {
198 return;
200 #endif
202 DebugOnly<bool> removed = mObservers->RemoveObserver(aObserver);
203 MOZ_ASSERT(removed);
205 if (mObservers->Length() == 0) {
206 DisableNotifications();
208 OnNotificationsDisabled();
210 delete mObservers;
211 mObservers = 0;
215 void BroadcastInformation(const InfoType& aInfo) {
216 // It is possible for mObservers to be NULL here on some platforms,
217 // because a call to BroadcastInformation gets queued up asynchronously
218 // while RemoveObserver is running (and before the notifications are
219 // disabled). The queued call can then get run after mObservers has
220 // been nulled out. See bug 757025.
221 if (!mObservers) {
222 return;
224 mObservers->Broadcast(aInfo);
227 protected:
228 virtual void EnableNotifications() = 0;
229 virtual void DisableNotifications() = 0;
230 virtual void OnNotificationsDisabled() {}
232 private:
233 mozilla::ObserverList<InfoType>* mObservers;
236 template <class InfoType>
237 class CachingObserversManager : public ObserversManager<InfoType>
239 public:
240 InfoType GetCurrentInformation() {
241 if (mHasValidCache) {
242 return mInfo;
245 GetCurrentInformationInternal(&mInfo);
246 mHasValidCache = true;
247 return mInfo;
250 void CacheInformation(const InfoType& aInfo) {
251 mHasValidCache = true;
252 mInfo = aInfo;
255 void BroadcastCachedInformation() {
256 this->BroadcastInformation(mInfo);
259 protected:
260 virtual void GetCurrentInformationInternal(InfoType*) = 0;
262 virtual void OnNotificationsDisabled() {
263 mHasValidCache = false;
266 private:
267 InfoType mInfo;
268 bool mHasValidCache;
271 class BatteryObserversManager : public CachingObserversManager<BatteryInformation>
273 protected:
274 void EnableNotifications() {
275 PROXY_IF_SANDBOXED(EnableBatteryNotifications());
278 void DisableNotifications() {
279 PROXY_IF_SANDBOXED(DisableBatteryNotifications());
282 void GetCurrentInformationInternal(BatteryInformation* aInfo) {
283 PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
287 static BatteryObserversManager sBatteryObservers;
289 class NetworkObserversManager : public CachingObserversManager<NetworkInformation>
291 protected:
292 void EnableNotifications() {
293 PROXY_IF_SANDBOXED(EnableNetworkNotifications());
296 void DisableNotifications() {
297 PROXY_IF_SANDBOXED(DisableNetworkNotifications());
300 void GetCurrentInformationInternal(NetworkInformation* aInfo) {
301 PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
305 static NetworkObserversManager sNetworkObservers;
307 class WakeLockObserversManager : public ObserversManager<WakeLockInformation>
309 protected:
310 void EnableNotifications() {
311 PROXY_IF_SANDBOXED(EnableWakeLockNotifications());
314 void DisableNotifications() {
315 PROXY_IF_SANDBOXED(DisableWakeLockNotifications());
319 static WakeLockObserversManager sWakeLockObservers;
321 class ScreenConfigurationObserversManager : public CachingObserversManager<ScreenConfiguration>
323 protected:
324 void EnableNotifications() {
325 PROXY_IF_SANDBOXED(EnableScreenConfigurationNotifications());
328 void DisableNotifications() {
329 PROXY_IF_SANDBOXED(DisableScreenConfigurationNotifications());
332 void GetCurrentInformationInternal(ScreenConfiguration* aInfo) {
333 PROXY_IF_SANDBOXED(GetCurrentScreenConfiguration(aInfo));
337 static ScreenConfigurationObserversManager sScreenConfigurationObservers;
339 void
340 RegisterBatteryObserver(BatteryObserver* aObserver)
342 AssertMainThread();
343 sBatteryObservers.AddObserver(aObserver);
346 void
347 UnregisterBatteryObserver(BatteryObserver* aObserver)
349 AssertMainThread();
350 sBatteryObservers.RemoveObserver(aObserver);
353 void
354 GetCurrentBatteryInformation(BatteryInformation* aInfo)
356 AssertMainThread();
357 *aInfo = sBatteryObservers.GetCurrentInformation();
360 void
361 NotifyBatteryChange(const BatteryInformation& aInfo)
363 AssertMainThread();
364 sBatteryObservers.CacheInformation(aInfo);
365 sBatteryObservers.BroadcastCachedInformation();
368 bool GetScreenEnabled()
370 AssertMainThread();
371 RETURN_PROXY_IF_SANDBOXED(GetScreenEnabled());
374 void SetScreenEnabled(bool enabled)
376 AssertMainThread();
377 PROXY_IF_SANDBOXED(SetScreenEnabled(enabled));
380 bool GetCpuSleepAllowed()
382 // Generally for interfaces that are accessible by normal web content
383 // we should cache the result and be notified on state changes, like
384 // what the battery API does. But since this is only used by
385 // privileged interface, the synchronous getter is OK here.
386 AssertMainThread();
387 RETURN_PROXY_IF_SANDBOXED(GetCpuSleepAllowed());
390 void SetCpuSleepAllowed(bool allowed)
392 AssertMainThread();
393 PROXY_IF_SANDBOXED(SetCpuSleepAllowed(allowed));
396 double GetScreenBrightness()
398 AssertMainThread();
399 RETURN_PROXY_IF_SANDBOXED(GetScreenBrightness());
402 void SetScreenBrightness(double brightness)
404 AssertMainThread();
405 PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness, 0.0, 1.0)));
408 bool SetLight(LightType light, const hal::LightConfiguration& aConfig)
410 AssertMainThread();
411 RETURN_PROXY_IF_SANDBOXED(SetLight(light, aConfig));
414 bool GetLight(LightType light, hal::LightConfiguration* aConfig)
416 AssertMainThread();
417 RETURN_PROXY_IF_SANDBOXED(GetLight(light, aConfig));
421 void
422 AdjustSystemClock(int32_t aDeltaMilliseconds)
424 AssertMainThread();
425 PROXY_IF_SANDBOXED(AdjustSystemClock(aDeltaMilliseconds));
428 void
429 SetTimezone(const nsCString& aTimezoneSpec)
431 AssertMainThread();
432 PROXY_IF_SANDBOXED(SetTimezone(aTimezoneSpec));
435 void
436 EnableSensorNotifications(SensorType aSensor) {
437 AssertMainThread();
438 PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
441 void
442 DisableSensorNotifications(SensorType aSensor) {
443 AssertMainThread();
444 PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor));
447 typedef mozilla::ObserverList<SensorData> SensorObserverList;
448 static SensorObserverList* gSensorObservers = NULL;
450 static SensorObserverList &
451 GetSensorObservers(SensorType sensor_type) {
452 MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
454 if(gSensorObservers == NULL)
455 gSensorObservers = new SensorObserverList[NUM_SENSOR_TYPE];
456 return gSensorObservers[sensor_type];
459 void
460 RegisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) {
461 SensorObserverList &observers = GetSensorObservers(aSensor);
463 AssertMainThread();
465 observers.AddObserver(aObserver);
466 if(observers.Length() == 1) {
467 EnableSensorNotifications(aSensor);
471 void
472 UnregisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) {
473 SensorObserverList &observers = GetSensorObservers(aSensor);
475 AssertMainThread();
477 observers.RemoveObserver(aObserver);
478 if (observers.Length() > 0) {
479 return;
481 DisableSensorNotifications(aSensor);
483 // Destroy sSensorObservers only if all observer lists are empty.
484 for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
485 if (gSensorObservers[i].Length() > 0) {
486 return;
489 delete [] gSensorObservers;
490 gSensorObservers = nullptr;
493 void
494 NotifySensorChange(const SensorData &aSensorData) {
495 SensorObserverList &observers = GetSensorObservers(aSensorData.sensor());
497 AssertMainThread();
499 observers.Broadcast(aSensorData);
502 void
503 RegisterNetworkObserver(NetworkObserver* aObserver)
505 AssertMainThread();
506 sNetworkObservers.AddObserver(aObserver);
509 void
510 UnregisterNetworkObserver(NetworkObserver* aObserver)
512 AssertMainThread();
513 sNetworkObservers.RemoveObserver(aObserver);
516 void
517 GetCurrentNetworkInformation(NetworkInformation* aInfo)
519 AssertMainThread();
520 *aInfo = sNetworkObservers.GetCurrentInformation();
523 void
524 NotifyNetworkChange(const NetworkInformation& aInfo)
526 sNetworkObservers.CacheInformation(aInfo);
527 sNetworkObservers.BroadcastCachedInformation();
530 void Reboot()
532 AssertMainThread();
533 PROXY_IF_SANDBOXED(Reboot());
536 void PowerOff()
538 AssertMainThread();
539 PROXY_IF_SANDBOXED(PowerOff());
542 void
543 RegisterWakeLockObserver(WakeLockObserver* aObserver)
545 AssertMainThread();
546 sWakeLockObservers.AddObserver(aObserver);
549 void
550 UnregisterWakeLockObserver(WakeLockObserver* aObserver)
552 AssertMainThread();
553 sWakeLockObservers.RemoveObserver(aObserver);
556 void
557 ModifyWakeLock(const nsAString &aTopic,
558 hal::WakeLockControl aLockAdjust,
559 hal::WakeLockControl aHiddenAdjust)
561 AssertMainThread();
562 PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust));
565 void
566 GetWakeLockInfo(const nsAString &aTopic, WakeLockInformation *aWakeLockInfo)
568 AssertMainThread();
569 PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));
572 void
573 NotifyWakeLockChange(const WakeLockInformation& aInfo)
575 AssertMainThread();
576 sWakeLockObservers.BroadcastInformation(aInfo);
579 void
580 RegisterScreenConfigurationObserver(ScreenConfigurationObserver* aObserver)
582 AssertMainThread();
583 sScreenConfigurationObservers.AddObserver(aObserver);
586 void
587 UnregisterScreenConfigurationObserver(ScreenConfigurationObserver* aObserver)
589 AssertMainThread();
590 sScreenConfigurationObservers.RemoveObserver(aObserver);
593 void
594 GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration)
596 AssertMainThread();
597 *aScreenConfiguration = sScreenConfigurationObservers.GetCurrentInformation();
600 void
601 NotifyScreenConfigurationChange(const ScreenConfiguration& aScreenConfiguration)
603 sScreenConfigurationObservers.CacheInformation(aScreenConfiguration);
604 sScreenConfigurationObservers.BroadcastCachedInformation();
607 bool
608 LockScreenOrientation(const dom::ScreenOrientation& aOrientation)
610 AssertMainThread();
611 RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation));
614 void
615 UnlockScreenOrientation()
617 AssertMainThread();
618 PROXY_IF_SANDBOXED(UnlockScreenOrientation());
621 void
622 EnableSwitchNotifications(hal::SwitchDevice aDevice) {
623 AssertMainThread();
624 PROXY_IF_SANDBOXED(EnableSwitchNotifications(aDevice));
627 void
628 DisableSwitchNotifications(hal::SwitchDevice aDevice) {
629 AssertMainThread();
630 PROXY_IF_SANDBOXED(DisableSwitchNotifications(aDevice));
633 hal::SwitchState GetCurrentSwitchState(hal::SwitchDevice aDevice)
635 AssertMainThread();
636 RETURN_PROXY_IF_SANDBOXED(GetCurrentSwitchState(aDevice));
639 typedef mozilla::ObserverList<SwitchEvent> SwitchObserverList;
641 static SwitchObserverList *sSwitchObserverLists = NULL;
643 static SwitchObserverList&
644 GetSwitchObserverList(hal::SwitchDevice aDevice) {
645 MOZ_ASSERT(0 <= aDevice && aDevice < NUM_SWITCH_DEVICE);
646 if (sSwitchObserverLists == NULL) {
647 sSwitchObserverLists = new SwitchObserverList[NUM_SWITCH_DEVICE];
649 return sSwitchObserverLists[aDevice];
652 static void
653 ReleaseObserversIfNeeded() {
654 for (int i = 0; i < NUM_SWITCH_DEVICE; i++) {
655 if (sSwitchObserverLists[i].Length() != 0)
656 return;
659 //The length of every list is 0, no observer in the list.
660 delete [] sSwitchObserverLists;
661 sSwitchObserverLists = NULL;
664 void
665 RegisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserver)
667 AssertMainThread();
668 SwitchObserverList& observer = GetSwitchObserverList(aDevice);
669 observer.AddObserver(aObserver);
670 if (observer.Length() == 1) {
671 EnableSwitchNotifications(aDevice);
675 void
676 UnregisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserver)
678 AssertMainThread();
679 SwitchObserverList& observer = GetSwitchObserverList(aDevice);
680 observer.RemoveObserver(aObserver);
681 if (observer.Length() == 0) {
682 DisableSwitchNotifications(aDevice);
683 ReleaseObserversIfNeeded();
687 void
688 NotifySwitchChange(const hal::SwitchEvent& aEvent)
690 // When callback this notification, main thread may call unregister function
691 // first. We should check if this pointer is valid.
692 if (!sSwitchObserverLists)
693 return;
695 SwitchObserverList& observer = GetSwitchObserverList(aEvent.device());
696 observer.Broadcast(aEvent);
699 static AlarmObserver* sAlarmObserver;
701 bool
702 RegisterTheOneAlarmObserver(AlarmObserver* aObserver)
704 MOZ_ASSERT(!InSandbox());
705 MOZ_ASSERT(!sAlarmObserver);
707 sAlarmObserver = aObserver;
708 RETURN_PROXY_IF_SANDBOXED(EnableAlarm());
711 void
712 UnregisterTheOneAlarmObserver()
714 if (sAlarmObserver) {
715 sAlarmObserver = NULL;
716 PROXY_IF_SANDBOXED(DisableAlarm());
720 void
721 NotifyAlarmFired()
723 if (sAlarmObserver) {
724 sAlarmObserver->Notify(void_t());
728 bool
729 SetAlarm(PRInt32 aSeconds, PRInt32 aNanoseconds)
731 // It's pointless to program an alarm nothing is going to observe ...
732 MOZ_ASSERT(sAlarmObserver);
733 RETURN_PROXY_IF_SANDBOXED(SetAlarm(aSeconds, aNanoseconds));
736 void
737 SetProcessPriority(int aPid, ProcessPriority aPriority)
739 if (InSandbox()) {
740 hal_sandbox::SetProcessPriority(aPid, aPriority);
742 else {
743 hal_impl::SetProcessPriority(aPid, aPriority);
747 } // namespace hal
748 } // namespace mozilla