зеркало из https://github.com/mozilla/gecko-dev.git
168 строки
4.7 KiB
C++
168 строки
4.7 KiB
C++
/* -*- 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
|