Bug 1610630 [wpt PR 21320] - Add meta:timeout=long to FileSystemBaseHandle-postMessag...
[gecko.git] / hal / Hal.cpp
blobf3646b3a9b3b7834734a46e03322bfed7be369e0
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 "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"
23 #ifdef XP_WIN
24 # include <process.h>
25 # define getpid _getpid
26 #endif
28 using namespace mozilla::services;
29 using namespace mozilla::dom;
31 #define PROXY_IF_SANDBOXED(_call) \
32 do { \
33 if (InSandbox()) { \
34 if (!hal_sandbox::HalChildDestroyed()) { \
35 hal_sandbox::_call; \
36 } \
37 } else { \
38 hal_impl::_call; \
39 } \
40 } while (0)
42 #define RETURN_PROXY_IF_SANDBOXED(_call, defValue) \
43 do { \
44 if (InSandbox()) { \
45 if (hal_sandbox::HalChildDestroyed()) { \
46 return defValue; \
47 } \
48 return hal_sandbox::_call; \
49 } else { \
50 return hal_impl::_call; \
51 } \
52 } while (0)
54 namespace mozilla::hal {
56 static bool sInitialized = false;
58 mozilla::LogModule* GetHalLog() {
59 static mozilla::LazyLogModule sHalLog("hal");
60 return sHalLog;
63 namespace {
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) {
78 if (!InSandbox()) {
79 *gLastIDToVibrate = aId.AsArray();
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());
104 } // namespace
106 void Vibrate(const nsTArray<uint32_t>& pattern, nsPIDOMWindowInner* window) {
107 Vibrate(pattern, WindowIdentifier(window));
110 void Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier& id) {
111 AssertMainThread();
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.");
121 return;
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.
129 PROXY_IF_SANDBOXED(Vibrate(pattern, InSandbox() ? id : WindowIdentifier()));
132 void CancelVibrate(nsPIDOMWindowInner* window) {
133 CancelVibrate(WindowIdentifier(window));
136 void CancelVibrate(const WindowIdentifier& id) {
137 AssertMainThread();
139 if (MayCancelVibration(id)) {
140 // Don't forward our ID if we are not in the sandbox, because hal_impl
141 // doesn't need it, and we don't want it to be tempted to read it. The
142 // empty identifier will assert if it's used.
143 PROXY_IF_SANDBOXED(CancelVibrate(InSandbox() ? id : WindowIdentifier()));
147 template <class InfoType>
148 class ObserversManager {
149 public:
150 void AddObserver(Observer<InfoType>* aObserver) {
151 mObservers.AddObserver(aObserver);
153 if (mObservers.Length() == 1) {
154 EnableNotifications();
158 void RemoveObserver(Observer<InfoType>* aObserver) {
159 bool removed = mObservers.RemoveObserver(aObserver);
160 if (!removed) {
161 return;
164 if (mObservers.Length() == 0) {
165 DisableNotifications();
166 OnNotificationsDisabled();
170 void BroadcastInformation(const InfoType& aInfo) {
171 mObservers.Broadcast(aInfo);
174 protected:
175 ~ObserversManager() { MOZ_ASSERT(mObservers.Length() == 0); }
177 virtual void EnableNotifications() = 0;
178 virtual void DisableNotifications() = 0;
179 virtual void OnNotificationsDisabled() {}
181 private:
182 mozilla::ObserverList<InfoType> mObservers;
185 template <class InfoType>
186 class CachingObserversManager : public ObserversManager<InfoType> {
187 public:
188 InfoType GetCurrentInformation() {
189 if (mHasValidCache) {
190 return mInfo;
193 GetCurrentInformationInternal(&mInfo);
194 mHasValidCache = true;
195 return mInfo;
198 void CacheInformation(const InfoType& aInfo) {
199 mHasValidCache = true;
200 mInfo = aInfo;
203 void BroadcastCachedInformation() { this->BroadcastInformation(mInfo); }
205 protected:
206 virtual void GetCurrentInformationInternal(InfoType*) = 0;
208 void OnNotificationsDisabled() override { mHasValidCache = false; }
210 private:
211 InfoType mInfo;
212 bool mHasValidCache;
215 class BatteryObserversManager final
216 : public CachingObserversManager<BatteryInformation> {
217 protected:
218 void EnableNotifications() override {
219 PROXY_IF_SANDBOXED(EnableBatteryNotifications());
222 void DisableNotifications() override {
223 PROXY_IF_SANDBOXED(DisableBatteryNotifications());
226 void GetCurrentInformationInternal(BatteryInformation* aInfo) override {
227 PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
231 class NetworkObserversManager final
232 : public CachingObserversManager<NetworkInformation> {
233 protected:
234 void EnableNotifications() override {
235 PROXY_IF_SANDBOXED(EnableNetworkNotifications());
238 void DisableNotifications() override {
239 PROXY_IF_SANDBOXED(DisableNetworkNotifications());
242 void GetCurrentInformationInternal(NetworkInformation* aInfo) override {
243 PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
247 class WakeLockObserversManager final
248 : public ObserversManager<WakeLockInformation> {
249 protected:
250 void EnableNotifications() override {
251 PROXY_IF_SANDBOXED(EnableWakeLockNotifications());
254 void DisableNotifications() override {
255 PROXY_IF_SANDBOXED(DisableWakeLockNotifications());
259 class ScreenConfigurationObserversManager final
260 : public CachingObserversManager<ScreenConfiguration> {
261 protected:
262 void EnableNotifications() override {
263 PROXY_IF_SANDBOXED(EnableScreenConfigurationNotifications());
266 void DisableNotifications() override {
267 PROXY_IF_SANDBOXED(DisableScreenConfigurationNotifications());
270 void GetCurrentInformationInternal(ScreenConfiguration* aInfo) override {
271 PROXY_IF_SANDBOXED(GetCurrentScreenConfiguration(aInfo));
275 typedef mozilla::ObserverList<SensorData> SensorObserverList;
276 StaticAutoPtr<SensorObserverList> sSensorObservers[NUM_SENSOR_TYPE];
278 static SensorObserverList* GetSensorObservers(SensorType sensor_type) {
279 AssertMainThread();
280 MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
282 if (!sSensorObservers[sensor_type]) {
283 sSensorObservers[sensor_type] = new SensorObserverList();
286 return sSensorObservers[sensor_type];
289 #define MOZ_IMPL_HAL_OBSERVER(name_) \
290 StaticAutoPtr<name_##ObserversManager> s##name_##Observers; \
292 static name_##ObserversManager* name_##Observers() { \
293 AssertMainThread(); \
295 if (!s##name_##Observers) { \
296 MOZ_ASSERT(sInitialized); \
297 s##name_##Observers = new name_##ObserversManager(); \
300 return s##name_##Observers; \
303 void Register##name_##Observer(name_##Observer* aObserver) { \
304 AssertMainThread(); \
305 name_##Observers()->AddObserver(aObserver); \
308 void Unregister##name_##Observer(name_##Observer* aObserver) { \
309 AssertMainThread(); \
310 name_##Observers()->RemoveObserver(aObserver); \
313 MOZ_IMPL_HAL_OBSERVER(Battery)
315 void GetCurrentBatteryInformation(BatteryInformation* aInfo) {
316 *aInfo = BatteryObservers()->GetCurrentInformation();
319 void NotifyBatteryChange(const BatteryInformation& aInfo) {
320 BatteryObservers()->CacheInformation(aInfo);
321 BatteryObservers()->BroadcastCachedInformation();
324 void EnableSensorNotifications(SensorType aSensor) {
325 AssertMainThread();
326 PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
329 void DisableSensorNotifications(SensorType aSensor) {
330 AssertMainThread();
331 PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor));
334 void RegisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
335 SensorObserverList* observers = GetSensorObservers(aSensor);
337 observers->AddObserver(aObserver);
338 if (observers->Length() == 1) {
339 EnableSensorNotifications(aSensor);
343 void UnregisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
344 SensorObserverList* observers = GetSensorObservers(aSensor);
345 if (!observers->RemoveObserver(aObserver) || observers->Length() > 0) {
346 return;
348 DisableSensorNotifications(aSensor);
351 void NotifySensorChange(const SensorData& aSensorData) {
352 SensorObserverList* observers = GetSensorObservers(aSensorData.sensor());
354 observers->Broadcast(aSensorData);
357 MOZ_IMPL_HAL_OBSERVER(Network)
359 void GetCurrentNetworkInformation(NetworkInformation* aInfo) {
360 *aInfo = NetworkObservers()->GetCurrentInformation();
363 void NotifyNetworkChange(const NetworkInformation& aInfo) {
364 NetworkObservers()->CacheInformation(aInfo);
365 NetworkObservers()->BroadcastCachedInformation();
368 MOZ_IMPL_HAL_OBSERVER(WakeLock)
370 void ModifyWakeLock(const nsAString& aTopic, WakeLockControl aLockAdjust,
371 WakeLockControl aHiddenAdjust,
372 uint64_t aProcessID /* = CONTENT_PROCESS_ID_UNKNOWN */) {
373 AssertMainThread();
375 if (aProcessID == CONTENT_PROCESS_ID_UNKNOWN) {
376 aProcessID = InSandbox() ? ContentChild::GetSingleton()->GetID()
377 : CONTENT_PROCESS_ID_MAIN;
380 PROXY_IF_SANDBOXED(
381 ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust, aProcessID));
384 void GetWakeLockInfo(const nsAString& aTopic,
385 WakeLockInformation* aWakeLockInfo) {
386 AssertMainThread();
387 PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));
390 void NotifyWakeLockChange(const WakeLockInformation& aInfo) {
391 AssertMainThread();
392 WakeLockObservers()->BroadcastInformation(aInfo);
395 MOZ_IMPL_HAL_OBSERVER(ScreenConfiguration)
397 void GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration) {
398 *aScreenConfiguration =
399 ScreenConfigurationObservers()->GetCurrentInformation();
402 void NotifyScreenConfigurationChange(
403 const ScreenConfiguration& aScreenConfiguration) {
404 ScreenConfigurationObservers()->CacheInformation(aScreenConfiguration);
405 ScreenConfigurationObservers()->BroadcastCachedInformation();
408 bool LockScreenOrientation(const ScreenOrientation& aOrientation) {
409 AssertMainThread();
410 RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), false);
413 void UnlockScreenOrientation() {
414 AssertMainThread();
415 PROXY_IF_SANDBOXED(UnlockScreenOrientation());
418 bool SetProcessPrioritySupported() {
419 RETURN_PROXY_IF_SANDBOXED(SetProcessPrioritySupported(), false);
422 void SetProcessPriority(int aPid, ProcessPriority aPriority) {
423 // n.b. The sandboxed implementation crashes; SetProcessPriority works only
424 // from the main process.
425 PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority));
428 // From HalTypes.h.
429 const char* ProcessPriorityToString(ProcessPriority aPriority) {
430 switch (aPriority) {
431 case PROCESS_PRIORITY_MASTER:
432 return "MASTER";
433 case PROCESS_PRIORITY_PREALLOC:
434 return "PREALLOC";
435 case PROCESS_PRIORITY_FOREGROUND_HIGH:
436 return "FOREGROUND_HIGH";
437 case PROCESS_PRIORITY_FOREGROUND:
438 return "FOREGROUND";
439 case PROCESS_PRIORITY_FOREGROUND_KEYBOARD:
440 return "FOREGROUND_KEYBOARD";
441 case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
442 return "BACKGROUND_PERCEIVABLE";
443 case PROCESS_PRIORITY_BACKGROUND:
444 return "BACKGROUND";
445 case PROCESS_PRIORITY_UNKNOWN:
446 return "UNKNOWN";
447 default:
448 MOZ_ASSERT(false);
449 return "???";
453 void Init() {
454 MOZ_ASSERT(!sInitialized);
456 if (!InSandbox()) {
457 gLastIDToVibrate = new WindowIdentifier::IDArrayType();
460 WakeLockInit();
462 sInitialized = true;
465 void Shutdown() {
466 MOZ_ASSERT(sInitialized);
468 gLastIDToVibrate = nullptr;
470 sBatteryObservers = nullptr;
471 sNetworkObservers = nullptr;
472 sWakeLockObservers = nullptr;
473 sScreenConfigurationObservers = nullptr;
475 for (auto& sensorObserver : sSensorObservers) {
476 sensorObserver = nullptr;
479 sInitialized = false;
482 } // namespace mozilla::hal