Bug 999327 - Consider the wake-locks held by the main process when computing priorities. r=fabrice
authorGabriele Svelto <gsvelto@mozilla.com>
Thu, 01 May 2014 15:47:26 +0200
changeset 181718 e8c9253239a5bdff82933198ee1abe0c4b4e96ee
parent 181717 e8eceeb7fa65b17d70bfe7cf630295067babadcd
child 181719 e4fe6d86d885a51d68abbbb0f8cec3e27f994796
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersfabrice
bugs999327
milestone32.0a1
Bug 999327 - Consider the wake-locks held by the main process when computing priorities. r=fabrice
dom/browser-element/mochitest/priority/test_HighPriorityDowngrade.html
dom/ipc/ProcessPriorityManager.cpp
--- a/dom/browser-element/mochitest/priority/test_HighPriorityDowngrade.html
+++ b/dom/browser-element/mochitest/priority/test_HighPriorityDowngrade.html
@@ -26,44 +26,57 @@ var childID = null;
 function runTest() {
   var iframe = document.createElement('iframe');
   iframe.setAttribute('mozbrowser', true);
 
   iframe.src = browserElementTestHelpers.emptyPage1;
 
   var highPriorityIframe = null;
   var childID = null;
+  var lock = null;
+  var p = null;
 
   expectProcessCreated().then(function(chid) {
     childID = chid;
     return expectPriorityChange(childID, 'FOREGROUND', 'CPU_NORMAL');
   }).then(function() {
     // Create a new, high-priority iframe.
     highPriorityIframe = document.createElement('iframe');
     highPriorityIframe.setAttribute('mozbrowser', true);
     highPriorityIframe.setAttribute('expecting-system-message', true);
     highPriorityIframe.setAttribute('mozapptype', 'critical');
     highPriorityIframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
     highPriorityIframe.src = browserElementTestHelpers.emptyPage2;
 
-    var p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_LOW');
+    p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_LOW');
 
     document.body.appendChild(highPriorityIframe);
 
     return p;
   }).then(function() {
     return expectPriorityChange(childID, 'FOREGROUND', 'CPU_NORMAL');
+  }).then(function() {
+    p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_LOW');
+    lock = navigator.requestWakeLock('high-priority');
+    return p;
+  }).then(function() {
+    p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_NORMAL');
+    lock.unlock();
+    return p;
   }).then(SimpleTest.finish);
 
   document.body.appendChild(iframe);
 }
 
 addEventListener('testready', function() {
-  // Cause the CPU wake lock taken on behalf of the high-priority process to
-  // time out after 1s.
   SpecialPowers.pushPrefEnv(
-    {set: [["dom.ipc.systemMessageCPULockTimeoutSec", 1]]},
+    {set: [
+      /* Cause the CPU wake lock taken on behalf of the high-priority process
+       * to time out after 1s. */
+       ["dom.ipc.systemMessageCPULockTimeoutSec", 1],
+       ["dom.wakelock.enabled", true]
+    ]},
     runTest);
 });
 
 </script>
 </body>
 </html>
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -104,16 +104,17 @@ class ParticularProcessPriorityManager;
  *
  * ProcessPriorityManager::CurrentProcessIsForeground() and
  * ProcessPriorityManager::AnyProcessHasHighPriority() which can be called in
  * any process, are handled separately, by the ProcessPriorityManagerChild
  * class.
  */
 class ProcessPriorityManagerImpl MOZ_FINAL
   : public nsIObserver
+  , public WakeLockObserver
 {
 public:
   /**
    * If we're in the main process, get the ProcessPriorityManagerImpl
    * singleton.  If we're in a child process, return null.
    */
   static ProcessPriorityManagerImpl* GetSingleton();
 
@@ -152,38 +153,46 @@ public:
   /**
    * This must be called by a ParticularProcessPriorityManager when it changes
    * its priority.
    */
   void NotifyProcessPriorityChanged(
     ParticularProcessPriorityManager* aParticularManager,
     hal::ProcessPriority aOldPriority);
 
+  /**
+   * Implements WakeLockObserver, used to monitor wake lock changes in the
+   * main process.
+   */
+  virtual void Notify(const WakeLockInformation& aInfo) MOZ_OVERRIDE;
+
 private:
   static bool sPrefListenersRegistered;
   static bool sInitialized;
   static StaticRefPtr<ProcessPriorityManagerImpl> sSingleton;
 
   static void PrefChangedCallback(const char* aPref, void* aClosure);
 
   ProcessPriorityManagerImpl();
-  ~ProcessPriorityManagerImpl() {}
+  ~ProcessPriorityManagerImpl();
   DISALLOW_EVIL_CONSTRUCTORS(ProcessPriorityManagerImpl);
 
   void Init();
 
   already_AddRefed<ParticularProcessPriorityManager>
   GetParticularProcessPriorityManager(ContentParent* aContentParent);
 
   void ObserveContentParentCreated(nsISupports* aContentParent);
   void ObserveContentParentDestroyed(nsISupports* aSubject);
+  void ResetAllCPUPriorities();
 
   nsDataHashtable<nsUint64HashKey, nsRefPtr<ParticularProcessPriorityManager> >
     mParticularManagers;
 
+  bool mHighPriority;
   nsTHashtable<nsUint64HashKey> mHighPriorityChildIDs;
 };
 
 /**
  * This singleton class implements the parts of the process priority manager
  * that are available from all processes.
  */
 class ProcessPriorityManagerChild MOZ_FINAL
@@ -406,18 +415,25 @@ ProcessPriorityManagerImpl::GetSingleton
   if (!sSingleton) {
     StaticInit();
   }
 
   return sSingleton;
 }
 
 ProcessPriorityManagerImpl::ProcessPriorityManagerImpl()
+    : mHighPriority(false)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
+  RegisterWakeLockObserver(this);
+}
+
+ProcessPriorityManagerImpl::~ProcessPriorityManagerImpl()
+{
+  UnregisterWakeLockObserver(this);
 }
 
 void
 ProcessPriorityManagerImpl::Init()
 {
   LOG("Starting up.  This is the master process.");
 
   // The master process's priority never changes; set it here and then forget
@@ -521,32 +537,40 @@ ProcessPriorityManagerImpl::ObserveConte
   }
 
   mParticularManagers.Remove(childID);
 
   if (mHighPriorityChildIDs.Contains(childID)) {
     mHighPriorityChildIDs.RemoveEntry(childID);
 
     // We just lost a high-priority process; reset everyone's CPU priorities.
-    nsTArray<nsRefPtr<ParticularProcessPriorityManager> > pppms;
-    mParticularManagers.EnumerateRead(
-      &EnumerateParticularProcessPriorityManagers,
-      &pppms);
+    ResetAllCPUPriorities();
+  }
+}
 
-    for (uint32_t i = 0; i < pppms.Length(); i++) {
-      pppms[i]->ResetCPUPriorityNow();
-    }
+void
+ProcessPriorityManagerImpl::ResetAllCPUPriorities( void )
+{
+  nsTArray<nsRefPtr<ParticularProcessPriorityManager> > pppms;
+  mParticularManagers.EnumerateRead(
+    &EnumerateParticularProcessPriorityManagers,
+    &pppms);
+
+  for (uint32_t i = 0; i < pppms.Length(); i++) {
+    pppms[i]->ResetCPUPriorityNow();
   }
 }
 
 bool
 ProcessPriorityManagerImpl::OtherProcessHasHighPriority(
   ParticularProcessPriorityManager* aParticularManager)
 {
-  if (mHighPriorityChildIDs.Contains(aParticularManager->ChildID())) {
+  if (mHighPriority) {
+    return true;
+  } else if (mHighPriorityChildIDs.Contains(aParticularManager->ChildID())) {
     return mHighPriorityChildIDs.Count() > 1;
   }
   return mHighPriorityChildIDs.Count() > 0;
 }
 
 bool
 ProcessPriorityManagerImpl::ChildProcessHasHighPriority( void )
 {
@@ -582,16 +606,39 @@ ProcessPriorityManagerImpl::NotifyProces
 
   for (uint32_t i = 0; i < pppms.Length(); i++) {
     if (pppms[i] != aParticularManager) {
       pppms[i]->ResetCPUPriorityNow();
     }
   }
 }
 
+/* virtual */ void
+ProcessPriorityManagerImpl::Notify(const WakeLockInformation& aInfo)
+{
+  /* The main process always has an ID of 0, if it is present in the wake-lock
+   * information then we explicitly requested a high-priority wake-lock for the
+   * main process. */
+  if (aInfo.topic().EqualsLiteral("high-priority")) {
+    if (aInfo.lockingProcesses().Contains((uint64_t)0)) {
+      mHighPriority = true;
+    } else {
+      mHighPriority = false;
+    }
+
+    /* The main process got a high-priority wakelock change; reset everyone's
+     * CPU priorities. */
+    ResetAllCPUPriorities();
+
+    LOG("Got wake lock changed event. "
+        "Now mHighPriorityParent = %d\n", mHighPriority);
+  }
+}
+
+
 NS_IMPL_ISUPPORTS(ParticularProcessPriorityManager,
                   nsIObserver,
                   nsITimerCallback,
                   nsISupportsWeakReference);
 
 ParticularProcessPriorityManager::ParticularProcessPriorityManager(
   ContentParent* aContentParent)
   : mContentParent(aContentParent)