Bug 1517622 [wpt PR 14704] - Update wpt metadata, a=testonly
[gecko.git] / hal / Hal.cpp
blobf231914808b5fe0b589fb98f8bd28e6eb0ebbed6
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"
9 #include "HalImpl.h"
10 #include "HalLog.h"
11 #include "HalSandbox.h"
12 #include "HalWakeLockInternal.h"
13 #include "nsIDOMWindow.h"
14 #include "mozilla/dom/Document.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"
27 #ifdef XP_WIN
28 # include <process.h>
29 # define getpid _getpid
30 #endif
32 using namespace mozilla::services;
33 using namespace mozilla::dom;
35 #define PROXY_IF_SANDBOXED(_call) \
36 do { \
37 if (InSandbox()) { \
38 if (!hal_sandbox::HalChildDestroyed()) { \
39 hal_sandbox::_call; \
40 } \
41 } else { \
42 hal_impl::_call; \
43 } \
44 } while (0)
46 #define RETURN_PROXY_IF_SANDBOXED(_call, defValue) \
47 do { \
48 if (InSandbox()) { \
49 if (hal_sandbox::HalChildDestroyed()) { \
50 return defValue; \
51 } \
52 return hal_sandbox::_call; \
53 } else { \
54 return hal_impl::_call; \
55 } \
56 } while (0)
58 namespace mozilla {
59 namespace hal {
61 static bool sInitialized = false;
63 mozilla::LogModule* GetHalLog() {
64 static mozilla::LazyLogModule sHalLog("hal");
65 return sHalLog;
68 namespace {
70 void AssertMainThread() { MOZ_ASSERT(NS_IsMainThread()); }
72 bool InSandbox() { return GeckoProcessType_Content == XRE_GetProcessType(); }
74 bool WindowIsActive(nsPIDOMWindowInner* aWindow) {
75 dom::Document* document = aWindow->GetDoc();
76 NS_ENSURE_TRUE(document, false);
77 return !document->Hidden();
80 StaticAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
82 static void RecordLastIDToVibrate(const WindowIdentifier& aId) {
83 if (!InSandbox()) {
84 *gLastIDToVibrate = aId.AsArray();
88 static bool MayCancelVibration(const WindowIdentifier& aId) {
89 // Although only active windows may start vibrations, a window may
90 // cancel its own vibration even if it's no longer active.
92 // After a window is marked as inactive, it sends a CancelVibrate
93 // request. We want this request to cancel a playing vibration
94 // started by that window, so we certainly don't want to reject the
95 // cancellation request because the window is now inactive.
97 // But it could be the case that, after this window became inactive,
98 // some other window came along and started a vibration. We don't
99 // want this window's cancellation request to cancel that window's
100 // actively-playing vibration!
102 // To solve this problem, we keep track of the id of the last window
103 // to start a vibration, and only accepts cancellation requests from
104 // the same window. All other cancellation requests are ignored.
106 return InSandbox() || (*gLastIDToVibrate == aId.AsArray());
109 } // namespace
111 void Vibrate(const nsTArray<uint32_t>& pattern, nsPIDOMWindowInner* window) {
112 Vibrate(pattern, WindowIdentifier(window));
115 void Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier& id) {
116 AssertMainThread();
118 // Only active windows may start vibrations. If |id| hasn't gone
119 // through the IPC layer -- that is, if our caller is the outside
120 // world, not hal_proxy -- check whether the window is active. If
121 // |id| has gone through IPC, don't check the window's visibility;
122 // only the window corresponding to the bottommost process has its
123 // visibility state set correctly.
124 if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
125 HAL_LOG("Vibrate: Window is inactive, dropping vibrate.");
126 return;
129 RecordLastIDToVibrate(id);
131 // Don't forward our ID if we are not in the sandbox, because hal_impl
132 // doesn't need it, and we don't want it to be tempted to read it. The
133 // empty identifier will assert if it's used.
134 PROXY_IF_SANDBOXED(Vibrate(pattern, InSandbox() ? id : WindowIdentifier()));
137 void CancelVibrate(nsPIDOMWindowInner* window) {
138 CancelVibrate(WindowIdentifier(window));
141 void CancelVibrate(const WindowIdentifier& id) {
142 AssertMainThread();
144 if (MayCancelVibration(id)) {
145 // Don't forward our ID if we are not in the sandbox, because hal_impl
146 // doesn't need it, and we don't want it to be tempted to read it. The
147 // empty identifier will assert if it's used.
148 PROXY_IF_SANDBOXED(CancelVibrate(InSandbox() ? id : WindowIdentifier()));
152 template <class InfoType>
153 class ObserversManager {
154 public:
155 void AddObserver(Observer<InfoType>* aObserver) {
156 mObservers.AddObserver(aObserver);
158 if (mObservers.Length() == 1) {
159 EnableNotifications();
163 void RemoveObserver(Observer<InfoType>* aObserver) {
164 bool removed = mObservers.RemoveObserver(aObserver);
165 if (!removed) {
166 return;
169 if (mObservers.Length() == 0) {
170 DisableNotifications();
171 OnNotificationsDisabled();
175 void BroadcastInformation(const InfoType& aInfo) {
176 mObservers.Broadcast(aInfo);
179 protected:
180 ~ObserversManager() { MOZ_ASSERT(mObservers.Length() == 0); }
182 virtual void EnableNotifications() = 0;
183 virtual void DisableNotifications() = 0;
184 virtual void OnNotificationsDisabled() {}
186 private:
187 mozilla::ObserverList<InfoType> mObservers;
190 template <class InfoType>
191 class CachingObserversManager : public ObserversManager<InfoType> {
192 public:
193 InfoType GetCurrentInformation() {
194 if (mHasValidCache) {
195 return mInfo;
198 GetCurrentInformationInternal(&mInfo);
199 mHasValidCache = true;
200 return mInfo;
203 void CacheInformation(const InfoType& aInfo) {
204 mHasValidCache = true;
205 mInfo = aInfo;
208 void BroadcastCachedInformation() { this->BroadcastInformation(mInfo); }
210 protected:
211 virtual void GetCurrentInformationInternal(InfoType*) = 0;
213 void OnNotificationsDisabled() override { mHasValidCache = false; }
215 private:
216 InfoType mInfo;
217 bool mHasValidCache;
220 class BatteryObserversManager final
221 : public CachingObserversManager<BatteryInformation> {
222 protected:
223 void EnableNotifications() override {
224 PROXY_IF_SANDBOXED(EnableBatteryNotifications());
227 void DisableNotifications() override {
228 PROXY_IF_SANDBOXED(DisableBatteryNotifications());
231 void GetCurrentInformationInternal(BatteryInformation* aInfo) override {
232 PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
236 class NetworkObserversManager final
237 : public CachingObserversManager<NetworkInformation> {
238 protected:
239 void EnableNotifications() override {
240 PROXY_IF_SANDBOXED(EnableNetworkNotifications());
243 void DisableNotifications() override {
244 PROXY_IF_SANDBOXED(DisableNetworkNotifications());
247 void GetCurrentInformationInternal(NetworkInformation* aInfo) override {
248 PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
252 class WakeLockObserversManager final
253 : public ObserversManager<WakeLockInformation> {
254 protected:
255 void EnableNotifications() override {
256 PROXY_IF_SANDBOXED(EnableWakeLockNotifications());
259 void DisableNotifications() override {
260 PROXY_IF_SANDBOXED(DisableWakeLockNotifications());
264 class ScreenConfigurationObserversManager final
265 : public CachingObserversManager<ScreenConfiguration> {
266 protected:
267 void EnableNotifications() override {
268 PROXY_IF_SANDBOXED(EnableScreenConfigurationNotifications());
271 void DisableNotifications() override {
272 PROXY_IF_SANDBOXED(DisableScreenConfigurationNotifications());
275 void GetCurrentInformationInternal(ScreenConfiguration* aInfo) override {
276 PROXY_IF_SANDBOXED(GetCurrentScreenConfiguration(aInfo));
280 typedef mozilla::ObserverList<SensorData> SensorObserverList;
281 StaticAutoPtr<SensorObserverList> sSensorObservers[NUM_SENSOR_TYPE];
283 static SensorObserverList* GetSensorObservers(SensorType sensor_type) {
284 AssertMainThread();
285 MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
287 if (!sSensorObservers[sensor_type]) {
288 sSensorObservers[sensor_type] = new SensorObserverList();
291 return sSensorObservers[sensor_type];
294 #define MOZ_IMPL_HAL_OBSERVER(name_) \
295 StaticAutoPtr<name_##ObserversManager> s##name_##Observers; \
297 static name_##ObserversManager* name_##Observers() { \
298 AssertMainThread(); \
300 if (!s##name_##Observers) { \
301 MOZ_ASSERT(sInitialized); \
302 s##name_##Observers = new name_##ObserversManager(); \
305 return s##name_##Observers; \
308 void Register##name_##Observer(name_##Observer* aObserver) { \
309 AssertMainThread(); \
310 name_##Observers()->AddObserver(aObserver); \
313 void Unregister##name_##Observer(name_##Observer* aObserver) { \
314 AssertMainThread(); \
315 name_##Observers()->RemoveObserver(aObserver); \
318 MOZ_IMPL_HAL_OBSERVER(Battery)
320 void GetCurrentBatteryInformation(BatteryInformation* aInfo) {
321 *aInfo = BatteryObservers()->GetCurrentInformation();
324 void NotifyBatteryChange(const BatteryInformation& aInfo) {
325 BatteryObservers()->CacheInformation(aInfo);
326 BatteryObservers()->BroadcastCachedInformation();
329 void EnableSensorNotifications(SensorType aSensor) {
330 AssertMainThread();
331 PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
334 void DisableSensorNotifications(SensorType aSensor) {
335 AssertMainThread();
336 PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor));
339 void RegisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
340 SensorObserverList* observers = GetSensorObservers(aSensor);
342 observers->AddObserver(aObserver);
343 if (observers->Length() == 1) {
344 EnableSensorNotifications(aSensor);
348 void UnregisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
349 SensorObserverList* observers = GetSensorObservers(aSensor);
350 if (!observers->RemoveObserver(aObserver) || observers->Length() > 0) {
351 return;
353 DisableSensorNotifications(aSensor);
356 void NotifySensorChange(const SensorData& aSensorData) {
357 SensorObserverList* observers = GetSensorObservers(aSensorData.sensor());
359 observers->Broadcast(aSensorData);
362 MOZ_IMPL_HAL_OBSERVER(Network)
364 void GetCurrentNetworkInformation(NetworkInformation* aInfo) {
365 *aInfo = NetworkObservers()->GetCurrentInformation();
368 void NotifyNetworkChange(const NetworkInformation& aInfo) {
369 NetworkObservers()->CacheInformation(aInfo);
370 NetworkObservers()->BroadcastCachedInformation();
373 MOZ_IMPL_HAL_OBSERVER(WakeLock)
375 void ModifyWakeLock(const nsAString& aTopic, WakeLockControl aLockAdjust,
376 WakeLockControl aHiddenAdjust,
377 uint64_t aProcessID /* = CONTENT_PROCESS_ID_UNKNOWN */) {
378 AssertMainThread();
380 if (aProcessID == CONTENT_PROCESS_ID_UNKNOWN) {
381 aProcessID = InSandbox() ? ContentChild::GetSingleton()->GetID()
382 : CONTENT_PROCESS_ID_MAIN;
385 PROXY_IF_SANDBOXED(
386 ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust, aProcessID));
389 void GetWakeLockInfo(const nsAString& aTopic,
390 WakeLockInformation* aWakeLockInfo) {
391 AssertMainThread();
392 PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));
395 void NotifyWakeLockChange(const WakeLockInformation& aInfo) {
396 AssertMainThread();
397 WakeLockObservers()->BroadcastInformation(aInfo);
400 MOZ_IMPL_HAL_OBSERVER(ScreenConfiguration)
402 void GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration) {
403 *aScreenConfiguration =
404 ScreenConfigurationObservers()->GetCurrentInformation();
407 void NotifyScreenConfigurationChange(
408 const ScreenConfiguration& aScreenConfiguration) {
409 ScreenConfigurationObservers()->CacheInformation(aScreenConfiguration);
410 ScreenConfigurationObservers()->BroadcastCachedInformation();
413 bool LockScreenOrientation(const ScreenOrientation& aOrientation) {
414 AssertMainThread();
415 RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), false);
418 void UnlockScreenOrientation() {
419 AssertMainThread();
420 PROXY_IF_SANDBOXED(UnlockScreenOrientation());
423 bool SetProcessPrioritySupported() {
424 RETURN_PROXY_IF_SANDBOXED(SetProcessPrioritySupported(), false);
427 void SetProcessPriority(int aPid, ProcessPriority aPriority) {
428 // n.b. The sandboxed implementation crashes; SetProcessPriority works only
429 // from the main process.
430 PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority));
433 // From HalTypes.h.
434 const char* ProcessPriorityToString(ProcessPriority aPriority) {
435 switch (aPriority) {
436 case PROCESS_PRIORITY_MASTER:
437 return "MASTER";
438 case PROCESS_PRIORITY_PREALLOC:
439 return "PREALLOC";
440 case PROCESS_PRIORITY_FOREGROUND_HIGH:
441 return "FOREGROUND_HIGH";
442 case PROCESS_PRIORITY_FOREGROUND:
443 return "FOREGROUND";
444 case PROCESS_PRIORITY_FOREGROUND_KEYBOARD:
445 return "FOREGROUND_KEYBOARD";
446 case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
447 return "BACKGROUND_PERCEIVABLE";
448 case PROCESS_PRIORITY_BACKGROUND:
449 return "BACKGROUND";
450 case PROCESS_PRIORITY_UNKNOWN:
451 return "UNKNOWN";
452 default:
453 MOZ_ASSERT(false);
454 return "???";
458 void Init() {
459 MOZ_ASSERT(!sInitialized);
461 if (!InSandbox()) {
462 gLastIDToVibrate = new WindowIdentifier::IDArrayType();
465 WakeLockInit();
467 sInitialized = true;
470 void Shutdown() {
471 MOZ_ASSERT(sInitialized);
473 gLastIDToVibrate = nullptr;
475 sBatteryObservers = nullptr;
476 sNetworkObservers = nullptr;
477 sWakeLockObservers = nullptr;
478 sScreenConfigurationObservers = nullptr;
480 for (auto& sensorObserver : sSensorObservers) {
481 sensorObserver = nullptr;
484 sInitialized = false;
487 } // namespace hal
488 } // namespace mozilla