author | Gene Lian <clian@mozilla.com> |
Tue, 02 Oct 2012 15:26:32 +0800 | |
changeset 108958 | 6bcb5f9359d8cae3ee2f2d4ee452b13e3f093b35 |
parent 108957 | c2d3a2496dc95f4c88dd7f2a393b51d30dc0dd19 |
child 108959 | 1d4bafc6c4817a3e76d65219b6752fa02c8df247 |
push id | 23602 |
push user | emorley@mozilla.com |
push date | Wed, 03 Oct 2012 12:57:12 +0000 |
treeherder | mozilla-central@5ac283a12f02 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | cjones |
bugs | 793970 |
milestone | 18.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/b2g/components/UpdatePrompt.js +++ b/b2g/components/UpdatePrompt.js @@ -243,27 +243,26 @@ UpdatePrompt.prototype = { } this.finishOSUpdate(updateFile.path); }, restartProcess: function UP_restartProcess() { log("Update downloaded, restarting to apply it"); +#ifndef MOZ_WIDGET_GONK let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] - .getService(Ci.nsIAppStartup); - // NB: on Gonk, we rely on the system process manager to restart - // us. Trying to restart here would conflict with the process - // manager. We should be using a runtime check to detect Gonk - // instead of this gross ifdef, but the ifdef works for now. - appStartup.quit(appStartup.eForceQuit -#ifndef ANDROID - | appStartup.eRestart + .getService(Ci.nsIAppStartup); + appStartup.quit(appStartup.eForceQuit | appStartup.eRestart); +#else + // NB: on Gonk, we rely on the system process manager to restart us. + let pmService = Cc["@mozilla.org/power/powermanagerservice;1"] + .getService(Ci.nsIPowerManagerService); + pmService.restart(); #endif - ); }, finishOSUpdate: function UP_finishOSUpdate(aOsUpdatePath) { let recoveryService = Cc["@mozilla.org/recovery-service;1"] .getService(Ci.nsIRecoveryService); log("Rebooting into recovery to apply FOTA update: " + aOsUpdatePath);
--- a/dom/power/PowerManagerService.cpp +++ b/dom/power/PowerManagerService.cpp @@ -1,76 +1,92 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Hal.h" #include "mozilla/HalWakeLock.h" #include "mozilla/ClearOnShutdown.h" +#include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "nsIDOMWakeLockListener.h" #include "nsIDOMWindow.h" #include "nsIObserverService.h" #include "PowerManagerService.h" #include "WakeLock.h" +// For _exit(). +#ifdef XP_WIN +#include <process.h> +#else +#include <unistd.h> +#endif + namespace mozilla { namespace dom { namespace power { +using namespace hal; + NS_IMPL_ISUPPORTS1(PowerManagerService, nsIPowerManagerService) /* static */ StaticRefPtr<PowerManagerService> PowerManagerService::sSingleton; -/* static */ already_AddRefed<nsIPowerManagerService> +/* static */ already_AddRefed<PowerManagerService> PowerManagerService::GetInstance() { if (!sSingleton) { sSingleton = new PowerManagerService(); sSingleton->Init(); ClearOnShutdown(&sSingleton); } - nsCOMPtr<nsIPowerManagerService> service(do_QueryInterface(sSingleton)); + nsRefPtr<PowerManagerService> service = sSingleton.get(); return service.forget(); } void PowerManagerService::Init() { - hal::RegisterWakeLockObserver(this); + RegisterWakeLockObserver(this); + + // NB: default to *enabling* the watchdog even when the pref is + // absent, in case the profile might be damaged and we need to + // restart to repair it. + mWatchdogTimeoutSecs = + Preferences::GetInt("shutdown.watchdog.timeoutSecs", 5); } PowerManagerService::~PowerManagerService() { - hal::UnregisterWakeLockObserver(this); + UnregisterWakeLockObserver(this); } void -PowerManagerService::ComputeWakeLockState(const hal::WakeLockInformation& aWakeLockInfo, +PowerManagerService::ComputeWakeLockState(const WakeLockInformation& aWakeLockInfo, nsAString &aState) { - hal::WakeLockState state = hal::ComputeWakeLockState(aWakeLockInfo.numLocks(), - aWakeLockInfo.numHidden()); + WakeLockState state = hal::ComputeWakeLockState(aWakeLockInfo.numLocks(), + aWakeLockInfo.numHidden()); switch (state) { - case hal::WAKE_LOCK_STATE_UNLOCKED: + case WAKE_LOCK_STATE_UNLOCKED: aState.AssignLiteral("unlocked"); break; - case hal::WAKE_LOCK_STATE_HIDDEN: + case WAKE_LOCK_STATE_HIDDEN: aState.AssignLiteral("locked-background"); break; - case hal::WAKE_LOCK_STATE_VISIBLE: + case WAKE_LOCK_STATE_VISIBLE: aState.AssignLiteral("locked-foreground"); break; } } void -PowerManagerService::Notify(const hal::WakeLockInformation& aWakeLockInfo) +PowerManagerService::Notify(const WakeLockInformation& aWakeLockInfo) { nsAutoString state; ComputeWakeLockState(aWakeLockInfo, state); /** * Copy the listeners list before we walk through the callbacks * because the callbacks may install new listeners. We expect no * more than one listener per window, so it shouldn't be too long. @@ -80,48 +96,62 @@ PowerManagerService::Notify(const hal::W for (uint32_t i = 0; i < listeners.Length(); ++i) { listeners[i]->Callback(aWakeLockInfo.topic(), state); } } void PowerManagerService::SyncProfile() { - // FIXME/bug 793970: We need to start a watchdog thread to force gecko - // to really power off or reboot if the profile synchronizing hangs. nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService(); if (obsServ) { NS_NAMED_LITERAL_STRING(context, "shutdown-persist"); obsServ->NotifyObservers(nullptr, "profile-change-net-teardown", context.get()); obsServ->NotifyObservers(nullptr, "profile-change-teardown", context.get()); obsServ->NotifyObservers(nullptr, "profile-before-change", context.get()); } } NS_IMETHODIMP PowerManagerService::Reboot() { + StartForceQuitWatchdog(eHalShutdownMode_Reboot, mWatchdogTimeoutSecs); // To synchronize any unsaved user data before rebooting. SyncProfile(); hal::Reboot(); MOZ_NOT_REACHED(); return NS_OK; } NS_IMETHODIMP PowerManagerService::PowerOff() { + StartForceQuitWatchdog(eHalShutdownMode_PowerOff, mWatchdogTimeoutSecs); // To synchronize any unsaved user data before powering off. SyncProfile(); hal::PowerOff(); MOZ_NOT_REACHED(); return NS_OK; } NS_IMETHODIMP +PowerManagerService::Restart() +{ + // FIXME/bug 796826 this implementation is currently gonk-specific, + // because it relies on the Gonk to initialize the Gecko processes to + // restart B2G. It's better to do it here to have a real "restart". + StartForceQuitWatchdog(eHalShutdownMode_Restart, mWatchdogTimeoutSecs); + // To synchronize any unsaved user data before restarting. + SyncProfile(); + _exit(0); + MOZ_NOT_REACHED(); + return NS_OK; +} + +NS_IMETHODIMP PowerManagerService::AddWakeLockListener(nsIDOMMozWakeLockListener *aListener) { if (mWakeLockListeners.Contains(aListener)) return NS_OK; mWakeLockListeners.AppendElement(aListener); return NS_OK; } @@ -131,18 +161,18 @@ PowerManagerService::RemoveWakeLockListe { mWakeLockListeners.RemoveElement(aListener); return NS_OK; } NS_IMETHODIMP PowerManagerService::GetWakeLockState(const nsAString &aTopic, nsAString &aState) { - hal::WakeLockInformation info; - hal::GetWakeLockInfo(aTopic, &info); + WakeLockInformation info; + GetWakeLockInfo(aTopic, &info); ComputeWakeLockState(info, aState); return NS_OK; } NS_IMETHODIMP PowerManagerService::NewWakeLock(const nsAString &aTopic,
--- a/dom/power/PowerManagerService.h +++ b/dom/power/PowerManagerService.h @@ -21,17 +21,17 @@ namespace power { class PowerManagerService : public nsIPowerManagerService , public WakeLockObserver { public: NS_DECL_ISUPPORTS NS_DECL_NSIPOWERMANAGERSERVICE - static already_AddRefed<nsIPowerManagerService> GetInstance(); + static already_AddRefed<PowerManagerService> GetInstance(); void Init(); // Implement WakeLockObserver void Notify(const hal::WakeLockInformation& aWakeLockInfo); private: @@ -40,15 +40,17 @@ private: void ComputeWakeLockState(const hal::WakeLockInformation& aWakeLockInfo, nsAString &aState); void SyncProfile(); static StaticRefPtr<PowerManagerService> sSingleton; nsTArray<nsCOMPtr<nsIDOMMozWakeLockListener> > mWakeLockListeners; + + int32_t mWatchdogTimeoutSecs; }; } // namespace power } // namespace dom } // namespace mozilla #endif // mozilla_dom_power_PowerManagerService_h
--- a/dom/power/nsIPowerManagerService.idl +++ b/dom/power/nsIPowerManagerService.idl @@ -12,21 +12,34 @@ interface nsIDOMMozWakeLock; interface nsIDOMMozWakeLockListener; interface nsIDOMWindow; /** * For use with non-content code. */ -[scriptable, builtinclass, uuid(235ca1a1-d0c8-41f3-9b4a-dbaa4437d69c)] +[scriptable, builtinclass, uuid(a232e826-07bd-11e2-8a8f-236186ff1a14)] interface nsIPowerManagerService : nsISupports { + /** + * This API will power off the machine. + */ void powerOff(); + + /** + * This API will completely shut down and boot the machine. + */ void reboot(); + + /** + * This API will restart the Gecko processes without powering off the machine. + */ + void restart(); + void addWakeLockListener(in nsIDOMMozWakeLockListener aListener); void removeWakeLockListener(in nsIDOMMozWakeLockListener aListener); DOMString getWakeLockState(in DOMString aTopic); /** * Return a wake lock object of aTopic associated with aWindow. * A wake lock without associated window, e.g. used in chrome, is * always considered invisible.
--- a/hal/Hal.cpp +++ b/hal/Hal.cpp @@ -574,16 +574,23 @@ void Reboot() void PowerOff() { AssertMainProcess(); AssertMainThread(); PROXY_IF_SANDBOXED(PowerOff()); } +void StartForceQuitWatchdog(ShutdownMode aMode, int32_t aTimeoutSecs) +{ + AssertMainProcess(); + AssertMainThread(); + PROXY_IF_SANDBOXED(StartForceQuitWatchdog(aMode, aTimeoutSecs)); +} + void RegisterWakeLockObserver(WakeLockObserver* aObserver) { AssertMainThread(); sWakeLockObservers.AddObserver(aObserver); } void
--- a/hal/Hal.h +++ b/hal/Hal.h @@ -503,16 +503,25 @@ uint32_t GetFMRadioSignalStrength(); */ void CancelFMRadioSeek(); /** * Get FM radio band settings by country. */ hal::FMRadioSettings GetFMBandSettings(hal::FMRadioCountry aCountry); +/** + * Start a watchdog to compulsively shutdown the system if it hangs. + * @param aMode Specify how to shutdown the system. + * @param aTimeoutSecs Specify the delayed seconds to shutdown the system. + * + * This API is currently only allowed to be used from the main process. + */ +void StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs); + } // namespace MOZ_HAL_NAMESPACE } // namespace mozilla #ifdef MOZ_DEFINED_HAL_NAMESPACE # undef MOZ_DEFINED_HAL_NAMESPACE # undef MOZ_HAL_NAMESPACE #endif
--- a/hal/HalTypes.h +++ b/hal/HalTypes.h @@ -12,36 +12,44 @@ namespace mozilla { namespace hal { /** * These are defined by libhardware, specifically, hardware/libhardware/include/hardware/lights.h * in the gonk subsystem. * If these change and are exposed to JS, make sure nsIHal.idl is updated as well. */ enum LightType { - eHalLightID_Backlight = 0, - eHalLightID_Keyboard = 1, - eHalLightID_Buttons = 2, - eHalLightID_Battery = 3, - eHalLightID_Notifications = 4, - eHalLightID_Attention = 5, - eHalLightID_Bluetooth = 6, - eHalLightID_Wifi = 7, - eHalLightID_Count = 8 // This should stay at the end + eHalLightID_Backlight = 0, + eHalLightID_Keyboard = 1, + eHalLightID_Buttons = 2, + eHalLightID_Battery = 3, + eHalLightID_Notifications = 4, + eHalLightID_Attention = 5, + eHalLightID_Bluetooth = 6, + eHalLightID_Wifi = 7, + eHalLightID_Count = 8 // This should stay at the end }; enum LightMode { - eHalLightMode_User = 0, // brightness is managed by user setting - eHalLightMode_Sensor = 1, // brightness is managed by a light sensor - eHalLightMode_Count + eHalLightMode_User = 0, // brightness is managed by user setting + eHalLightMode_Sensor = 1, // brightness is managed by a light sensor + eHalLightMode_Count }; enum FlashMode { - eHalLightFlash_None = 0, - eHalLightFlash_Timed = 1, // timed flashing. Use flashOnMS and flashOffMS for timing - eHalLightFlash_Hardware = 2, // hardware assisted flashing - eHalLightFlash_Count + eHalLightFlash_None = 0, + eHalLightFlash_Timed = 1, // timed flashing. Use flashOnMS and flashOffMS for timing + eHalLightFlash_Hardware = 2, // hardware assisted flashing + eHalLightFlash_Count +}; + +enum ShutdownMode { + eHalShutdownMode_Unknown = -1, + eHalShutdownMode_PowerOff = 0, + eHalShutdownMode_Reboot = 1, + eHalShutdownMode_Restart = 2, + eHalShutdownMode_Count = 3 }; class SwitchEvent; enum SwitchDevice { SWITCH_DEVICE_UNKNOWN = -1, SWITCH_HEADPHONES, SWITCH_USB, @@ -191,16 +199,26 @@ struct ParamTraits<mozilla::hal::LightMo template <> struct ParamTraits<mozilla::hal::FlashMode> : public EnumSerializer<mozilla::hal::FlashMode, mozilla::hal::eHalLightFlash_None, mozilla::hal::eHalLightFlash_Count> {}; /** + * Serializer for ShutdownMode. + */ +template <> +struct ParamTraits<mozilla::hal::ShutdownMode> + : public EnumSerializer<mozilla::hal::ShutdownMode, + mozilla::hal::eHalShutdownMode_Unknown, + mozilla::hal::eHalShutdownMode_Count> +{}; + +/** * WakeLockControl serializer. */ template <> struct ParamTraits<mozilla::hal::WakeLockControl> : public EnumSerializer<mozilla::hal::WakeLockControl, mozilla::hal::WAKE_LOCK_REMOVE_ONE, mozilla::hal::NUM_WAKE_LOCK> {};
--- a/hal/fallback/FallbackPower.cpp +++ b/hal/fallback/FallbackPower.cpp @@ -1,19 +1,25 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set sw=2 ts=8 et ft=cpp : */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "Hal.h" + namespace mozilla { namespace hal_impl { void Reboot() {} void PowerOff() {} +void +StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs) +{} + } // hal_impl } // namespace mozilla
--- a/hal/linux/LinuxPower.cpp +++ b/hal/linux/LinuxPower.cpp @@ -18,10 +18,92 @@ Reboot() } void PowerOff() { reboot(RB_POWER_OFF); } +// Structure to specify how watchdog pthread is going to work. +typedef struct watchdogParam +{ + hal::ShutdownMode mode; // Specify how to shutdown the system. + int32_t timeoutSecs; // Specify the delayed seconds to shutdown the system. + + watchdogParam(hal::ShutdownMode aMode, int32_t aTimeoutSecs) + : mode(aMode), timeoutSecs(aTimeoutSecs) {} +} watchdogParam_t; + +// Function to complusively shut down the system with a given mode. +static void +QuitHard(hal::ShutdownMode aMode) +{ + switch (aMode) + { + case hal::eHalShutdownMode_PowerOff: + PowerOff(); + break; + case hal::eHalShutdownMode_Reboot: + Reboot(); + break; + case hal::eHalShutdownMode_Restart: + // Don't let signal handlers affect forced shutdown. + kill(0, SIGKILL); + // If we can't SIGKILL our process group, something is badly + // wrong. Trying to deliver a catch-able signal to ourselves can + // invoke signal handlers and might cause problems. So try + // _exit() and hope we go away. + _exit(1); + break; + default: + MOZ_NOT_REACHED(); + break; + } + MOZ_NOT_REACHED(); +} + +// Function to complusively shut down the system with a given mode when timeout. +static void* +ForceQuitWatchdog(void* aParamPtr) +{ + watchdogParam_t* paramPtr = reinterpret_cast<watchdogParam_t*>(aParamPtr); + if (paramPtr->timeoutSecs > 0 && paramPtr->timeoutSecs <= 30) { + // If we shut down normally before the timeout, this thread will + // be harmlessly reaped by the OS. + sleep(paramPtr->timeoutSecs); + } + hal::ShutdownMode mode = paramPtr->mode; + delete paramPtr; + QuitHard(mode); + return nullptr; +} + +void +StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs) +{ + // Force-quits are intepreted a little more ferociously on Gonk, + // because while Gecko is in the process of shutting down, the user + // can't call 911, for example. And if we hang on shutdown, bad + // things happen. So, make sure that doesn't happen. + if (aTimeoutSecs <= 0) { + return; + } + + // Use a raw pthread here to insulate ourselves from bugs in other + // Gecko code that we're trying to protect! + // + // Note that we let the watchdog in charge of releasing |paramPtr| + // if the pthread is successfully created. + watchdogParam_t* paramPtr = new watchdogParam_t(aMode, aTimeoutSecs); + pthread_t watchdog; + if (pthread_create(&watchdog, nullptr, + ForceQuitWatchdog, + reinterpret_cast<void*>(paramPtr))) { + // Better safe than sorry. + delete paramPtr; + QuitHard(aMode); + } + // The watchdog thread is off and running now. +} + } // hal_impl } // mozilla
--- a/hal/sandbox/SandboxHal.cpp +++ b/hal/sandbox/SandboxHal.cpp @@ -223,16 +223,22 @@ Reboot() void PowerOff() { NS_RUNTIMEABORT("PowerOff() can't be called from sandboxed contexts."); } void +StartForceQuitWatchdog(ShutdownMode aMode, int32_t aTimeoutSecs) +{ + NS_RUNTIMEABORT("StartForceQuitWatchdog() can't be called from sandboxed contexts."); +} + +void EnableSensorNotifications(SensorType aSensor) { Hal()->SendEnableSensorNotifications(aSensor); } void DisableSensorNotifications(SensorType aSensor) { Hal()->SendDisableSensorNotifications(aSensor); }
--- a/toolkit/components/startup/nsAppStartup.cpp +++ b/toolkit/components/startup/nsAppStartup.cpp @@ -368,60 +368,16 @@ RecordShutdownEndTimeStamp() { PR_Delete(tmpName.get()); return; } PR_Delete(name.get()); PR_Rename(tmpName.get(), name.get()); } } -#ifdef MOZ_WIDGET_GONK -static void -QuitHard() -{ - // Don't let signal handlers affect forced shutdown. - kill(0, SIGKILL); - // If we can't SIGKILL our process group, something is badly - // wrong. Trying to deliver a catch-able signal to ourselves can - // invoke signal handlers and might cause problems. So try - // _exit() and hope we go away. - _exit(1); -} - -static void* -ForceQuitWatchdog(void* aTimeoutSecs) -{ - int32_t timeoutSecs = int32_t(intptr_t(aTimeoutSecs)); - if (timeoutSecs > 0 && timeoutSecs <= 30) { - // If we shut down normally before the timeout, this thread will - // be harmlessly reaped by the OS. - sleep(timeoutSecs); - } - - QuitHard(); - MOZ_NOT_REACHED(); - return nullptr; -} - -static void -StartForceQuitWatchdog(int32_t aTimeoutSecs) -{ - // Use a raw pthread here to insulate ourselves from bugs in other - // Gecko code that we're trying to protect! - pthread_t watchdog; - if (pthread_create(&watchdog, nullptr, - ForceQuitWatchdog, - reinterpret_cast<void*>(intptr_t(aTimeoutSecs)))) { - // Better safe than sorry. - QuitHard(); - } - // The watchdog thread is off and running now. -} -#endif - NS_IMETHODIMP nsAppStartup::Quit(uint32_t aMode) { uint32_t ferocity = (aMode & 0xF); // Quit the application. We will asynchronously call the appshell's // Exit() method via nsAppExitEvent to allow one last pass // through any events in the queue. This guarantees a tidy cleanup. @@ -457,35 +413,16 @@ nsAppStartup::Quit(uint32_t aMode) if (!hiddenWindow || usefulHiddenWindow) return NS_OK; ferocity = eAttemptQuit; } #endif } -#ifdef MOZ_WIDGET_GONK - // Force-quits are intepreted a little more ferociously on Gonk, - // because while Gecko is in the process of shutting down, the user - // can't call 911, for example. And if we hang on shutdown, bad - // things happen. So, make sure that doesn't happen. - // - // We rely on a service manager to restart us, so we can get away - // with these kind of shenanigans. - // - // NB: default to *enabling* the watchdog even when the pref is - // absent, in case the profile might be damaged and we need to - // restart to repair it. - int32_t timeoutSecs = - Preferences::GetInt("shutdown.watchdog.timeoutSecs", 5); - if (ferocity == eForceQuit && timeoutSecs > 0) { - StartForceQuitWatchdog(timeoutSecs); - } -#endif - nsCOMPtr<nsIObserverService> obsService; if (ferocity == eAttemptQuit || ferocity == eForceQuit) { nsCOMPtr<nsISimpleEnumerator> windowEnumerator; nsCOMPtr<nsIWindowMediator> mediator (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); if (mediator) { mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator)); if (windowEnumerator) {