Bug 793105 - Add a "backgroundPerceivable" class for audio-channel-content. r=jlebar,roc a=blocking-basecamp
authorKan-Ru Chen (陳侃如) <kanru@kanru.info>
Sat, 05 Jan 2013 13:03:51 +0800
changeset 122494 f257035878ec6b6cf3bd800e2c5e024776064011
parent 122493 1aae9f7f0cf594400ba19ceaebd9ae32782f9aa8
child 122495 39a162ff4025aff93030e9354daa5f93a56d718b
push id1997
push userakeybl@mozilla.com
push dateMon, 07 Jan 2013 21:25:26 +0000
treeherdermozilla-beta@4baf45cdcf21 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar, roc, blocking-basecamp
bugs793105
milestone19.0a2
Bug 793105 - Add a "backgroundPerceivable" class for audio-channel-content. r=jlebar,roc a=blocking-basecamp
b2g/app/b2g.js
dom/audiochannel/AudioChannelService.cpp
dom/audiochannel/AudioChannelService.h
dom/audiochannel/AudioChannelServiceChild.cpp
dom/ipc/ProcessPriorityManager.cpp
hal/HalTypes.h
hal/gonk/GonkHal.cpp
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -538,16 +538,18 @@ pref("dom.ipc.processPriorityManager.ena
 pref("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
 
 // Kernel parameters for how processes are killed on low-memory.
 pref("gonk.systemMemoryPressureRecoveryPollMS", 5000);
 pref("hal.processPriorityManager.gonk.masterOomScoreAdjust", 0);
 pref("hal.processPriorityManager.gonk.masterKillUnderMB", 1);
 pref("hal.processPriorityManager.gonk.foregroundOomScoreAdjust", 67);
 pref("hal.processPriorityManager.gonk.foregroundKillUnderMB", 4);
+pref("hal.processPriorityManager.gonk.backgroundPerceivableOomScoreAdjust", 134);
+pref("hal.processPriorityManager.gonk.backgroundPerceivebleKillUnderMB", 5);
 pref("hal.processPriorityManager.gonk.backgroundHomescreenOomScoreAdjust", 200);
 pref("hal.processPriorityManager.gonk.backgroundHomescreenKillUnderMB", 5);
 pref("hal.processPriorityManager.gonk.backgroundOomScoreAdjust", 400);
 pref("hal.processPriorityManager.gonk.backgroundKillUnderMB", 8);
 pref("hal.processPriorityManager.gonk.notifyLowMemUnderMB", 10);
 
 // Niceness values (i.e., CPU priorities) for B2G processes.
 pref("hal.processPriorityManager.gonk.masterNice", -1);
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -220,16 +220,22 @@ AudioChannelService::GetMuted(AudioChann
       nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
       obs->NotifyObservers(nullptr, "audio-channel-changed", channelName.get());
     }
   }
 
   return muted;
 }
 
+bool
+AudioChannelService::ContentChannelIsActive()
+{
+  return mChannelCounters[AUDIO_CHANNEL_CONTENT].Length() > 0;
+}
+
 static PLDHashOperator
 NotifyEnumerator(AudioChannelAgent* aAgent,
                  AudioChannelType aType, void* aData)
 {
   if (aAgent) {
     aAgent->NotifyAudioChannelStateChanged();
   }
   return PL_DHASH_NEXT;
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -48,16 +48,22 @@ public:
    */
   virtual void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
 
   /**
    * Return true if this type should be muted.
    */
   virtual bool GetMuted(AudioChannelType aType, bool aElementHidden);
 
+  /**
+   * Return true if there is a content channel active in this process
+   * or one of its subprocesses.
+   */
+  virtual bool ContentChannelIsActive();
+
 protected:
   void Notify();
 
   /* Register/Unregister IPC types: */
   void RegisterType(AudioChannelType aType, uint64_t aChildID);
   void UnregisterType(AudioChannelType aType, uint64_t aChildID);
 
   AudioChannelService();
--- a/dom/audiochannel/AudioChannelServiceChild.cpp
+++ b/dom/audiochannel/AudioChannelServiceChild.cpp
@@ -7,21 +7,18 @@
 #include "AudioChannelServiceChild.h"
 
 #include "base/basictypes.h"
 
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/unused.h"
 #include "mozilla/Util.h"
-
 #include "mozilla/dom/ContentChild.h"
-
-#include "base/basictypes.h"
-
+#include "nsIObserverService.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 StaticRefPtr<AudioChannelServiceChild> gAudioChannelServiceChild;
 
 // static
@@ -77,26 +74,35 @@ AudioChannelServiceChild::RegisterAudioC
                                                     AudioChannelType aType)
 {
   AudioChannelService::RegisterAudioChannelAgent(aAgent, aType);
 
   ContentChild *cc = ContentChild::GetSingleton();
   if (cc) {
     cc->SendAudioChannelRegisterType(aType);
   }
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->NotifyObservers(nullptr, "audio-channel-agent-changed", nullptr);
+  }
 }
 
 void
 AudioChannelServiceChild::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
 {
   AudioChannelType type;
   if (!mAgents.Get(aAgent, &type)) {
     return;
   }
 
   AudioChannelService::UnregisterAudioChannelAgent(aAgent);
 
   ContentChild *cc = ContentChild::GetSingleton();
   if (cc) {
     cc->SendAudioChannelUnregisterType(type);
   }
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->NotifyObservers(nullptr, "audio-channel-agent-changed", nullptr);
+  }
 }
-
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/dom/ipc/ProcessPriorityManager.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/Hal.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/HalTypes.h"
 #include "mozilla/TimeStamp.h"
+#include "AudioChannelService.h"
 #include "prlog.h"
 #include "nsWeakPtr.h"
 #include "nsXULAppAPI.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsITimer.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsIDocument.h"
@@ -75,16 +76,21 @@ GetPPMLog()
 #endif
 
 /**
  * Get the appropriate backround priority for this process.
  */
 ProcessPriority
 GetBackgroundPriority()
 {
+  AudioChannelService* service = AudioChannelService::GetAudioChannelService();
+  if (service->ContentChannelIsActive()) {
+    return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
+  }
+
   bool isHomescreen = false;
 
   ContentChild* contentChild = ContentChild::GetSingleton();
   if (contentChild) {
     const InfallibleTArray<PBrowserChild*>& browsers =
       contentChild->ManagedPBrowserChild();
     for (uint32_t i = 0; i < browsers.Length(); i++) {
       nsAutoString appType;
@@ -97,16 +103,27 @@ GetBackgroundPriority()
   }
 
   return isHomescreen ?
          PROCESS_PRIORITY_BACKGROUND_HOMESCREEN :
          PROCESS_PRIORITY_BACKGROUND;
 }
 
 /**
+ * Determine if the priority is a backround priority.
+ */
+bool
+IsBackgroundPriority(ProcessPriority aPriority)
+{
+  return (aPriority == PROCESS_PRIORITY_BACKGROUND ||
+          aPriority == PROCESS_PRIORITY_BACKGROUND_HOMESCREEN ||
+          aPriority == PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE);
+}
+
+/**
  * This class listens to window creation and visibilitychange events and
  * informs the hal back-end when this process transitions between having no
  * visible top-level windows, and when it has at least one visible top-level
  * window.
  *
  *
  * An important heuristic here is that we don't mark a process as background
  * until it's had no visible top-level windows for some amount of time.
@@ -130,16 +147,17 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIDOMEVENTLISTENER
 
   ProcessPriority GetPriority() const { return mProcessPriority; }
 
 private:
   void SetPriority(ProcessPriority aPriority);
+  void OnAudioChannelAgentChanged();
   void OnContentDocumentGlobalCreated(nsISupports* aOuterWindow);
   void OnInnerWindowDestroyed();
   void OnGracePeriodTimerFired();
   void RecomputeNumVisibleWindows();
 
   // mProcessPriority tracks the priority we've given this process in hal,
   // except that, when the grace period timer is active, mProcessPriority ==
   // BACKGROUND or HOMESCREEN_BACKGROUND even though hal still thinks we're a
@@ -165,48 +183,59 @@ ProcessPriorityManager::Init()
 {
   LOG("Starting up.");
 
   // We can't do this in the constructor because we need to hold a strong ref
   // to |this| before calling these methods.
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   os->AddObserver(this, "content-document-global-created", /* ownsWeak = */ false);
   os->AddObserver(this, "inner-window-destroyed", /* ownsWeak = */ false);
+  os->AddObserver(this, "audio-channel-agent-changed", /* ownsWeak = */ false);
 
   SetPriority(PROCESS_PRIORITY_FOREGROUND);
 }
 
 NS_IMETHODIMP
 ProcessPriorityManager::Observe(
   nsISupports* aSubject,
   const char* aTopic,
   const PRUnichar* aData)
 {
   if (!strcmp(aTopic, "content-document-global-created")) {
     OnContentDocumentGlobalCreated(aSubject);
   } else if (!strcmp(aTopic, "inner-window-destroyed")) {
     OnInnerWindowDestroyed();
   } else if (!strcmp(aTopic, "timer-callback")) {
     OnGracePeriodTimerFired();
+  } else if (!strcmp(aTopic, "audio-channel-agent-changed")) {
+    OnAudioChannelAgentChanged();
   } else {
     MOZ_ASSERT(false);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ProcessPriorityManager::HandleEvent(
   nsIDOMEvent* aEvent)
 {
   LOG("Got visibilitychange.");
   RecomputeNumVisibleWindows();
   return NS_OK;
 }
 
 void
+ProcessPriorityManager::OnAudioChannelAgentChanged()
+{
+  if (IsBackgroundPriority(mProcessPriority)) {
+    SetPriority(GetBackgroundPriority());
+  }
+}
+
+void
 ProcessPriorityManager::OnContentDocumentGlobalCreated(
   nsISupports* aOuterWindow)
 {
   // Get the inner window (the topic of content-document-global-created is
   // the /outer/ window!).
   nsCOMPtr<nsPIDOMWindow> outerWindow = do_QueryInterface(aOuterWindow);
   NS_ENSURE_TRUE_VOID(outerWindow);
   nsCOMPtr<nsPIDOMWindow> innerWindow = outerWindow->GetCurrentInnerWindow();
@@ -292,18 +321,17 @@ ProcessPriorityManager::RecomputeNumVisi
 
 void
 ProcessPriorityManager::SetPriority(ProcessPriority aPriority)
 {
   if (aPriority == mProcessPriority) {
     return;
   }
 
-  if (aPriority == PROCESS_PRIORITY_BACKGROUND ||
-      aPriority == PROCESS_PRIORITY_BACKGROUND_HOMESCREEN) {
+  if (IsBackgroundPriority(aPriority)) {
     // If this is a foreground --> background transition, give ourselves a
     // grace period before informing hal.
     uint32_t gracePeriodMS = Preferences::GetUint("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
     if (mGracePeriodTimer) {
       LOG("Grace period timer already active.");
       return;
     }
 
@@ -340,18 +368,17 @@ void
 ProcessPriorityManager::OnGracePeriodTimerFired()
 {
   LOG("Grace period timer fired; setting priority to %d.",
       mProcessPriority);
 
   // mProcessPriority should already be one of the BACKGROUND values: We set it
   // in SetPriority(BACKGROUND), and we canceled this timer if there was an
   // intervening SetPriority(FOREGROUND) call.
-  MOZ_ASSERT(mProcessPriority == PROCESS_PRIORITY_BACKGROUND ||
-             mProcessPriority == PROCESS_PRIORITY_BACKGROUND_HOMESCREEN);
+  MOZ_ASSERT(IsBackgroundPriority(mProcessPriority));
 
   mGracePeriodTimer = nullptr;
   hal::SetProcessPriority(getpid(), mProcessPriority);
 
   // We're in the background; dump as much memory as we can.
   nsCOMPtr<nsIMemoryReporterManager> mgr =
     do_GetService("@mozilla.org/memory-reporter-manager;1");
   if (mgr) {
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -65,16 +65,17 @@ enum SwitchState {
   NUM_SWITCH_STATE
 };
 
 typedef Observer<SwitchEvent> SwitchObserver;
 
 enum ProcessPriority {
   PROCESS_PRIORITY_BACKGROUND,
   PROCESS_PRIORITY_BACKGROUND_HOMESCREEN,
+  PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE,
   // Any priority greater than or equal to FOREGROUND is considered
   // "foreground" for the purposes of priority testing, for example
   // CurrentProcessIsForeground().
   PROCESS_PRIORITY_FOREGROUND,
   PROCESS_PRIORITY_MASTER,
   NUM_PROCESS_PRIORITY
 };
 
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -968,18 +968,23 @@ EnsureKernelLowMemKillerParamsSet()
   // notify_trigger is a single integer.   If we set notify_trigger=Z, then
   // we'll get notified when there are fewer than Z pages of memory free.  (See
   // GonkMemoryPressureMonitoring.cpp.)
 
   // Build the adj and minfree strings.
   nsAutoCString adjParams;
   nsAutoCString minfreeParams;
 
-  const char* priorityClasses[] =
-    {"master", "foreground", "background", "backgroundHomescreen"};
+  const char* priorityClasses[] = {
+    "master",
+    "foreground",
+    "background",
+    "backgroundHomescreen",
+    "backgroundPerceivable"
+  };
   for (size_t i = 0; i < NS_ARRAY_LENGTH(priorityClasses); i++) {
     int32_t oomScoreAdj;
     if (!NS_SUCCEEDED(Preferences::GetInt(nsPrintfCString(
           "hal.processPriorityManager.gonk.%sOomScoreAdjust",
           priorityClasses[i]).get(), &oomScoreAdj))) {
       continue;
     }
 
@@ -1034,16 +1039,19 @@ SetProcessPriority(int aPid, ProcessPrio
   const char* priorityStr = NULL;
   switch (aPriority) {
   case PROCESS_PRIORITY_BACKGROUND:
     priorityStr = "background";
     break;
   case PROCESS_PRIORITY_BACKGROUND_HOMESCREEN:
     priorityStr = "backgroundHomescreen";
     break;
+  case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
+    priorityStr = "backgroundPerceivable";
+    break;
   case PROCESS_PRIORITY_FOREGROUND:
     priorityStr = "foreground";
     break;
   case PROCESS_PRIORITY_MASTER:
     priorityStr = "master";
     break;
   default:
     MOZ_NOT_REACHED();