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/. */
11 #include "HalSandbox.h"
12 #include "HalWakeLockInternal.h"
13 #include "mozilla/dom/Document.h"
14 #include "nsThreadUtils.h"
15 #include "nsXULAppAPI.h"
16 #include "nsPIDOMWindow.h"
17 #include "nsJSUtils.h"
18 #include "mozilla/ClearOnShutdown.h"
19 #include "mozilla/Observer.h"
20 #include "mozilla/dom/ContentChild.h"
21 #include "WindowIdentifier.h"
25 # define getpid _getpid
28 using namespace mozilla::services
;
29 using namespace mozilla::dom
;
31 #define PROXY_IF_SANDBOXED(_call) \
34 if (!hal_sandbox::HalChildDestroyed()) { \
42 #define RETURN_PROXY_IF_SANDBOXED(_call, defValue) \
45 if (hal_sandbox::HalChildDestroyed()) { \
48 return hal_sandbox::_call; \
50 return hal_impl::_call; \
54 namespace mozilla::hal
{
56 static bool sInitialized
= false;
58 mozilla::LogModule
* GetHalLog() {
59 static mozilla::LazyLogModule
sHalLog("hal");
65 void AssertMainThread() { MOZ_ASSERT(NS_IsMainThread()); }
67 bool InSandbox() { return GeckoProcessType_Content
== XRE_GetProcessType(); }
69 bool WindowIsActive(nsPIDOMWindowInner
* aWindow
) {
70 dom::Document
* document
= aWindow
->GetDoc();
71 NS_ENSURE_TRUE(document
, false);
72 return !document
->Hidden();
75 StaticAutoPtr
<WindowIdentifier::IDArrayType
> gLastIDToVibrate
;
77 static void RecordLastIDToVibrate(const WindowIdentifier
& aId
) {
79 *gLastIDToVibrate
= aId
.AsArray().Clone();
83 static bool MayCancelVibration(const WindowIdentifier
& aId
) {
84 // Although only active windows may start vibrations, a window may
85 // cancel its own vibration even if it's no longer active.
87 // After a window is marked as inactive, it sends a CancelVibrate
88 // request. We want this request to cancel a playing vibration
89 // started by that window, so we certainly don't want to reject the
90 // cancellation request because the window is now inactive.
92 // But it could be the case that, after this window became inactive,
93 // some other window came along and started a vibration. We don't
94 // want this window's cancellation request to cancel that window's
95 // actively-playing vibration!
97 // To solve this problem, we keep track of the id of the last window
98 // to start a vibration, and only accepts cancellation requests from
99 // the same window. All other cancellation requests are ignored.
101 return InSandbox() || (*gLastIDToVibrate
== aId
.AsArray());
106 void Vibrate(const nsTArray
<uint32_t>& pattern
, nsPIDOMWindowInner
* window
) {
107 Vibrate(pattern
, WindowIdentifier(window
));
110 void Vibrate(const nsTArray
<uint32_t>& pattern
, WindowIdentifier
&& id
) {
113 // Only active windows may start vibrations. If |id| hasn't gone
114 // through the IPC layer -- that is, if our caller is the outside
115 // world, not hal_proxy -- check whether the window is active. If
116 // |id| has gone through IPC, don't check the window's visibility;
117 // only the window corresponding to the bottommost process has its
118 // visibility state set correctly.
119 if (!id
.HasTraveledThroughIPC() && !WindowIsActive(id
.GetWindow())) {
120 HAL_LOG("Vibrate: Window is inactive, dropping vibrate.");
124 RecordLastIDToVibrate(id
);
126 // Don't forward our ID if we are not in the sandbox, because hal_impl
127 // doesn't need it, and we don't want it to be tempted to read it. The
128 // empty identifier will assert if it's used.
130 Vibrate(pattern
, InSandbox() ? std::move(id
) : WindowIdentifier()));
133 void CancelVibrate(nsPIDOMWindowInner
* window
) {
134 CancelVibrate(WindowIdentifier(window
));
137 void CancelVibrate(WindowIdentifier
&& id
) {
140 if (MayCancelVibration(id
)) {
141 // Don't forward our ID if we are not in the sandbox, because hal_impl
142 // doesn't need it, and we don't want it to be tempted to read it. The
143 // empty identifier will assert if it's used.
145 CancelVibrate(InSandbox() ? std::move(id
) : WindowIdentifier()));
149 template <class InfoType
>
150 class ObserversManager
{
152 void AddObserver(Observer
<InfoType
>* aObserver
) {
153 mObservers
.AddObserver(aObserver
);
155 if (mObservers
.Length() == 1) {
156 EnableNotifications();
160 void RemoveObserver(Observer
<InfoType
>* aObserver
) {
161 bool removed
= mObservers
.RemoveObserver(aObserver
);
166 if (mObservers
.Length() == 0) {
167 DisableNotifications();
168 OnNotificationsDisabled();
172 void BroadcastInformation(const InfoType
& aInfo
) {
173 mObservers
.Broadcast(aInfo
);
177 ~ObserversManager() { MOZ_ASSERT(mObservers
.Length() == 0); }
179 virtual void EnableNotifications() = 0;
180 virtual void DisableNotifications() = 0;
181 virtual void OnNotificationsDisabled() {}
184 mozilla::ObserverList
<InfoType
> mObservers
;
187 template <class InfoType
>
188 class CachingObserversManager
: public ObserversManager
<InfoType
> {
190 InfoType
GetCurrentInformation() {
191 if (mHasValidCache
) {
195 GetCurrentInformationInternal(&mInfo
);
196 mHasValidCache
= true;
200 void CacheInformation(const InfoType
& aInfo
) {
201 mHasValidCache
= true;
205 void BroadcastCachedInformation() { this->BroadcastInformation(mInfo
); }
208 virtual void GetCurrentInformationInternal(InfoType
*) = 0;
210 void OnNotificationsDisabled() override
{ mHasValidCache
= false; }
217 class BatteryObserversManager final
218 : public CachingObserversManager
<BatteryInformation
> {
220 void EnableNotifications() override
{
221 PROXY_IF_SANDBOXED(EnableBatteryNotifications());
224 void DisableNotifications() override
{
225 PROXY_IF_SANDBOXED(DisableBatteryNotifications());
228 void GetCurrentInformationInternal(BatteryInformation
* aInfo
) override
{
229 PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo
));
233 class NetworkObserversManager final
234 : public CachingObserversManager
<NetworkInformation
> {
236 void EnableNotifications() override
{
237 PROXY_IF_SANDBOXED(EnableNetworkNotifications());
240 void DisableNotifications() override
{
241 PROXY_IF_SANDBOXED(DisableNetworkNotifications());
244 void GetCurrentInformationInternal(NetworkInformation
* aInfo
) override
{
245 PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo
));
249 class WakeLockObserversManager final
250 : public ObserversManager
<WakeLockInformation
> {
252 void EnableNotifications() override
{
253 PROXY_IF_SANDBOXED(EnableWakeLockNotifications());
256 void DisableNotifications() override
{
257 PROXY_IF_SANDBOXED(DisableWakeLockNotifications());
261 class ScreenConfigurationObserversManager final
262 : public CachingObserversManager
<ScreenConfiguration
> {
264 void EnableNotifications() override
{
265 PROXY_IF_SANDBOXED(EnableScreenConfigurationNotifications());
268 void DisableNotifications() override
{
269 PROXY_IF_SANDBOXED(DisableScreenConfigurationNotifications());
272 void GetCurrentInformationInternal(ScreenConfiguration
* aInfo
) override
{
273 PROXY_IF_SANDBOXED(GetCurrentScreenConfiguration(aInfo
));
277 typedef mozilla::ObserverList
<SensorData
> SensorObserverList
;
278 StaticAutoPtr
<SensorObserverList
> sSensorObservers
[NUM_SENSOR_TYPE
];
280 static SensorObserverList
* GetSensorObservers(SensorType sensor_type
) {
282 MOZ_ASSERT(sensor_type
< NUM_SENSOR_TYPE
);
284 if (!sSensorObservers
[sensor_type
]) {
285 sSensorObservers
[sensor_type
] = new SensorObserverList();
288 return sSensorObservers
[sensor_type
];
291 #define MOZ_IMPL_HAL_OBSERVER(name_) \
292 StaticAutoPtr<name_##ObserversManager> s##name_##Observers; \
294 static name_##ObserversManager* name_##Observers() { \
295 AssertMainThread(); \
297 if (!s##name_##Observers) { \
298 MOZ_ASSERT(sInitialized); \
299 s##name_##Observers = new name_##ObserversManager(); \
302 return s##name_##Observers; \
305 void Register##name_##Observer(name_##Observer* aObserver) { \
306 AssertMainThread(); \
307 name_##Observers()->AddObserver(aObserver); \
310 void Unregister##name_##Observer(name_##Observer* aObserver) { \
311 AssertMainThread(); \
312 name_##Observers()->RemoveObserver(aObserver); \
315 MOZ_IMPL_HAL_OBSERVER(Battery
)
317 void GetCurrentBatteryInformation(BatteryInformation
* aInfo
) {
318 *aInfo
= BatteryObservers()->GetCurrentInformation();
321 void NotifyBatteryChange(const BatteryInformation
& aInfo
) {
322 BatteryObservers()->CacheInformation(aInfo
);
323 BatteryObservers()->BroadcastCachedInformation();
326 void EnableSensorNotifications(SensorType aSensor
) {
328 PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor
));
331 void DisableSensorNotifications(SensorType aSensor
) {
333 PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor
));
336 void RegisterSensorObserver(SensorType aSensor
, ISensorObserver
* aObserver
) {
337 SensorObserverList
* observers
= GetSensorObservers(aSensor
);
339 observers
->AddObserver(aObserver
);
340 if (observers
->Length() == 1) {
341 EnableSensorNotifications(aSensor
);
345 void UnregisterSensorObserver(SensorType aSensor
, ISensorObserver
* aObserver
) {
346 SensorObserverList
* observers
= GetSensorObservers(aSensor
);
347 if (!observers
->RemoveObserver(aObserver
) || observers
->Length() > 0) {
350 DisableSensorNotifications(aSensor
);
353 void NotifySensorChange(const SensorData
& aSensorData
) {
354 SensorObserverList
* observers
= GetSensorObservers(aSensorData
.sensor());
356 observers
->Broadcast(aSensorData
);
359 MOZ_IMPL_HAL_OBSERVER(Network
)
361 void GetCurrentNetworkInformation(NetworkInformation
* aInfo
) {
362 *aInfo
= NetworkObservers()->GetCurrentInformation();
365 void NotifyNetworkChange(const NetworkInformation
& aInfo
) {
366 NetworkObservers()->CacheInformation(aInfo
);
367 NetworkObservers()->BroadcastCachedInformation();
370 MOZ_IMPL_HAL_OBSERVER(WakeLock
)
372 void ModifyWakeLock(const nsAString
& aTopic
, WakeLockControl aLockAdjust
,
373 WakeLockControl aHiddenAdjust
,
374 uint64_t aProcessID
/* = CONTENT_PROCESS_ID_UNKNOWN */) {
377 if (aProcessID
== CONTENT_PROCESS_ID_UNKNOWN
) {
378 aProcessID
= InSandbox() ? ContentChild::GetSingleton()->GetID()
379 : CONTENT_PROCESS_ID_MAIN
;
383 ModifyWakeLock(aTopic
, aLockAdjust
, aHiddenAdjust
, aProcessID
));
386 void GetWakeLockInfo(const nsAString
& aTopic
,
387 WakeLockInformation
* aWakeLockInfo
) {
389 PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic
, aWakeLockInfo
));
392 void NotifyWakeLockChange(const WakeLockInformation
& aInfo
) {
394 WakeLockObservers()->BroadcastInformation(aInfo
);
397 MOZ_IMPL_HAL_OBSERVER(ScreenConfiguration
)
399 void GetCurrentScreenConfiguration(ScreenConfiguration
* aScreenConfiguration
) {
400 *aScreenConfiguration
=
401 ScreenConfigurationObservers()->GetCurrentInformation();
404 void NotifyScreenConfigurationChange(
405 const ScreenConfiguration
& aScreenConfiguration
) {
406 ScreenConfigurationObservers()->CacheInformation(aScreenConfiguration
);
407 ScreenConfigurationObservers()->BroadcastCachedInformation();
410 bool LockScreenOrientation(const ScreenOrientation
& aOrientation
) {
412 RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation
), false);
415 void UnlockScreenOrientation() {
417 PROXY_IF_SANDBOXED(UnlockScreenOrientation());
420 void SetProcessPriority(int aPid
, ProcessPriority aPriority
) {
421 // n.b. The sandboxed implementation crashes; SetProcessPriority works only
422 // from the main process.
423 PROXY_IF_SANDBOXED(SetProcessPriority(aPid
, aPriority
));
427 const char* ProcessPriorityToString(ProcessPriority aPriority
) {
429 case PROCESS_PRIORITY_PARENT_PROCESS
:
430 return "PARENT_PROCESS";
431 case PROCESS_PRIORITY_PREALLOC
:
433 case PROCESS_PRIORITY_FOREGROUND_HIGH
:
434 return "FOREGROUND_HIGH";
435 case PROCESS_PRIORITY_FOREGROUND
:
437 case PROCESS_PRIORITY_FOREGROUND_KEYBOARD
:
438 return "FOREGROUND_KEYBOARD";
439 case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE
:
440 return "BACKGROUND_PERCEIVABLE";
441 case PROCESS_PRIORITY_BACKGROUND
:
443 case PROCESS_PRIORITY_UNKNOWN
:
452 MOZ_ASSERT(!sInitialized
);
455 gLastIDToVibrate
= new WindowIdentifier::IDArrayType();
464 MOZ_ASSERT(sInitialized
);
466 gLastIDToVibrate
= nullptr;
468 sBatteryObservers
= nullptr;
469 sNetworkObservers
= nullptr;
470 sWakeLockObservers
= nullptr;
471 sScreenConfigurationObservers
= nullptr;
473 for (auto& sensorObserver
: sSensorObservers
) {
474 sensorObserver
= nullptr;
477 sInitialized
= false;
480 } // namespace mozilla::hal