Bug 1568860 - Part 2: Make getAllFonts fission compatible. r=ochameau
[gecko.git] / hal / Hal.cpp
blob0891763549eeaaac0d70da12b4aa45f05a5b67dd
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 "nsIDocShell.h"
15 #include "nsIBrowserChild.h"
16 #include "nsIWebNavigation.h"
17 #include "nsThreadUtils.h"
18 #include "nsXULAppAPI.h"
19 #include "nsPIDOMWindow.h"
20 #include "nsJSUtils.h"
21 #include "mozilla/ClearOnShutdown.h"
22 #include "mozilla/Observer.h"
23 #include "mozilla/dom/ContentChild.h"
24 #include "WindowIdentifier.h"
26 #ifdef XP_WIN
27 # include <process.h>
28 # define getpid _getpid
29 #endif
31 using namespace mozilla::services;
32 using namespace mozilla::dom;
34 #define PROXY_IF_SANDBOXED(_call) \
35 do { \
36 if (InSandbox()) { \
37 if (!hal_sandbox::HalChildDestroyed()) { \
38 hal_sandbox::_call; \
39 } \
40 } else { \
41 hal_impl::_call; \
42 } \
43 } while (0)
45 #define RETURN_PROXY_IF_SANDBOXED(_call, defValue) \
46 do { \
47 if (InSandbox()) { \
48 if (hal_sandbox::HalChildDestroyed()) { \
49 return defValue; \
50 } \
51 return hal_sandbox::_call; \
52 } else { \
53 return hal_impl::_call; \
54 } \
55 } while (0)
57 namespace mozilla {
58 namespace hal {
60 static bool sInitialized = false;
62 mozilla::LogModule* GetHalLog() {
63 static mozilla::LazyLogModule sHalLog("hal");
64 return sHalLog;
67 namespace {
69 void AssertMainThread() { MOZ_ASSERT(NS_IsMainThread()); }
71 bool InSandbox() { return GeckoProcessType_Content == XRE_GetProcessType(); }
73 bool WindowIsActive(nsPIDOMWindowInner* aWindow) {
74 dom::Document* document = aWindow->GetDoc();
75 NS_ENSURE_TRUE(document, false);
76 return !document->Hidden();
79 StaticAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
81 static void RecordLastIDToVibrate(const WindowIdentifier& aId) {
82 if (!InSandbox()) {
83 *gLastIDToVibrate = aId.AsArray();
87 static bool MayCancelVibration(const WindowIdentifier& aId) {
88 // Although only active windows may start vibrations, a window may
89 // cancel its own vibration even if it's no longer active.
91 // After a window is marked as inactive, it sends a CancelVibrate
92 // request. We want this request to cancel a playing vibration
93 // started by that window, so we certainly don't want to reject the
94 // cancellation request because the window is now inactive.
96 // But it could be the case that, after this window became inactive,
97 // some other window came along and started a vibration. We don't
98 // want this window's cancellation request to cancel that window's
99 // actively-playing vibration!
101 // To solve this problem, we keep track of the id of the last window
102 // to start a vibration, and only accepts cancellation requests from
103 // the same window. All other cancellation requests are ignored.
105 return InSandbox() || (*gLastIDToVibrate == aId.AsArray());
108 } // namespace
110 void Vibrate(const nsTArray<uint32_t>& pattern, nsPIDOMWindowInner* window) {
111 Vibrate(pattern, WindowIdentifier(window));
114 void Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier& id) {
115 AssertMainThread();
117 // Only active windows may start vibrations. If |id| hasn't gone
118 // through the IPC layer -- that is, if our caller is the outside
119 // world, not hal_proxy -- check whether the window is active. If
120 // |id| has gone through IPC, don't check the window's visibility;
121 // only the window corresponding to the bottommost process has its
122 // visibility state set correctly.
123 if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
124 HAL_LOG("Vibrate: Window is inactive, dropping vibrate.");
125 return;
128 RecordLastIDToVibrate(id);
130 // Don't forward our ID if we are not in the sandbox, because hal_impl
131 // doesn't need it, and we don't want it to be tempted to read it. The
132 // empty identifier will assert if it's used.
133 PROXY_IF_SANDBOXED(Vibrate(pattern, InSandbox() ? id : WindowIdentifier()));
136 void CancelVibrate(nsPIDOMWindowInner* window) {
137 CancelVibrate(WindowIdentifier(window));
140 void CancelVibrate(const WindowIdentifier& id) {
141 AssertMainThread();
143 if (MayCancelVibration(id)) {
144 // Don't forward our ID if we are not in the sandbox, because hal_impl
145 // doesn't need it, and we don't want it to be tempted to read it. The
146 // empty identifier will assert if it's used.
147 PROXY_IF_SANDBOXED(CancelVibrate(InSandbox() ? id : WindowIdentifier()));
151 template <class InfoType>
152 class ObserversManager {
153 public:
154 void AddObserver(Observer<InfoType>* aObserver) {
155 mObservers.AddObserver(aObserver);
157 if (mObservers.Length() == 1) {
158 EnableNotifications();
162 void RemoveObserver(Observer<InfoType>* aObserver) {
163 bool removed = mObservers.RemoveObserver(aObserver);
164 if (!removed) {
165 return;
168 if (mObservers.Length() == 0) {
169 DisableNotifications();
170 OnNotificationsDisabled();
174 void BroadcastInformation(const InfoType& aInfo) {
175 mObservers.Broadcast(aInfo);
178 protected:
179 ~ObserversManager() { MOZ_ASSERT(mObservers.Length() == 0); }
181 virtual void EnableNotifications() = 0;
182 virtual void DisableNotifications() = 0;
183 virtual void OnNotificationsDisabled() {}
185 private:
186 mozilla::ObserverList<InfoType> mObservers;
189 template <class InfoType>
190 class CachingObserversManager : public ObserversManager<InfoType> {
191 public:
192 InfoType GetCurrentInformation() {
193 if (mHasValidCache) {
194 return mInfo;
197 GetCurrentInformationInternal(&mInfo);
198 mHasValidCache = true;
199 return mInfo;
202 void CacheInformation(const InfoType& aInfo) {
203 mHasValidCache = true;
204 mInfo = aInfo;
207 void BroadcastCachedInformation() { this->BroadcastInformation(mInfo); }
209 protected:
210 virtual void GetCurrentInformationInternal(InfoType*) = 0;
212 void OnNotificationsDisabled() override { mHasValidCache = false; }
214 private:
215 InfoType mInfo;
216 bool mHasValidCache;
219 class BatteryObserversManager final
220 : public CachingObserversManager<BatteryInformation> {
221 protected:
222 void EnableNotifications() override {
223 PROXY_IF_SANDBOXED(EnableBatteryNotifications());
226 void DisableNotifications() override {
227 PROXY_IF_SANDBOXED(DisableBatteryNotifications());
230 void GetCurrentInformationInternal(BatteryInformation* aInfo) override {
231 PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
235 class NetworkObserversManager final
236 : public CachingObserversManager<NetworkInformation> {
237 protected:
238 void EnableNotifications() override {
239 PROXY_IF_SANDBOXED(EnableNetworkNotifications());
242 void DisableNotifications() override {
243 PROXY_IF_SANDBOXED(DisableNetworkNotifications());
246 void GetCurrentInformationInternal(NetworkInformation* aInfo) override {
247 PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
251 class WakeLockObserversManager final
252 : public ObserversManager<WakeLockInformation> {
253 protected:
254 void EnableNotifications() override {
255 PROXY_IF_SANDBOXED(EnableWakeLockNotifications());
258 void DisableNotifications() override {
259 PROXY_IF_SANDBOXED(DisableWakeLockNotifications());
263 class ScreenConfigurationObserversManager final
264 : public CachingObserversManager<ScreenConfiguration> {
265 protected:
266 void EnableNotifications() override {
267 PROXY_IF_SANDBOXED(EnableScreenConfigurationNotifications());
270 void DisableNotifications() override {
271 PROXY_IF_SANDBOXED(DisableScreenConfigurationNotifications());
274 void GetCurrentInformationInternal(ScreenConfiguration* aInfo) override {
275 PROXY_IF_SANDBOXED(GetCurrentScreenConfiguration(aInfo));
279 typedef mozilla::ObserverList<SensorData> SensorObserverList;
280 StaticAutoPtr<SensorObserverList> sSensorObservers[NUM_SENSOR_TYPE];
282 static SensorObserverList* GetSensorObservers(SensorType sensor_type) {
283 AssertMainThread();
284 MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
286 if (!sSensorObservers[sensor_type]) {
287 sSensorObservers[sensor_type] = new SensorObserverList();
290 return sSensorObservers[sensor_type];
293 #define MOZ_IMPL_HAL_OBSERVER(name_) \
294 StaticAutoPtr<name_##ObserversManager> s##name_##Observers; \
296 static name_##ObserversManager* name_##Observers() { \
297 AssertMainThread(); \
299 if (!s##name_##Observers) { \
300 MOZ_ASSERT(sInitialized); \
301 s##name_##Observers = new name_##ObserversManager(); \
304 return s##name_##Observers; \
307 void Register##name_##Observer(name_##Observer* aObserver) { \
308 AssertMainThread(); \
309 name_##Observers()->AddObserver(aObserver); \
312 void Unregister##name_##Observer(name_##Observer* aObserver) { \
313 AssertMainThread(); \
314 name_##Observers()->RemoveObserver(aObserver); \
317 MOZ_IMPL_HAL_OBSERVER(Battery)
319 void GetCurrentBatteryInformation(BatteryInformation* aInfo) {
320 *aInfo = BatteryObservers()->GetCurrentInformation();
323 void NotifyBatteryChange(const BatteryInformation& aInfo) {
324 BatteryObservers()->CacheInformation(aInfo);
325 BatteryObservers()->BroadcastCachedInformation();
328 void EnableSensorNotifications(SensorType aSensor) {
329 AssertMainThread();
330 PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
333 void DisableSensorNotifications(SensorType aSensor) {
334 AssertMainThread();
335 PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor));
338 void RegisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
339 SensorObserverList* observers = GetSensorObservers(aSensor);
341 observers->AddObserver(aObserver);
342 if (observers->Length() == 1) {
343 EnableSensorNotifications(aSensor);
347 void UnregisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
348 SensorObserverList* observers = GetSensorObservers(aSensor);
349 if (!observers->RemoveObserver(aObserver) || observers->Length() > 0) {
350 return;
352 DisableSensorNotifications(aSensor);
355 void NotifySensorChange(const SensorData& aSensorData) {
356 SensorObserverList* observers = GetSensorObservers(aSensorData.sensor());
358 observers->Broadcast(aSensorData);
361 MOZ_IMPL_HAL_OBSERVER(Network)
363 void GetCurrentNetworkInformation(NetworkInformation* aInfo) {
364 *aInfo = NetworkObservers()->GetCurrentInformation();
367 void NotifyNetworkChange(const NetworkInformation& aInfo) {
368 NetworkObservers()->CacheInformation(aInfo);
369 NetworkObservers()->BroadcastCachedInformation();
372 MOZ_IMPL_HAL_OBSERVER(WakeLock)
374 void ModifyWakeLock(const nsAString& aTopic, WakeLockControl aLockAdjust,
375 WakeLockControl aHiddenAdjust,
376 uint64_t aProcessID /* = CONTENT_PROCESS_ID_UNKNOWN */) {
377 AssertMainThread();
379 if (aProcessID == CONTENT_PROCESS_ID_UNKNOWN) {
380 aProcessID = InSandbox() ? ContentChild::GetSingleton()->GetID()
381 : CONTENT_PROCESS_ID_MAIN;
384 PROXY_IF_SANDBOXED(
385 ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust, aProcessID));
388 void GetWakeLockInfo(const nsAString& aTopic,
389 WakeLockInformation* aWakeLockInfo) {
390 AssertMainThread();
391 PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));
394 void NotifyWakeLockChange(const WakeLockInformation& aInfo) {
395 AssertMainThread();
396 WakeLockObservers()->BroadcastInformation(aInfo);
399 MOZ_IMPL_HAL_OBSERVER(ScreenConfiguration)
401 void GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration) {
402 *aScreenConfiguration =
403 ScreenConfigurationObservers()->GetCurrentInformation();
406 void NotifyScreenConfigurationChange(
407 const ScreenConfiguration& aScreenConfiguration) {
408 ScreenConfigurationObservers()->CacheInformation(aScreenConfiguration);
409 ScreenConfigurationObservers()->BroadcastCachedInformation();
412 bool LockScreenOrientation(const ScreenOrientation& aOrientation) {
413 AssertMainThread();
414 RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), false);
417 void UnlockScreenOrientation() {
418 AssertMainThread();
419 PROXY_IF_SANDBOXED(UnlockScreenOrientation());
422 bool SetProcessPrioritySupported() {
423 RETURN_PROXY_IF_SANDBOXED(SetProcessPrioritySupported(), false);
426 void SetProcessPriority(int aPid, ProcessPriority aPriority) {
427 // n.b. The sandboxed implementation crashes; SetProcessPriority works only
428 // from the main process.
429 PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority));
432 // From HalTypes.h.
433 const char* ProcessPriorityToString(ProcessPriority aPriority) {
434 switch (aPriority) {
435 case PROCESS_PRIORITY_MASTER:
436 return "MASTER";
437 case PROCESS_PRIORITY_PREALLOC:
438 return "PREALLOC";
439 case PROCESS_PRIORITY_FOREGROUND_HIGH:
440 return "FOREGROUND_HIGH";
441 case PROCESS_PRIORITY_FOREGROUND:
442 return "FOREGROUND";
443 case PROCESS_PRIORITY_FOREGROUND_KEYBOARD:
444 return "FOREGROUND_KEYBOARD";
445 case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
446 return "BACKGROUND_PERCEIVABLE";
447 case PROCESS_PRIORITY_BACKGROUND:
448 return "BACKGROUND";
449 case PROCESS_PRIORITY_UNKNOWN:
450 return "UNKNOWN";
451 default:
452 MOZ_ASSERT(false);
453 return "???";
457 void Init() {
458 MOZ_ASSERT(!sInitialized);
460 if (!InSandbox()) {
461 gLastIDToVibrate = new WindowIdentifier::IDArrayType();
464 WakeLockInit();
466 sInitialized = true;
469 void Shutdown() {
470 MOZ_ASSERT(sInitialized);
472 gLastIDToVibrate = nullptr;
474 sBatteryObservers = nullptr;
475 sNetworkObservers = nullptr;
476 sWakeLockObservers = nullptr;
477 sScreenConfigurationObservers = nullptr;
479 for (auto& sensorObserver : sSensorObservers) {
480 sensorObserver = nullptr;
483 sInitialized = false;
486 } // namespace hal
487 } // namespace mozilla