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