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
PowerCtl(const char * aValue,int aCmd)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
Reboot()38 Reboot()
39 {
40 if (NS_IsMainThread()) {
41 nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
42 if (obsServ) {
43 obsServ->NotifyObservers(nullptr, "system-reboot", nullptr);
44 }
45 }
46
47 #if !defined(MOZ_WIDGET_GONK)
48 sync();
49 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 }
56
57 void
PowerOff()58 PowerOff()
59 {
60 if (NS_IsMainThread()) {
61 nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
62 if (obsServ) {
63 obsServ->NotifyObservers(nullptr, "system-power-off", nullptr);
64 }
65 }
66
67 #if !defined(MOZ_WIDGET_GONK)
68 sync();
69 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 }
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
watchdogParammozilla::hal_impl::watchdogParam83 watchdogParam(hal::ShutdownMode aMode, int32_t aTimeoutSecs)
84 : mode(aMode), timeoutSecs(aTimeoutSecs) {}
85 } watchdogParam_t;
86
87 // Function to complusively shut down the system with a given mode.
88 static void
QuitHard(hal::ShutdownMode aMode)89 QuitHard(hal::ShutdownMode aMode)
90 {
91 switch (aMode)
92 {
93 case hal::eHalShutdownMode_PowerOff:
94 PowerOff();
95 break;
96 case hal::eHalShutdownMode_Reboot:
97 Reboot();
98 break;
99 case hal::eHalShutdownMode_Restart:
100 // Don't let signal handlers affect forced shutdown.
101 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 _exit(1);
107 break;
108 default:
109 MOZ_CRASH();
110 }
111 }
112
113 // Function to complusively shut down the system with a given mode when timeout.
114 static void*
ForceQuitWatchdog(void * aParamPtr)115 ForceQuitWatchdog(void* aParamPtr)
116 {
117 watchdogParam_t* paramPtr = reinterpret_cast<watchdogParam_t*>(aParamPtr);
118 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 (TimeStamp::Now() + TimeDuration::FromSeconds(paramPtr->timeoutSecs));
123 while (true) {
124 TimeDuration remaining = (deadline - TimeStamp::Now());
125 int sleepSeconds = int(remaining.ToSeconds());
126 if (sleepSeconds <= 0) {
127 break;
128 }
129 sleep(sleepSeconds);
130 }
131 }
132 hal::ShutdownMode mode = paramPtr->mode;
133 delete paramPtr;
134 QuitHard(mode);
135 return nullptr;
136 }
137
138 void
StartForceQuitWatchdog(hal::ShutdownMode aMode,int32_t aTimeoutSecs)139 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 if (aTimeoutSecs <= 0) {
146 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 watchdogParam_t* paramPtr = new watchdogParam_t(aMode, aTimeoutSecs);
155 pthread_t watchdog;
156 if (pthread_create(&watchdog, nullptr,
157 ForceQuitWatchdog,
158 reinterpret_cast<void*>(paramPtr))) {
159 // Better safe than sorry.
160 delete paramPtr;
161 QuitHard(aMode);
162 }
163 // The watchdog thread is off and running now.
164 }
165
166 } // hal_impl
167 } // mozilla
168