Bug 1337730 - part1: releaseCachedProcesses API for testing. r=mrbkap
authorGabor Krizsanits <gkrizsanits@mozilla.com>
Tue, 21 Feb 2017 11:27:23 +0100
changeset 344051 624ab6547d94741399aaadee25a858c2f5f8eb3c
parent 344050 59d4978e8726f56e6d0ad1752a489b8cb8fcf7f8
child 344052 f135648694f203a184f1684424bcfb87ee3ad773
push id31397
push userkwierso@gmail.com
push dateWed, 22 Feb 2017 01:35:07 +0000
treeherdermozilla-central@9f871c40b36f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1337730
milestone54.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 1337730 - part1: releaseCachedProcesses API for testing. r=mrbkap
dom/base/nsFrameMessageManager.cpp
dom/base/nsIMessageManager.idl
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -30,17 +30,17 @@
 #include "nsIDOMClassInfo.h"
 #include "xpcpublic.h"
 #include "mozilla/CycleCollectedJSContext.h"
 #include "mozilla/IntentionalCrash.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/MessagePort.h"
-#include "mozilla/dom/nsIContentParent.h"
+#include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/ProcessGlobal.h"
 #include "mozilla/dom/SameProcessMessageQueue.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/dom/DOMStringList.h"
@@ -773,16 +773,22 @@ nsFrameMessageManager::GetChildAt(uint32
 {
   *aMM = nullptr;
   nsCOMPtr<nsIMessageListenerManager> mm =
     do_QueryInterface(mChildManagers.SafeObjectAt(static_cast<uint32_t>(aIndex)));
   mm.swap(*aMM);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsFrameMessageManager::ReleaseCachedProcesses()
+{
+  ContentParent::ReleaseCachedProcesses();
+  return NS_OK;
+}
 
 // nsIContentFrameMessageManager
 
 NS_IMETHODIMP
 nsFrameMessageManager::Dump(const nsAString& aStr)
 {
 #ifdef ANDROID
   __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", NS_ConvertUTF16toUTF8(aStr).get());
--- a/dom/base/nsIMessageManager.idl
+++ b/dom/base/nsIMessageManager.idl
@@ -322,16 +322,22 @@ interface nsIMessageBroadcaster : nsIMes
    * Number of subordinate message managers.
    */
   readonly attribute unsigned long childCount;
 
   /**
    * Return a single subordinate message manager.
    */
   nsIMessageListenerManager getChildAt(in unsigned long aIndex);
+
+  /**
+   * Some processes are kept alive after their last tab/window are closed for testing
+   * (see dom.ipc.keepProcessesAlive). This function releases those.
+   */
+   void releaseCachedProcesses();
 };
 
 [scriptable, builtinclass, uuid(0e602c9e-1977-422a-a8e4-fe0d4a4f78d0)]
 interface nsISyncMessageSender : nsIMessageSender
 {
   /**
    * Like |sendAsyncMessage()|, except blocks the sender until all
    * listeners of the message have been invoked.  Returns an array
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -645,16 +645,42 @@ ContentParent::GetMaxProcessCount(const 
 }
 
 /*static*/ bool
 ContentParent::IsMaxProcessCountReached(const nsAString& aContentProcessType)
 {
   return GetPoolSize(aContentProcessType) >= GetMaxProcessCount(aContentProcessType);
 }
 
+/*static*/ void
+ContentParent::ReleaseCachedProcesses()
+{
+  // We might want to extend this for other process types as well in the future...
+  nsTArray<ContentParent*>& contentParents = GetOrCreatePool(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
+  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
+  nsTArray<ContentParent*> toRelease;
+
+  // Shuting down these processes will change the array so let's use another array for the removal.
+  for (auto* cp : contentParents) {
+    nsTArray<TabId> tabIds = cpm->GetTabParentsByProcessId(cp->mChildID);
+    if (!tabIds.Length()) {
+      toRelease.AppendElement(cp);
+    }
+  }
+
+  for (auto* cp : toRelease) {
+    // Start a soft shutdown.
+    cp->ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
+    // Make sure we don't select this process for new tabs.
+    cp->MarkAsDead();
+    // Make sure that this process is no longer accessible from JS by its message manager.
+    cp->ShutDownMessageManager();
+  }
+}
+
 /*static*/ already_AddRefed<ContentParent>
 ContentParent::RandomSelect(const nsTArray<ContentParent*>& aContentParents,
                             ContentParent* aOpener, int32_t aMaxContentParents)
 {
   uint32_t maxSelectable = std::min(static_cast<uint32_t>(aContentParents.Length()),
                                     static_cast<uint32_t>(aMaxContentParents));
   uint32_t startIdx = rand() % maxSelectable;
   uint32_t currIdx = startIdx;
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -148,16 +148,18 @@ public:
   static void JoinAllSubprocesses();
 
   static uint32_t GetPoolSize(const nsAString& aContentProcessType);
 
   static uint32_t GetMaxProcessCount(const nsAString& aContentProcessType);
 
   static bool IsMaxProcessCountReached(const nsAString& aContentProcessType);
 
+  static void ReleaseCachedProcesses();
+
   /**
    * Picks a random content parent from |aContentParents| with a given |aOpener|
    * respecting the index limit set by |aMaxContentParents|.
    * Returns null if non available.
    */
   static already_AddRefed<ContentParent>
   RandomSelect(const nsTArray<ContentParent*>& aContentParents,
                ContentParent* aOpener,