Bug 793105 - Add a "backgroundPerceivable" class for audio-channel-content. r=jlebar,roc
authorKan-Ru Chen (陳侃如) <kanru@kanru.info>
Sat, 05 Jan 2013 13:03:51 +0800
changeset 117697 dcd2c2de5e65da154a6ebf6fe5da17ce45b3a7b3
parent 117696 c8b2ab4ec62dda386e34ef8415e30e67b605358f
child 117698 ea909ce6007b1c67b3bb9ef0d197ef8845399e9c
push id20652
push userkchen@mozilla.com
push dateSat, 05 Jan 2013 05:04:02 +0000
treeherdermozilla-inbound@dcd2c2de5e65 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar, roc
bugs793105
milestone20.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 793105 - Add a "backgroundPerceivable" class for audio-channel-content. r=jlebar,roc
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
@@ -539,16 +539,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
@@ -234,16 +234,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
@@ -1041,18 +1041,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;
     }
 
@@ -1107,16 +1112,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();