dom/power/PowerManagerService.cpp

changeset 0
6474c204b198
     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

mercurial