Bug 852925 - Freeze priority changes when the screen is turned off. r=khuey
authorGabriele Svelto <gsvelto@mozilla.com>
Mon, 09 Mar 2015 16:33:33 +0100
changeset 233373 d34f33fae4e8b5deeb2938e5a81338f6aa69b2c8
parent 233372 a30c985bc8dd336683b1b65d672b08577909f89d
child 233374 785891c8e9978cdbb3e248bee4b12ec0a17158e5
push id28410
push userryanvm@gmail.com
push dateThu, 12 Mar 2015 22:06:36 +0000
treeherdermozilla-central@42afc7ef5ccb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs852925
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 852925 - Freeze priority changes when the screen is turned off. r=khuey
dom/ipc/ProcessPriorityManager.cpp
dom/ipc/ProcessPriorityManager.h
widget/gonk/nsWindow.cpp
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -190,19 +190,31 @@ public:
     hal::ProcessPriority aOldPriority);
 
   /**
    * Implements WakeLockObserver, used to monitor wake lock changes in the
    * main process.
    */
   virtual void Notify(const WakeLockInformation& aInfo) MOZ_OVERRIDE;
 
+  /**
+   * Prevents processes from changing priority until unfrozen.
+   */
+  void Freeze();
+
+  /**
+   * Allow process' priorities to change again.  This will immediately adjust
+   * processes whose priority change did not happen because of the freeze.
+   */
+  void Unfreeze();
+
 private:
   static bool sPrefListenersRegistered;
   static bool sInitialized;
+  static bool sFrozen;
   static StaticRefPtr<ProcessPriorityManagerImpl> sSingleton;
 
   static void PrefChangedCallback(const char* aPref, void* aClosure);
 
   ProcessPriorityManagerImpl();
   ~ProcessPriorityManagerImpl();
   DISALLOW_EVIL_CONSTRUCTORS(ProcessPriorityManagerImpl);
 
@@ -266,17 +278,18 @@ private:
 class ParticularProcessPriorityManager MOZ_FINAL
   : public WakeLockObserver
   , public nsIObserver
   , public nsITimerCallback
   , public nsSupportsWeakReference
 {
   ~ParticularProcessPriorityManager();
 public:
-  explicit ParticularProcessPriorityManager(ContentParent* aContentParent);
+  explicit ParticularProcessPriorityManager(ContentParent* aContentParent,
+                                            bool aFrozen = false);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSITIMERCALLBACK
 
   virtual void Notify(const WakeLockInformation& aInfo) MOZ_OVERRIDE;
   void Init();
 
@@ -305,16 +318,18 @@ public:
 
   ProcessPriority CurrentPriority();
   ProcessPriority ComputePriority();
 
   void ScheduleResetPriority(const char* aTimeoutPref);
   void ResetPriority();
   void ResetPriorityNow();
   void SetPriorityNow(ProcessPriority aPriority, uint32_t aLRU = 0);
+  void Freeze();
+  void Unfreeze();
 
   void ShutDown();
 
 private:
   void FireTestOnlyObserverNotification(
     const char* aTopic,
     const nsACString& aData = EmptyCString());
 
@@ -323,27 +338,29 @@ private:
     const char* aData = nullptr);
 
   ContentParent* mContentParent;
   uint64_t mChildID;
   ProcessPriority mPriority;
   uint32_t mLRU;
   bool mHoldsCPUWakeLock;
   bool mHoldsHighPriorityWakeLock;
+  bool mFrozen;
 
   /**
    * Used to implement NameWithComma().
    */
   nsAutoCString mNameWithComma;
 
   nsCOMPtr<nsITimer> mResetPriorityTimer;
 };
 
 /* static */ bool ProcessPriorityManagerImpl::sInitialized = false;
 /* static */ bool ProcessPriorityManagerImpl::sPrefListenersRegistered = false;
+/* static */ bool ProcessPriorityManagerImpl::sFrozen = false;
 /* static */ StaticRefPtr<ProcessPriorityManagerImpl>
   ProcessPriorityManagerImpl::sSingleton;
 
 NS_IMPL_ISUPPORTS(ProcessPriorityManagerImpl,
                   nsIObserver);
 
 /* static */ void
 ProcessPriorityManagerImpl::PrefChangedCallback(const char* aPref,
@@ -464,17 +481,17 @@ ProcessPriorityManagerImpl::GetParticula
     return nullptr;
   }
 #endif
 
   nsRefPtr<ParticularProcessPriorityManager> pppm;
   uint64_t cpId = aContentParent->ChildID();
   mParticularManagers.Get(cpId, &pppm);
   if (!pppm) {
-    pppm = new ParticularProcessPriorityManager(aContentParent);
+    pppm = new ParticularProcessPriorityManager(aContentParent, sFrozen);
     pppm->Init();
     mParticularManagers.Put(cpId, pppm);
 
     FireTestOnlyObserverNotification("process-created",
       nsPrintfCString("%lld", cpId));
   }
 
   return pppm.forget();
@@ -585,29 +602,66 @@ ProcessPriorityManagerImpl::Notify(const
       mHighPriority = false;
     }
 
     LOG("Got wake lock changed event. "
         "Now mHighPriorityParent = %d\n", mHighPriority);
   }
 }
 
+static PLDHashOperator
+FreezeParticularProcessPriorityManagers(
+  const uint64_t& aKey,
+  nsRefPtr<ParticularProcessPriorityManager> aValue,
+  void* aUserData)
+{
+  aValue->Freeze();
+  return PL_DHASH_NEXT;
+}
+
+void
+ProcessPriorityManagerImpl::Freeze()
+{
+  sFrozen = true;
+  mParticularManagers.EnumerateRead(&FreezeParticularProcessPriorityManagers,
+                                    nullptr);
+}
+
+static PLDHashOperator
+UnfreezeParticularProcessPriorityManagers(
+  const uint64_t& aKey,
+  nsRefPtr<ParticularProcessPriorityManager> aValue,
+  void* aUserData)
+{
+  aValue->Unfreeze();
+  return PL_DHASH_NEXT;
+}
+
+void
+ProcessPriorityManagerImpl::Unfreeze()
+{
+  sFrozen = false;
+  mParticularManagers.EnumerateRead(&UnfreezeParticularProcessPriorityManagers,
+                                    nullptr);
+}
+
 NS_IMPL_ISUPPORTS(ParticularProcessPriorityManager,
                   nsIObserver,
                   nsITimerCallback,
                   nsISupportsWeakReference);
 
 ParticularProcessPriorityManager::ParticularProcessPriorityManager(
-  ContentParent* aContentParent)
+  ContentParent* aContentParent, bool aFrozen)
   : mContentParent(aContentParent)
   , mChildID(aContentParent->ChildID())
   , mPriority(PROCESS_PRIORITY_UNKNOWN)
   , mLRU(0)
   , mHoldsCPUWakeLock(false)
   , mHoldsHighPriorityWakeLock(false)
+  , mFrozen(aFrozen)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   LOGP("Creating ParticularProcessPriorityManager.");
 }
 
 void
 ParticularProcessPriorityManager::Init()
 {
@@ -967,16 +1021,17 @@ ParticularProcessPriorityManager::SetPri
 {
   if (aPriority == PROCESS_PRIORITY_UNKNOWN) {
     MOZ_ASSERT(false);
     return;
   }
 
   if (!ProcessPriorityManagerImpl::PrefsEnabled() ||
       !mContentParent ||
+      mFrozen ||
       ((mPriority == aPriority) && (mLRU == aLRU))) {
     return;
   }
 
   if ((mPriority == aPriority) && (mLRU != aLRU)) {
     mLRU = aLRU;
     hal::SetProcessPriority(Pid(), mPriority, aLRU);
 
@@ -1008,16 +1063,29 @@ ParticularProcessPriorityManager::SetPri
     unused << mContentParent->SendFlushMemory(NS_LITERAL_STRING("low-memory"));
   }
 
   FireTestOnlyObserverNotification("process-priority-set",
     ProcessPriorityToString(mPriority));
 }
 
 void
+ParticularProcessPriorityManager::Freeze()
+{
+  mFrozen = true;
+}
+
+void
+ParticularProcessPriorityManager::Unfreeze()
+{
+  mFrozen = false;
+  ResetPriorityNow();
+}
+
+void
 ParticularProcessPriorityManager::ShutDown()
 {
   MOZ_ASSERT(mContentParent);
 
   UnregisterWakeLockObserver(this);
 
   if (mResetPriorityTimer) {
     mResetPriorityTimer->Cancel();
@@ -1312,9 +1380,29 @@ ProcessPriorityManager::AnyProcessHasHig
   if (singleton) {
     return singleton->ChildProcessHasHighPriority();
   } else {
     return ProcessPriorityManagerChild::Singleton()->
       CurrentProcessIsHighPriority();
   }
 }
 
+/* static */ void
+ProcessPriorityManager::Freeze()
+{
+  ProcessPriorityManagerImpl* singleton =
+    ProcessPriorityManagerImpl::GetSingleton();
+  if (singleton) {
+    singleton->Freeze();
+  }
+}
+
+/* static */ void
+ProcessPriorityManager::Unfreeze()
+{
+  ProcessPriorityManagerImpl* singleton =
+    ProcessPriorityManagerImpl::GetSingleton();
+  if (singleton) {
+    singleton->Unfreeze();
+  }
+}
+
 } // namespace mozilla
--- a/dom/ipc/ProcessPriorityManager.h
+++ b/dom/ipc/ProcessPriorityManager.h
@@ -69,16 +69,27 @@ public:
   static bool CurrentProcessIsForeground();
 
   /**
    * Returns true if one or more processes with FOREGROUND_HIGH priority are
    * present, false otherwise.
    */
   static bool AnyProcessHasHighPriority();
 
+  /**
+   * Prevents processes from changing priority until unfrozen.
+   */
+  static void Freeze();
+
+  /**
+   * Allow process' priorities to change again.  This will immediately adjust
+   * processes whose priority change did not happen because of the freeze.
+   */
+  static void Unfreeze();
+
 private:
   ProcessPriorityManager();
   DISALLOW_EVIL_CONSTRUCTORS(ProcessPriorityManager);
 };
 
 } // namespace mozilla
 
 #endif
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -17,16 +17,17 @@
 
 #include <fcntl.h>
 
 #include "android/log.h"
 
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/Hal.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/ProcessPriorityManager.h"
 #include "mozilla/Services.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "GLContextProvider.h"
 #include "GLContext.h"
@@ -89,16 +90,23 @@ EffectiveScreenRotation()
 
 class ScreenOnOffEvent : public nsRunnable {
 public:
     ScreenOnOffEvent(bool on)
         : mIsOn(on)
     {}
 
     NS_IMETHOD Run() {
+        // When the screen is off prevent priority changes.
+        if (mIsOn) {
+          ProcessPriorityManager::Unfreeze();
+        } else {
+          ProcessPriorityManager::Freeze();
+        }
+
         for (uint32_t i = 0; i < sTopWindows.Length(); i++) {
             nsWindow *win = sTopWindows[i];
 
             if (nsIWidgetListener* listener = win->GetWidgetListener()) {
                 listener->SizeModeChanged(mIsOn ? nsSizeMode_Fullscreen : nsSizeMode_Minimized);
             }
         }