Bug 821440 - Allow the B2G homescreen to run in the background with a decreased oom_score_adj compared to vanilla background apps. r=cjones
authorJustin Lebar <justin.lebar@gmail.com>
Tue, 18 Dec 2012 21:37:35 -0500
changeset 125597 7da46060c2d9
parent 125596 c3722e35a871
child 125598 ecf4fc10c92a
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs821440
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 821440 - Allow the B2G homescreen to run in the background with a decreased oom_score_adj compared to vanilla background apps. r=cjones
b2g/app/b2g.js
content/base/src/nsFrameLoader.cpp
content/base/src/nsGkAtomList.h
dom/ipc/PBrowser.ipdl
dom/ipc/ProcessPriorityManager.cpp
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
hal/HalTypes.h
hal/gonk/GonkHal.cpp
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -549,16 +549,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.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);
 pref("hal.processPriorityManager.gonk.foregroundNice", 0);
 pref("hal.processPriorityManager.gonk.backgroundNice", 10);
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -2059,16 +2059,24 @@ nsFrameLoader::TryRemoteBrowser()
     context.SetTabContextForBrowserFrame(containingApp, scrollingBehavior);
   }
 
   mRemoteBrowser = ContentParent::CreateBrowserOrApp(context);
   if (mRemoteBrowser) {
     nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
     mRemoteBrowser->SetOwnerElement(element);
 
+    // If we're an app, send the frame element's mozapptype down to the child
+    // process.  This ends up in TabChild::GetAppType().
+    if (ownApp) {
+      nsAutoString appType;
+      mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapptype, appType);
+      mRemoteBrowser->SendSetAppType(appType);
+    }
+
     nsCOMPtr<nsIDocShellTreeItem> rootItem;
     parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
     nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
     nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
     NS_ABORT_IF_FALSE(rootChromeWin, "How did we not get a chrome window here?");
 
     nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
     rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -84,16 +84,17 @@ GK_ATOM(always, "always")
 GK_ATOM(ancestor, "ancestor")
 GK_ATOM(ancestorOrSelf, "ancestor-or-self")
 GK_ATOM(_and, "and")
 GK_ATOM(any, "any")
 GK_ATOM(mozapp, "mozapp")
 GK_ATOM(applet, "applet")
 GK_ATOM(applyImports, "apply-imports")
 GK_ATOM(applyTemplates, "apply-templates")
+GK_ATOM(mozapptype, "mozapptype")
 GK_ATOM(archive, "archive")
 GK_ATOM(area, "area")
 GK_ATOM(article, "article")
 GK_ATOM(ascending, "ascending")
 GK_ATOM(aside, "aside")
 GK_ATOM(aspectRatio, "aspect-ratio")
 GK_ATOM(assign, "assign")
 GK_ATOM(async, "async")
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -378,16 +378,30 @@ child:
      * the document.  The rendered image will be of size |renderSize|.
      */
     PDocumentRenderer(nsRect documentRect, gfxMatrix transform,
                       nsString bgcolor,
                       uint32_t renderFlags, bool flushLayout,
                       nsIntSize renderSize);
 
     /**
+     * Send the child its app type.  The app type identifies the kind of app
+     * shown in this PBrowser.  Currently, the only recognized app type is
+     * "homescreen".
+     *
+     * The value here corresponds to the "mozapptype" attribute on iframes.  For
+     * example, <iframe mozbrowser mozapp="..." mozapptype="homescreen">.
+     *
+     * Only app frames (i.e., frames with an app-id) should have a non-empty app
+     * type.  If you try to SetAppType() with a non-empty app type on a non-app
+     * PBrowserChild, we may assert.
+     */
+    SetAppType(nsString appType);
+
+    /**
      * Sent by the chrome process when it no longer wants this remote
      * <browser>.  The child side cleans up in response, then
      * finalizing its death by sending back __delete__() to the
      * parent.
      */
     Destroy();
 
 /*
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #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 "prlog.h"
 #include "nsWeakPtr.h"
 #include "nsXULAppAPI.h"
@@ -64,16 +66,43 @@ GetPPMLog()
 #define LOG(fmt, ...) \
   PR_LOG(GetPPMLog(), PR_LOG_DEBUG,                                     \
          ("[%d] ProcessPriorityManager - " fmt, getpid(), ##__VA_ARGS__))
 #else
 #define LOG(fmt, ...)
 #endif
 
 /**
+ * Get the appropriate backround priority for this process.
+ */
+ProcessPriority
+GetBackgroundPriority()
+{
+  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;
+      static_cast<TabChild*>(browsers[i])->GetAppType(appType);
+      if (appType.EqualsLiteral("homescreen")) {
+        isHomescreen = true;
+        break;
+      }
+    }
+  }
+
+  return isHomescreen ?
+         PROCESS_PRIORITY_BACKGROUND_HOMESCREEN :
+         PROCESS_PRIORITY_BACKGROUND;
+}
+
+/**
  * 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.
@@ -101,18 +130,18 @@ public:
 private:
   void SetPriority(ProcessPriority aPriority);
   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 even though hal still thinks we're a
+  // except that, when the grace period timer is active, mProcessPriority ==
+  // BACKGROUND or HOMESCREEN_BACKGROUND even though hal still thinks we're a
   // foreground process.
   ProcessPriority mProcessPriority;
 
   nsTArray<nsWeakPtr> mWindows;
   nsCOMPtr<nsITimer> mGracePeriodTimer;
   nsWeakPtr mMemoryMinimizerRunnable;
   TimeStamp mStartupTime;
 };
@@ -246,28 +275,29 @@ ProcessPriorityManager::RecomputeNumVisi
     allHidden = allHidden && hidden;
 
     // We could break out early from this loop if
     //   !hidden && mProcessPriority == BACKGROUND,
     // but then we might not clean up all the weak refs.
   }
 
   SetPriority(allHidden ?
-              PROCESS_PRIORITY_BACKGROUND :
+              GetBackgroundPriority() :
               PROCESS_PRIORITY_FOREGROUND);
 }
 
 void
 ProcessPriorityManager::SetPriority(ProcessPriority aPriority)
 {
   if (aPriority == mProcessPriority) {
     return;
   }
 
-  if (aPriority == PROCESS_PRIORITY_BACKGROUND) {
+  if (aPriority == PROCESS_PRIORITY_BACKGROUND ||
+      aPriority == PROCESS_PRIORITY_BACKGROUND_HOMESCREEN) {
     // 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;
     }
 
@@ -299,25 +329,26 @@ ProcessPriorityManager::SetPriority(Proc
     MOZ_ASSERT(false);
   }
 }
 
 void
 ProcessPriorityManager::OnGracePeriodTimerFired()
 {
   LOG("Grace period timer fired; setting priority to %d.",
-      PROCESS_PRIORITY_BACKGROUND);
+      mProcessPriority);
 
-  // mProcessPriority should already be BACKGROUND: We set it in
-  // SetPriority(BACKGROUND), and we canceled this timer if there was an
+  // 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);
+  MOZ_ASSERT(mProcessPriority == PROCESS_PRIORITY_BACKGROUND ||
+             mProcessPriority == PROCESS_PRIORITY_BACKGROUND_HOMESCREEN);
 
   mGracePeriodTimer = nullptr;
-  hal::SetProcessPriority(getpid(), PROCESS_PRIORITY_BACKGROUND);
+  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) {
     nsCOMPtr<nsICancelableRunnable> runnable =
       do_QueryReferent(mMemoryMinimizerRunnable);
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1688,16 +1688,24 @@ TabChild::RecvDestroy()
   }
 
   // XXX what other code in ~TabChild() should we be running here?
   DestroyWindow();
 
   return Send__delete__(this);
 }
 
+/* virtual */ bool
+TabChild::RecvSetAppType(const nsString& aAppType)
+{
+  MOZ_ASSERT_IF(!aAppType.IsEmpty(), HasOwnApp());
+  mAppType = aAppType;
+  return true;
+}
+
 PRenderFrameChild*
 TabChild::AllocPRenderFrame(ScrollingBehavior* aScrolling,
                             LayersBackend* aBackend,
                             int32_t* aMaxTextureSize,
                             uint64_t* aLayersId)
 {
     return new RenderFrameChild();
 }
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -302,16 +302,26 @@ public:
     /**
      * Signal to this TabChild that it should be made visible:
      * activated widget, retained layer tree, etc.  (Respectively,
      * made not visible.)
      */
     void MakeVisible();
     void MakeHidden();
 
+    virtual bool RecvSetAppType(const nsString& aAppType);
+
+    /**
+     * Get this object's app type.
+     *
+     * A TabChild's app type corresponds to the value of its frame element's
+     * "mozapptype" attribute.
+     */
+    void GetAppType(nsAString& aAppType) const { aAppType = mAppType; }
+
 protected:
     virtual PRenderFrameChild* AllocPRenderFrame(ScrollingBehavior* aScrolling,
                                                  LayersBackend* aBackend,
                                                  int32_t* aMaxTextureSize,
                                                  uint64_t* aLayersId) MOZ_OVERRIDE;
     virtual bool DeallocPRenderFrame(PRenderFrameChild* aFrame) MOZ_OVERRIDE;
     virtual bool RecvDestroy() MOZ_OVERRIDE;
 
@@ -403,16 +413,17 @@ private:
     nsIntSize mInnerSize;
     float mOldViewportWidth;
     nscolor mLastBackgroundColor;
     ScrollingBehavior mScrolling;
     bool mDidFakeShow;
     bool mNotified;
     bool mContentDocumentIsDisplayed;
     bool mTriedBrowserInit;
+    nsString mAppType;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 inline TabChild*
 GetTabChildFrom(nsIDocShell* aDocShell)
 {
     nsCOMPtr<nsITabChild> tc = do_GetInterface(aDocShell);
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -64,16 +64,17 @@ enum SwitchState {
   SWITCH_STATE_HEADPHONE,        // without microphone
   NUM_SWITCH_STATE
 };
 
 typedef Observer<SwitchEvent> SwitchObserver;
 
 enum ProcessPriority {
   PROCESS_PRIORITY_BACKGROUND,
+  PROCESS_PRIORITY_BACKGROUND_HOMESCREEN,
   PROCESS_PRIORITY_FOREGROUND,
   PROCESS_PRIORITY_MASTER,
   NUM_PROCESS_PRIORITY
 };
 
 /**
  * Used by ModifyWakeLock
  */
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -1041,17 +1041,18 @@ 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"};
+  const char* priorityClasses[] =
+    {"master", "foreground", "background", "backgroundHomescreen"};
   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;
     }
 
@@ -1103,16 +1104,19 @@ SetProcessPriority(int aPid, ProcessPrio
   // SetProcessPriority being called early in startup.
   EnsureKernelLowMemKillerParamsSet();
 
   const char* priorityStr = NULL;
   switch (aPriority) {
   case PROCESS_PRIORITY_BACKGROUND:
     priorityStr = "background";
     break;
+  case PROCESS_PRIORITY_BACKGROUND_HOMESCREEN:
+    priorityStr = "backgroundHomescreen";
+    break;
   case PROCESS_PRIORITY_FOREGROUND:
     priorityStr = "foreground";
     break;
   case PROCESS_PRIORITY_MASTER:
     priorityStr = "master";
     break;
   default:
     MOZ_NOT_REACHED();