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 115256 6bcb5f9359d8cae3ee2f2d4ee452b13e3f093b35
parent 115255 c2d3a2496dc95f4c88dd7f2a393b51d30dc0dd19
child 115257 1d4bafc6c4817a3e76d65219b6752fa02c8df247
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs793970
milestone18.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
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) {