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/. */
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"
27 #define getpid _getpid
30 using namespace mozilla::services
;
32 #define PROXY_IF_SANDBOXED(_call) \
41 #define RETURN_PROXY_IF_SANDBOXED(_call) \
44 return hal_sandbox::_call; \
46 return hal_impl::_call; \
53 PRLogModuleInfo
*sHalLog
= PR_LOG_DEFINE("hal");
60 MOZ_ASSERT(NS_IsMainThread());
66 return GeckoProcessType_Content
== XRE_GetProcessType();
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);
79 doc
->GetMozHidden(&hidden
);
83 StaticAutoPtr
<WindowIdentifier::IDArrayType
> gLastIDToVibrate
;
85 void InitLastIDToVibrate()
87 gLastIDToVibrate
= new WindowIdentifier::IDArrayType();
88 ClearOnShutdown(&gLastIDToVibrate
);
91 } // anonymous namespace
94 Vibrate(const nsTArray
<uint32_t>& pattern
, nsIDOMWindow
* window
)
96 Vibrate(pattern
, WindowIdentifier(window
));
100 Vibrate(const nsTArray
<uint32_t>& pattern
, const WindowIdentifier
&id
)
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."));
116 hal_sandbox::Vibrate(pattern
, id
);
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());
132 CancelVibrate(nsIDOMWindow
* window
)
134 CancelVibrate(WindowIdentifier(window
));
138 CancelVibrate(const WindowIdentifier
&id
)
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.
160 hal_sandbox::CancelVibrate(id
);
162 else if (gLastIDToVibrate
&& *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
175 void AddObserver(Observer
<InfoType
>* aObserver
) {
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
194 MOZ_ASSERT(mObservers
);
202 DebugOnly
<bool> removed
= mObservers
->RemoveObserver(aObserver
);
205 if (mObservers
->Length() == 0) {
206 DisableNotifications();
208 OnNotificationsDisabled();
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.
224 mObservers
->Broadcast(aInfo
);
228 virtual void EnableNotifications() = 0;
229 virtual void DisableNotifications() = 0;
230 virtual void OnNotificationsDisabled() {}
233 mozilla::ObserverList
<InfoType
>* mObservers
;
236 template <class InfoType
>
237 class CachingObserversManager
: public ObserversManager
<InfoType
>
240 InfoType
GetCurrentInformation() {
241 if (mHasValidCache
) {
245 GetCurrentInformationInternal(&mInfo
);
246 mHasValidCache
= true;
250 void CacheInformation(const InfoType
& aInfo
) {
251 mHasValidCache
= true;
255 void BroadcastCachedInformation() {
256 this->BroadcastInformation(mInfo
);
260 virtual void GetCurrentInformationInternal(InfoType
*) = 0;
262 virtual void OnNotificationsDisabled() {
263 mHasValidCache
= false;
271 class BatteryObserversManager
: public CachingObserversManager
<BatteryInformation
>
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
>
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
>
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
>
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
;
340 RegisterBatteryObserver(BatteryObserver
* aObserver
)
343 sBatteryObservers
.AddObserver(aObserver
);
347 UnregisterBatteryObserver(BatteryObserver
* aObserver
)
350 sBatteryObservers
.RemoveObserver(aObserver
);
354 GetCurrentBatteryInformation(BatteryInformation
* aInfo
)
357 *aInfo
= sBatteryObservers
.GetCurrentInformation();
361 NotifyBatteryChange(const BatteryInformation
& aInfo
)
364 sBatteryObservers
.CacheInformation(aInfo
);
365 sBatteryObservers
.BroadcastCachedInformation();
368 bool GetScreenEnabled()
371 RETURN_PROXY_IF_SANDBOXED(GetScreenEnabled());
374 void SetScreenEnabled(bool enabled
)
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.
387 RETURN_PROXY_IF_SANDBOXED(GetCpuSleepAllowed());
390 void SetCpuSleepAllowed(bool allowed
)
393 PROXY_IF_SANDBOXED(SetCpuSleepAllowed(allowed
));
396 double GetScreenBrightness()
399 RETURN_PROXY_IF_SANDBOXED(GetScreenBrightness());
402 void SetScreenBrightness(double brightness
)
405 PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness
, 0.0, 1.0)));
408 bool SetLight(LightType light
, const hal::LightConfiguration
& aConfig
)
411 RETURN_PROXY_IF_SANDBOXED(SetLight(light
, aConfig
));
414 bool GetLight(LightType light
, hal::LightConfiguration
* aConfig
)
417 RETURN_PROXY_IF_SANDBOXED(GetLight(light
, aConfig
));
422 AdjustSystemClock(int32_t aDeltaMilliseconds
)
425 PROXY_IF_SANDBOXED(AdjustSystemClock(aDeltaMilliseconds
));
429 SetTimezone(const nsCString
& aTimezoneSpec
)
432 PROXY_IF_SANDBOXED(SetTimezone(aTimezoneSpec
));
436 EnableSensorNotifications(SensorType aSensor
) {
438 PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor
));
442 DisableSensorNotifications(SensorType aSensor
) {
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
];
460 RegisterSensorObserver(SensorType aSensor
, ISensorObserver
*aObserver
) {
461 SensorObserverList
&observers
= GetSensorObservers(aSensor
);
465 observers
.AddObserver(aObserver
);
466 if(observers
.Length() == 1) {
467 EnableSensorNotifications(aSensor
);
472 UnregisterSensorObserver(SensorType aSensor
, ISensorObserver
*aObserver
) {
473 SensorObserverList
&observers
= GetSensorObservers(aSensor
);
477 observers
.RemoveObserver(aObserver
);
478 if (observers
.Length() > 0) {
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) {
489 delete [] gSensorObservers
;
490 gSensorObservers
= nullptr;
494 NotifySensorChange(const SensorData
&aSensorData
) {
495 SensorObserverList
&observers
= GetSensorObservers(aSensorData
.sensor());
499 observers
.Broadcast(aSensorData
);
503 RegisterNetworkObserver(NetworkObserver
* aObserver
)
506 sNetworkObservers
.AddObserver(aObserver
);
510 UnregisterNetworkObserver(NetworkObserver
* aObserver
)
513 sNetworkObservers
.RemoveObserver(aObserver
);
517 GetCurrentNetworkInformation(NetworkInformation
* aInfo
)
520 *aInfo
= sNetworkObservers
.GetCurrentInformation();
524 NotifyNetworkChange(const NetworkInformation
& aInfo
)
526 sNetworkObservers
.CacheInformation(aInfo
);
527 sNetworkObservers
.BroadcastCachedInformation();
533 PROXY_IF_SANDBOXED(Reboot());
539 PROXY_IF_SANDBOXED(PowerOff());
543 RegisterWakeLockObserver(WakeLockObserver
* aObserver
)
546 sWakeLockObservers
.AddObserver(aObserver
);
550 UnregisterWakeLockObserver(WakeLockObserver
* aObserver
)
553 sWakeLockObservers
.RemoveObserver(aObserver
);
557 ModifyWakeLock(const nsAString
&aTopic
,
558 hal::WakeLockControl aLockAdjust
,
559 hal::WakeLockControl aHiddenAdjust
)
562 PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic
, aLockAdjust
, aHiddenAdjust
));
566 GetWakeLockInfo(const nsAString
&aTopic
, WakeLockInformation
*aWakeLockInfo
)
569 PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic
, aWakeLockInfo
));
573 NotifyWakeLockChange(const WakeLockInformation
& aInfo
)
576 sWakeLockObservers
.BroadcastInformation(aInfo
);
580 RegisterScreenConfigurationObserver(ScreenConfigurationObserver
* aObserver
)
583 sScreenConfigurationObservers
.AddObserver(aObserver
);
587 UnregisterScreenConfigurationObserver(ScreenConfigurationObserver
* aObserver
)
590 sScreenConfigurationObservers
.RemoveObserver(aObserver
);
594 GetCurrentScreenConfiguration(ScreenConfiguration
* aScreenConfiguration
)
597 *aScreenConfiguration
= sScreenConfigurationObservers
.GetCurrentInformation();
601 NotifyScreenConfigurationChange(const ScreenConfiguration
& aScreenConfiguration
)
603 sScreenConfigurationObservers
.CacheInformation(aScreenConfiguration
);
604 sScreenConfigurationObservers
.BroadcastCachedInformation();
608 LockScreenOrientation(const dom::ScreenOrientation
& aOrientation
)
611 RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation
));
615 UnlockScreenOrientation()
618 PROXY_IF_SANDBOXED(UnlockScreenOrientation());
622 EnableSwitchNotifications(hal::SwitchDevice aDevice
) {
624 PROXY_IF_SANDBOXED(EnableSwitchNotifications(aDevice
));
628 DisableSwitchNotifications(hal::SwitchDevice aDevice
) {
630 PROXY_IF_SANDBOXED(DisableSwitchNotifications(aDevice
));
633 hal::SwitchState
GetCurrentSwitchState(hal::SwitchDevice aDevice
)
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
];
653 ReleaseObserversIfNeeded() {
654 for (int i
= 0; i
< NUM_SWITCH_DEVICE
; i
++) {
655 if (sSwitchObserverLists
[i
].Length() != 0)
659 //The length of every list is 0, no observer in the list.
660 delete [] sSwitchObserverLists
;
661 sSwitchObserverLists
= NULL
;
665 RegisterSwitchObserver(hal::SwitchDevice aDevice
, hal::SwitchObserver
*aObserver
)
668 SwitchObserverList
& observer
= GetSwitchObserverList(aDevice
);
669 observer
.AddObserver(aObserver
);
670 if (observer
.Length() == 1) {
671 EnableSwitchNotifications(aDevice
);
676 UnregisterSwitchObserver(hal::SwitchDevice aDevice
, hal::SwitchObserver
*aObserver
)
679 SwitchObserverList
& observer
= GetSwitchObserverList(aDevice
);
680 observer
.RemoveObserver(aObserver
);
681 if (observer
.Length() == 0) {
682 DisableSwitchNotifications(aDevice
);
683 ReleaseObserversIfNeeded();
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
)
695 SwitchObserverList
& observer
= GetSwitchObserverList(aEvent
.device());
696 observer
.Broadcast(aEvent
);
699 static AlarmObserver
* sAlarmObserver
;
702 RegisterTheOneAlarmObserver(AlarmObserver
* aObserver
)
704 MOZ_ASSERT(!InSandbox());
705 MOZ_ASSERT(!sAlarmObserver
);
707 sAlarmObserver
= aObserver
;
708 RETURN_PROXY_IF_SANDBOXED(EnableAlarm());
712 UnregisterTheOneAlarmObserver()
714 if (sAlarmObserver
) {
715 sAlarmObserver
= NULL
;
716 PROXY_IF_SANDBOXED(DisableAlarm());
723 if (sAlarmObserver
) {
724 sAlarmObserver
->Notify(void_t());
729 SetAlarm(int32_t aSeconds
, int32_t 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
));
737 SetProcessPriority(int aPid
, ProcessPriority aPriority
)
740 hal_sandbox::SetProcessPriority(aPid
, aPriority
);
743 hal_impl::SetProcessPriority(aPid
, aPriority
);
748 } // namespace mozilla