michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=8 et ft=cpp : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "Hal.h" michael@0: #include "HalImpl.h" michael@0: #include "HalSandbox.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsXULAppAPI.h" michael@0: #include "mozilla/Observer.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsIDOMWindow.h" michael@0: #include "mozilla/Services.h" michael@0: #include "nsIWebNavigation.h" michael@0: #include "nsITabChild.h" michael@0: #include "nsIDocShell.h" michael@0: #include "mozilla/StaticPtr.h" michael@0: #include "mozilla/ClearOnShutdown.h" michael@0: #include "WindowIdentifier.h" michael@0: #include "mozilla/dom/ScreenOrientation.h" michael@0: #include "mozilla/dom/ContentChild.h" michael@0: #include "mozilla/dom/ContentParent.h" michael@0: michael@0: #ifdef XP_WIN michael@0: #include michael@0: #define getpid _getpid michael@0: #endif michael@0: michael@0: using namespace mozilla::services; michael@0: using namespace mozilla::dom; michael@0: michael@0: #define PROXY_IF_SANDBOXED(_call) \ michael@0: do { \ michael@0: if (InSandbox()) { \ michael@0: if (!hal_sandbox::HalChildDestroyed()) { \ michael@0: hal_sandbox::_call; \ michael@0: } \ michael@0: } else { \ michael@0: hal_impl::_call; \ michael@0: } \ michael@0: } while (0) michael@0: michael@0: #define RETURN_PROXY_IF_SANDBOXED(_call, defValue)\ michael@0: do { \ michael@0: if (InSandbox()) { \ michael@0: if (hal_sandbox::HalChildDestroyed()) { \ michael@0: return defValue; \ michael@0: } \ michael@0: return hal_sandbox::_call; \ michael@0: } else { \ michael@0: return hal_impl::_call; \ michael@0: } \ michael@0: } while (0) michael@0: michael@0: namespace mozilla { michael@0: namespace hal { michael@0: michael@0: PRLogModuleInfo * michael@0: GetHalLog() michael@0: { michael@0: static PRLogModuleInfo *sHalLog; michael@0: if (!sHalLog) { michael@0: sHalLog = PR_NewLogModule("hal"); michael@0: } michael@0: return sHalLog; michael@0: } michael@0: michael@0: namespace { michael@0: michael@0: void michael@0: AssertMainThread() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: } michael@0: michael@0: bool michael@0: InSandbox() michael@0: { michael@0: return GeckoProcessType_Content == XRE_GetProcessType(); michael@0: } michael@0: michael@0: void michael@0: AssertMainProcess() michael@0: { michael@0: MOZ_ASSERT(GeckoProcessType_Default == XRE_GetProcessType()); michael@0: } michael@0: michael@0: bool michael@0: WindowIsActive(nsIDOMWindow* aWindow) michael@0: { michael@0: nsCOMPtr window = do_QueryInterface(aWindow); michael@0: NS_ENSURE_TRUE(window, false); michael@0: michael@0: nsIDocument* document = window->GetDoc(); michael@0: NS_ENSURE_TRUE(document, false); michael@0: michael@0: return !document->Hidden(); michael@0: } michael@0: michael@0: StaticAutoPtr gLastIDToVibrate; michael@0: michael@0: void InitLastIDToVibrate() michael@0: { michael@0: gLastIDToVibrate = new WindowIdentifier::IDArrayType(); michael@0: ClearOnShutdown(&gLastIDToVibrate); michael@0: } michael@0: michael@0: } // anonymous namespace michael@0: michael@0: void michael@0: Vibrate(const nsTArray& pattern, nsIDOMWindow* window) michael@0: { michael@0: Vibrate(pattern, WindowIdentifier(window)); michael@0: } michael@0: michael@0: void michael@0: Vibrate(const nsTArray& pattern, const WindowIdentifier &id) michael@0: { michael@0: AssertMainThread(); michael@0: michael@0: // Only active windows may start vibrations. If |id| hasn't gone michael@0: // through the IPC layer -- that is, if our caller is the outside michael@0: // world, not hal_proxy -- check whether the window is active. If michael@0: // |id| has gone through IPC, don't check the window's visibility; michael@0: // only the window corresponding to the bottommost process has its michael@0: // visibility state set correctly. michael@0: if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) { michael@0: HAL_LOG(("Vibrate: Window is inactive, dropping vibrate.")); michael@0: return; michael@0: } michael@0: michael@0: if (!InSandbox()) { michael@0: if (!gLastIDToVibrate) { michael@0: InitLastIDToVibrate(); michael@0: } michael@0: *gLastIDToVibrate = id.AsArray(); michael@0: } michael@0: michael@0: // Don't forward our ID if we are not in the sandbox, because hal_impl michael@0: // doesn't need it, and we don't want it to be tempted to read it. The michael@0: // empty identifier will assert if it's used. michael@0: PROXY_IF_SANDBOXED(Vibrate(pattern, InSandbox() ? id : WindowIdentifier())); michael@0: } michael@0: michael@0: void michael@0: CancelVibrate(nsIDOMWindow* window) michael@0: { michael@0: CancelVibrate(WindowIdentifier(window)); michael@0: } michael@0: michael@0: void michael@0: CancelVibrate(const WindowIdentifier &id) michael@0: { michael@0: AssertMainThread(); michael@0: michael@0: // Although only active windows may start vibrations, a window may michael@0: // cancel its own vibration even if it's no longer active. michael@0: // michael@0: // After a window is marked as inactive, it sends a CancelVibrate michael@0: // request. We want this request to cancel a playing vibration michael@0: // started by that window, so we certainly don't want to reject the michael@0: // cancellation request because the window is now inactive. michael@0: // michael@0: // But it could be the case that, after this window became inactive, michael@0: // some other window came along and started a vibration. We don't michael@0: // want this window's cancellation request to cancel that window's michael@0: // actively-playing vibration! michael@0: // michael@0: // To solve this problem, we keep track of the id of the last window michael@0: // to start a vibration, and only accepts cancellation requests from michael@0: // the same window. All other cancellation requests are ignored. michael@0: michael@0: if (InSandbox() || (gLastIDToVibrate && *gLastIDToVibrate == id.AsArray())) { michael@0: // Don't forward our ID if we are not in the sandbox, because hal_impl michael@0: // doesn't need it, and we don't want it to be tempted to read it. The michael@0: // empty identifier will assert if it's used. michael@0: PROXY_IF_SANDBOXED(CancelVibrate(InSandbox() ? id : WindowIdentifier())); michael@0: } michael@0: } michael@0: michael@0: template michael@0: class ObserversManager michael@0: { michael@0: public: michael@0: void AddObserver(Observer* aObserver) { michael@0: if (!mObservers) { michael@0: mObservers = new mozilla::ObserverList(); michael@0: } michael@0: michael@0: mObservers->AddObserver(aObserver); michael@0: michael@0: if (mObservers->Length() == 1) { michael@0: EnableNotifications(); michael@0: } michael@0: } michael@0: michael@0: void RemoveObserver(Observer* aObserver) { michael@0: bool removed = mObservers && mObservers->RemoveObserver(aObserver); michael@0: if (!removed) { michael@0: NS_WARNING("RemoveObserver() called for unregistered observer"); michael@0: return; michael@0: } michael@0: michael@0: if (mObservers->Length() == 0) { michael@0: DisableNotifications(); michael@0: michael@0: OnNotificationsDisabled(); michael@0: michael@0: delete mObservers; michael@0: mObservers = nullptr; michael@0: } michael@0: } michael@0: michael@0: void BroadcastInformation(const InfoType& aInfo) { michael@0: // It is possible for mObservers to be nullptr here on some platforms, michael@0: // because a call to BroadcastInformation gets queued up asynchronously michael@0: // while RemoveObserver is running (and before the notifications are michael@0: // disabled). The queued call can then get run after mObservers has michael@0: // been nulled out. See bug 757025. michael@0: if (!mObservers) { michael@0: return; michael@0: } michael@0: mObservers->Broadcast(aInfo); michael@0: } michael@0: michael@0: protected: michael@0: virtual void EnableNotifications() = 0; michael@0: virtual void DisableNotifications() = 0; michael@0: virtual void OnNotificationsDisabled() {} michael@0: michael@0: private: michael@0: mozilla::ObserverList* mObservers; michael@0: }; michael@0: michael@0: template michael@0: class CachingObserversManager : public ObserversManager michael@0: { michael@0: public: michael@0: InfoType GetCurrentInformation() { michael@0: if (mHasValidCache) { michael@0: return mInfo; michael@0: } michael@0: michael@0: GetCurrentInformationInternal(&mInfo); michael@0: mHasValidCache = true; michael@0: return mInfo; michael@0: } michael@0: michael@0: void CacheInformation(const InfoType& aInfo) { michael@0: mHasValidCache = true; michael@0: mInfo = aInfo; michael@0: } michael@0: michael@0: void BroadcastCachedInformation() { michael@0: this->BroadcastInformation(mInfo); michael@0: } michael@0: michael@0: protected: michael@0: virtual void GetCurrentInformationInternal(InfoType*) = 0; michael@0: michael@0: virtual void OnNotificationsDisabled() { michael@0: mHasValidCache = false; michael@0: } michael@0: michael@0: private: michael@0: InfoType mInfo; michael@0: bool mHasValidCache; michael@0: }; michael@0: michael@0: class BatteryObserversManager : public CachingObserversManager michael@0: { michael@0: protected: michael@0: void EnableNotifications() { michael@0: PROXY_IF_SANDBOXED(EnableBatteryNotifications()); michael@0: } michael@0: michael@0: void DisableNotifications() { michael@0: PROXY_IF_SANDBOXED(DisableBatteryNotifications()); michael@0: } michael@0: michael@0: void GetCurrentInformationInternal(BatteryInformation* aInfo) { michael@0: PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo)); michael@0: } michael@0: }; michael@0: michael@0: static BatteryObserversManager sBatteryObservers; michael@0: michael@0: class NetworkObserversManager : public CachingObserversManager michael@0: { michael@0: protected: michael@0: void EnableNotifications() { michael@0: PROXY_IF_SANDBOXED(EnableNetworkNotifications()); michael@0: } michael@0: michael@0: void DisableNotifications() { michael@0: PROXY_IF_SANDBOXED(DisableNetworkNotifications()); michael@0: } michael@0: michael@0: void GetCurrentInformationInternal(NetworkInformation* aInfo) { michael@0: PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo)); michael@0: } michael@0: }; michael@0: michael@0: static NetworkObserversManager sNetworkObservers; michael@0: michael@0: class WakeLockObserversManager : public ObserversManager michael@0: { michael@0: protected: michael@0: void EnableNotifications() { michael@0: PROXY_IF_SANDBOXED(EnableWakeLockNotifications()); michael@0: } michael@0: michael@0: void DisableNotifications() { michael@0: PROXY_IF_SANDBOXED(DisableWakeLockNotifications()); michael@0: } michael@0: }; michael@0: michael@0: static WakeLockObserversManager sWakeLockObservers; michael@0: michael@0: class ScreenConfigurationObserversManager : public CachingObserversManager michael@0: { michael@0: protected: michael@0: void EnableNotifications() { michael@0: PROXY_IF_SANDBOXED(EnableScreenConfigurationNotifications()); michael@0: } michael@0: michael@0: void DisableNotifications() { michael@0: PROXY_IF_SANDBOXED(DisableScreenConfigurationNotifications()); michael@0: } michael@0: michael@0: void GetCurrentInformationInternal(ScreenConfiguration* aInfo) { michael@0: PROXY_IF_SANDBOXED(GetCurrentScreenConfiguration(aInfo)); michael@0: } michael@0: }; michael@0: michael@0: static ScreenConfigurationObserversManager sScreenConfigurationObservers; michael@0: michael@0: void michael@0: RegisterBatteryObserver(BatteryObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sBatteryObservers.AddObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: UnregisterBatteryObserver(BatteryObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sBatteryObservers.RemoveObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: GetCurrentBatteryInformation(BatteryInformation* aInfo) michael@0: { michael@0: AssertMainThread(); michael@0: *aInfo = sBatteryObservers.GetCurrentInformation(); michael@0: } michael@0: michael@0: void michael@0: NotifyBatteryChange(const BatteryInformation& aInfo) michael@0: { michael@0: AssertMainThread(); michael@0: sBatteryObservers.CacheInformation(aInfo); michael@0: sBatteryObservers.BroadcastCachedInformation(); michael@0: } michael@0: michael@0: bool GetScreenEnabled() michael@0: { michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(GetScreenEnabled(), false); michael@0: } michael@0: michael@0: void SetScreenEnabled(bool enabled) michael@0: { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(SetScreenEnabled(enabled)); michael@0: } michael@0: michael@0: bool GetCpuSleepAllowed() michael@0: { michael@0: // Generally for interfaces that are accessible by normal web content michael@0: // we should cache the result and be notified on state changes, like michael@0: // what the battery API does. But since this is only used by michael@0: // privileged interface, the synchronous getter is OK here. michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(GetCpuSleepAllowed(), true); michael@0: } michael@0: michael@0: void SetCpuSleepAllowed(bool allowed) michael@0: { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(SetCpuSleepAllowed(allowed)); michael@0: } michael@0: michael@0: double GetScreenBrightness() michael@0: { michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(GetScreenBrightness(), 0); michael@0: } michael@0: michael@0: void SetScreenBrightness(double brightness) michael@0: { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness, 0.0, 1.0))); michael@0: } michael@0: michael@0: bool SetLight(LightType light, const LightConfiguration& aConfig) michael@0: { michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(SetLight(light, aConfig), false); michael@0: } michael@0: michael@0: bool GetLight(LightType light, LightConfiguration* aConfig) michael@0: { michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(GetLight(light, aConfig), false); michael@0: } michael@0: michael@0: class SystemClockChangeObserversManager : public ObserversManager michael@0: { michael@0: protected: michael@0: void EnableNotifications() { michael@0: PROXY_IF_SANDBOXED(EnableSystemClockChangeNotifications()); michael@0: } michael@0: michael@0: void DisableNotifications() { michael@0: PROXY_IF_SANDBOXED(DisableSystemClockChangeNotifications()); michael@0: } michael@0: }; michael@0: michael@0: static SystemClockChangeObserversManager sSystemClockChangeObservers; michael@0: michael@0: void michael@0: RegisterSystemClockChangeObserver(SystemClockChangeObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sSystemClockChangeObservers.AddObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: UnregisterSystemClockChangeObserver(SystemClockChangeObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sSystemClockChangeObservers.RemoveObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: NotifySystemClockChange(const int64_t& aClockDeltaMS) michael@0: { michael@0: sSystemClockChangeObservers.BroadcastInformation(aClockDeltaMS); michael@0: } michael@0: michael@0: class SystemTimezoneChangeObserversManager : public ObserversManager michael@0: { michael@0: protected: michael@0: void EnableNotifications() { michael@0: PROXY_IF_SANDBOXED(EnableSystemTimezoneChangeNotifications()); michael@0: } michael@0: michael@0: void DisableNotifications() { michael@0: PROXY_IF_SANDBOXED(DisableSystemTimezoneChangeNotifications()); michael@0: } michael@0: }; michael@0: michael@0: static SystemTimezoneChangeObserversManager sSystemTimezoneChangeObservers; michael@0: michael@0: void michael@0: RegisterSystemTimezoneChangeObserver(SystemTimezoneChangeObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sSystemTimezoneChangeObservers.AddObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: UnregisterSystemTimezoneChangeObserver(SystemTimezoneChangeObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sSystemTimezoneChangeObservers.RemoveObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: NotifySystemTimezoneChange(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) michael@0: { michael@0: sSystemTimezoneChangeObservers.BroadcastInformation(aSystemTimezoneChangeInfo); michael@0: } michael@0: michael@0: void michael@0: AdjustSystemClock(int64_t aDeltaMilliseconds) michael@0: { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(AdjustSystemClock(aDeltaMilliseconds)); michael@0: } michael@0: michael@0: void michael@0: SetTimezone(const nsCString& aTimezoneSpec) michael@0: { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(SetTimezone(aTimezoneSpec)); michael@0: } michael@0: michael@0: int32_t michael@0: GetTimezoneOffset() michael@0: { michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(GetTimezoneOffset(), 0); michael@0: } michael@0: michael@0: nsCString michael@0: GetTimezone() michael@0: { michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(GetTimezone(), nsCString("")); michael@0: } michael@0: michael@0: void michael@0: EnableSensorNotifications(SensorType aSensor) { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor)); michael@0: } michael@0: michael@0: void michael@0: DisableSensorNotifications(SensorType aSensor) { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor)); michael@0: } michael@0: michael@0: typedef mozilla::ObserverList SensorObserverList; michael@0: static SensorObserverList* gSensorObservers = nullptr; michael@0: michael@0: static SensorObserverList & michael@0: GetSensorObservers(SensorType sensor_type) { michael@0: MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE); michael@0: michael@0: if(!gSensorObservers) { michael@0: gSensorObservers = new SensorObserverList[NUM_SENSOR_TYPE]; michael@0: } michael@0: return gSensorObservers[sensor_type]; michael@0: } michael@0: michael@0: void michael@0: RegisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) { michael@0: SensorObserverList &observers = GetSensorObservers(aSensor); michael@0: michael@0: AssertMainThread(); michael@0: michael@0: observers.AddObserver(aObserver); michael@0: if(observers.Length() == 1) { michael@0: EnableSensorNotifications(aSensor); michael@0: } michael@0: } michael@0: michael@0: void michael@0: UnregisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) { michael@0: AssertMainThread(); michael@0: michael@0: if (!gSensorObservers) { michael@0: return; michael@0: } michael@0: michael@0: SensorObserverList &observers = GetSensorObservers(aSensor); michael@0: if (!observers.RemoveObserver(aObserver) || observers.Length() > 0) { michael@0: return; michael@0: } michael@0: DisableSensorNotifications(aSensor); michael@0: michael@0: // Destroy sSensorObservers only if all observer lists are empty. michael@0: for (int i = 0; i < NUM_SENSOR_TYPE; i++) { michael@0: if (gSensorObservers[i].Length() > 0) { michael@0: return; michael@0: } michael@0: } michael@0: delete [] gSensorObservers; michael@0: gSensorObservers = nullptr; michael@0: } michael@0: michael@0: void michael@0: NotifySensorChange(const SensorData &aSensorData) { michael@0: SensorObserverList &observers = GetSensorObservers(aSensorData.sensor()); michael@0: michael@0: AssertMainThread(); michael@0: michael@0: observers.Broadcast(aSensorData); michael@0: } michael@0: michael@0: void michael@0: RegisterNetworkObserver(NetworkObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sNetworkObservers.AddObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: UnregisterNetworkObserver(NetworkObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sNetworkObservers.RemoveObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: GetCurrentNetworkInformation(NetworkInformation* aInfo) michael@0: { michael@0: AssertMainThread(); michael@0: *aInfo = sNetworkObservers.GetCurrentInformation(); michael@0: } michael@0: michael@0: void michael@0: NotifyNetworkChange(const NetworkInformation& aInfo) michael@0: { michael@0: sNetworkObservers.CacheInformation(aInfo); michael@0: sNetworkObservers.BroadcastCachedInformation(); michael@0: } michael@0: michael@0: void Reboot() michael@0: { michael@0: AssertMainProcess(); michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(Reboot()); michael@0: } michael@0: michael@0: void PowerOff() michael@0: { michael@0: AssertMainProcess(); michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(PowerOff()); michael@0: } michael@0: michael@0: void StartForceQuitWatchdog(ShutdownMode aMode, int32_t aTimeoutSecs) michael@0: { michael@0: AssertMainProcess(); michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(StartForceQuitWatchdog(aMode, aTimeoutSecs)); michael@0: } michael@0: michael@0: void StartMonitoringGamepadStatus() michael@0: { michael@0: PROXY_IF_SANDBOXED(StartMonitoringGamepadStatus()); michael@0: } michael@0: michael@0: void StopMonitoringGamepadStatus() michael@0: { michael@0: PROXY_IF_SANDBOXED(StopMonitoringGamepadStatus()); michael@0: } michael@0: michael@0: void michael@0: RegisterWakeLockObserver(WakeLockObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sWakeLockObservers.AddObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: UnregisterWakeLockObserver(WakeLockObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sWakeLockObservers.RemoveObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: ModifyWakeLock(const nsAString& aTopic, michael@0: WakeLockControl aLockAdjust, michael@0: WakeLockControl aHiddenAdjust, michael@0: uint64_t aProcessID /* = CONTENT_PROCESS_ID_UNKNOWN */) michael@0: { michael@0: AssertMainThread(); michael@0: michael@0: if (aProcessID == CONTENT_PROCESS_ID_UNKNOWN) { michael@0: aProcessID = InSandbox() ? ContentChild::GetSingleton()->GetID() : michael@0: CONTENT_PROCESS_ID_MAIN; michael@0: } michael@0: michael@0: PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic, aLockAdjust, michael@0: aHiddenAdjust, aProcessID)); michael@0: } michael@0: michael@0: void michael@0: GetWakeLockInfo(const nsAString& aTopic, WakeLockInformation* aWakeLockInfo) michael@0: { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo)); michael@0: } michael@0: michael@0: void michael@0: NotifyWakeLockChange(const WakeLockInformation& aInfo) michael@0: { michael@0: AssertMainThread(); michael@0: sWakeLockObservers.BroadcastInformation(aInfo); michael@0: } michael@0: michael@0: void michael@0: RegisterScreenConfigurationObserver(ScreenConfigurationObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sScreenConfigurationObservers.AddObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: UnregisterScreenConfigurationObserver(ScreenConfigurationObserver* aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: sScreenConfigurationObservers.RemoveObserver(aObserver); michael@0: } michael@0: michael@0: void michael@0: GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration) michael@0: { michael@0: AssertMainThread(); michael@0: *aScreenConfiguration = sScreenConfigurationObservers.GetCurrentInformation(); michael@0: } michael@0: michael@0: void michael@0: NotifyScreenConfigurationChange(const ScreenConfiguration& aScreenConfiguration) michael@0: { michael@0: sScreenConfigurationObservers.CacheInformation(aScreenConfiguration); michael@0: sScreenConfigurationObservers.BroadcastCachedInformation(); michael@0: } michael@0: michael@0: bool michael@0: LockScreenOrientation(const dom::ScreenOrientation& aOrientation) michael@0: { michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), false); michael@0: } michael@0: michael@0: void michael@0: UnlockScreenOrientation() michael@0: { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(UnlockScreenOrientation()); michael@0: } michael@0: michael@0: void michael@0: EnableSwitchNotifications(SwitchDevice aDevice) { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(EnableSwitchNotifications(aDevice)); michael@0: } michael@0: michael@0: void michael@0: DisableSwitchNotifications(SwitchDevice aDevice) { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(DisableSwitchNotifications(aDevice)); michael@0: } michael@0: michael@0: SwitchState GetCurrentSwitchState(SwitchDevice aDevice) michael@0: { michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(GetCurrentSwitchState(aDevice), SWITCH_STATE_UNKNOWN); michael@0: } michael@0: michael@0: void NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState) michael@0: { michael@0: PROXY_IF_SANDBOXED(NotifySwitchStateFromInputDevice(aDevice, aState)); michael@0: } michael@0: michael@0: typedef mozilla::ObserverList SwitchObserverList; michael@0: michael@0: static SwitchObserverList *sSwitchObserverLists = nullptr; michael@0: michael@0: static SwitchObserverList& michael@0: GetSwitchObserverList(SwitchDevice aDevice) { michael@0: MOZ_ASSERT(0 <= aDevice && aDevice < NUM_SWITCH_DEVICE); michael@0: if (sSwitchObserverLists == nullptr) { michael@0: sSwitchObserverLists = new SwitchObserverList[NUM_SWITCH_DEVICE]; michael@0: } michael@0: return sSwitchObserverLists[aDevice]; michael@0: } michael@0: michael@0: static void michael@0: ReleaseObserversIfNeeded() { michael@0: for (int i = 0; i < NUM_SWITCH_DEVICE; i++) { michael@0: if (sSwitchObserverLists[i].Length() != 0) michael@0: return; michael@0: } michael@0: michael@0: //The length of every list is 0, no observer in the list. michael@0: delete [] sSwitchObserverLists; michael@0: sSwitchObserverLists = nullptr; michael@0: } michael@0: michael@0: void michael@0: RegisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: SwitchObserverList& observer = GetSwitchObserverList(aDevice); michael@0: observer.AddObserver(aObserver); michael@0: if (observer.Length() == 1) { michael@0: EnableSwitchNotifications(aDevice); michael@0: } michael@0: } michael@0: michael@0: void michael@0: UnregisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver) michael@0: { michael@0: AssertMainThread(); michael@0: michael@0: if (!sSwitchObserverLists) { michael@0: return; michael@0: } michael@0: michael@0: SwitchObserverList& observer = GetSwitchObserverList(aDevice); michael@0: if (!observer.RemoveObserver(aObserver) || observer.Length() > 0) { michael@0: return; michael@0: } michael@0: michael@0: DisableSwitchNotifications(aDevice); michael@0: ReleaseObserversIfNeeded(); michael@0: } michael@0: michael@0: void michael@0: NotifySwitchChange(const SwitchEvent& aEvent) michael@0: { michael@0: // When callback this notification, main thread may call unregister function michael@0: // first. We should check if this pointer is valid. michael@0: if (!sSwitchObserverLists) michael@0: return; michael@0: michael@0: SwitchObserverList& observer = GetSwitchObserverList(aEvent.device()); michael@0: observer.Broadcast(aEvent); michael@0: } michael@0: michael@0: static AlarmObserver* sAlarmObserver; michael@0: michael@0: bool michael@0: RegisterTheOneAlarmObserver(AlarmObserver* aObserver) michael@0: { michael@0: MOZ_ASSERT(!InSandbox()); michael@0: MOZ_ASSERT(!sAlarmObserver); michael@0: michael@0: sAlarmObserver = aObserver; michael@0: RETURN_PROXY_IF_SANDBOXED(EnableAlarm(), false); michael@0: } michael@0: michael@0: void michael@0: UnregisterTheOneAlarmObserver() michael@0: { michael@0: if (sAlarmObserver) { michael@0: sAlarmObserver = nullptr; michael@0: PROXY_IF_SANDBOXED(DisableAlarm()); michael@0: } michael@0: } michael@0: michael@0: void michael@0: NotifyAlarmFired() michael@0: { michael@0: if (sAlarmObserver) { michael@0: sAlarmObserver->Notify(void_t()); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: SetAlarm(int32_t aSeconds, int32_t aNanoseconds) michael@0: { michael@0: // It's pointless to program an alarm nothing is going to observe ... michael@0: MOZ_ASSERT(sAlarmObserver); michael@0: RETURN_PROXY_IF_SANDBOXED(SetAlarm(aSeconds, aNanoseconds), false); michael@0: } michael@0: michael@0: void michael@0: SetProcessPriority(int aPid, michael@0: ProcessPriority aPriority, michael@0: ProcessCPUPriority aCPUPriority, michael@0: uint32_t aBackgroundLRU) michael@0: { michael@0: // n.b. The sandboxed implementation crashes; SetProcessPriority works only michael@0: // from the main process. michael@0: MOZ_ASSERT(aBackgroundLRU == 0 || aPriority == PROCESS_PRIORITY_BACKGROUND); michael@0: PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority, aCPUPriority, michael@0: aBackgroundLRU)); michael@0: } michael@0: michael@0: // From HalTypes.h. michael@0: const char* michael@0: ProcessPriorityToString(ProcessPriority aPriority) michael@0: { michael@0: switch (aPriority) { michael@0: case PROCESS_PRIORITY_MASTER: michael@0: return "MASTER"; michael@0: case PROCESS_PRIORITY_PREALLOC: michael@0: return "PREALLOC"; michael@0: case PROCESS_PRIORITY_FOREGROUND_HIGH: michael@0: return "FOREGROUND_HIGH"; michael@0: case PROCESS_PRIORITY_FOREGROUND: michael@0: return "FOREGROUND"; michael@0: case PROCESS_PRIORITY_FOREGROUND_KEYBOARD: michael@0: return "FOREGROUND_KEYBOARD"; michael@0: case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE: michael@0: return "BACKGROUND_PERCEIVABLE"; michael@0: case PROCESS_PRIORITY_BACKGROUND_HOMESCREEN: michael@0: return "BACKGROUND_HOMESCREEN"; michael@0: case PROCESS_PRIORITY_BACKGROUND: michael@0: return "BACKGROUND"; michael@0: case PROCESS_PRIORITY_UNKNOWN: michael@0: return "UNKNOWN"; michael@0: default: michael@0: MOZ_ASSERT(false); michael@0: return "???"; michael@0: } michael@0: } michael@0: michael@0: // From HalTypes.h. michael@0: const char* michael@0: ProcessPriorityToString(ProcessPriority aPriority, michael@0: ProcessCPUPriority aCPUPriority) michael@0: { michael@0: // Sorry this is ugly. At least it's all in one place. michael@0: // michael@0: // We intentionally fall through if aCPUPriority is invalid; we won't hit any michael@0: // of the if statements further down, so it's OK. michael@0: michael@0: switch (aPriority) { michael@0: case PROCESS_PRIORITY_MASTER: michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) { michael@0: return "MASTER:CPU_NORMAL"; michael@0: } michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) { michael@0: return "MASTER:CPU_LOW"; michael@0: } michael@0: case PROCESS_PRIORITY_PREALLOC: michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) { michael@0: return "PREALLOC:CPU_NORMAL"; michael@0: } michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) { michael@0: return "PREALLOC:CPU_LOW"; michael@0: } michael@0: case PROCESS_PRIORITY_FOREGROUND_HIGH: michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) { michael@0: return "FOREGROUND_HIGH:CPU_NORMAL"; michael@0: } michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) { michael@0: return "FOREGROUND_HIGH:CPU_LOW"; michael@0: } michael@0: case PROCESS_PRIORITY_FOREGROUND: michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) { michael@0: return "FOREGROUND:CPU_NORMAL"; michael@0: } michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) { michael@0: return "FOREGROUND:CPU_LOW"; michael@0: } michael@0: case PROCESS_PRIORITY_FOREGROUND_KEYBOARD: michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) { michael@0: return "FOREGROUND_KEYBOARD:CPU_NORMAL"; michael@0: } michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) { michael@0: return "FOREGROUND_KEYBOARD:CPU_LOW"; michael@0: } michael@0: case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE: michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) { michael@0: return "BACKGROUND_PERCEIVABLE:CPU_NORMAL"; michael@0: } michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) { michael@0: return "BACKGROUND_PERCEIVABLE:CPU_LOW"; michael@0: } michael@0: case PROCESS_PRIORITY_BACKGROUND_HOMESCREEN: michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) { michael@0: return "BACKGROUND_HOMESCREEN:CPU_NORMAL"; michael@0: } michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) { michael@0: return "BACKGROUND_HOMESCREEN:CPU_LOW"; michael@0: } michael@0: case PROCESS_PRIORITY_BACKGROUND: michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) { michael@0: return "BACKGROUND:CPU_NORMAL"; michael@0: } michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) { michael@0: return "BACKGROUND:CPU_LOW"; michael@0: } michael@0: case PROCESS_PRIORITY_UNKNOWN: michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) { michael@0: return "UNKNOWN:CPU_NORMAL"; michael@0: } michael@0: if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) { michael@0: return "UNKNOWN:CPU_LOW"; michael@0: } michael@0: default: michael@0: // Fall through. (|default| is here to silence warnings.) michael@0: break; michael@0: } michael@0: michael@0: MOZ_ASSERT(false); michael@0: return "???"; michael@0: } michael@0: michael@0: static StaticAutoPtr > sFMRadioObservers; michael@0: michael@0: static void michael@0: InitializeFMRadioObserver() michael@0: { michael@0: if (!sFMRadioObservers) { michael@0: sFMRadioObservers = new ObserverList; michael@0: ClearOnShutdown(&sFMRadioObservers); michael@0: } michael@0: } michael@0: michael@0: void michael@0: RegisterFMRadioObserver(FMRadioObserver* aFMRadioObserver) { michael@0: AssertMainThread(); michael@0: InitializeFMRadioObserver(); michael@0: sFMRadioObservers->AddObserver(aFMRadioObserver); michael@0: } michael@0: michael@0: void michael@0: UnregisterFMRadioObserver(FMRadioObserver* aFMRadioObserver) { michael@0: AssertMainThread(); michael@0: InitializeFMRadioObserver(); michael@0: sFMRadioObservers->RemoveObserver(aFMRadioObserver); michael@0: } michael@0: michael@0: void michael@0: NotifyFMRadioStatus(const FMRadioOperationInformation& aFMRadioState) { michael@0: InitializeFMRadioObserver(); michael@0: sFMRadioObservers->Broadcast(aFMRadioState); michael@0: } michael@0: michael@0: void michael@0: EnableFMRadio(const FMRadioSettings& aInfo) { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(EnableFMRadio(aInfo)); michael@0: } michael@0: michael@0: void michael@0: DisableFMRadio() { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(DisableFMRadio()); michael@0: } michael@0: michael@0: void michael@0: FMRadioSeek(const FMRadioSeekDirection& aDirection) { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(FMRadioSeek(aDirection)); michael@0: } michael@0: michael@0: void michael@0: GetFMRadioSettings(FMRadioSettings* aInfo) { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(GetFMRadioSettings(aInfo)); michael@0: } michael@0: michael@0: void michael@0: SetFMRadioFrequency(const uint32_t aFrequency) { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(SetFMRadioFrequency(aFrequency)); michael@0: } michael@0: michael@0: uint32_t michael@0: GetFMRadioFrequency() { michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(GetFMRadioFrequency(), 0); michael@0: } michael@0: michael@0: bool michael@0: IsFMRadioOn() { michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(IsFMRadioOn(), false); michael@0: } michael@0: michael@0: uint32_t michael@0: GetFMRadioSignalStrength() { michael@0: AssertMainThread(); michael@0: RETURN_PROXY_IF_SANDBOXED(GetFMRadioSignalStrength(), 0); michael@0: } michael@0: michael@0: void michael@0: CancelFMRadioSeek() { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(CancelFMRadioSeek()); michael@0: } michael@0: michael@0: FMRadioSettings michael@0: GetFMBandSettings(FMRadioCountry aCountry) { michael@0: FMRadioSettings settings; michael@0: michael@0: switch (aCountry) { michael@0: case FM_RADIO_COUNTRY_US: michael@0: case FM_RADIO_COUNTRY_EU: michael@0: settings.upperLimit() = 108000; michael@0: settings.lowerLimit() = 87800; michael@0: settings.spaceType() = 200; michael@0: settings.preEmphasis() = 75; michael@0: break; michael@0: case FM_RADIO_COUNTRY_JP_STANDARD: michael@0: settings.upperLimit() = 76000; michael@0: settings.lowerLimit() = 90000; michael@0: settings.spaceType() = 100; michael@0: settings.preEmphasis() = 50; michael@0: break; michael@0: case FM_RADIO_COUNTRY_CY: michael@0: case FM_RADIO_COUNTRY_DE: michael@0: case FM_RADIO_COUNTRY_DK: michael@0: case FM_RADIO_COUNTRY_ES: michael@0: case FM_RADIO_COUNTRY_FI: michael@0: case FM_RADIO_COUNTRY_FR: michael@0: case FM_RADIO_COUNTRY_HU: michael@0: case FM_RADIO_COUNTRY_IR: michael@0: case FM_RADIO_COUNTRY_IT: michael@0: case FM_RADIO_COUNTRY_KW: michael@0: case FM_RADIO_COUNTRY_LT: michael@0: case FM_RADIO_COUNTRY_ML: michael@0: case FM_RADIO_COUNTRY_NO: michael@0: case FM_RADIO_COUNTRY_OM: michael@0: case FM_RADIO_COUNTRY_PG: michael@0: case FM_RADIO_COUNTRY_NL: michael@0: case FM_RADIO_COUNTRY_CZ: michael@0: case FM_RADIO_COUNTRY_UK: michael@0: case FM_RADIO_COUNTRY_RW: michael@0: case FM_RADIO_COUNTRY_SN: michael@0: case FM_RADIO_COUNTRY_SI: michael@0: case FM_RADIO_COUNTRY_ZA: michael@0: case FM_RADIO_COUNTRY_SE: michael@0: case FM_RADIO_COUNTRY_CH: michael@0: case FM_RADIO_COUNTRY_TW: michael@0: case FM_RADIO_COUNTRY_UA: michael@0: settings.upperLimit() = 108000; michael@0: settings.lowerLimit() = 87500; michael@0: settings.spaceType() = 100; michael@0: settings.preEmphasis() = 50; michael@0: break; michael@0: case FM_RADIO_COUNTRY_VA: michael@0: case FM_RADIO_COUNTRY_MA: michael@0: case FM_RADIO_COUNTRY_TR: michael@0: settings.upperLimit() = 10800; michael@0: settings.lowerLimit() = 87500; michael@0: settings.spaceType() = 100; michael@0: settings.preEmphasis() = 75; michael@0: break; michael@0: case FM_RADIO_COUNTRY_AU: michael@0: case FM_RADIO_COUNTRY_BD: michael@0: settings.upperLimit() = 108000; michael@0: settings.lowerLimit() = 87500; michael@0: settings.spaceType() = 200; michael@0: settings.preEmphasis() = 75; michael@0: break; michael@0: case FM_RADIO_COUNTRY_AW: michael@0: case FM_RADIO_COUNTRY_BS: michael@0: case FM_RADIO_COUNTRY_CO: michael@0: case FM_RADIO_COUNTRY_KR: michael@0: settings.upperLimit() = 108000; michael@0: settings.lowerLimit() = 88000; michael@0: settings.spaceType() = 200; michael@0: settings.preEmphasis() = 75; michael@0: break; michael@0: case FM_RADIO_COUNTRY_EC: michael@0: settings.upperLimit() = 108000; michael@0: settings.lowerLimit() = 88000; michael@0: settings.spaceType() = 200; michael@0: settings.preEmphasis() = 0; michael@0: break; michael@0: case FM_RADIO_COUNTRY_GM: michael@0: settings.upperLimit() = 108000; michael@0: settings.lowerLimit() = 88000; michael@0: settings.spaceType() = 0; michael@0: settings.preEmphasis() = 75; michael@0: break; michael@0: case FM_RADIO_COUNTRY_QA: michael@0: settings.upperLimit() = 108000; michael@0: settings.lowerLimit() = 88000; michael@0: settings.spaceType() = 200; michael@0: settings.preEmphasis() = 50; michael@0: break; michael@0: case FM_RADIO_COUNTRY_SG: michael@0: settings.upperLimit() = 108000; michael@0: settings.lowerLimit() = 88000; michael@0: settings.spaceType() = 200; michael@0: settings.preEmphasis() = 50; michael@0: break; michael@0: case FM_RADIO_COUNTRY_IN: michael@0: settings.upperLimit() = 100000; michael@0: settings.lowerLimit() = 108000; michael@0: settings.spaceType() = 100; michael@0: settings.preEmphasis() = 50; michael@0: break; michael@0: case FM_RADIO_COUNTRY_NZ: michael@0: settings.upperLimit() = 100000; michael@0: settings.lowerLimit() = 88000; michael@0: settings.spaceType() = 50; michael@0: settings.preEmphasis() = 50; michael@0: break; michael@0: case FM_RADIO_COUNTRY_USER_DEFINED: michael@0: break; michael@0: default: michael@0: MOZ_ASSERT(0); michael@0: break; michael@0: }; michael@0: return settings; michael@0: } michael@0: michael@0: void FactoryReset() michael@0: { michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(FactoryReset()); michael@0: } michael@0: michael@0: void michael@0: StartDiskSpaceWatcher() michael@0: { michael@0: AssertMainProcess(); michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(StartDiskSpaceWatcher()); michael@0: } michael@0: michael@0: void michael@0: StopDiskSpaceWatcher() michael@0: { michael@0: AssertMainProcess(); michael@0: AssertMainThread(); michael@0: PROXY_IF_SANDBOXED(StopDiskSpaceWatcher()); michael@0: } michael@0: michael@0: uint32_t michael@0: GetTotalSystemMemory() michael@0: { michael@0: return hal_impl::GetTotalSystemMemory(); michael@0: } michael@0: michael@0: michael@0: } // namespace hal michael@0: } // namespace mozilla