Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "Hal.h"
7 : #include "HalLog.h"
8 :
9 : #include <unistd.h>
10 : #include <sys/reboot.h>
11 : #include "nsIObserverService.h"
12 : #include "mozilla/Services.h"
13 : #include "MainThreadUtils.h"
14 :
15 : #if defined(MOZ_WIDGET_GONK)
16 : #include "cutils/android_reboot.h"
17 : #include "cutils/properties.h"
18 : #endif
19 :
20 : namespace mozilla {
21 : namespace hal_impl {
22 :
23 : #if (defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19)
24 : static void
25 : PowerCtl(const char* aValue, int aCmd)
26 : {
27 : // this invokes init's powerctl builtin via /init.rc
28 : property_set("sys.powerctl", aValue);
29 : // device should reboot in few moments, but if it doesn't - call
30 : // android_reboot() to make sure that init isn't stuck somewhere
31 : sleep(10);
32 : HAL_LOG("Powerctl call takes too long, forcing %s.", aValue);
33 : android_reboot(aCmd, 0, nullptr);
34 : }
35 : #endif
36 :
37 : void
38 0 : Reboot()
39 : {
40 0 : if (NS_IsMainThread()) {
41 0 : nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
42 0 : if (obsServ) {
43 0 : obsServ->NotifyObservers(nullptr, "system-reboot", nullptr);
44 : }
45 : }
46 :
47 : #if !defined(MOZ_WIDGET_GONK)
48 0 : sync();
49 0 : reboot(RB_AUTOBOOT);
50 : #elif (ANDROID_VERSION < 19)
51 : android_reboot(ANDROID_RB_RESTART, 0, nullptr);
52 : #else
53 : PowerCtl("reboot", ANDROID_RB_RESTART);
54 : #endif
55 0 : }
56 :
57 : void
58 0 : PowerOff()
59 : {
60 0 : if (NS_IsMainThread()) {
61 0 : nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
62 0 : if (obsServ) {
63 0 : obsServ->NotifyObservers(nullptr, "system-power-off", nullptr);
64 : }
65 : }
66 :
67 : #if !defined(MOZ_WIDGET_GONK)
68 0 : sync();
69 0 : reboot(RB_POWER_OFF);
70 : #elif (ANDROID_VERSION < 19)
71 : android_reboot(ANDROID_RB_POWEROFF, 0, nullptr);
72 : #else
73 : PowerCtl("shutdown", ANDROID_RB_POWEROFF);
74 : #endif
75 0 : }
76 :
77 : // Structure to specify how watchdog pthread is going to work.
78 : typedef struct watchdogParam
79 : {
80 : hal::ShutdownMode mode; // Specify how to shutdown the system.
81 : int32_t timeoutSecs; // Specify the delayed seconds to shutdown the system.
82 :
83 0 : watchdogParam(hal::ShutdownMode aMode, int32_t aTimeoutSecs)
84 0 : : mode(aMode), timeoutSecs(aTimeoutSecs) {}
85 : } watchdogParam_t;
86 :
87 : // Function to complusively shut down the system with a given mode.
88 : static void
89 0 : QuitHard(hal::ShutdownMode aMode)
90 : {
91 0 : switch (aMode)
92 : {
93 : case hal::eHalShutdownMode_PowerOff:
94 0 : PowerOff();
95 0 : break;
96 : case hal::eHalShutdownMode_Reboot:
97 0 : Reboot();
98 0 : break;
99 : case hal::eHalShutdownMode_Restart:
100 : // Don't let signal handlers affect forced shutdown.
101 0 : kill(0, SIGKILL);
102 : // If we can't SIGKILL our process group, something is badly
103 : // wrong. Trying to deliver a catch-able signal to ourselves can
104 : // invoke signal handlers and might cause problems. So try
105 : // _exit() and hope we go away.
106 0 : _exit(1);
107 : break;
108 : default:
109 0 : MOZ_CRASH();
110 : }
111 0 : }
112 :
113 : // Function to complusively shut down the system with a given mode when timeout.
114 : static void*
115 0 : ForceQuitWatchdog(void* aParamPtr)
116 : {
117 0 : watchdogParam_t* paramPtr = reinterpret_cast<watchdogParam_t*>(aParamPtr);
118 0 : if (paramPtr->timeoutSecs > 0 && paramPtr->timeoutSecs <= 30) {
119 : // If we shut down normally before the timeout, this thread will
120 : // be harmlessly reaped by the OS.
121 : TimeStamp deadline =
122 0 : (TimeStamp::Now() + TimeDuration::FromSeconds(paramPtr->timeoutSecs));
123 : while (true) {
124 0 : TimeDuration remaining = (deadline - TimeStamp::Now());
125 0 : int sleepSeconds = int(remaining.ToSeconds());
126 0 : if (sleepSeconds <= 0) {
127 0 : break;
128 : }
129 0 : sleep(sleepSeconds);
130 0 : }
131 : }
132 0 : hal::ShutdownMode mode = paramPtr->mode;
133 : delete paramPtr;
134 0 : QuitHard(mode);
135 0 : return nullptr;
136 : }
137 :
138 : void
139 0 : StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs)
140 : {
141 : // Force-quits are intepreted a little more ferociously on Gonk,
142 : // because while Gecko is in the process of shutting down, the user
143 : // can't call 911, for example. And if we hang on shutdown, bad
144 : // things happen. So, make sure that doesn't happen.
145 0 : if (aTimeoutSecs <= 0) {
146 0 : return;
147 : }
148 :
149 : // Use a raw pthread here to insulate ourselves from bugs in other
150 : // Gecko code that we're trying to protect!
151 : //
152 : // Note that we let the watchdog in charge of releasing |paramPtr|
153 : // if the pthread is successfully created.
154 0 : watchdogParam_t* paramPtr = new watchdogParam_t(aMode, aTimeoutSecs);
155 : pthread_t watchdog;
156 0 : if (pthread_create(&watchdog, nullptr,
157 : ForceQuitWatchdog,
158 : reinterpret_cast<void*>(paramPtr))) {
159 : // Better safe than sorry.
160 : delete paramPtr;
161 0 : QuitHard(aMode);
162 : }
163 : // The watchdog thread is off and running now.
164 : }
165 :
166 : } // hal_impl
167 : } // mozilla
|