Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/dom/ContentParent.h"
8 : #include "mozilla/Hal.h"
9 : #include "mozilla/HalWakeLock.h"
10 : #include "mozilla/ClearOnShutdown.h"
11 : #include "mozilla/Preferences.h"
12 : #include "mozilla/Services.h"
13 : #include "jsprf.h"
14 : #include "nsIDOMWakeLockListener.h"
15 : #include "nsIDOMWindow.h"
16 : #include "nsIObserverService.h"
17 : #include "PowerManagerService.h"
18 : #include "WakeLock.h"
19 :
20 : // For _exit().
21 : #ifdef XP_WIN
22 : #include <process.h>
23 : #else
24 : #include <unistd.h>
25 : #endif
26 :
27 : #ifdef ANDROID
28 : #include <android/log.h>
29 : extern "C" char* PrintJSStack();
30 : static void LogFunctionAndJSStack(const char* funcname) {
31 : char *jsstack = PrintJSStack();
32 : __android_log_print(ANDROID_LOG_INFO, "PowerManagerService", \
33 : "Call to %s. The JS stack is:\n%s\n",
34 : funcname,
35 : jsstack ? jsstack : "<no JS stack>");
36 : JS_smprintf_free(jsstack);
37 : }
38 : // bug 839452
39 : #define LOG_FUNCTION_AND_JS_STACK() \
40 : LogFunctionAndJSStack(__PRETTY_FUNCTION__);
41 : #else
42 : #define LOG_FUNCTION_AND_JS_STACK()
43 : #endif
44 :
45 : namespace mozilla {
46 : namespace dom {
47 : namespace power {
48 :
49 : using namespace hal;
50 :
51 16 : NS_IMPL_ISUPPORTS(PowerManagerService, nsIPowerManagerService)
52 :
53 3 : /* static */ StaticRefPtr<PowerManagerService> PowerManagerService::sSingleton;
54 :
55 : /* static */ already_AddRefed<PowerManagerService>
56 1 : PowerManagerService::GetInstance()
57 : {
58 1 : if (!sSingleton) {
59 1 : sSingleton = new PowerManagerService();
60 1 : sSingleton->Init();
61 1 : ClearOnShutdown(&sSingleton);
62 : }
63 :
64 2 : RefPtr<PowerManagerService> service = sSingleton.get();
65 2 : return service.forget();
66 : }
67 :
68 : void
69 1 : PowerManagerService::Init()
70 : {
71 1 : RegisterWakeLockObserver(this);
72 :
73 : // NB: default to *enabling* the watchdog even when the pref is
74 : // absent, in case the profile might be damaged and we need to
75 : // restart to repair it.
76 1 : mWatchdogTimeoutSecs =
77 1 : Preferences::GetInt("shutdown.watchdog.timeoutSecs", 10);
78 1 : }
79 :
80 0 : PowerManagerService::~PowerManagerService()
81 : {
82 0 : UnregisterWakeLockObserver(this);
83 0 : }
84 :
85 : void
86 0 : PowerManagerService::ComputeWakeLockState(const WakeLockInformation& aWakeLockInfo,
87 : nsAString &aState)
88 : {
89 0 : WakeLockState state = hal::ComputeWakeLockState(aWakeLockInfo.numLocks(),
90 0 : aWakeLockInfo.numHidden());
91 0 : switch (state) {
92 : case WAKE_LOCK_STATE_UNLOCKED:
93 0 : aState.AssignLiteral("unlocked");
94 0 : break;
95 : case WAKE_LOCK_STATE_HIDDEN:
96 0 : aState.AssignLiteral("locked-background");
97 0 : break;
98 : case WAKE_LOCK_STATE_VISIBLE:
99 0 : aState.AssignLiteral("locked-foreground");
100 0 : break;
101 : }
102 0 : }
103 :
104 : void
105 0 : PowerManagerService::Notify(const WakeLockInformation& aWakeLockInfo)
106 : {
107 0 : nsAutoString state;
108 0 : ComputeWakeLockState(aWakeLockInfo, state);
109 :
110 : /**
111 : * Copy the listeners list before we walk through the callbacks
112 : * because the callbacks may install new listeners. We expect no
113 : * more than one listener per window, so it shouldn't be too long.
114 : */
115 0 : AutoTArray<nsCOMPtr<nsIDOMMozWakeLockListener>, 2> listeners(mWakeLockListeners);
116 :
117 0 : for (uint32_t i = 0; i < listeners.Length(); ++i) {
118 0 : listeners[i]->Callback(aWakeLockInfo.topic(), state);
119 : }
120 0 : }
121 :
122 : void
123 0 : PowerManagerService::SyncProfile()
124 : {
125 0 : nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
126 0 : if (obsServ) {
127 0 : const char16_t* context = u"shutdown-persist";
128 0 : obsServ->NotifyObservers(nullptr, "profile-change-net-teardown", context);
129 0 : obsServ->NotifyObservers(nullptr, "profile-change-teardown", context);
130 0 : obsServ->NotifyObservers(nullptr, "profile-before-change", context);
131 0 : obsServ->NotifyObservers(nullptr, "profile-before-change-qm", context);
132 0 : obsServ->NotifyObservers(nullptr, "profile-before-change-telemetry", context);
133 : }
134 0 : }
135 :
136 : NS_IMETHODIMP
137 0 : PowerManagerService::Reboot()
138 : {
139 : LOG_FUNCTION_AND_JS_STACK() // bug 839452
140 :
141 0 : StartForceQuitWatchdog(eHalShutdownMode_Reboot, mWatchdogTimeoutSecs);
142 : // To synchronize any unsaved user data before rebooting.
143 0 : SyncProfile();
144 0 : hal::Reboot();
145 0 : MOZ_CRASH("hal::Reboot() shouldn't return");
146 : }
147 :
148 : NS_IMETHODIMP
149 0 : PowerManagerService::PowerOff()
150 : {
151 : LOG_FUNCTION_AND_JS_STACK() // bug 839452
152 :
153 0 : StartForceQuitWatchdog(eHalShutdownMode_PowerOff, mWatchdogTimeoutSecs);
154 : // To synchronize any unsaved user data before powering off.
155 0 : SyncProfile();
156 0 : hal::PowerOff();
157 0 : MOZ_CRASH("hal::PowerOff() shouldn't return");
158 : }
159 :
160 : NS_IMETHODIMP
161 0 : PowerManagerService::Restart()
162 : {
163 : LOG_FUNCTION_AND_JS_STACK() // bug 839452
164 :
165 : // FIXME/bug 796826 this implementation is currently gonk-specific,
166 : // because it relies on the Gonk to initialize the Gecko processes to
167 : // restart B2G. It's better to do it here to have a real "restart".
168 0 : StartForceQuitWatchdog(eHalShutdownMode_Restart, mWatchdogTimeoutSecs);
169 : // Ensure all content processes are dead before we continue
170 : // restarting. This code is used to restart to apply updates, and
171 : // if we don't join all the subprocesses, race conditions can cause
172 : // them to see an inconsistent view of the application directory.
173 0 : ContentParent::JoinAllSubprocesses();
174 :
175 : // To synchronize any unsaved user data before restarting.
176 0 : SyncProfile();
177 : #ifdef XP_UNIX
178 0 : sync();
179 : #endif
180 0 : _exit(0);
181 : MOZ_CRASH("_exit() shouldn't return");
182 : }
183 :
184 : NS_IMETHODIMP
185 1 : PowerManagerService::AddWakeLockListener(nsIDOMMozWakeLockListener *aListener)
186 : {
187 1 : if (mWakeLockListeners.Contains(aListener))
188 0 : return NS_OK;
189 :
190 1 : mWakeLockListeners.AppendElement(aListener);
191 1 : return NS_OK;
192 : }
193 :
194 : NS_IMETHODIMP
195 0 : PowerManagerService::RemoveWakeLockListener(nsIDOMMozWakeLockListener *aListener)
196 : {
197 0 : mWakeLockListeners.RemoveElement(aListener);
198 0 : return NS_OK;
199 : }
200 :
201 : NS_IMETHODIMP
202 0 : PowerManagerService::GetWakeLockState(const nsAString &aTopic, nsAString &aState)
203 : {
204 0 : WakeLockInformation info;
205 0 : GetWakeLockInfo(aTopic, &info);
206 :
207 0 : ComputeWakeLockState(info, aState);
208 :
209 0 : return NS_OK;
210 : }
211 :
212 : already_AddRefed<WakeLock>
213 0 : PowerManagerService::NewWakeLock(const nsAString& aTopic,
214 : nsPIDOMWindowInner* aWindow,
215 : mozilla::ErrorResult& aRv)
216 : {
217 0 : RefPtr<WakeLock> wakelock = new WakeLock();
218 0 : aRv = wakelock->Init(aTopic, aWindow);
219 0 : if (aRv.Failed()) {
220 0 : return nullptr;
221 : }
222 :
223 0 : return wakelock.forget();
224 : }
225 :
226 : NS_IMETHODIMP
227 0 : PowerManagerService::NewWakeLock(const nsAString &aTopic,
228 : mozIDOMWindow *aWindow,
229 : nsISupports **aWakeLock)
230 : {
231 0 : mozilla::ErrorResult rv;
232 : RefPtr<WakeLock> wakelock =
233 0 : NewWakeLock(aTopic, nsPIDOMWindowInner::From(aWindow), rv);
234 0 : if (rv.Failed()) {
235 0 : return rv.StealNSResult();
236 : }
237 :
238 0 : nsCOMPtr<nsIDOMEventListener> eventListener = wakelock.get();
239 0 : eventListener.forget(aWakeLock);
240 0 : return NS_OK;
241 : }
242 :
243 : already_AddRefed<WakeLock>
244 0 : PowerManagerService::NewWakeLockOnBehalfOfProcess(const nsAString& aTopic,
245 : ContentParent* aContentParent)
246 : {
247 0 : RefPtr<WakeLock> wakelock = new WakeLock();
248 0 : nsresult rv = wakelock->Init(aTopic, aContentParent);
249 0 : NS_ENSURE_SUCCESS(rv, nullptr);
250 0 : return wakelock.forget();
251 : }
252 :
253 : } // namespace power
254 : } // namespace dom
255 : } // namespace mozilla
|