Bug 793970 - Reuse nsAppStartup's watchdog to compulsively power-off/reboot/quit Gecko if profile synchronizing hangs. r=cjones
authorGene Lian <clian@mozilla.com>
Tue, 02 Oct 2012 15:26:32 +0800
changeset 112554 6bcb5f9359d8cae3ee2f2d4ee452b13e3f093b35
parent 112553 c2d3a2496dc95f4c88dd7f2a393b51d30dc0dd19
child 112555 1d4bafc6c4817a3e76d65219b6752fa02c8df247
push id2248
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 19:23:44 +0000
treeherdermozilla-aurora@118a3b748323 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs793970
milestone18.0a1
Bug 793970 - Reuse nsAppStartup's watchdog to compulsively power-off/reboot/quit Gecko if profile synchronizing hangs. r=cjones
b2g/components/UpdatePrompt.js
dom/power/PowerManagerService.cpp
dom/power/PowerManagerService.h
dom/power/nsIPowerManagerService.idl
hal/Hal.cpp
hal/Hal.h
hal/HalTypes.h
hal/fallback/FallbackPower.cpp
hal/linux/LinuxPower.cpp
hal/sandbox/SandboxHal.cpp
toolkit/components/startup/nsAppStartup.cpp
--- 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) {