Bug 1201394 - Use cached preferences value in ProcessPriorityManager. r=gsvelto
authorKan-Ru Chen <kanru@kanru.info>
Fri, 04 Sep 2015 11:09:06 +0800
changeset 293694 f5047a4f41b4144c2fbf9e78a2bd1cb7edccf60f
parent 293693 9c26b3b787f8a6666a742591f4ff6c6e8b95834c
child 293695 16a9a63857202ca2d58aba72379d0ec6d19bb091
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgsvelto
bugs1201394
milestone43.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 1201394 - Use cached preferences value in ProcessPriorityManager. r=gsvelto
dom/base/test/test_frameLoader_switchProcess.html
dom/ipc/ProcessPriorityManager.cpp
--- a/dom/base/test/test_frameLoader_switchProcess.html
+++ b/dom/base/test/test_frameLoader_switchProcess.html
@@ -63,20 +63,17 @@
       });
     }))
     .then(SimpleTest.finish);
 
     document.body.appendChild(iframe);
   }
 
   SpecialPowers.pushPrefEnv(
-    // XXX Set LRUPoolLevels to 2 to avoid breaking priority tests
-    { "set": [["dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels", 2],
-              ["dom.ipc.processPriorityManager.BACKGROUND_PERCEIVABLE.LRUPoolLevels", 2],
-              ["dom.ipc.processPriorityManager.testMode", true],
+    { "set": [["dom.ipc.processPriorityManager.testMode", true],
               ["dom.ipc.processPriorityManager.enabled", true],
               ["dom.ipc.tabs.disabled", false],
               ["dom.ipc.processCount", 3],
               ["dom.mozBrowserFramesEnabled", true]] },
     () => SpecialPowers.pushPermissions([
       { "type": "browser", "allow": 1, "context": document }
     ], runTest));
 </script>
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -139,26 +139,28 @@ private:
  * ProcessPriorityManager::CurrentProcessIsForeground() and
  * ProcessPriorityManager::AnyProcessHasHighPriority() which can be called in
  * any process, are handled separately, by the ProcessPriorityManagerChild
  * class.
  */
 class ProcessPriorityManagerImpl final
   : public nsIObserver
   , public WakeLockObserver
+  , public nsSupportsWeakReference
 {
 public:
   /**
    * If we're in the main process, get the ProcessPriorityManagerImpl
    * singleton.  If we're in a child process, return null.
    */
   static ProcessPriorityManagerImpl* GetSingleton();
 
   static void StaticInit();
   static bool PrefsEnabled();
+  static bool TestMode();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   /**
    * This function implements ProcessPriorityManager::SetProcessPriority.
    */
   void SetProcessPriority(ContentParent* aContentParent,
@@ -197,17 +199,26 @@ public:
   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();
 
+  /**
+   * Call ShutDown before destroying the ProcessPriorityManager because
+   * WakeLockObserver hols a strong reference to it.
+   */
+  void ShutDown();
+
 private:
+  static bool sPrefsEnabled;
+  static bool sRemoteTabsDisabled;
+  static bool sTestMode;
   static bool sPrefListenersRegistered;
   static bool sInitialized;
   static bool sFrozen;
   static StaticRefPtr<ProcessPriorityManagerImpl> sSingleton;
 
   static void PrefChangedCallback(const char* aPref, void* aClosure);
 
   ProcessPriorityManagerImpl();
@@ -283,16 +294,17 @@ public:
   explicit ParticularProcessPriorityManager(ContentParent* aContentParent,
                                             bool aFrozen = false);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSITIMERCALLBACK
 
   virtual void Notify(const WakeLockInformation& aInfo) override;
+  static void StaticInit();
   void Init();
 
   int32_t Pid() const;
   uint64_t ChildID() const;
   bool IsPreallocated() const;
 
   /**
    * Used in logging, this method returns the ContentParent's name followed by
@@ -313,26 +325,34 @@ public:
   void OnTabParentDestroyed(nsISupports* aSubject);
   void OnFrameloaderVisibleChanged(nsISupports* aSubject);
   void OnActivityOpened(const char16_t* aData);
   void OnActivityClosed(const char16_t* aData);
 
   ProcessPriority CurrentPriority();
   ProcessPriority ComputePriority();
 
-  void ScheduleResetPriority(const char* aTimeoutPref);
+  enum TimeoutPref {
+    BACKGROUND_PERCEIVABLE_GRACE_PERIOD,
+    BACKGROUND_GRACE_PERIOD,
+  };
+
+  void ScheduleResetPriority(TimeoutPref aTimeoutPref);
   void ResetPriority();
   void ResetPriorityNow();
   void SetPriorityNow(ProcessPriority aPriority, uint32_t aLRU = 0);
   void Freeze();
   void Unfreeze();
 
   void ShutDown();
 
 private:
+  static uint32_t sBackgroundPerceivableGracePeriodMS;
+  static uint32_t sBackgroundGracePeriodMS;
+
   void FireTestOnlyObserverNotification(
     const char* aTopic,
     const nsACString& aData = EmptyCString());
 
   void FireTestOnlyObserverNotification(
     const char* aTopic,
     const char* aData = nullptr);
 
@@ -349,51 +369,76 @@ private:
    * Used to implement NameWithComma().
    */
   nsAutoCString mNameWithComma;
 
   nsCOMPtr<nsITimer> mResetPriorityTimer;
 };
 
 /* static */ bool ProcessPriorityManagerImpl::sInitialized = false;
+/* static */ bool ProcessPriorityManagerImpl::sPrefsEnabled = false;
+/* static */ bool ProcessPriorityManagerImpl::sRemoteTabsDisabled = true;
+/* static */ bool ProcessPriorityManagerImpl::sTestMode = false;
 /* static */ bool ProcessPriorityManagerImpl::sPrefListenersRegistered = false;
 /* static */ bool ProcessPriorityManagerImpl::sFrozen = false;
 /* static */ StaticRefPtr<ProcessPriorityManagerImpl>
   ProcessPriorityManagerImpl::sSingleton;
+/* static */ uint32_t ParticularProcessPriorityManager::sBackgroundPerceivableGracePeriodMS = 0;
+/* static */ uint32_t ParticularProcessPriorityManager::sBackgroundGracePeriodMS = 0;
 
 NS_IMPL_ISUPPORTS(ProcessPriorityManagerImpl,
-                  nsIObserver);
+                  nsIObserver,
+                  nsISupportsWeakReference);
 
 /* static */ void
 ProcessPriorityManagerImpl::PrefChangedCallback(const char* aPref,
                                                 void* aClosure)
 {
   StaticInit();
+  if (!PrefsEnabled() && sSingleton) {
+    sSingleton->ShutDown();
+    sSingleton = nullptr;
+    sInitialized = false;
+  }
 }
 
 /* static */ bool
 ProcessPriorityManagerImpl::PrefsEnabled()
 {
-  return Preferences::GetBool("dom.ipc.processPriorityManager.enabled") &&
-         !Preferences::GetBool("dom.ipc.tabs.disabled");
+  return sPrefsEnabled && !sRemoteTabsDisabled;
+}
+
+/* static */ bool
+ProcessPriorityManagerImpl::TestMode()
+{
+  return sTestMode;
 }
 
 /* static */ void
 ProcessPriorityManagerImpl::StaticInit()
 {
   if (sInitialized) {
     return;
   }
 
   // The process priority manager is main-process only.
   if (!XRE_IsParentProcess()) {
     sInitialized = true;
     return;
   }
 
+  if (!sPrefListenersRegistered) {
+    Preferences::AddBoolVarCache(&sPrefsEnabled,
+                                 "dom.ipc.processPriorityManager.enabled");
+    Preferences::AddBoolVarCache(&sRemoteTabsDisabled,
+                                 "dom.ipc.tabs.disabled");
+    Preferences::AddBoolVarCache(&sTestMode,
+                                 "dom.ipc.processPriorityManager.testMode");
+  }
+
   // If IPC tabs aren't enabled at startup, don't bother with any of this.
   if (!PrefsEnabled()) {
     LOG("InitProcessPriorityManager bailing due to prefs.");
 
     // Run StaticInit() again if the prefs change.  We don't expect this to
     // happen in normal operation, but it happens during testing.
     if (!sPrefListenersRegistered) {
       sPrefListenersRegistered = true;
@@ -428,34 +473,40 @@ ProcessPriorityManagerImpl::ProcessPrior
     , mBackgroundPerceivableLRUPool(PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
   RegisterWakeLockObserver(this);
 }
 
 ProcessPriorityManagerImpl::~ProcessPriorityManagerImpl()
 {
+  ShutDown();
+}
+
+void
+ProcessPriorityManagerImpl::ShutDown()
+{
   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
   // about it.  We'll manage only subprocesses' priorities using the process
   // priority manager.
   hal::SetProcessPriority(getpid(), PROCESS_PRIORITY_MASTER);
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (os) {
-    os->AddObserver(this, "ipc:content-created", /* ownsWeak */ false);
-    os->AddObserver(this, "ipc:content-shutdown", /* ownsWeak */ false);
-    os->AddObserver(this, "screen-state-changed", /* ownsWeak */ false);
+    os->AddObserver(this, "ipc:content-created", /* ownsWeak */ true);
+    os->AddObserver(this, "ipc:content-shutdown", /* ownsWeak */ true);
+    os->AddObserver(this, "screen-state-changed", /* ownsWeak */ true);
   }
 }
 
 NS_IMETHODIMP
 ProcessPriorityManagerImpl::Observe(
   nsISupports* aSubject,
   const char* aTopic,
   const char16_t* aData)
@@ -660,16 +711,25 @@ ParticularProcessPriorityManager::Partic
   , mIsActivityOpener(false)
   , mFrozen(aFrozen)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
   LOGP("Creating ParticularProcessPriorityManager.");
 }
 
 void
+ParticularProcessPriorityManager::StaticInit()
+{
+  Preferences::AddUintVarCache(&sBackgroundPerceivableGracePeriodMS,
+                               "dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS");
+  Preferences::AddUintVarCache(&sBackgroundGracePeriodMS,
+                               "dom.ipc.processPriorityManager.backgroundGracePeriodMS");
+}
+
+void
 ParticularProcessPriorityManager::Init()
 {
   RegisterWakeLockObserver(this);
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (os) {
     os->AddObserver(this, "audio-channel-process-changed", /* ownsWeak */ true);
     os->AddObserver(this, "remote-browser-shown", /* ownsWeak */ true);
@@ -925,42 +985,53 @@ ParticularProcessPriorityManager::ResetP
   if (mPriority == PROCESS_PRIORITY_UNKNOWN ||
       mPriority > processPriority) {
     // Apps set at a perceivable background priority are often playing media.
     // Most media will have short gaps while changing tracks between songs,
     // switching videos, etc.  Give these apps a longer grace period so they
     // can get their next track started, if there is one, before getting
     // downgraded.
     if (mPriority == PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE) {
-      ScheduleResetPriority("backgroundPerceivableGracePeriodMS");
+      ScheduleResetPriority(BACKGROUND_PERCEIVABLE_GRACE_PERIOD);
     } else {
-      ScheduleResetPriority("backgroundGracePeriodMS");
+      ScheduleResetPriority(BACKGROUND_GRACE_PERIOD);
     }
     return;
   }
 
   SetPriorityNow(processPriority);
 }
 
 void
 ParticularProcessPriorityManager::ResetPriorityNow()
 {
   SetPriorityNow(ComputePriority());
 }
 
 void
-ParticularProcessPriorityManager::ScheduleResetPriority(const char* aTimeoutPref)
+ParticularProcessPriorityManager::ScheduleResetPriority(TimeoutPref aTimeoutPref)
 {
   if (mResetPriorityTimer) {
     LOGP("ScheduleResetPriority bailing; the timer is already running.");
     return;
   }
 
-  uint32_t timeout = Preferences::GetUint(
-    nsPrintfCString("dom.ipc.processPriorityManager.%s", aTimeoutPref).get());
+  uint32_t timeout = 0;
+  switch (aTimeoutPref) {
+    case BACKGROUND_PERCEIVABLE_GRACE_PERIOD:
+      timeout = sBackgroundPerceivableGracePeriodMS;
+      break;
+    case BACKGROUND_GRACE_PERIOD:
+      timeout = sBackgroundGracePeriodMS;
+      break;
+    default:
+      MOZ_ASSERT(false, "Unrecognized timeout pref");
+      break;
+  }
+
   LOGP("Scheduling reset timer to fire in %dms.", timeout);
   mResetPriorityTimer = do_CreateInstance("@mozilla.org/timer;1");
   mResetPriorityTimer->InitWithCallback(this, timeout, nsITimer::TYPE_ONE_SHOT);
 }
 
 NS_IMETHODIMP
 ParticularProcessPriorityManager::Notify(nsITimer* aTimer)
 {
@@ -1129,17 +1200,17 @@ ParticularProcessPriorityManager::ShutDo
   mContentParent = nullptr;
 }
 
 void
 ProcessPriorityManagerImpl::FireTestOnlyObserverNotification(
   const char* aTopic,
   const nsACString& aData /* = EmptyCString() */)
 {
-  if (!Preferences::GetBool("dom.ipc.processPriorityManager.testMode")) {
+  if (!TestMode()) {
     return;
   }
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   NS_ENSURE_TRUE_VOID(os);
 
   nsPrintfCString topic("process-priority-manager:TEST-ONLY:%s", aTopic);
 
@@ -1148,34 +1219,34 @@ ProcessPriorityManagerImpl::FireTestOnly
   os->NotifyObservers(nullptr, topic.get(), NS_ConvertUTF8toUTF16(aData).get());
 }
 
 void
 ParticularProcessPriorityManager::FireTestOnlyObserverNotification(
   const char* aTopic,
   const char* aData /* = nullptr */ )
 {
-  if (!Preferences::GetBool("dom.ipc.processPriorityManager.testMode")) {
+  if (!ProcessPriorityManagerImpl::TestMode()) {
     return;
   }
 
   nsAutoCString data;
   if (aData) {
     data.AppendASCII(aData);
   }
 
   FireTestOnlyObserverNotification(aTopic, data);
 }
 
 void
 ParticularProcessPriorityManager::FireTestOnlyObserverNotification(
   const char* aTopic,
   const nsACString& aData /* = EmptyCString() */)
 {
-  if (!Preferences::GetBool("dom.ipc.processPriorityManager.testMode")) {
+  if (!ProcessPriorityManagerImpl::TestMode()) {
     return;
   }
 
   nsAutoCString data(nsPrintfCString("%lld", ChildID()));
   if (!aData.IsEmpty()) {
     data.Append(':');
     data.Append(aData);
   }
@@ -1376,16 +1447,17 @@ ProcessLRUPool::Add(ParticularProcessPri
 
 namespace mozilla {
 
 /* static */ void
 ProcessPriorityManager::Init()
 {
   ProcessPriorityManagerImpl::StaticInit();
   ProcessPriorityManagerChild::StaticInit();
+  ParticularProcessPriorityManager::StaticInit();
 }
 
 /* static */ void
 ProcessPriorityManager::SetProcessPriority(ContentParent* aContentParent,
                                            ProcessPriority aPriority)
 {
   MOZ_ASSERT(aContentParent);