Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
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"
8 #include "HalImpl.h"
9 #include "HalSandbox.h"
10 #include "nsThreadUtils.h"
11 #include "nsXULAppAPI.h"
12 #include "mozilla/Observer.h"
13 #include "nsIDocument.h"
14 #include "nsIDOMDocument.h"
15 #include "nsPIDOMWindow.h"
16 #include "nsIDOMWindow.h"
17 #include "mozilla/Services.h"
18 #include "nsIWebNavigation.h"
19 #include "nsITabChild.h"
20 #include "nsIDocShell.h"
21 #include "mozilla/StaticPtr.h"
22 #include "mozilla/ClearOnShutdown.h"
23 #include "WindowIdentifier.h"
24 #include "mozilla/dom/ScreenOrientation.h"
25 #include "mozilla/dom/ContentChild.h"
26 #include "mozilla/dom/ContentParent.h"
28 #ifdef XP_WIN
29 #include <process.h>
30 #define getpid _getpid
31 #endif
33 using namespace mozilla::services;
34 using namespace mozilla::dom;
36 #define PROXY_IF_SANDBOXED(_call) \
37 do { \
38 if (InSandbox()) { \
39 if (!hal_sandbox::HalChildDestroyed()) { \
40 hal_sandbox::_call; \
41 } \
42 } else { \
43 hal_impl::_call; \
44 } \
45 } while (0)
47 #define RETURN_PROXY_IF_SANDBOXED(_call, defValue)\
48 do { \
49 if (InSandbox()) { \
50 if (hal_sandbox::HalChildDestroyed()) { \
51 return defValue; \
52 } \
53 return hal_sandbox::_call; \
54 } else { \
55 return hal_impl::_call; \
56 } \
57 } while (0)
59 namespace mozilla {
60 namespace hal {
62 PRLogModuleInfo *
63 GetHalLog()
64 {
65 static PRLogModuleInfo *sHalLog;
66 if (!sHalLog) {
67 sHalLog = PR_NewLogModule("hal");
68 }
69 return sHalLog;
70 }
72 namespace {
74 void
75 AssertMainThread()
76 {
77 MOZ_ASSERT(NS_IsMainThread());
78 }
80 bool
81 InSandbox()
82 {
83 return GeckoProcessType_Content == XRE_GetProcessType();
84 }
86 void
87 AssertMainProcess()
88 {
89 MOZ_ASSERT(GeckoProcessType_Default == XRE_GetProcessType());
90 }
92 bool
93 WindowIsActive(nsIDOMWindow* aWindow)
94 {
95 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
96 NS_ENSURE_TRUE(window, false);
98 nsIDocument* document = window->GetDoc();
99 NS_ENSURE_TRUE(document, false);
101 return !document->Hidden();
102 }
104 StaticAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
106 void InitLastIDToVibrate()
107 {
108 gLastIDToVibrate = new WindowIdentifier::IDArrayType();
109 ClearOnShutdown(&gLastIDToVibrate);
110 }
112 } // anonymous namespace
114 void
115 Vibrate(const nsTArray<uint32_t>& pattern, nsIDOMWindow* window)
116 {
117 Vibrate(pattern, WindowIdentifier(window));
118 }
120 void
121 Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier &id)
122 {
123 AssertMainThread();
125 // Only active windows may start vibrations. If |id| hasn't gone
126 // through the IPC layer -- that is, if our caller is the outside
127 // world, not hal_proxy -- check whether the window is active. If
128 // |id| has gone through IPC, don't check the window's visibility;
129 // only the window corresponding to the bottommost process has its
130 // visibility state set correctly.
131 if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
132 HAL_LOG(("Vibrate: Window is inactive, dropping vibrate."));
133 return;
134 }
136 if (!InSandbox()) {
137 if (!gLastIDToVibrate) {
138 InitLastIDToVibrate();
139 }
140 *gLastIDToVibrate = id.AsArray();
141 }
143 // Don't forward our ID if we are not in the sandbox, because hal_impl
144 // doesn't need it, and we don't want it to be tempted to read it. The
145 // empty identifier will assert if it's used.
146 PROXY_IF_SANDBOXED(Vibrate(pattern, InSandbox() ? id : WindowIdentifier()));
147 }
149 void
150 CancelVibrate(nsIDOMWindow* window)
151 {
152 CancelVibrate(WindowIdentifier(window));
153 }
155 void
156 CancelVibrate(const WindowIdentifier &id)
157 {
158 AssertMainThread();
160 // Although only active windows may start vibrations, a window may
161 // cancel its own vibration even if it's no longer active.
162 //
163 // After a window is marked as inactive, it sends a CancelVibrate
164 // request. We want this request to cancel a playing vibration
165 // started by that window, so we certainly don't want to reject the
166 // cancellation request because the window is now inactive.
167 //
168 // But it could be the case that, after this window became inactive,
169 // some other window came along and started a vibration. We don't
170 // want this window's cancellation request to cancel that window's
171 // actively-playing vibration!
172 //
173 // To solve this problem, we keep track of the id of the last window
174 // to start a vibration, and only accepts cancellation requests from
175 // the same window. All other cancellation requests are ignored.
177 if (InSandbox() || (gLastIDToVibrate && *gLastIDToVibrate == id.AsArray())) {
178 // Don't forward our ID if we are not in the sandbox, because hal_impl
179 // doesn't need it, and we don't want it to be tempted to read it. The
180 // empty identifier will assert if it's used.
181 PROXY_IF_SANDBOXED(CancelVibrate(InSandbox() ? id : WindowIdentifier()));
182 }
183 }
185 template <class InfoType>
186 class ObserversManager
187 {
188 public:
189 void AddObserver(Observer<InfoType>* aObserver) {
190 if (!mObservers) {
191 mObservers = new mozilla::ObserverList<InfoType>();
192 }
194 mObservers->AddObserver(aObserver);
196 if (mObservers->Length() == 1) {
197 EnableNotifications();
198 }
199 }
201 void RemoveObserver(Observer<InfoType>* aObserver) {
202 bool removed = mObservers && mObservers->RemoveObserver(aObserver);
203 if (!removed) {
204 NS_WARNING("RemoveObserver() called for unregistered observer");
205 return;
206 }
208 if (mObservers->Length() == 0) {
209 DisableNotifications();
211 OnNotificationsDisabled();
213 delete mObservers;
214 mObservers = nullptr;
215 }
216 }
218 void BroadcastInformation(const InfoType& aInfo) {
219 // It is possible for mObservers to be nullptr here on some platforms,
220 // because a call to BroadcastInformation gets queued up asynchronously
221 // while RemoveObserver is running (and before the notifications are
222 // disabled). The queued call can then get run after mObservers has
223 // been nulled out. See bug 757025.
224 if (!mObservers) {
225 return;
226 }
227 mObservers->Broadcast(aInfo);
228 }
230 protected:
231 virtual void EnableNotifications() = 0;
232 virtual void DisableNotifications() = 0;
233 virtual void OnNotificationsDisabled() {}
235 private:
236 mozilla::ObserverList<InfoType>* mObservers;
237 };
239 template <class InfoType>
240 class CachingObserversManager : public ObserversManager<InfoType>
241 {
242 public:
243 InfoType GetCurrentInformation() {
244 if (mHasValidCache) {
245 return mInfo;
246 }
248 GetCurrentInformationInternal(&mInfo);
249 mHasValidCache = true;
250 return mInfo;
251 }
253 void CacheInformation(const InfoType& aInfo) {
254 mHasValidCache = true;
255 mInfo = aInfo;
256 }
258 void BroadcastCachedInformation() {
259 this->BroadcastInformation(mInfo);
260 }
262 protected:
263 virtual void GetCurrentInformationInternal(InfoType*) = 0;
265 virtual void OnNotificationsDisabled() {
266 mHasValidCache = false;
267 }
269 private:
270 InfoType mInfo;
271 bool mHasValidCache;
272 };
274 class BatteryObserversManager : public CachingObserversManager<BatteryInformation>
275 {
276 protected:
277 void EnableNotifications() {
278 PROXY_IF_SANDBOXED(EnableBatteryNotifications());
279 }
281 void DisableNotifications() {
282 PROXY_IF_SANDBOXED(DisableBatteryNotifications());
283 }
285 void GetCurrentInformationInternal(BatteryInformation* aInfo) {
286 PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
287 }
288 };
290 static BatteryObserversManager sBatteryObservers;
292 class NetworkObserversManager : public CachingObserversManager<NetworkInformation>
293 {
294 protected:
295 void EnableNotifications() {
296 PROXY_IF_SANDBOXED(EnableNetworkNotifications());
297 }
299 void DisableNotifications() {
300 PROXY_IF_SANDBOXED(DisableNetworkNotifications());
301 }
303 void GetCurrentInformationInternal(NetworkInformation* aInfo) {
304 PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
305 }
306 };
308 static NetworkObserversManager sNetworkObservers;
310 class WakeLockObserversManager : public ObserversManager<WakeLockInformation>
311 {
312 protected:
313 void EnableNotifications() {
314 PROXY_IF_SANDBOXED(EnableWakeLockNotifications());
315 }
317 void DisableNotifications() {
318 PROXY_IF_SANDBOXED(DisableWakeLockNotifications());
319 }
320 };
322 static WakeLockObserversManager sWakeLockObservers;
324 class ScreenConfigurationObserversManager : public CachingObserversManager<ScreenConfiguration>
325 {
326 protected:
327 void EnableNotifications() {
328 PROXY_IF_SANDBOXED(EnableScreenConfigurationNotifications());
329 }
331 void DisableNotifications() {
332 PROXY_IF_SANDBOXED(DisableScreenConfigurationNotifications());
333 }
335 void GetCurrentInformationInternal(ScreenConfiguration* aInfo) {
336 PROXY_IF_SANDBOXED(GetCurrentScreenConfiguration(aInfo));
337 }
338 };
340 static ScreenConfigurationObserversManager sScreenConfigurationObservers;
342 void
343 RegisterBatteryObserver(BatteryObserver* aObserver)
344 {
345 AssertMainThread();
346 sBatteryObservers.AddObserver(aObserver);
347 }
349 void
350 UnregisterBatteryObserver(BatteryObserver* aObserver)
351 {
352 AssertMainThread();
353 sBatteryObservers.RemoveObserver(aObserver);
354 }
356 void
357 GetCurrentBatteryInformation(BatteryInformation* aInfo)
358 {
359 AssertMainThread();
360 *aInfo = sBatteryObservers.GetCurrentInformation();
361 }
363 void
364 NotifyBatteryChange(const BatteryInformation& aInfo)
365 {
366 AssertMainThread();
367 sBatteryObservers.CacheInformation(aInfo);
368 sBatteryObservers.BroadcastCachedInformation();
369 }
371 bool GetScreenEnabled()
372 {
373 AssertMainThread();
374 RETURN_PROXY_IF_SANDBOXED(GetScreenEnabled(), false);
375 }
377 void SetScreenEnabled(bool enabled)
378 {
379 AssertMainThread();
380 PROXY_IF_SANDBOXED(SetScreenEnabled(enabled));
381 }
383 bool GetCpuSleepAllowed()
384 {
385 // Generally for interfaces that are accessible by normal web content
386 // we should cache the result and be notified on state changes, like
387 // what the battery API does. But since this is only used by
388 // privileged interface, the synchronous getter is OK here.
389 AssertMainThread();
390 RETURN_PROXY_IF_SANDBOXED(GetCpuSleepAllowed(), true);
391 }
393 void SetCpuSleepAllowed(bool allowed)
394 {
395 AssertMainThread();
396 PROXY_IF_SANDBOXED(SetCpuSleepAllowed(allowed));
397 }
399 double GetScreenBrightness()
400 {
401 AssertMainThread();
402 RETURN_PROXY_IF_SANDBOXED(GetScreenBrightness(), 0);
403 }
405 void SetScreenBrightness(double brightness)
406 {
407 AssertMainThread();
408 PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness, 0.0, 1.0)));
409 }
411 bool SetLight(LightType light, const LightConfiguration& aConfig)
412 {
413 AssertMainThread();
414 RETURN_PROXY_IF_SANDBOXED(SetLight(light, aConfig), false);
415 }
417 bool GetLight(LightType light, LightConfiguration* aConfig)
418 {
419 AssertMainThread();
420 RETURN_PROXY_IF_SANDBOXED(GetLight(light, aConfig), false);
421 }
423 class SystemClockChangeObserversManager : public ObserversManager<int64_t>
424 {
425 protected:
426 void EnableNotifications() {
427 PROXY_IF_SANDBOXED(EnableSystemClockChangeNotifications());
428 }
430 void DisableNotifications() {
431 PROXY_IF_SANDBOXED(DisableSystemClockChangeNotifications());
432 }
433 };
435 static SystemClockChangeObserversManager sSystemClockChangeObservers;
437 void
438 RegisterSystemClockChangeObserver(SystemClockChangeObserver* aObserver)
439 {
440 AssertMainThread();
441 sSystemClockChangeObservers.AddObserver(aObserver);
442 }
444 void
445 UnregisterSystemClockChangeObserver(SystemClockChangeObserver* aObserver)
446 {
447 AssertMainThread();
448 sSystemClockChangeObservers.RemoveObserver(aObserver);
449 }
451 void
452 NotifySystemClockChange(const int64_t& aClockDeltaMS)
453 {
454 sSystemClockChangeObservers.BroadcastInformation(aClockDeltaMS);
455 }
457 class SystemTimezoneChangeObserversManager : public ObserversManager<SystemTimezoneChangeInformation>
458 {
459 protected:
460 void EnableNotifications() {
461 PROXY_IF_SANDBOXED(EnableSystemTimezoneChangeNotifications());
462 }
464 void DisableNotifications() {
465 PROXY_IF_SANDBOXED(DisableSystemTimezoneChangeNotifications());
466 }
467 };
469 static SystemTimezoneChangeObserversManager sSystemTimezoneChangeObservers;
471 void
472 RegisterSystemTimezoneChangeObserver(SystemTimezoneChangeObserver* aObserver)
473 {
474 AssertMainThread();
475 sSystemTimezoneChangeObservers.AddObserver(aObserver);
476 }
478 void
479 UnregisterSystemTimezoneChangeObserver(SystemTimezoneChangeObserver* aObserver)
480 {
481 AssertMainThread();
482 sSystemTimezoneChangeObservers.RemoveObserver(aObserver);
483 }
485 void
486 NotifySystemTimezoneChange(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
487 {
488 sSystemTimezoneChangeObservers.BroadcastInformation(aSystemTimezoneChangeInfo);
489 }
491 void
492 AdjustSystemClock(int64_t aDeltaMilliseconds)
493 {
494 AssertMainThread();
495 PROXY_IF_SANDBOXED(AdjustSystemClock(aDeltaMilliseconds));
496 }
498 void
499 SetTimezone(const nsCString& aTimezoneSpec)
500 {
501 AssertMainThread();
502 PROXY_IF_SANDBOXED(SetTimezone(aTimezoneSpec));
503 }
505 int32_t
506 GetTimezoneOffset()
507 {
508 AssertMainThread();
509 RETURN_PROXY_IF_SANDBOXED(GetTimezoneOffset(), 0);
510 }
512 nsCString
513 GetTimezone()
514 {
515 AssertMainThread();
516 RETURN_PROXY_IF_SANDBOXED(GetTimezone(), nsCString(""));
517 }
519 void
520 EnableSensorNotifications(SensorType aSensor) {
521 AssertMainThread();
522 PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
523 }
525 void
526 DisableSensorNotifications(SensorType aSensor) {
527 AssertMainThread();
528 PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor));
529 }
531 typedef mozilla::ObserverList<SensorData> SensorObserverList;
532 static SensorObserverList* gSensorObservers = nullptr;
534 static SensorObserverList &
535 GetSensorObservers(SensorType sensor_type) {
536 MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
538 if(!gSensorObservers) {
539 gSensorObservers = new SensorObserverList[NUM_SENSOR_TYPE];
540 }
541 return gSensorObservers[sensor_type];
542 }
544 void
545 RegisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) {
546 SensorObserverList &observers = GetSensorObservers(aSensor);
548 AssertMainThread();
550 observers.AddObserver(aObserver);
551 if(observers.Length() == 1) {
552 EnableSensorNotifications(aSensor);
553 }
554 }
556 void
557 UnregisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) {
558 AssertMainThread();
560 if (!gSensorObservers) {
561 return;
562 }
564 SensorObserverList &observers = GetSensorObservers(aSensor);
565 if (!observers.RemoveObserver(aObserver) || observers.Length() > 0) {
566 return;
567 }
568 DisableSensorNotifications(aSensor);
570 // Destroy sSensorObservers only if all observer lists are empty.
571 for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
572 if (gSensorObservers[i].Length() > 0) {
573 return;
574 }
575 }
576 delete [] gSensorObservers;
577 gSensorObservers = nullptr;
578 }
580 void
581 NotifySensorChange(const SensorData &aSensorData) {
582 SensorObserverList &observers = GetSensorObservers(aSensorData.sensor());
584 AssertMainThread();
586 observers.Broadcast(aSensorData);
587 }
589 void
590 RegisterNetworkObserver(NetworkObserver* aObserver)
591 {
592 AssertMainThread();
593 sNetworkObservers.AddObserver(aObserver);
594 }
596 void
597 UnregisterNetworkObserver(NetworkObserver* aObserver)
598 {
599 AssertMainThread();
600 sNetworkObservers.RemoveObserver(aObserver);
601 }
603 void
604 GetCurrentNetworkInformation(NetworkInformation* aInfo)
605 {
606 AssertMainThread();
607 *aInfo = sNetworkObservers.GetCurrentInformation();
608 }
610 void
611 NotifyNetworkChange(const NetworkInformation& aInfo)
612 {
613 sNetworkObservers.CacheInformation(aInfo);
614 sNetworkObservers.BroadcastCachedInformation();
615 }
617 void Reboot()
618 {
619 AssertMainProcess();
620 AssertMainThread();
621 PROXY_IF_SANDBOXED(Reboot());
622 }
624 void PowerOff()
625 {
626 AssertMainProcess();
627 AssertMainThread();
628 PROXY_IF_SANDBOXED(PowerOff());
629 }
631 void StartForceQuitWatchdog(ShutdownMode aMode, int32_t aTimeoutSecs)
632 {
633 AssertMainProcess();
634 AssertMainThread();
635 PROXY_IF_SANDBOXED(StartForceQuitWatchdog(aMode, aTimeoutSecs));
636 }
638 void StartMonitoringGamepadStatus()
639 {
640 PROXY_IF_SANDBOXED(StartMonitoringGamepadStatus());
641 }
643 void StopMonitoringGamepadStatus()
644 {
645 PROXY_IF_SANDBOXED(StopMonitoringGamepadStatus());
646 }
648 void
649 RegisterWakeLockObserver(WakeLockObserver* aObserver)
650 {
651 AssertMainThread();
652 sWakeLockObservers.AddObserver(aObserver);
653 }
655 void
656 UnregisterWakeLockObserver(WakeLockObserver* aObserver)
657 {
658 AssertMainThread();
659 sWakeLockObservers.RemoveObserver(aObserver);
660 }
662 void
663 ModifyWakeLock(const nsAString& aTopic,
664 WakeLockControl aLockAdjust,
665 WakeLockControl aHiddenAdjust,
666 uint64_t aProcessID /* = CONTENT_PROCESS_ID_UNKNOWN */)
667 {
668 AssertMainThread();
670 if (aProcessID == CONTENT_PROCESS_ID_UNKNOWN) {
671 aProcessID = InSandbox() ? ContentChild::GetSingleton()->GetID() :
672 CONTENT_PROCESS_ID_MAIN;
673 }
675 PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic, aLockAdjust,
676 aHiddenAdjust, aProcessID));
677 }
679 void
680 GetWakeLockInfo(const nsAString& aTopic, WakeLockInformation* aWakeLockInfo)
681 {
682 AssertMainThread();
683 PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));
684 }
686 void
687 NotifyWakeLockChange(const WakeLockInformation& aInfo)
688 {
689 AssertMainThread();
690 sWakeLockObservers.BroadcastInformation(aInfo);
691 }
693 void
694 RegisterScreenConfigurationObserver(ScreenConfigurationObserver* aObserver)
695 {
696 AssertMainThread();
697 sScreenConfigurationObservers.AddObserver(aObserver);
698 }
700 void
701 UnregisterScreenConfigurationObserver(ScreenConfigurationObserver* aObserver)
702 {
703 AssertMainThread();
704 sScreenConfigurationObservers.RemoveObserver(aObserver);
705 }
707 void
708 GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration)
709 {
710 AssertMainThread();
711 *aScreenConfiguration = sScreenConfigurationObservers.GetCurrentInformation();
712 }
714 void
715 NotifyScreenConfigurationChange(const ScreenConfiguration& aScreenConfiguration)
716 {
717 sScreenConfigurationObservers.CacheInformation(aScreenConfiguration);
718 sScreenConfigurationObservers.BroadcastCachedInformation();
719 }
721 bool
722 LockScreenOrientation(const dom::ScreenOrientation& aOrientation)
723 {
724 AssertMainThread();
725 RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), false);
726 }
728 void
729 UnlockScreenOrientation()
730 {
731 AssertMainThread();
732 PROXY_IF_SANDBOXED(UnlockScreenOrientation());
733 }
735 void
736 EnableSwitchNotifications(SwitchDevice aDevice) {
737 AssertMainThread();
738 PROXY_IF_SANDBOXED(EnableSwitchNotifications(aDevice));
739 }
741 void
742 DisableSwitchNotifications(SwitchDevice aDevice) {
743 AssertMainThread();
744 PROXY_IF_SANDBOXED(DisableSwitchNotifications(aDevice));
745 }
747 SwitchState GetCurrentSwitchState(SwitchDevice aDevice)
748 {
749 AssertMainThread();
750 RETURN_PROXY_IF_SANDBOXED(GetCurrentSwitchState(aDevice), SWITCH_STATE_UNKNOWN);
751 }
753 void NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
754 {
755 PROXY_IF_SANDBOXED(NotifySwitchStateFromInputDevice(aDevice, aState));
756 }
758 typedef mozilla::ObserverList<SwitchEvent> SwitchObserverList;
760 static SwitchObserverList *sSwitchObserverLists = nullptr;
762 static SwitchObserverList&
763 GetSwitchObserverList(SwitchDevice aDevice) {
764 MOZ_ASSERT(0 <= aDevice && aDevice < NUM_SWITCH_DEVICE);
765 if (sSwitchObserverLists == nullptr) {
766 sSwitchObserverLists = new SwitchObserverList[NUM_SWITCH_DEVICE];
767 }
768 return sSwitchObserverLists[aDevice];
769 }
771 static void
772 ReleaseObserversIfNeeded() {
773 for (int i = 0; i < NUM_SWITCH_DEVICE; i++) {
774 if (sSwitchObserverLists[i].Length() != 0)
775 return;
776 }
778 //The length of every list is 0, no observer in the list.
779 delete [] sSwitchObserverLists;
780 sSwitchObserverLists = nullptr;
781 }
783 void
784 RegisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver)
785 {
786 AssertMainThread();
787 SwitchObserverList& observer = GetSwitchObserverList(aDevice);
788 observer.AddObserver(aObserver);
789 if (observer.Length() == 1) {
790 EnableSwitchNotifications(aDevice);
791 }
792 }
794 void
795 UnregisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver)
796 {
797 AssertMainThread();
799 if (!sSwitchObserverLists) {
800 return;
801 }
803 SwitchObserverList& observer = GetSwitchObserverList(aDevice);
804 if (!observer.RemoveObserver(aObserver) || observer.Length() > 0) {
805 return;
806 }
808 DisableSwitchNotifications(aDevice);
809 ReleaseObserversIfNeeded();
810 }
812 void
813 NotifySwitchChange(const SwitchEvent& aEvent)
814 {
815 // When callback this notification, main thread may call unregister function
816 // first. We should check if this pointer is valid.
817 if (!sSwitchObserverLists)
818 return;
820 SwitchObserverList& observer = GetSwitchObserverList(aEvent.device());
821 observer.Broadcast(aEvent);
822 }
824 static AlarmObserver* sAlarmObserver;
826 bool
827 RegisterTheOneAlarmObserver(AlarmObserver* aObserver)
828 {
829 MOZ_ASSERT(!InSandbox());
830 MOZ_ASSERT(!sAlarmObserver);
832 sAlarmObserver = aObserver;
833 RETURN_PROXY_IF_SANDBOXED(EnableAlarm(), false);
834 }
836 void
837 UnregisterTheOneAlarmObserver()
838 {
839 if (sAlarmObserver) {
840 sAlarmObserver = nullptr;
841 PROXY_IF_SANDBOXED(DisableAlarm());
842 }
843 }
845 void
846 NotifyAlarmFired()
847 {
848 if (sAlarmObserver) {
849 sAlarmObserver->Notify(void_t());
850 }
851 }
853 bool
854 SetAlarm(int32_t aSeconds, int32_t aNanoseconds)
855 {
856 // It's pointless to program an alarm nothing is going to observe ...
857 MOZ_ASSERT(sAlarmObserver);
858 RETURN_PROXY_IF_SANDBOXED(SetAlarm(aSeconds, aNanoseconds), false);
859 }
861 void
862 SetProcessPriority(int aPid,
863 ProcessPriority aPriority,
864 ProcessCPUPriority aCPUPriority,
865 uint32_t aBackgroundLRU)
866 {
867 // n.b. The sandboxed implementation crashes; SetProcessPriority works only
868 // from the main process.
869 MOZ_ASSERT(aBackgroundLRU == 0 || aPriority == PROCESS_PRIORITY_BACKGROUND);
870 PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority, aCPUPriority,
871 aBackgroundLRU));
872 }
874 // From HalTypes.h.
875 const char*
876 ProcessPriorityToString(ProcessPriority aPriority)
877 {
878 switch (aPriority) {
879 case PROCESS_PRIORITY_MASTER:
880 return "MASTER";
881 case PROCESS_PRIORITY_PREALLOC:
882 return "PREALLOC";
883 case PROCESS_PRIORITY_FOREGROUND_HIGH:
884 return "FOREGROUND_HIGH";
885 case PROCESS_PRIORITY_FOREGROUND:
886 return "FOREGROUND";
887 case PROCESS_PRIORITY_FOREGROUND_KEYBOARD:
888 return "FOREGROUND_KEYBOARD";
889 case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
890 return "BACKGROUND_PERCEIVABLE";
891 case PROCESS_PRIORITY_BACKGROUND_HOMESCREEN:
892 return "BACKGROUND_HOMESCREEN";
893 case PROCESS_PRIORITY_BACKGROUND:
894 return "BACKGROUND";
895 case PROCESS_PRIORITY_UNKNOWN:
896 return "UNKNOWN";
897 default:
898 MOZ_ASSERT(false);
899 return "???";
900 }
901 }
903 // From HalTypes.h.
904 const char*
905 ProcessPriorityToString(ProcessPriority aPriority,
906 ProcessCPUPriority aCPUPriority)
907 {
908 // Sorry this is ugly. At least it's all in one place.
909 //
910 // We intentionally fall through if aCPUPriority is invalid; we won't hit any
911 // of the if statements further down, so it's OK.
913 switch (aPriority) {
914 case PROCESS_PRIORITY_MASTER:
915 if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
916 return "MASTER:CPU_NORMAL";
917 }
918 if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
919 return "MASTER:CPU_LOW";
920 }
921 case PROCESS_PRIORITY_PREALLOC:
922 if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
923 return "PREALLOC:CPU_NORMAL";
924 }
925 if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
926 return "PREALLOC:CPU_LOW";
927 }
928 case PROCESS_PRIORITY_FOREGROUND_HIGH:
929 if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
930 return "FOREGROUND_HIGH:CPU_NORMAL";
931 }
932 if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
933 return "FOREGROUND_HIGH:CPU_LOW";
934 }
935 case PROCESS_PRIORITY_FOREGROUND:
936 if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
937 return "FOREGROUND:CPU_NORMAL";
938 }
939 if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
940 return "FOREGROUND:CPU_LOW";
941 }
942 case PROCESS_PRIORITY_FOREGROUND_KEYBOARD:
943 if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
944 return "FOREGROUND_KEYBOARD:CPU_NORMAL";
945 }
946 if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
947 return "FOREGROUND_KEYBOARD:CPU_LOW";
948 }
949 case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
950 if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
951 return "BACKGROUND_PERCEIVABLE:CPU_NORMAL";
952 }
953 if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
954 return "BACKGROUND_PERCEIVABLE:CPU_LOW";
955 }
956 case PROCESS_PRIORITY_BACKGROUND_HOMESCREEN:
957 if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
958 return "BACKGROUND_HOMESCREEN:CPU_NORMAL";
959 }
960 if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
961 return "BACKGROUND_HOMESCREEN:CPU_LOW";
962 }
963 case PROCESS_PRIORITY_BACKGROUND:
964 if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
965 return "BACKGROUND:CPU_NORMAL";
966 }
967 if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
968 return "BACKGROUND:CPU_LOW";
969 }
970 case PROCESS_PRIORITY_UNKNOWN:
971 if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
972 return "UNKNOWN:CPU_NORMAL";
973 }
974 if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
975 return "UNKNOWN:CPU_LOW";
976 }
977 default:
978 // Fall through. (|default| is here to silence warnings.)
979 break;
980 }
982 MOZ_ASSERT(false);
983 return "???";
984 }
986 static StaticAutoPtr<ObserverList<FMRadioOperationInformation> > sFMRadioObservers;
988 static void
989 InitializeFMRadioObserver()
990 {
991 if (!sFMRadioObservers) {
992 sFMRadioObservers = new ObserverList<FMRadioOperationInformation>;
993 ClearOnShutdown(&sFMRadioObservers);
994 }
995 }
997 void
998 RegisterFMRadioObserver(FMRadioObserver* aFMRadioObserver) {
999 AssertMainThread();
1000 InitializeFMRadioObserver();
1001 sFMRadioObservers->AddObserver(aFMRadioObserver);
1002 }
1004 void
1005 UnregisterFMRadioObserver(FMRadioObserver* aFMRadioObserver) {
1006 AssertMainThread();
1007 InitializeFMRadioObserver();
1008 sFMRadioObservers->RemoveObserver(aFMRadioObserver);
1009 }
1011 void
1012 NotifyFMRadioStatus(const FMRadioOperationInformation& aFMRadioState) {
1013 InitializeFMRadioObserver();
1014 sFMRadioObservers->Broadcast(aFMRadioState);
1015 }
1017 void
1018 EnableFMRadio(const FMRadioSettings& aInfo) {
1019 AssertMainThread();
1020 PROXY_IF_SANDBOXED(EnableFMRadio(aInfo));
1021 }
1023 void
1024 DisableFMRadio() {
1025 AssertMainThread();
1026 PROXY_IF_SANDBOXED(DisableFMRadio());
1027 }
1029 void
1030 FMRadioSeek(const FMRadioSeekDirection& aDirection) {
1031 AssertMainThread();
1032 PROXY_IF_SANDBOXED(FMRadioSeek(aDirection));
1033 }
1035 void
1036 GetFMRadioSettings(FMRadioSettings* aInfo) {
1037 AssertMainThread();
1038 PROXY_IF_SANDBOXED(GetFMRadioSettings(aInfo));
1039 }
1041 void
1042 SetFMRadioFrequency(const uint32_t aFrequency) {
1043 AssertMainThread();
1044 PROXY_IF_SANDBOXED(SetFMRadioFrequency(aFrequency));
1045 }
1047 uint32_t
1048 GetFMRadioFrequency() {
1049 AssertMainThread();
1050 RETURN_PROXY_IF_SANDBOXED(GetFMRadioFrequency(), 0);
1051 }
1053 bool
1054 IsFMRadioOn() {
1055 AssertMainThread();
1056 RETURN_PROXY_IF_SANDBOXED(IsFMRadioOn(), false);
1057 }
1059 uint32_t
1060 GetFMRadioSignalStrength() {
1061 AssertMainThread();
1062 RETURN_PROXY_IF_SANDBOXED(GetFMRadioSignalStrength(), 0);
1063 }
1065 void
1066 CancelFMRadioSeek() {
1067 AssertMainThread();
1068 PROXY_IF_SANDBOXED(CancelFMRadioSeek());
1069 }
1071 FMRadioSettings
1072 GetFMBandSettings(FMRadioCountry aCountry) {
1073 FMRadioSettings settings;
1075 switch (aCountry) {
1076 case FM_RADIO_COUNTRY_US:
1077 case FM_RADIO_COUNTRY_EU:
1078 settings.upperLimit() = 108000;
1079 settings.lowerLimit() = 87800;
1080 settings.spaceType() = 200;
1081 settings.preEmphasis() = 75;
1082 break;
1083 case FM_RADIO_COUNTRY_JP_STANDARD:
1084 settings.upperLimit() = 76000;
1085 settings.lowerLimit() = 90000;
1086 settings.spaceType() = 100;
1087 settings.preEmphasis() = 50;
1088 break;
1089 case FM_RADIO_COUNTRY_CY:
1090 case FM_RADIO_COUNTRY_DE:
1091 case FM_RADIO_COUNTRY_DK:
1092 case FM_RADIO_COUNTRY_ES:
1093 case FM_RADIO_COUNTRY_FI:
1094 case FM_RADIO_COUNTRY_FR:
1095 case FM_RADIO_COUNTRY_HU:
1096 case FM_RADIO_COUNTRY_IR:
1097 case FM_RADIO_COUNTRY_IT:
1098 case FM_RADIO_COUNTRY_KW:
1099 case FM_RADIO_COUNTRY_LT:
1100 case FM_RADIO_COUNTRY_ML:
1101 case FM_RADIO_COUNTRY_NO:
1102 case FM_RADIO_COUNTRY_OM:
1103 case FM_RADIO_COUNTRY_PG:
1104 case FM_RADIO_COUNTRY_NL:
1105 case FM_RADIO_COUNTRY_CZ:
1106 case FM_RADIO_COUNTRY_UK:
1107 case FM_RADIO_COUNTRY_RW:
1108 case FM_RADIO_COUNTRY_SN:
1109 case FM_RADIO_COUNTRY_SI:
1110 case FM_RADIO_COUNTRY_ZA:
1111 case FM_RADIO_COUNTRY_SE:
1112 case FM_RADIO_COUNTRY_CH:
1113 case FM_RADIO_COUNTRY_TW:
1114 case FM_RADIO_COUNTRY_UA:
1115 settings.upperLimit() = 108000;
1116 settings.lowerLimit() = 87500;
1117 settings.spaceType() = 100;
1118 settings.preEmphasis() = 50;
1119 break;
1120 case FM_RADIO_COUNTRY_VA:
1121 case FM_RADIO_COUNTRY_MA:
1122 case FM_RADIO_COUNTRY_TR:
1123 settings.upperLimit() = 10800;
1124 settings.lowerLimit() = 87500;
1125 settings.spaceType() = 100;
1126 settings.preEmphasis() = 75;
1127 break;
1128 case FM_RADIO_COUNTRY_AU:
1129 case FM_RADIO_COUNTRY_BD:
1130 settings.upperLimit() = 108000;
1131 settings.lowerLimit() = 87500;
1132 settings.spaceType() = 200;
1133 settings.preEmphasis() = 75;
1134 break;
1135 case FM_RADIO_COUNTRY_AW:
1136 case FM_RADIO_COUNTRY_BS:
1137 case FM_RADIO_COUNTRY_CO:
1138 case FM_RADIO_COUNTRY_KR:
1139 settings.upperLimit() = 108000;
1140 settings.lowerLimit() = 88000;
1141 settings.spaceType() = 200;
1142 settings.preEmphasis() = 75;
1143 break;
1144 case FM_RADIO_COUNTRY_EC:
1145 settings.upperLimit() = 108000;
1146 settings.lowerLimit() = 88000;
1147 settings.spaceType() = 200;
1148 settings.preEmphasis() = 0;
1149 break;
1150 case FM_RADIO_COUNTRY_GM:
1151 settings.upperLimit() = 108000;
1152 settings.lowerLimit() = 88000;
1153 settings.spaceType() = 0;
1154 settings.preEmphasis() = 75;
1155 break;
1156 case FM_RADIO_COUNTRY_QA:
1157 settings.upperLimit() = 108000;
1158 settings.lowerLimit() = 88000;
1159 settings.spaceType() = 200;
1160 settings.preEmphasis() = 50;
1161 break;
1162 case FM_RADIO_COUNTRY_SG:
1163 settings.upperLimit() = 108000;
1164 settings.lowerLimit() = 88000;
1165 settings.spaceType() = 200;
1166 settings.preEmphasis() = 50;
1167 break;
1168 case FM_RADIO_COUNTRY_IN:
1169 settings.upperLimit() = 100000;
1170 settings.lowerLimit() = 108000;
1171 settings.spaceType() = 100;
1172 settings.preEmphasis() = 50;
1173 break;
1174 case FM_RADIO_COUNTRY_NZ:
1175 settings.upperLimit() = 100000;
1176 settings.lowerLimit() = 88000;
1177 settings.spaceType() = 50;
1178 settings.preEmphasis() = 50;
1179 break;
1180 case FM_RADIO_COUNTRY_USER_DEFINED:
1181 break;
1182 default:
1183 MOZ_ASSERT(0);
1184 break;
1185 };
1186 return settings;
1187 }
1189 void FactoryReset()
1190 {
1191 AssertMainThread();
1192 PROXY_IF_SANDBOXED(FactoryReset());
1193 }
1195 void
1196 StartDiskSpaceWatcher()
1197 {
1198 AssertMainProcess();
1199 AssertMainThread();
1200 PROXY_IF_SANDBOXED(StartDiskSpaceWatcher());
1201 }
1203 void
1204 StopDiskSpaceWatcher()
1205 {
1206 AssertMainProcess();
1207 AssertMainThread();
1208 PROXY_IF_SANDBOXED(StopDiskSpaceWatcher());
1209 }
1211 uint32_t
1212 GetTotalSystemMemory()
1213 {
1214 return hal_impl::GetTotalSystemMemory();
1215 }
1218 } // namespace hal
1219 } // namespace mozilla