diff options
Diffstat (limited to 'hal/linux/LinuxPower.cpp')
-rw-r--r-- | hal/linux/LinuxPower.cpp | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/hal/linux/LinuxPower.cpp b/hal/linux/LinuxPower.cpp new file mode 100644 index 0000000000..70ab4a3f6e --- /dev/null +++ b/hal/linux/LinuxPower.cpp @@ -0,0 +1,167 @@ +/* -*- 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 "Hal.h" +#include "HalLog.h" + +#include <unistd.h> +#include <sys/reboot.h> +#include "nsIObserverService.h" +#include "mozilla/Services.h" +#include "MainThreadUtils.h" + +#if defined(MOZ_WIDGET_GONK) +#include "cutils/android_reboot.h" +#include "cutils/properties.h" +#endif + +namespace mozilla { +namespace hal_impl { + +#if (defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19) +static void +PowerCtl(const char* aValue, int aCmd) +{ + // this invokes init's powerctl builtin via /init.rc + property_set("sys.powerctl", aValue); + // device should reboot in few moments, but if it doesn't - call + // android_reboot() to make sure that init isn't stuck somewhere + sleep(10); + HAL_LOG("Powerctl call takes too long, forcing %s.", aValue); + android_reboot(aCmd, 0, nullptr); +} +#endif + +void +Reboot() +{ + if (NS_IsMainThread()) { + nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService(); + if (obsServ) { + obsServ->NotifyObservers(nullptr, "system-reboot", nullptr); + } + } + +#if !defined(MOZ_WIDGET_GONK) + sync(); + reboot(RB_AUTOBOOT); +#elif (ANDROID_VERSION < 19) + android_reboot(ANDROID_RB_RESTART, 0, nullptr); +#else + PowerCtl("reboot", ANDROID_RB_RESTART); +#endif +} + +void +PowerOff() +{ + if (NS_IsMainThread()) { + nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService(); + if (obsServ) { + obsServ->NotifyObservers(nullptr, "system-power-off", nullptr); + } + } + +#if !defined(MOZ_WIDGET_GONK) + sync(); + reboot(RB_POWER_OFF); +#elif (ANDROID_VERSION < 19) + android_reboot(ANDROID_RB_POWEROFF, 0, nullptr); +#else + PowerCtl("shutdown", ANDROID_RB_POWEROFF); +#endif +} + +// 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_CRASH(); + } +} + +// 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. + TimeStamp deadline = + (TimeStamp::Now() + TimeDuration::FromSeconds(paramPtr->timeoutSecs)); + while (true) { + TimeDuration remaining = (deadline - TimeStamp::Now()); + int sleepSeconds = int(remaining.ToSeconds()); + if (sleepSeconds <= 0) { + break; + } + sleep(sleepSeconds); + } + } + 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 |