Bug 1686820 [wpt PR 27193] - Origin-keyed agent clusters: make COI imply origin-keyin...
[gecko.git] / hal / Hal.cpp
blob8784b28f6a89bf9fe1656e9922e9e3f2a0857346
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().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());
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, 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(
130 Vibrate(pattern, InSandbox() ? std::move(id) : WindowIdentifier()));
133 void CancelVibrate(nsPIDOMWindowInner* window) {
134 CancelVibrate(WindowIdentifier(window));
137 void CancelVibrate(WindowIdentifier&& id) {
138 AssertMainThread();
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.
144 PROXY_IF_SANDBOXED(
145 CancelVibrate(InSandbox() ? std::move(id) : WindowIdentifier()));
149 template <class InfoType>
150 class ObserversManager {
151 public:
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);
162 if (!removed) {
163 return;
166 if (mObservers.Length() == 0) {
167 DisableNotifications();
168 OnNotificationsDisabled();
172 void BroadcastInformation(const InfoType& aInfo) {
173 mObservers.Broadcast(aInfo);
176 protected:
177 ~ObserversManager() { MOZ_ASSERT(mObservers.Length() == 0); }
179 virtual void EnableNotifications() = 0;
180 virtual void DisableNotifications() = 0;
181 virtual void OnNotificationsDisabled() {}
183 private:
184 mozilla::ObserverList<InfoType> mObservers;
187 template <class InfoType>
188 class CachingObserversManager : public ObserversManager<InfoType> {
189 public:
190 InfoType GetCurrentInformation() {
191 if (mHasValidCache) {
192 return mInfo;
195 GetCurrentInformationInternal(&mInfo);
196 mHasValidCache = true;
197 return mInfo;
200 void CacheInformation(const InfoType& aInfo) {
201 mHasValidCache = true;
202 mInfo = aInfo;
205 void BroadcastCachedInformation() { this->BroadcastInformation(mInfo); }
207 protected:
208 virtual void GetCurrentInformationInternal(InfoType*) = 0;
210 void OnNotificationsDisabled() override { mHasValidCache = false; }
212 private:
213 InfoType mInfo;
214 bool mHasValidCache;
217 class BatteryObserversManager final
218 : public CachingObserversManager<BatteryInformation> {
219 protected:
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> {
235 protected:
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> {
251 protected:
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> {
263 protected:
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) {
281 AssertMainThread();
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) {
327 AssertMainThread();
328 PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
331 void DisableSensorNotifications(SensorType aSensor) {
332 AssertMainThread();
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) {
348 return;
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 */) {
375 AssertMainThread();
377 if (aProcessID == CONTENT_PROCESS_ID_UNKNOWN) {
378 aProcessID = InSandbox() ? ContentChild::GetSingleton()->GetID()
379 : CONTENT_PROCESS_ID_MAIN;
382 PROXY_IF_SANDBOXED(
383 ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust, aProcessID));
386 void GetWakeLockInfo(const nsAString& aTopic,
387 WakeLockInformation* aWakeLockInfo) {
388 AssertMainThread();
389 PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));
392 void NotifyWakeLockChange(const WakeLockInformation& aInfo) {
393 AssertMainThread();
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) {
411 AssertMainThread();
412 RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), false);
415 void UnlockScreenOrientation() {
416 AssertMainThread();
417 PROXY_IF_SANDBOXED(UnlockScreenOrientation());
420 bool SetProcessPrioritySupported() {
421 RETURN_PROXY_IF_SANDBOXED(SetProcessPrioritySupported(), false);
424 void SetProcessPriority(int aPid, ProcessPriority aPriority) {
425 // n.b. The sandboxed implementation crashes; SetProcessPriority works only
426 // from the main process.
427 PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority));
430 // From HalTypes.h.
431 const char* ProcessPriorityToString(ProcessPriority aPriority) {
432 switch (aPriority) {
433 case PROCESS_PRIORITY_PARENT_PROCESS:
434 return "PARENT_PROCESS";
435 case PROCESS_PRIORITY_PREALLOC:
436 return "PREALLOC";
437 case PROCESS_PRIORITY_FOREGROUND_HIGH:
438 return "FOREGROUND_HIGH";
439 case PROCESS_PRIORITY_FOREGROUND:
440 return "FOREGROUND";
441 case PROCESS_PRIORITY_FOREGROUND_KEYBOARD:
442 return "FOREGROUND_KEYBOARD";
443 case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
444 return "BACKGROUND_PERCEIVABLE";
445 case PROCESS_PRIORITY_BACKGROUND:
446 return "BACKGROUND";
447 case PROCESS_PRIORITY_UNKNOWN:
448 return "UNKNOWN";
449 default:
450 MOZ_ASSERT(false);
451 return "???";
455 void Init() {
456 MOZ_ASSERT(!sInitialized);
458 if (!InSandbox()) {
459 gLastIDToVibrate = new WindowIdentifier::IDArrayType();
462 WakeLockInit();
464 sInitialized = true;
467 void Shutdown() {
468 MOZ_ASSERT(sInitialized);
470 gLastIDToVibrate = nullptr;
472 sBatteryObservers = nullptr;
473 sNetworkObservers = nullptr;
474 sWakeLockObservers = nullptr;
475 sScreenConfigurationObservers = nullptr;
477 for (auto& sensorObserver : sSensorObservers) {
478 sensorObserver = nullptr;
481 sInitialized = false;
484 } // namespace mozilla::hal