Bug 739913 - Use kernel wake lock when the "cpu" topic is locked. r=cjones
authorKan-Ru Chen <kanru@kanru.info>
Thu, 12 Apr 2012 19:24:20 -0400
changeset 91566 b589fe2441a521a89b941712e7f34e8cca6d52f2
parent 91565 db23b2dac69c1fcf1dc99c5210cf4eaf628c8fe6
child 91567 8f0af0cf88a945230cadf0d707b002a286ebaabd
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerscjones
bugs739913
milestone14.0a1
Bug 739913 - Use kernel wake lock when the "cpu" topic is locked. r=cjones
b2g/chrome/content/shell.js
dom/power/PowerManager.cpp
dom/power/nsIDOMPowerManager.idl
hal/Hal.cpp
hal/Hal.h
hal/android/AndroidHal.cpp
hal/gonk/GonkHal.cpp
hal/linux/LinuxHal.cpp
hal/sandbox/PHal.ipdl
hal/sandbox/SandboxHal.cpp
hal/windows/WindowsHal.cpp
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -313,16 +313,20 @@ var shell = {
       if (state != "locked-foreground") {
         if (Services.idle.idleTime > idleTimeout*1000) {
           navigator.mozPower.screenEnabled = false;
         }
       } else {
         navigator.mozPower.screenEnabled = true;
       }
     }
+    if (topic == "cpu") {
+      navigator.mozPower.cpuSleepAllowed = (state != "locked-foreground" &&
+                                            state != "locked-background");
+    }
   }
 
   let idleTimeout = Services.prefs.getIntPref("power.screen.timeout");
   if (!('mozSettings' in navigator))
     return;
 
   let request = navigator.mozSettings.getLock().get("power.screen.timeout");
   request.onsuccess = function onSuccess() {
--- a/dom/power/PowerManager.cpp
+++ b/dom/power/PowerManager.cpp
@@ -231,11 +231,32 @@ PowerManager::SetScreenBrightness(double
 {
   NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
 
   NS_ENSURE_TRUE(0 <= aBrightness && aBrightness <= 1, NS_ERROR_INVALID_ARG);
   hal::SetScreenBrightness(aBrightness);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+PowerManager::GetCpuSleepAllowed(bool *aEnabled)
+{
+  if (!CheckPermission()) {
+    *aEnabled = true;
+    return NS_OK;
+  }
+
+  *aEnabled = hal::GetCpuSleepAllowed();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PowerManager::SetCpuSleepAllowed(bool aEnabled)
+{
+  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
+
+  hal::SetCpuSleepAllowed(aEnabled);
+  return NS_OK;
+}
+
 } // power
 } // dom
 } // mozilla
--- a/dom/power/nsIDOMPowerManager.idl
+++ b/dom/power/nsIDOMPowerManager.idl
@@ -37,17 +37,17 @@
 
 #include "nsISupports.idl"
 
 interface nsIDOMMozWakeLockListener;
 
 /**
  * This interface implements navigator.mozPower
  */
-[scriptable, uuid(4586bed1-cf78-4436-b503-88277d645b68)]
+[scriptable, uuid(256a3287-f528-45b5-9ba8-2b3650c056e6)]
 interface nsIDOMMozPowerManager : nsISupports
 {
     void    powerOff();
     void    reboot();
 
     /**
      * The listeners are notified when a resource changes its lock state to:
      *  - unlocked
@@ -91,9 +91,16 @@ interface nsIDOMMozPowerManager : nsISup
      * If you write a value of X into this attribute, the attribute may not have
      * the same value X when you later read it.  Most screens don't support as
      * many different brightness levels as there are doubles between 0 and 1, so
      * we may reduce the value's precision before storing it.
      *
      * @throw NS_ERROR_INVALID_ARG if brightness is not in the range [0, 1].
      */
     attribute double screenBrightness;
+
+    /**
+     * Is it possible that the device's CPU will sleep after the screen is
+     * disabled?  Setting this attribute to false will prevent the device
+     * entering suspend state.
+     */
+    attribute boolean cpuSleepAllowed;
 };
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -358,16 +358,32 @@ bool GetScreenEnabled()
 }
 
 void SetScreenEnabled(bool enabled)
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(SetScreenEnabled(enabled));
 }
 
+bool GetCpuSleepAllowed()
+{
+  // Generally for interfaces that are accessible by normal web content
+  // we should cache the result and be notified on state changes, like
+  // what the battery API does. But since this is only used by
+  // privileged interface, the synchronous getter is OK here.
+  AssertMainThread();
+  RETURN_PROXY_IF_SANDBOXED(GetCpuSleepAllowed());
+}
+
+void SetCpuSleepAllowed(bool enabled)
+{
+  AssertMainThread();
+  PROXY_IF_SANDBOXED(SetCpuSleepAllowed(enabled));
+}
+
 double GetScreenBrightness()
 {
   AssertMainThread();
   RETURN_PROXY_IF_SANDBOXED(GetScreenBrightness());
 }
 
 void SetScreenBrightness(double brightness)
 {
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -144,16 +144,27 @@ double GetScreenBrightness();
  * Note that we may reduce the resolution of the given brightness value before
  * sending it to the screen.  Therefore if you call SetScreenBrightness(x)
  * followed by GetScreenBrightness(), the value returned by
  * GetScreenBrightness() may not be exactly x.
  */
 void SetScreenBrightness(double brightness);
 
 /**
+ * Determine whether the device is allowed to sleep.
+ */
+bool GetCpuSleepAllowed();
+
+/**
+ * Set whether the device is allowed to suspend automatically after
+ * the screen is disabled.
+ */
+void SetCpuSleepAllowed(bool enabled);
+
+/**
  * Set the value of a light to a particular color, with a specific flash pattern.
  * light specifices which light.  See Hal.idl for the list of constants
  * mode specifies user set or based on ambient light sensor
  * flash specifies whether or how to flash the light
  * flashOnMS and flashOffMS specify the pattern for XXX flash mode
  * color specifies the color.  If the light doesn't support color, the given color is
  * transformed into a brightness, or just an on/off if that is all the light is capable of.
  * returns true if successful and false if failed.
--- a/hal/android/AndroidHal.cpp
+++ b/hal/android/AndroidHal.cpp
@@ -136,16 +136,26 @@ GetScreenBrightness()
 {
   return 1;
 }
 
 void
 SetScreenBrightness(double brightness)
 {}
 
+bool
+GetCpuSleepAllowed()
+{
+  return true;
+}
+
+void
+SetCpuSleepAllowed(bool enabled)
+{}
+
 void
 EnableNetworkNotifications()
 {
   AndroidBridge* bridge = AndroidBridge::Bridge();
   if (!bridge) {
     return;
   }
 
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -317,16 +317,18 @@ GetCurrentBatteryInformation(hal::Batter
 }
 
 namespace {
 
 /**
  * RAII class to help us remember to close file descriptors.
  */
 const char *screenEnabledFilename = "/sys/power/state";
+const char *wakeLockFilename = "/sys/power/wake_lock";
+const char *wakeUnlockFilename = "/sys/power/wake_unlock";
 
 template<ssize_t n>
 bool ReadFromFile(const char *filename, char (&buf)[n])
 {
   int fd = open(filename, O_RDONLY);
   ScopedClose autoClose(fd);
   if (fd < 0) {
     HAL_LOG(("Unable to open file %s.", filename));
@@ -358,16 +360,22 @@ void WriteToFile(const char *filename, c
   }
 }
 
 // We can write to screenEnabledFilename to enable/disable the screen, but when
 // we read, we always get "mem"!  So we have to keep track ourselves whether
 // the screen is on or not.
 bool sScreenEnabled = true;
 
+// We can read wakeLockFilename to find out whether the cpu wake lock
+// is already acquired, but reading and parsing it is a lot more work
+// than tracking it ourselves, and it won't be accurate anyway (kernel
+// internal wake locks aren't counted here.)
+bool sCpuSleepAllowed = true;
+
 } // anonymous namespace
 
 bool
 GetScreenEnabled()
 {
   return sScreenEnabled;
 }
 
@@ -410,16 +418,29 @@ SetScreenBrightness(double brightness)
   aConfig.mode() = hal::eHalLightMode_User;
   aConfig.flash() = hal::eHalLightFlash_None;
   aConfig.flashOnMS() = aConfig.flashOffMS() = 0;
   aConfig.color() = color;
   hal::SetLight(hal::eHalLightID_Backlight, aConfig);
   hal::SetLight(hal::eHalLightID_Buttons, aConfig);
 }
 
+bool
+GetCpuSleepAllowed()
+{
+  return sCpuSleepAllowed;
+}
+
+void
+SetCpuSleepAllowed(bool aAllowed)
+{
+  WriteToFile(aAllowed ? wakeUnlockFilename : wakeLockFilename, "gecko");
+  sCpuSleepAllowed = aAllowed;
+}
+
 static light_device_t* sLights[hal::eHalLightID_Count];	// will be initialized to NULL
 
 light_device_t* GetDevice(hw_module_t* module, char const* name)
 {
   int err;
   hw_device_t* device;
   err = module->methods->open(module, name, &device);
   if (err == 0) {
--- a/hal/linux/LinuxHal.cpp
+++ b/hal/linux/LinuxHal.cpp
@@ -86,16 +86,26 @@ GetScreenBrightness()
 {
   return 1;
 }
 
 void
 SetScreenBrightness(double brightness)
 {}
 
+bool
+GetCpuSleepAllowed()
+{
+  return true;
+}
+
+void
+SetCpuSleepAllowed(bool enabled)
+{}
+
 void
 EnableNetworkNotifications()
 {}
 
 void
 DisableNetworkNotifications()
 {}
 
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -115,16 +115,19 @@ parent:
     EnableNetworkNotifications();
     DisableNetworkNotifications();
     sync GetCurrentNetworkInformation()
       returns (NetworkInformation aNetworkInfo);
 
     sync GetScreenEnabled() returns (bool enabled);
     SetScreenEnabled(bool enabled);
 
+    sync GetCpuSleepAllowed() returns (bool enabled);
+    SetCpuSleepAllowed(bool enabled);
+
     sync GetScreenBrightness() returns (double brightness);
     SetScreenBrightness(double brightness);
     
     AdjustSystemClock(int32 aDeltaMilliseconds);
     SetTimezone(nsCString aTimezoneSpec);
 
     sync SetLight(LightType light, LightConfiguration aConfig)
       returns (bool status);
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -133,16 +133,30 @@ GetScreenEnabled()
 }
 
 void
 SetScreenEnabled(bool enabled)
 {
   Hal()->SendSetScreenEnabled(enabled);
 }
 
+bool
+GetCpuSleepAllowed()
+{
+  bool enabled = false;
+  Hal()->SendGetCpuSleepAllowed(&enabled);
+  return enabled;
+}
+
+void
+SetCpuSleepAllowed(bool enabled)
+{
+  Hal()->SendSetCpuSleepAllowed(enabled);
+}
+
 double
 GetScreenBrightness()
 {
   double brightness = 0;
   Hal()->SendGetScreenBrightness(&brightness);
   return brightness;
 }
 
@@ -363,16 +377,30 @@ public:
   NS_OVERRIDE virtual bool
   RecvSetScreenEnabled(const bool &enabled)
   {
     hal::SetScreenEnabled(enabled);
     return true;
   }
 
   NS_OVERRIDE virtual bool
+  RecvGetCpuSleepAllowed(bool *enabled)
+  {
+    *enabled = hal::GetCpuSleepAllowed();
+    return true;
+  }
+
+  NS_OVERRIDE virtual bool
+  RecvSetCpuSleepAllowed(const bool &enabled)
+  {
+    hal::SetCpuSleepAllowed(enabled);
+    return true;
+  }
+
+  NS_OVERRIDE virtual bool
   RecvGetScreenBrightness(double *brightness)
   {
     *brightness = hal::GetScreenBrightness();
     return true;
   }
 
   NS_OVERRIDE virtual bool
   RecvSetScreenBrightness(const double &brightness)
--- a/hal/windows/WindowsHal.cpp
+++ b/hal/windows/WindowsHal.cpp
@@ -64,16 +64,26 @@ GetScreenBrightness()
 {
   return 1;
 }
 
 void
 SetScreenBrightness(double brightness)
 {}
 
+bool
+GetCpuSleepAllowed()
+{
+  return true;
+}
+
+void
+SetCpuSleepAllowed(bool enabled)
+{}
+
 void
 EnableNetworkNotifications()
 {}
 
 void
 DisableNetworkNotifications()
 {}