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