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 "nsIDOMWindow.h"
14 #include "nsIDocument.h"
15 #include "nsIDocShell.h"
16 #include "nsITabChild.h"
17 #include "nsIWebNavigation.h"
18 #include "nsThreadUtils.h"
19 #include "nsXULAppAPI.h"
20 #include "nsPIDOMWindow.h"
21 #include "nsJSUtils.h"
22 #include "mozilla/ClearOnShutdown.h"
23 #include "mozilla/Observer.h"
24 #include "mozilla/dom/ContentChild.h"
25 #include "WindowIdentifier.h"
29 #define getpid _getpid
32 using namespace mozilla::services
;
33 using namespace mozilla::dom
;
35 #define PROXY_IF_SANDBOXED(_call) \
38 if (!hal_sandbox::HalChildDestroyed()) { \
46 #define RETURN_PROXY_IF_SANDBOXED(_call, defValue)\
49 if (hal_sandbox::HalChildDestroyed()) { \
52 return hal_sandbox::_call; \
54 return hal_impl::_call; \
61 static bool sInitialized
= false;
66 static mozilla::LazyLogModule
sHalLog("hal");
75 MOZ_ASSERT(NS_IsMainThread());
81 return GeckoProcessType_Content
== XRE_GetProcessType();
85 WindowIsActive(nsPIDOMWindowInner
* aWindow
)
87 nsIDocument
* document
= aWindow
->GetDoc();
88 NS_ENSURE_TRUE(document
, false);
90 return !document
->Hidden();
93 StaticAutoPtr
<WindowIdentifier::IDArrayType
> gLastIDToVibrate
;
96 RecordLastIDToVibrate(const WindowIdentifier
& aId
)
99 *gLastIDToVibrate
= aId
.AsArray();
104 MayCancelVibration(const WindowIdentifier
& aId
)
106 // Although only active windows may start vibrations, a window may
107 // cancel its own vibration even if it's no longer active.
109 // After a window is marked as inactive, it sends a CancelVibrate
110 // request. We want this request to cancel a playing vibration
111 // started by that window, so we certainly don't want to reject the
112 // cancellation request because the window is now inactive.
114 // But it could be the case that, after this window became inactive,
115 // some other window came along and started a vibration. We don't
116 // want this window's cancellation request to cancel that window's
117 // actively-playing vibration!
119 // To solve this problem, we keep track of the id of the last window
120 // to start a vibration, and only accepts cancellation requests from
121 // the same window. All other cancellation requests are ignored.
123 return InSandbox() || (*gLastIDToVibrate
== aId
.AsArray());
129 Vibrate(const nsTArray
<uint32_t>& pattern
, nsPIDOMWindowInner
* window
)
131 Vibrate(pattern
, WindowIdentifier(window
));
135 Vibrate(const nsTArray
<uint32_t>& pattern
, const WindowIdentifier
&id
)
139 // Only active windows may start vibrations. If |id| hasn't gone
140 // through the IPC layer -- that is, if our caller is the outside
141 // world, not hal_proxy -- check whether the window is active. If
142 // |id| has gone through IPC, don't check the window's visibility;
143 // only the window corresponding to the bottommost process has its
144 // visibility state set correctly.
145 if (!id
.HasTraveledThroughIPC() && !WindowIsActive(id
.GetWindow())) {
146 HAL_LOG("Vibrate: Window is inactive, dropping vibrate.");
150 RecordLastIDToVibrate(id
);
152 // Don't forward our ID if we are not in the sandbox, because hal_impl
153 // doesn't need it, and we don't want it to be tempted to read it. The
154 // empty identifier will assert if it's used.
155 PROXY_IF_SANDBOXED(Vibrate(pattern
, InSandbox() ? id
: WindowIdentifier()));
159 CancelVibrate(nsPIDOMWindowInner
* window
)
161 CancelVibrate(WindowIdentifier(window
));
165 CancelVibrate(const WindowIdentifier
&id
)
169 if (MayCancelVibration(id
)) {
170 // Don't forward our ID if we are not in the sandbox, because hal_impl
171 // doesn't need it, and we don't want it to be tempted to read it. The
172 // empty identifier will assert if it's used.
173 PROXY_IF_SANDBOXED(CancelVibrate(InSandbox() ? id
: WindowIdentifier()));
177 template <class InfoType
>
178 class ObserversManager
181 void AddObserver(Observer
<InfoType
>* aObserver
) {
182 mObservers
.AddObserver(aObserver
);
184 if (mObservers
.Length() == 1) {
185 EnableNotifications();
189 void RemoveObserver(Observer
<InfoType
>* aObserver
) {
190 bool removed
= mObservers
.RemoveObserver(aObserver
);
195 if (mObservers
.Length() == 0) {
196 DisableNotifications();
197 OnNotificationsDisabled();
201 void BroadcastInformation(const InfoType
& aInfo
) {
202 mObservers
.Broadcast(aInfo
);
206 ~ObserversManager() {
207 MOZ_ASSERT(mObservers
.Length() == 0);
210 virtual void EnableNotifications() = 0;
211 virtual void DisableNotifications() = 0;
212 virtual void OnNotificationsDisabled() {}
215 mozilla::ObserverList
<InfoType
> mObservers
;
218 template <class InfoType
>
219 class CachingObserversManager
: public ObserversManager
<InfoType
>
222 InfoType
GetCurrentInformation() {
223 if (mHasValidCache
) {
227 GetCurrentInformationInternal(&mInfo
);
228 mHasValidCache
= true;
232 void CacheInformation(const InfoType
& aInfo
) {
233 mHasValidCache
= true;
237 void BroadcastCachedInformation() {
238 this->BroadcastInformation(mInfo
);
242 virtual void GetCurrentInformationInternal(InfoType
*) = 0;
244 void OnNotificationsDisabled() override
{
245 mHasValidCache
= false;
253 class BatteryObserversManager final
254 : public CachingObserversManager
<BatteryInformation
>
257 void EnableNotifications() override
{
258 PROXY_IF_SANDBOXED(EnableBatteryNotifications());
261 void DisableNotifications() override
{
262 PROXY_IF_SANDBOXED(DisableBatteryNotifications());
265 void GetCurrentInformationInternal(BatteryInformation
* aInfo
) override
{
266 PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo
));
270 class NetworkObserversManager final
271 : public CachingObserversManager
<NetworkInformation
>
274 void EnableNotifications() override
{
275 PROXY_IF_SANDBOXED(EnableNetworkNotifications());
278 void DisableNotifications() override
{
279 PROXY_IF_SANDBOXED(DisableNetworkNotifications());
282 void GetCurrentInformationInternal(NetworkInformation
* aInfo
) override
{
283 PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo
));
287 class WakeLockObserversManager final
288 : public ObserversManager
<WakeLockInformation
>
291 void EnableNotifications() override
{
292 PROXY_IF_SANDBOXED(EnableWakeLockNotifications());
295 void DisableNotifications() override
{
296 PROXY_IF_SANDBOXED(DisableWakeLockNotifications());
300 class ScreenConfigurationObserversManager final
301 : public CachingObserversManager
<ScreenConfiguration
>
304 void EnableNotifications() override
{
305 PROXY_IF_SANDBOXED(EnableScreenConfigurationNotifications());
308 void DisableNotifications() override
{
309 PROXY_IF_SANDBOXED(DisableScreenConfigurationNotifications());
312 void GetCurrentInformationInternal(ScreenConfiguration
* aInfo
) override
{
313 PROXY_IF_SANDBOXED(GetCurrentScreenConfiguration(aInfo
));
317 typedef mozilla::ObserverList
<SensorData
> SensorObserverList
;
318 StaticAutoPtr
<SensorObserverList
> sSensorObservers
[NUM_SENSOR_TYPE
];
320 static SensorObserverList
*
321 GetSensorObservers(SensorType sensor_type
) {
323 MOZ_ASSERT(sensor_type
< NUM_SENSOR_TYPE
);
325 if (!sSensorObservers
[sensor_type
]) {
326 sSensorObservers
[sensor_type
] = new SensorObserverList();
329 return sSensorObservers
[sensor_type
];
332 #define MOZ_IMPL_HAL_OBSERVER(name_) \
333 StaticAutoPtr<name_##ObserversManager> s##name_##Observers; \
335 static name_##ObserversManager* \
338 AssertMainThread(); \
340 if (!s##name_##Observers) { \
341 MOZ_ASSERT(sInitialized); \
342 s##name_##Observers = new name_##ObserversManager(); \
345 return s##name_##Observers; \
349 Register##name_##Observer(name_##Observer* aObserver) \
351 AssertMainThread(); \
352 name_##Observers()->AddObserver(aObserver); \
356 Unregister##name_##Observer(name_##Observer* aObserver) \
358 AssertMainThread(); \
359 name_##Observers()->RemoveObserver(aObserver); \
362 MOZ_IMPL_HAL_OBSERVER(Battery
)
365 GetCurrentBatteryInformation(BatteryInformation
* aInfo
)
367 *aInfo
= BatteryObservers()->GetCurrentInformation();
371 NotifyBatteryChange(const BatteryInformation
& aInfo
)
373 BatteryObservers()->CacheInformation(aInfo
);
374 BatteryObservers()->BroadcastCachedInformation();
378 EnableSensorNotifications(SensorType aSensor
) {
380 PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor
));
384 DisableSensorNotifications(SensorType aSensor
) {
386 PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor
));
390 RegisterSensorObserver(SensorType aSensor
, ISensorObserver
*aObserver
) {
391 SensorObserverList
* observers
= GetSensorObservers(aSensor
);
393 observers
->AddObserver(aObserver
);
394 if (observers
->Length() == 1) {
395 EnableSensorNotifications(aSensor
);
400 UnregisterSensorObserver(SensorType aSensor
, ISensorObserver
*aObserver
) {
401 SensorObserverList
* observers
= GetSensorObservers(aSensor
);
402 if (!observers
->RemoveObserver(aObserver
) || observers
->Length() > 0) {
405 DisableSensorNotifications(aSensor
);
409 NotifySensorChange(const SensorData
&aSensorData
) {
410 SensorObserverList
* observers
= GetSensorObservers(aSensorData
.sensor());
412 observers
->Broadcast(aSensorData
);
415 MOZ_IMPL_HAL_OBSERVER(Network
)
418 GetCurrentNetworkInformation(NetworkInformation
* aInfo
)
420 *aInfo
= NetworkObservers()->GetCurrentInformation();
424 NotifyNetworkChange(const NetworkInformation
& aInfo
)
426 NetworkObservers()->CacheInformation(aInfo
);
427 NetworkObservers()->BroadcastCachedInformation();
430 MOZ_IMPL_HAL_OBSERVER(WakeLock
)
433 ModifyWakeLock(const nsAString
& aTopic
,
434 WakeLockControl aLockAdjust
,
435 WakeLockControl aHiddenAdjust
,
436 uint64_t aProcessID
/* = CONTENT_PROCESS_ID_UNKNOWN */)
440 if (aProcessID
== CONTENT_PROCESS_ID_UNKNOWN
) {
441 aProcessID
= InSandbox() ? ContentChild::GetSingleton()->GetID() :
442 CONTENT_PROCESS_ID_MAIN
;
445 PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic
, aLockAdjust
,
446 aHiddenAdjust
, aProcessID
));
450 GetWakeLockInfo(const nsAString
& aTopic
, WakeLockInformation
* aWakeLockInfo
)
453 PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic
, aWakeLockInfo
));
457 NotifyWakeLockChange(const WakeLockInformation
& aInfo
)
460 WakeLockObservers()->BroadcastInformation(aInfo
);
463 MOZ_IMPL_HAL_OBSERVER(ScreenConfiguration
)
466 GetCurrentScreenConfiguration(ScreenConfiguration
* aScreenConfiguration
)
468 *aScreenConfiguration
=
469 ScreenConfigurationObservers()->GetCurrentInformation();
473 NotifyScreenConfigurationChange(const ScreenConfiguration
& aScreenConfiguration
)
475 ScreenConfigurationObservers()->CacheInformation(aScreenConfiguration
);
476 ScreenConfigurationObservers()->BroadcastCachedInformation();
480 LockScreenOrientation(const ScreenOrientation
& aOrientation
)
483 RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation
), false);
487 UnlockScreenOrientation()
490 PROXY_IF_SANDBOXED(UnlockScreenOrientation());
494 SetProcessPrioritySupported()
496 RETURN_PROXY_IF_SANDBOXED(SetProcessPrioritySupported(), false);
500 SetProcessPriority(int aPid
, ProcessPriority aPriority
)
502 // n.b. The sandboxed implementation crashes; SetProcessPriority works only
503 // from the main process.
504 PROXY_IF_SANDBOXED(SetProcessPriority(aPid
, aPriority
));
509 ProcessPriorityToString(ProcessPriority aPriority
)
512 case PROCESS_PRIORITY_MASTER
:
514 case PROCESS_PRIORITY_PREALLOC
:
516 case PROCESS_PRIORITY_FOREGROUND_HIGH
:
517 return "FOREGROUND_HIGH";
518 case PROCESS_PRIORITY_FOREGROUND
:
520 case PROCESS_PRIORITY_FOREGROUND_KEYBOARD
:
521 return "FOREGROUND_KEYBOARD";
522 case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE
:
523 return "BACKGROUND_PERCEIVABLE";
524 case PROCESS_PRIORITY_BACKGROUND
:
526 case PROCESS_PRIORITY_UNKNOWN
:
537 MOZ_ASSERT(!sInitialized
);
540 gLastIDToVibrate
= new WindowIdentifier::IDArrayType();
551 MOZ_ASSERT(sInitialized
);
553 gLastIDToVibrate
= nullptr;
555 sBatteryObservers
= nullptr;
556 sNetworkObservers
= nullptr;
557 sWakeLockObservers
= nullptr;
558 sScreenConfigurationObservers
= nullptr;
560 for (auto& sensorObserver
: sSensorObservers
) {
561 sensorObserver
= nullptr;
564 sInitialized
= false;
568 } // namespace mozilla