Bug 1814798 - pt 1. Add bool to enable/disable PHC at runtime r=glandium
[gecko.git] / hal / Hal.cpp
blob92d99cf43eb72470e07c47d4c1b9a896cb205243
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 "nsXULAppAPI.h"
15 #include "nsPIDOMWindow.h"
16 #include "mozilla/Observer.h"
17 #include "mozilla/dom/ContentChild.h"
18 #include "WindowIdentifier.h"
20 #ifdef XP_WIN
21 # include <process.h>
22 # define getpid _getpid
23 #endif
25 using namespace mozilla::services;
26 using namespace mozilla::dom;
28 #define PROXY_IF_SANDBOXED(_call) \
29 do { \
30 if (InSandbox()) { \
31 if (!hal_sandbox::HalChildDestroyed()) { \
32 hal_sandbox::_call; \
33 } \
34 } else { \
35 hal_impl::_call; \
36 } \
37 } while (0)
39 #define RETURN_PROXY_IF_SANDBOXED(_call, defValue) \
40 do { \
41 if (InSandbox()) { \
42 if (hal_sandbox::HalChildDestroyed()) { \
43 return defValue; \
44 } \
45 return hal_sandbox::_call; \
46 } else { \
47 return hal_impl::_call; \
48 } \
49 } while (0)
51 namespace mozilla::hal {
53 static bool sInitialized = false;
55 mozilla::LogModule* GetHalLog() {
56 static mozilla::LazyLogModule sHalLog("hal");
57 return sHalLog;
60 namespace {
62 void AssertMainThread() { MOZ_ASSERT(NS_IsMainThread()); }
64 bool InSandbox() { return GeckoProcessType_Content == XRE_GetProcessType(); }
66 bool WindowIsActive(nsPIDOMWindowInner* aWindow) {
67 dom::Document* document = aWindow->GetDoc();
68 NS_ENSURE_TRUE(document, false);
69 return !document->Hidden();
72 StaticAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
74 static void RecordLastIDToVibrate(const WindowIdentifier& aId) {
75 if (!InSandbox()) {
76 *gLastIDToVibrate = aId.AsArray().Clone();
80 static bool MayCancelVibration(const WindowIdentifier& aId) {
81 // Although only active windows may start vibrations, a window may
82 // cancel its own vibration even if it's no longer active.
84 // After a window is marked as inactive, it sends a CancelVibrate
85 // request. We want this request to cancel a playing vibration
86 // started by that window, so we certainly don't want to reject the
87 // cancellation request because the window is now inactive.
89 // But it could be the case that, after this window became inactive,
90 // some other window came along and started a vibration. We don't
91 // want this window's cancellation request to cancel that window's
92 // actively-playing vibration!
94 // To solve this problem, we keep track of the id of the last window
95 // to start a vibration, and only accepts cancellation requests from
96 // the same window. All other cancellation requests are ignored.
98 return InSandbox() || (*gLastIDToVibrate == aId.AsArray());
101 } // namespace
103 void Vibrate(const nsTArray<uint32_t>& pattern, nsPIDOMWindowInner* window) {
104 Vibrate(pattern, WindowIdentifier(window));
107 void Vibrate(const nsTArray<uint32_t>& pattern, WindowIdentifier&& id) {
108 AssertMainThread();
110 // Only active windows may start vibrations. If |id| hasn't gone
111 // through the IPC layer -- that is, if our caller is the outside
112 // world, not hal_proxy -- check whether the window is active. If
113 // |id| has gone through IPC, don't check the window's visibility;
114 // only the window corresponding to the bottommost process has its
115 // visibility state set correctly.
116 if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
117 HAL_LOG("Vibrate: Window is inactive, dropping vibrate.");
118 return;
121 RecordLastIDToVibrate(id);
123 // Don't forward our ID if we are not in the sandbox, because hal_impl
124 // doesn't need it, and we don't want it to be tempted to read it. The
125 // empty identifier will assert if it's used.
126 PROXY_IF_SANDBOXED(
127 Vibrate(pattern, InSandbox() ? std::move(id) : WindowIdentifier()));
130 void CancelVibrate(nsPIDOMWindowInner* window) {
131 CancelVibrate(WindowIdentifier(window));
134 void CancelVibrate(WindowIdentifier&& id) {
135 AssertMainThread();
137 if (MayCancelVibration(id)) {
138 // Don't forward our ID if we are not in the sandbox, because hal_impl
139 // doesn't need it, and we don't want it to be tempted to read it. The
140 // empty identifier will assert if it's used.
141 PROXY_IF_SANDBOXED(
142 CancelVibrate(InSandbox() ? std::move(id) : WindowIdentifier()));
146 template <class InfoType>
147 class ObserversManager {
148 public:
149 void AddObserver(Observer<InfoType>* aObserver) {
150 mObservers.AddObserver(aObserver);
152 if (mObservers.Length() == 1) {
153 EnableNotifications();
157 void RemoveObserver(Observer<InfoType>* aObserver) {
158 bool removed = mObservers.RemoveObserver(aObserver);
159 if (!removed) {
160 return;
163 if (mObservers.Length() == 0) {
164 DisableNotifications();
165 OnNotificationsDisabled();
169 void BroadcastInformation(const InfoType& aInfo) {
170 mObservers.Broadcast(aInfo);
173 protected:
174 ~ObserversManager() { MOZ_ASSERT(mObservers.Length() == 0); }
176 virtual void EnableNotifications() = 0;
177 virtual void DisableNotifications() = 0;
178 virtual void OnNotificationsDisabled() {}
180 private:
181 mozilla::ObserverList<InfoType> mObservers;
184 template <class InfoType>
185 class CachingObserversManager : public ObserversManager<InfoType> {
186 public:
187 InfoType GetCurrentInformation() {
188 if (mHasValidCache) {
189 return mInfo;
192 GetCurrentInformationInternal(&mInfo);
193 mHasValidCache = true;
194 return mInfo;
197 void CacheInformation(const InfoType& aInfo) {
198 mHasValidCache = true;
199 mInfo = aInfo;
202 void BroadcastCachedInformation() { this->BroadcastInformation(mInfo); }
204 protected:
205 virtual void GetCurrentInformationInternal(InfoType*) = 0;
207 void OnNotificationsDisabled() override { mHasValidCache = false; }
209 private:
210 InfoType mInfo;
211 bool mHasValidCache;
214 class BatteryObserversManager final
215 : public CachingObserversManager<BatteryInformation> {
216 protected:
217 void EnableNotifications() override {
218 PROXY_IF_SANDBOXED(EnableBatteryNotifications());
221 void DisableNotifications() override {
222 PROXY_IF_SANDBOXED(DisableBatteryNotifications());
225 void GetCurrentInformationInternal(BatteryInformation* aInfo) override {
226 PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
230 class NetworkObserversManager final
231 : public CachingObserversManager<NetworkInformation> {
232 protected:
233 void EnableNotifications() override {
234 PROXY_IF_SANDBOXED(EnableNetworkNotifications());
237 void DisableNotifications() override {
238 PROXY_IF_SANDBOXED(DisableNetworkNotifications());
241 void GetCurrentInformationInternal(NetworkInformation* aInfo) override {
242 PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
246 class WakeLockObserversManager final
247 : public ObserversManager<WakeLockInformation> {
248 protected:
249 void EnableNotifications() override {
250 PROXY_IF_SANDBOXED(EnableWakeLockNotifications());
253 void DisableNotifications() override {
254 PROXY_IF_SANDBOXED(DisableWakeLockNotifications());
258 typedef mozilla::ObserverList<SensorData> SensorObserverList;
259 StaticAutoPtr<SensorObserverList> sSensorObservers[NUM_SENSOR_TYPE];
261 static SensorObserverList* GetSensorObservers(SensorType sensor_type) {
262 AssertMainThread();
263 MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
265 if (!sSensorObservers[sensor_type]) {
266 sSensorObservers[sensor_type] = new SensorObserverList();
269 return sSensorObservers[sensor_type];
272 #define MOZ_IMPL_HAL_OBSERVER(name_) \
273 StaticAutoPtr<name_##ObserversManager> s##name_##Observers; \
275 static name_##ObserversManager* name_##Observers() { \
276 AssertMainThread(); \
278 if (!s##name_##Observers) { \
279 MOZ_ASSERT(sInitialized); \
280 s##name_##Observers = new name_##ObserversManager(); \
283 return s##name_##Observers; \
286 void Register##name_##Observer(name_##Observer* aObserver) { \
287 AssertMainThread(); \
288 name_##Observers()->AddObserver(aObserver); \
291 void Unregister##name_##Observer(name_##Observer* aObserver) { \
292 AssertMainThread(); \
293 name_##Observers()->RemoveObserver(aObserver); \
296 MOZ_IMPL_HAL_OBSERVER(Battery)
298 void GetCurrentBatteryInformation(BatteryInformation* aInfo) {
299 *aInfo = BatteryObservers()->GetCurrentInformation();
302 void NotifyBatteryChange(const BatteryInformation& aInfo) {
303 BatteryObservers()->CacheInformation(aInfo);
304 BatteryObservers()->BroadcastCachedInformation();
307 void EnableSensorNotifications(SensorType aSensor) {
308 AssertMainThread();
309 PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
312 void DisableSensorNotifications(SensorType aSensor) {
313 AssertMainThread();
314 PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor));
317 void RegisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
318 SensorObserverList* observers = GetSensorObservers(aSensor);
320 observers->AddObserver(aObserver);
321 if (observers->Length() == 1) {
322 EnableSensorNotifications(aSensor);
326 void UnregisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
327 SensorObserverList* observers = GetSensorObservers(aSensor);
328 if (!observers->RemoveObserver(aObserver) || observers->Length() > 0) {
329 return;
331 DisableSensorNotifications(aSensor);
334 void NotifySensorChange(const SensorData& aSensorData) {
335 SensorObserverList* observers = GetSensorObservers(aSensorData.sensor());
337 observers->Broadcast(aSensorData);
340 MOZ_IMPL_HAL_OBSERVER(Network)
342 void GetCurrentNetworkInformation(NetworkInformation* aInfo) {
343 *aInfo = NetworkObservers()->GetCurrentInformation();
346 void NotifyNetworkChange(const NetworkInformation& aInfo) {
347 NetworkObservers()->CacheInformation(aInfo);
348 NetworkObservers()->BroadcastCachedInformation();
351 MOZ_IMPL_HAL_OBSERVER(WakeLock)
353 void ModifyWakeLock(const nsAString& aTopic, WakeLockControl aLockAdjust,
354 WakeLockControl aHiddenAdjust,
355 uint64_t aProcessID /* = CONTENT_PROCESS_ID_UNKNOWN */) {
356 AssertMainThread();
358 if (aProcessID == CONTENT_PROCESS_ID_UNKNOWN) {
359 aProcessID = InSandbox() ? ContentChild::GetSingleton()->GetID()
360 : CONTENT_PROCESS_ID_MAIN;
363 PROXY_IF_SANDBOXED(
364 ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust, aProcessID));
367 void GetWakeLockInfo(const nsAString& aTopic,
368 WakeLockInformation* aWakeLockInfo) {
369 AssertMainThread();
370 PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));
373 void NotifyWakeLockChange(const WakeLockInformation& aInfo) {
374 AssertMainThread();
375 WakeLockObservers()->BroadcastInformation(aInfo);
378 RefPtr<GenericNonExclusivePromise> LockScreenOrientation(
379 const ScreenOrientation& aOrientation) {
380 AssertMainThread();
381 RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), nullptr);
384 void UnlockScreenOrientation() {
385 AssertMainThread();
386 PROXY_IF_SANDBOXED(UnlockScreenOrientation());
389 void SetProcessPriority(int aPid, ProcessPriority aPriority) {
390 // n.b. The sandboxed implementation crashes; SetProcessPriority works only
391 // from the main process.
392 PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority));
395 // From HalTypes.h.
396 const char* ProcessPriorityToString(ProcessPriority aPriority) {
397 switch (aPriority) {
398 case PROCESS_PRIORITY_PARENT_PROCESS:
399 return "PARENT_PROCESS";
400 case PROCESS_PRIORITY_PREALLOC:
401 return "PREALLOC";
402 case PROCESS_PRIORITY_FOREGROUND_HIGH:
403 return "FOREGROUND_HIGH";
404 case PROCESS_PRIORITY_FOREGROUND:
405 return "FOREGROUND";
406 case PROCESS_PRIORITY_FOREGROUND_KEYBOARD:
407 return "FOREGROUND_KEYBOARD";
408 case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
409 return "BACKGROUND_PERCEIVABLE";
410 case PROCESS_PRIORITY_BACKGROUND:
411 return "BACKGROUND";
412 case PROCESS_PRIORITY_UNKNOWN:
413 return "UNKNOWN";
414 default:
415 MOZ_ASSERT(false);
416 return "???";
420 UniquePtr<hal::PerformanceHintSession> CreatePerformanceHintSession(
421 const nsTArray<PlatformThreadHandle>& aThreads,
422 mozilla::TimeDuration aTargetWorkDuration) {
423 return hal_impl::CreatePerformanceHintSession(aThreads, aTargetWorkDuration);
426 void Init() {
427 MOZ_ASSERT(!sInitialized);
429 if (!InSandbox()) {
430 gLastIDToVibrate = new WindowIdentifier::IDArrayType();
433 WakeLockInit();
435 sInitialized = true;
438 void Shutdown() {
439 MOZ_ASSERT(sInitialized);
441 gLastIDToVibrate = nullptr;
443 sBatteryObservers = nullptr;
444 sNetworkObservers = nullptr;
445 sWakeLockObservers = nullptr;
447 for (auto& sensorObserver : sSensorObservers) {
448 sensorObserver = nullptr;
451 sInitialized = false;
454 } // namespace mozilla::hal