1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/power/PowerManagerService.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,250 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/dom/ContentParent.h" 1.10 +#include "mozilla/Hal.h" 1.11 +#include "mozilla/HalWakeLock.h" 1.12 +#include "mozilla/ClearOnShutdown.h" 1.13 +#include "mozilla/Preferences.h" 1.14 +#include "mozilla/Services.h" 1.15 +#include "nsIDOMWakeLockListener.h" 1.16 +#include "nsIDOMWindow.h" 1.17 +#include "nsIObserverService.h" 1.18 +#include "PowerManagerService.h" 1.19 +#include "WakeLock.h" 1.20 + 1.21 +// For _exit(). 1.22 +#ifdef XP_WIN 1.23 +#include <process.h> 1.24 +#else 1.25 +#include <unistd.h> 1.26 +#endif 1.27 + 1.28 +#ifdef ANDROID 1.29 +#include <android/log.h> 1.30 +extern "C" char* PrintJSStack(); 1.31 +static void LogFunctionAndJSStack(const char* funcname) { 1.32 + char *jsstack = PrintJSStack(); 1.33 + __android_log_print(ANDROID_LOG_INFO, "PowerManagerService", \ 1.34 + "Call to %s. The JS stack is:\n%s\n", 1.35 + funcname, 1.36 + jsstack ? jsstack : "<no JS stack>"); 1.37 +} 1.38 +// bug 839452 1.39 +#define LOG_FUNCTION_AND_JS_STACK() \ 1.40 + LogFunctionAndJSStack(__PRETTY_FUNCTION__); 1.41 +#else 1.42 +#define LOG_FUNCTION_AND_JS_STACK() 1.43 +#endif 1.44 + 1.45 +namespace mozilla { 1.46 +namespace dom { 1.47 +namespace power { 1.48 + 1.49 +using namespace hal; 1.50 + 1.51 +NS_IMPL_ISUPPORTS(PowerManagerService, nsIPowerManagerService) 1.52 + 1.53 +/* static */ StaticRefPtr<PowerManagerService> PowerManagerService::sSingleton; 1.54 + 1.55 +/* static */ already_AddRefed<PowerManagerService> 1.56 +PowerManagerService::GetInstance() 1.57 +{ 1.58 + if (!sSingleton) { 1.59 + sSingleton = new PowerManagerService(); 1.60 + sSingleton->Init(); 1.61 + ClearOnShutdown(&sSingleton); 1.62 + } 1.63 + 1.64 + nsRefPtr<PowerManagerService> service = sSingleton.get(); 1.65 + return service.forget(); 1.66 +} 1.67 + 1.68 +void 1.69 +PowerManagerService::Init() 1.70 +{ 1.71 + RegisterWakeLockObserver(this); 1.72 + 1.73 + // NB: default to *enabling* the watchdog even when the pref is 1.74 + // absent, in case the profile might be damaged and we need to 1.75 + // restart to repair it. 1.76 + mWatchdogTimeoutSecs = 1.77 + Preferences::GetInt("shutdown.watchdog.timeoutSecs", 5); 1.78 +} 1.79 + 1.80 +PowerManagerService::~PowerManagerService() 1.81 +{ 1.82 + UnregisterWakeLockObserver(this); 1.83 +} 1.84 + 1.85 +void 1.86 +PowerManagerService::ComputeWakeLockState(const WakeLockInformation& aWakeLockInfo, 1.87 + nsAString &aState) 1.88 +{ 1.89 + WakeLockState state = hal::ComputeWakeLockState(aWakeLockInfo.numLocks(), 1.90 + aWakeLockInfo.numHidden()); 1.91 + switch (state) { 1.92 + case WAKE_LOCK_STATE_UNLOCKED: 1.93 + aState.AssignLiteral("unlocked"); 1.94 + break; 1.95 + case WAKE_LOCK_STATE_HIDDEN: 1.96 + aState.AssignLiteral("locked-background"); 1.97 + break; 1.98 + case WAKE_LOCK_STATE_VISIBLE: 1.99 + aState.AssignLiteral("locked-foreground"); 1.100 + break; 1.101 + } 1.102 +} 1.103 + 1.104 +void 1.105 +PowerManagerService::Notify(const WakeLockInformation& aWakeLockInfo) 1.106 +{ 1.107 + nsAutoString state; 1.108 + ComputeWakeLockState(aWakeLockInfo, state); 1.109 + 1.110 + /** 1.111 + * Copy the listeners list before we walk through the callbacks 1.112 + * because the callbacks may install new listeners. We expect no 1.113 + * more than one listener per window, so it shouldn't be too long. 1.114 + */ 1.115 + nsAutoTArray<nsCOMPtr<nsIDOMMozWakeLockListener>, 2> listeners(mWakeLockListeners); 1.116 + 1.117 + for (uint32_t i = 0; i < listeners.Length(); ++i) { 1.118 + listeners[i]->Callback(aWakeLockInfo.topic(), state); 1.119 + } 1.120 +} 1.121 + 1.122 +void 1.123 +PowerManagerService::SyncProfile() 1.124 +{ 1.125 + nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService(); 1.126 + if (obsServ) { 1.127 + NS_NAMED_LITERAL_STRING(context, "shutdown-persist"); 1.128 + obsServ->NotifyObservers(nullptr, "profile-change-net-teardown", context.get()); 1.129 + obsServ->NotifyObservers(nullptr, "profile-change-teardown", context.get()); 1.130 + obsServ->NotifyObservers(nullptr, "profile-before-change", context.get()); 1.131 + obsServ->NotifyObservers(nullptr, "profile-before-change2", context.get()); 1.132 + } 1.133 +} 1.134 + 1.135 +NS_IMETHODIMP 1.136 +PowerManagerService::Reboot() 1.137 +{ 1.138 + LOG_FUNCTION_AND_JS_STACK() // bug 839452 1.139 + 1.140 + StartForceQuitWatchdog(eHalShutdownMode_Reboot, mWatchdogTimeoutSecs); 1.141 + // To synchronize any unsaved user data before rebooting. 1.142 + SyncProfile(); 1.143 + hal::Reboot(); 1.144 + MOZ_CRASH("hal::Reboot() shouldn't return"); 1.145 +} 1.146 + 1.147 +NS_IMETHODIMP 1.148 +PowerManagerService::PowerOff() 1.149 +{ 1.150 + LOG_FUNCTION_AND_JS_STACK() // bug 839452 1.151 + 1.152 + StartForceQuitWatchdog(eHalShutdownMode_PowerOff, mWatchdogTimeoutSecs); 1.153 + // To synchronize any unsaved user data before powering off. 1.154 + SyncProfile(); 1.155 + hal::PowerOff(); 1.156 + MOZ_CRASH("hal::PowerOff() shouldn't return"); 1.157 +} 1.158 + 1.159 +NS_IMETHODIMP 1.160 +PowerManagerService::Restart() 1.161 +{ 1.162 + LOG_FUNCTION_AND_JS_STACK() // bug 839452 1.163 + 1.164 + // FIXME/bug 796826 this implementation is currently gonk-specific, 1.165 + // because it relies on the Gonk to initialize the Gecko processes to 1.166 + // restart B2G. It's better to do it here to have a real "restart". 1.167 + StartForceQuitWatchdog(eHalShutdownMode_Restart, mWatchdogTimeoutSecs); 1.168 + // Ensure all content processes are dead before we continue 1.169 + // restarting. This code is used to restart to apply updates, and 1.170 + // if we don't join all the subprocesses, race conditions can cause 1.171 + // them to see an inconsistent view of the application directory. 1.172 + ContentParent::JoinAllSubprocesses(); 1.173 + 1.174 + // To synchronize any unsaved user data before restarting. 1.175 + SyncProfile(); 1.176 +#ifdef XP_UNIX 1.177 + sync(); 1.178 +#endif 1.179 + _exit(0); 1.180 + MOZ_CRASH("_exit() shouldn't return"); 1.181 +} 1.182 + 1.183 +NS_IMETHODIMP 1.184 +PowerManagerService::AddWakeLockListener(nsIDOMMozWakeLockListener *aListener) 1.185 +{ 1.186 + if (mWakeLockListeners.Contains(aListener)) 1.187 + return NS_OK; 1.188 + 1.189 + mWakeLockListeners.AppendElement(aListener); 1.190 + return NS_OK; 1.191 +} 1.192 + 1.193 +NS_IMETHODIMP 1.194 +PowerManagerService::RemoveWakeLockListener(nsIDOMMozWakeLockListener *aListener) 1.195 +{ 1.196 + mWakeLockListeners.RemoveElement(aListener); 1.197 + return NS_OK; 1.198 +} 1.199 + 1.200 +NS_IMETHODIMP 1.201 +PowerManagerService::GetWakeLockState(const nsAString &aTopic, nsAString &aState) 1.202 +{ 1.203 + WakeLockInformation info; 1.204 + GetWakeLockInfo(aTopic, &info); 1.205 + 1.206 + ComputeWakeLockState(info, aState); 1.207 + 1.208 + return NS_OK; 1.209 +} 1.210 + 1.211 +already_AddRefed<WakeLock> 1.212 +PowerManagerService::NewWakeLock(const nsAString& aTopic, 1.213 + nsIDOMWindow* aWindow, 1.214 + mozilla::ErrorResult& aRv) 1.215 +{ 1.216 + nsRefPtr<WakeLock> wakelock = new WakeLock(); 1.217 + aRv = wakelock->Init(aTopic, aWindow); 1.218 + if (aRv.Failed()) { 1.219 + return nullptr; 1.220 + } 1.221 + 1.222 + return wakelock.forget(); 1.223 +} 1.224 + 1.225 +NS_IMETHODIMP 1.226 +PowerManagerService::NewWakeLock(const nsAString &aTopic, 1.227 + nsIDOMWindow *aWindow, 1.228 + nsISupports **aWakeLock) 1.229 +{ 1.230 + mozilla::ErrorResult rv; 1.231 + nsRefPtr<WakeLock> wakelock = NewWakeLock(aTopic, aWindow, rv); 1.232 + if (rv.Failed()) { 1.233 + return rv.ErrorCode(); 1.234 + } 1.235 + 1.236 + nsCOMPtr<nsIDOMEventListener> eventListener = wakelock.get(); 1.237 + eventListener.forget(aWakeLock); 1.238 + return NS_OK; 1.239 +} 1.240 + 1.241 +already_AddRefed<WakeLock> 1.242 +PowerManagerService::NewWakeLockOnBehalfOfProcess(const nsAString& aTopic, 1.243 + ContentParent* aContentParent) 1.244 +{ 1.245 + nsRefPtr<WakeLock> wakelock = new WakeLock(); 1.246 + nsresult rv = wakelock->Init(aTopic, aContentParent); 1.247 + NS_ENSURE_SUCCESS(rv, nullptr); 1.248 + return wakelock.forget(); 1.249 +} 1.250 + 1.251 +} // power 1.252 +} // dom 1.253 +} // mozilla