no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / hal / Hal.cpp
blobc8e25690bc619702210245b09e0c83dc056001a3
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 NS_ENSURE_TRUE(aWindow, false);
68 dom::Document* document = aWindow->GetDoc();
69 NS_ENSURE_TRUE(document, false);
70 return !document->Hidden();
73 StaticAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
75 static void RecordLastIDToVibrate(const WindowIdentifier& aId) {
76 if (!InSandbox()) {
77 *gLastIDToVibrate = aId.AsArray().Clone();
81 static bool MayCancelVibration(const WindowIdentifier& aId) {
82 // Although only active windows may start vibrations, a window may
83 // cancel its own vibration even if it's no longer active.
85 // After a window is marked as inactive, it sends a CancelVibrate
86 // request. We want this request to cancel a playing vibration
87 // started by that window, so we certainly don't want to reject the
88 // cancellation request because the window is now inactive.
90 // But it could be the case that, after this window became inactive,
91 // some other window came along and started a vibration. We don't
92 // want this window's cancellation request to cancel that window's
93 // actively-playing vibration!
95 // To solve this problem, we keep track of the id of the last window
96 // to start a vibration, and only accepts cancellation requests from
97 // the same window. All other cancellation requests are ignored.
99 return InSandbox() || (*gLastIDToVibrate == aId.AsArray());
102 } // namespace
104 void Vibrate(const nsTArray<uint32_t>& pattern, nsPIDOMWindowInner* window) {
105 Vibrate(pattern, WindowIdentifier(window));
108 void Vibrate(const nsTArray<uint32_t>& pattern, WindowIdentifier&& id) {
109 AssertMainThread();
111 // Only active windows may start vibrations. If |id| hasn't gone
112 // through the IPC layer -- that is, if our caller is the outside
113 // world, not hal_proxy -- check whether the window is active. If
114 // |id| has gone through IPC, don't check the window's visibility;
115 // only the window corresponding to the bottommost process has its
116 // visibility state set correctly.
117 if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
118 HAL_LOG("Vibrate: Window is inactive, dropping vibrate.");
119 return;
122 RecordLastIDToVibrate(id);
124 // Don't forward our ID if we are not in the sandbox, because hal_impl
125 // doesn't need it, and we don't want it to be tempted to read it. The
126 // empty identifier will assert if it's used.
127 PROXY_IF_SANDBOXED(
128 Vibrate(pattern, InSandbox() ? std::move(id) : WindowIdentifier()));
131 void CancelVibrate(nsPIDOMWindowInner* window) {
132 CancelVibrate(WindowIdentifier(window));
135 void CancelVibrate(WindowIdentifier&& id) {
136 AssertMainThread();
138 if (MayCancelVibration(id)) {
139 // Don't forward our ID if we are not in the sandbox, because hal_impl
140 // doesn't need it, and we don't want it to be tempted to read it. The
141 // empty identifier will assert if it's used.
142 PROXY_IF_SANDBOXED(
143 CancelVibrate(InSandbox() ? std::move(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 typedef mozilla::ObserverList<SensorData> SensorObserverList;
260 StaticAutoPtr<SensorObserverList> sSensorObservers[NUM_SENSOR_TYPE];
262 static SensorObserverList* GetSensorObservers(SensorType sensor_type) {
263 AssertMainThread();
264 MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
266 if (!sSensorObservers[sensor_type]) {
267 sSensorObservers[sensor_type] = new SensorObserverList();
270 return sSensorObservers[sensor_type];
273 #define MOZ_IMPL_HAL_OBSERVER(name_) \
274 StaticAutoPtr<name_##ObserversManager> s##name_##Observers; \
276 static name_##ObserversManager* name_##Observers() { \
277 AssertMainThread(); \
279 if (!s##name_##Observers) { \
280 MOZ_ASSERT(sInitialized); \
281 s##name_##Observers = new name_##ObserversManager(); \
284 return s##name_##Observers; \
287 void Register##name_##Observer(name_##Observer* aObserver) { \
288 AssertMainThread(); \
289 name_##Observers()->AddObserver(aObserver); \
292 void Unregister##name_##Observer(name_##Observer* aObserver) { \
293 AssertMainThread(); \
294 name_##Observers()->RemoveObserver(aObserver); \
297 MOZ_IMPL_HAL_OBSERVER(Battery)
299 void GetCurrentBatteryInformation(BatteryInformation* aInfo) {
300 *aInfo = BatteryObservers()->GetCurrentInformation();
303 void NotifyBatteryChange(const BatteryInformation& aInfo) {
304 BatteryObservers()->CacheInformation(aInfo);
305 BatteryObservers()->BroadcastCachedInformation();
308 void EnableSensorNotifications(SensorType aSensor) {
309 AssertMainThread();
310 PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
313 void DisableSensorNotifications(SensorType aSensor) {
314 AssertMainThread();
315 PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor));
318 void RegisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
319 SensorObserverList* observers = GetSensorObservers(aSensor);
321 observers->AddObserver(aObserver);
322 if (observers->Length() == 1) {
323 EnableSensorNotifications(aSensor);
327 void UnregisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
328 SensorObserverList* observers = GetSensorObservers(aSensor);
329 if (!observers->RemoveObserver(aObserver) || observers->Length() > 0) {
330 return;
332 DisableSensorNotifications(aSensor);
335 void NotifySensorChange(const SensorData& aSensorData) {
336 SensorObserverList* observers = GetSensorObservers(aSensorData.sensor());
338 observers->Broadcast(aSensorData);
341 MOZ_IMPL_HAL_OBSERVER(Network)
343 void GetCurrentNetworkInformation(NetworkInformation* aInfo) {
344 *aInfo = NetworkObservers()->GetCurrentInformation();
347 void NotifyNetworkChange(const NetworkInformation& aInfo) {
348 NetworkObservers()->CacheInformation(aInfo);
349 NetworkObservers()->BroadcastCachedInformation();
352 MOZ_IMPL_HAL_OBSERVER(WakeLock)
354 void ModifyWakeLock(const nsAString& aTopic, WakeLockControl aLockAdjust,
355 WakeLockControl aHiddenAdjust) {
356 AssertMainThread();
358 PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust));
361 void GetWakeLockInfo(const nsAString& aTopic,
362 WakeLockInformation* aWakeLockInfo) {
363 AssertMainThread();
364 PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));
367 void NotifyWakeLockChange(const WakeLockInformation& aInfo) {
368 AssertMainThread();
369 WakeLockObservers()->BroadcastInformation(aInfo);
372 RefPtr<GenericNonExclusivePromise> LockScreenOrientation(
373 const ScreenOrientation& aOrientation) {
374 AssertMainThread();
375 RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), nullptr);
378 void UnlockScreenOrientation() {
379 AssertMainThread();
380 PROXY_IF_SANDBOXED(UnlockScreenOrientation());
383 void SetProcessPriority(int aPid, ProcessPriority aPriority) {
384 // n.b. The sandboxed implementation crashes; SetProcessPriority works only
385 // from the main process.
386 PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority));
389 // From HalTypes.h.
390 const char* ProcessPriorityToString(ProcessPriority aPriority) {
391 switch (aPriority) {
392 case PROCESS_PRIORITY_PARENT_PROCESS:
393 return "PARENT_PROCESS";
394 case PROCESS_PRIORITY_PREALLOC:
395 return "PREALLOC";
396 case PROCESS_PRIORITY_FOREGROUND_HIGH:
397 return "FOREGROUND_HIGH";
398 case PROCESS_PRIORITY_FOREGROUND:
399 return "FOREGROUND";
400 case PROCESS_PRIORITY_FOREGROUND_KEYBOARD:
401 return "FOREGROUND_KEYBOARD";
402 case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
403 return "BACKGROUND_PERCEIVABLE";
404 case PROCESS_PRIORITY_BACKGROUND:
405 return "BACKGROUND";
406 case PROCESS_PRIORITY_UNKNOWN:
407 return "UNKNOWN";
408 default:
409 MOZ_ASSERT(false);
410 return "???";
414 UniquePtr<hal::PerformanceHintSession> CreatePerformanceHintSession(
415 const nsTArray<PlatformThreadHandle>& aThreads,
416 mozilla::TimeDuration aTargetWorkDuration) {
417 return hal_impl::CreatePerformanceHintSession(aThreads, aTargetWorkDuration);
420 const Maybe<hal::HeterogeneousCpuInfo>& GetHeterogeneousCpuInfo() {
421 return hal_impl::GetHeterogeneousCpuInfo();
424 void Init() {
425 MOZ_ASSERT(!sInitialized);
427 if (!InSandbox()) {
428 gLastIDToVibrate = new WindowIdentifier::IDArrayType();
431 WakeLockInit();
433 sInitialized = true;
436 void Shutdown() {
437 MOZ_ASSERT(sInitialized);
439 gLastIDToVibrate = nullptr;
441 sBatteryObservers = nullptr;
442 sNetworkObservers = nullptr;
443 sWakeLockObservers = nullptr;
445 for (auto& sensorObserver : sSensorObservers) {
446 sensorObserver = nullptr;
449 sInitialized = false;
452 } // namespace mozilla::hal