Merge the electrolysis branch to mozilla-central.
authorBenjamin Smedberg <benjamin@smedbergs.us>
Fri, 19 Aug 2011 10:15:52 -0400
changeset 76842 d963476cbf67a6a4e10223806842fa8af28ff03d
parent 76839 1881f9b5f8b50fa29a6b4f9885948e9ce632d22b (current diff)
parent 76841 0ecd5149132ccd658fa372f95f51c1f244ec2f50 (diff)
child 76843 53cbb774bab3d4386eb0d004160e07c838f6550f
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone9.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
Merge the electrolysis branch to mozilla-central.
content/base/src/nsFrameMessageManager.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
modules/libpref/src/init/all.js
toolkit/components/places/History.cpp
toolkit/xre/nsAppRunner.cpp
widget/src/android/nsWindow.cpp
--- a/content/base/public/nsIFrameMessageManager.idl
+++ b/content/base/public/nsIFrameMessageManager.idl
@@ -113,18 +113,25 @@ interface nsIContentFrameMessageManager 
 };
 
 [uuid(9c48d557-92fe-4edb-95fc-bfe97e77bdc3)]
 interface nsIInProcessContentFrameMessageManager : nsIContentFrameMessageManager
 {
   [notxpcom] nsIContent getOwnerContent();
 };
 
-[scriptable, uuid(ed6522fd-ffb6-4920-b50d-cf629309616b)]
-interface nsIChromeFrameMessageManager : nsIFrameMessageManager
+[scriptable, uuid(6331bbca-2c9f-4766-b3c7-ae75554bf1ec)]
+interface nsITreeItemFrameMessageManager : nsIFrameMessageManager
+{
+  readonly attribute unsigned long childCount;
+  nsITreeItemFrameMessageManager getChildAt(in unsigned long aIndex);
+};
+
+[scriptable, uuid(23e6ef7b-8cc5-4e8b-9391-453440a3b858)]
+interface nsIChromeFrameMessageManager : nsITreeItemFrameMessageManager
 {
   /*
    * Load a script in the (remote) frame. aURL must be the absolute URL.
    * data: URLs are also supported. For example data:,dump("foo\n");
    * If aAllowDelayedLoad is true, script will be loaded when the
    * remote frame becomes available. Otherwise the script will be loaded
    * only if the frame is already available.
    */
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -1786,17 +1786,17 @@ nsFrameLoader::TryRemoteBrowser()
   nsCOMPtr<nsIXULWindow> window(do_GetInterface(parentOwner));
   if (!window) {
     return false;
   }
   if (NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
     return false;
   }
 
-  ContentParent* parent = ContentParent::GetSingleton();
+  ContentParent* parent = ContentParent::GetNewOrUsed();
   NS_ASSERTION(parent->IsAlive(), "Process parent should be alive; something is very wrong!");
   mRemoteBrowser = parent->CreateTab(chromeFlags);
   if (mRemoteBrowser) {
     nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
     mRemoteBrowser->SetOwnerElement(element);
 
     nsCOMPtr<nsIDocShellTreeItem> rootItem;
     parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -93,16 +93,18 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
                                          static_cast<nsIChromeFrameMessageManager*>(this)) :
                                        static_cast<nsIFrameMessageManager*>(
                                          static_cast<nsIContentFrameMessageManager*>(this))))
   /* nsIContentFrameMessageManager is accessible only in TabChildGlobal. */
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIContentFrameMessageManager,
                                      !mChrome && !mIsProcessManager)
   /* Message managers in child process support nsISyncMessageSender. */
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISyncMessageSender, !mChrome)
+  /* Message managers in chrome process support nsITreeItemFrameMessageManager. */
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsITreeItemFrameMessageManager, mChrome)
   /* Process message manager doesn't support nsIChromeFrameMessageManager. */
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIChromeFrameMessageManager,
                                      mChrome && !mIsProcessManager)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameMessageManager)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameMessageManager)
 
@@ -319,16 +321,34 @@ nsFrameMessageManager::GetContent(nsIDOM
 NS_IMETHODIMP
 nsFrameMessageManager::GetDocShell(nsIDocShell** aDocShell)
 {
   *aDocShell = nsnull;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsFrameMessageManager::GetChildCount(PRUint32* aChildCount)
+{
+  *aChildCount = static_cast<PRUint32>(mChildManagers.Count()); 
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::GetChildAt(PRUint32 aIndex, 
+                                  nsITreeItemFrameMessageManager** aMM)
+{
+  *aMM = nsnull;
+  nsCOMPtr<nsITreeItemFrameMessageManager> mm =
+    do_QueryInterface(mChildManagers.SafeObjectAt(static_cast<PRUint32>(aIndex)));
+  mm.swap(*aMM);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsFrameMessageManager::Btoa(const nsAString& aBinaryData,
                             nsAString& aAsciiBase64String)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFrameMessageManager::Atob(const nsAString& aAsciiString,
@@ -818,17 +838,17 @@ NS_IMPL_ISUPPORTS1(nsScriptCacheCleaner,
 nsFrameMessageManager* nsFrameMessageManager::sChildProcessManager = nsnull;
 nsFrameMessageManager* nsFrameMessageManager::sParentProcessManager = nsnull;
 
 bool SendAsyncMessageToChildProcess(void* aCallbackData,
                                     const nsAString& aMessage,
                                     const nsAString& aJSON)
 {
   mozilla::dom::ContentParent* cp =
-    mozilla::dom::ContentParent::GetSingleton(PR_FALSE);
+    static_cast<mozilla::dom::ContentParent*>(aCallbackData);
   NS_WARN_IF_FALSE(cp, "No child process!");
   if (cp) {
     return cp->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
   }
   return true;
 }
 
 bool SendSyncMessageToParentProcess(void* aCallbackData,
@@ -852,36 +872,56 @@ bool SendAsyncMessageToParentProcess(voi
   mozilla::dom::ContentChild* cc =
     mozilla::dom::ContentChild::GetSingleton();
   if (cc) {
     return cc->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
   }
   return true;
 }
 
+// This creates the global parent process message manager.
 nsresult
 NS_NewParentProcessMessageManager(nsIFrameMessageManager** aResult)
 {
   NS_ASSERTION(!nsFrameMessageManager::sParentProcessManager,
                "Re-creating sParentProcessManager");
   NS_ENSURE_TRUE(IsChromeProcess(), NS_ERROR_NOT_AVAILABLE);
   nsFrameMessageManager* mm = new nsFrameMessageManager(PR_TRUE,
                                                         nsnull,
-                                                        SendAsyncMessageToChildProcess,
+                                                        nsnull,
                                                         nsnull,
-                                                        &nsFrameMessageManager::sParentProcessManager,
+                                                        nsnull,
                                                         nsnull,
                                                         nsnull,
                                                         PR_FALSE,
                                                         PR_TRUE);
   NS_ENSURE_TRUE(mm, NS_ERROR_OUT_OF_MEMORY);
   nsFrameMessageManager::sParentProcessManager = mm;
   return CallQueryInterface(mm, aResult);
 }
 
+nsFrameMessageManager*
+nsFrameMessageManager::NewProcessMessageManager(mozilla::dom::ContentParent* aProcess)
+{
+  if (!nsFrameMessageManager::sParentProcessManager) {
+     nsCOMPtr<nsIFrameMessageManager> dummy;
+     NS_NewParentProcessMessageManager(getter_AddRefs(dummy));
+  }
+
+  nsFrameMessageManager* mm = new nsFrameMessageManager(PR_TRUE,
+                                                        nsnull,
+                                                        SendAsyncMessageToChildProcess,
+                                                        nsnull,
+                                                        aProcess,
+                                                        nsFrameMessageManager::sParentProcessManager,
+                                                        nsnull,
+                                                        PR_FALSE,
+                                                        PR_TRUE);
+  return mm;
+}
 
 nsresult
 NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
 {
   NS_ASSERTION(!nsFrameMessageManager::sChildProcessManager,
                "Re-creating sChildProcessManager");
   NS_ENSURE_TRUE(!IsChromeProcess(), NS_ERROR_NOT_AVAILABLE);
   nsFrameMessageManager* mm = new nsFrameMessageManager(PR_FALSE,
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -47,16 +47,22 @@
 #include "nsCycleCollectionParticipant.h"
 #include "nsTArray.h"
 #include "nsIPrincipal.h"
 #include "nsIXPConnect.h"
 #include "nsDataHashtable.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 
+namespace mozilla {
+namespace dom {
+class ContentParent;
+}
+}
+
 class nsAXPCNativeCallContext;
 struct JSContext;
 struct JSObject;
 
 struct nsMessageListenerInfo
 {
   nsCOMPtr<nsIFrameMessageListener> mListener;
   nsCOMPtr<nsIAtom> mMessage;
@@ -120,16 +126,20 @@ public:
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameMessageManager,
                                            nsIContentFrameMessageManager)
   NS_DECL_NSIFRAMEMESSAGEMANAGER
   NS_DECL_NSISYNCMESSAGESENDER
   NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
   NS_DECL_NSICHROMEFRAMEMESSAGEMANAGER
+  NS_DECL_NSITREEITEMFRAMEMESSAGEMANAGER
+
+  static nsFrameMessageManager*
+  NewProcessMessageManager(mozilla::dom::ContentParent* aProcess);
 
   nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
                           PRBool aSync, const nsAString& aJSON,
                           JSObject* aObjectsArray,
                           InfallibleTArray<nsString>* aJSONRetVal,
                           JSContext* aContext = nsnull);
   void AddChildManager(nsFrameMessageManager* aManager,
                        PRBool aLoadScripts = PR_TRUE);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -39,16 +39,17 @@
 
 #include "ContentParent.h"
 
 #include "TabParent.h"
 #include "CrashReporterParent.h"
 #include "History.h"
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/net/NeckoParent.h"
+#include "mozilla/Preferences.h"
 #include "nsHashPropertyBag.h"
 #include "nsIFilePicker.h"
 #include "nsIWindowWatcher.h"
 #include "nsIDOMWindow.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefBranch2.h"
 #include "nsIPrefService.h"
 #include "nsIPrefLocalizedString.h"
@@ -106,16 +107,17 @@
 #endif
 
 #include "nsIClipboard.h"
 #include "nsWidgetsCID.h"
 #include "nsISupportsPrimitives.h"
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 static const char* sClipboardTextFlavors[] = { kUnicodeMime };
 
+using mozilla::Preferences;
 using namespace mozilla::ipc;
 using namespace mozilla::net;
 using namespace mozilla::places;
 using mozilla::unused; // heh
 using base::KillProcess;
 
 namespace mozilla {
 namespace dom {
@@ -149,31 +151,49 @@ MemoryReportRequestParent::Recv__delete_
     return true;
 }
 
 MemoryReportRequestParent::~MemoryReportRequestParent()
 {
     MOZ_COUNT_DTOR(MemoryReportRequestParent);
 }
 
-ContentParent* ContentParent::gSingleton;
+nsTArray<ContentParent*>* ContentParent::gContentParents;
 
 ContentParent*
-ContentParent::GetSingleton(PRBool aForceNew)
+ContentParent::GetNewOrUsed()
 {
-    if (gSingleton && !gSingleton->IsAlive())
-        gSingleton = nsnull;
-    
-    if (!gSingleton && aForceNew) {
-        nsRefPtr<ContentParent> parent = new ContentParent();
-        gSingleton = parent;
-        parent->Init();
+    if (!gContentParents)
+        gContentParents = new nsTArray<ContentParent*>();
+
+    PRInt32 maxContentProcesses = Preferences::GetInt("dom.ipc.processCount", 1);
+    if (maxContentProcesses < 1)
+        maxContentProcesses = 1;
+
+    if (gContentParents->Length() >= PRUint32(maxContentProcesses)) {
+        ContentParent* p = (*gContentParents)[rand() % gContentParents->Length()];
+        NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in gContentParents?");
+        return p;
+    }
+        
+    nsRefPtr<ContentParent> p = new ContentParent();
+    p->Init();
+    gContentParents->AppendElement(p);
+    return p;
+}
+
+void
+ContentParent::GetAll(nsTArray<ContentParent*>& aArray)
+{
+    if (!gContentParents) {
+        aArray.Clear();
+        return;
     }
 
-    return gSingleton;
+    aArray = *gContentParents;
 }
 
 void
 ContentParent::Init()
 {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
         obs->AddObserver(this, "xpcom-shutdown", PR_FALSE);
@@ -190,17 +210,17 @@ ContentParent::Init()
     }
     nsCOMPtr<nsIThreadInternal>
             threadInt(do_QueryInterface(NS_GetCurrentThread()));
     if (threadInt) {
         threadInt->GetObserver(getter_AddRefs(mOldObserver));
         threadInt->SetObserver(this);
     }
     if (obs) {
-        obs->NotifyObservers(nsnull, "ipc:content-created", nsnull);
+        obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created", nsnull);
     }
 
 #ifdef ACCESSIBILITY
     // If accessibility is running in chrome process then start it in content
     // process.
     if (nsIPresShell::IsAccessibilityActive()) {
         SendActivateA11y();
     }
@@ -269,16 +289,18 @@ ContentParent::ActorDestroy(ActorDestroy
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "memory-pressure");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-memory-reporter-request");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC);
 #ifdef ACCESSIBILITY
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "a11y-init-or-shutdown");
 #endif
     }
 
+    mMessageManager->Disconnect();
+
     // clear the child memory reporters
     InfallibleTArray<MemoryReport> empty;
     SetChildMemoryReporters(empty);
 
     // remove the global remote preferences observers
     nsCOMPtr<nsIPrefBranch2> prefs 
             (do_GetService(NS_PREFSERVICE_CONTRACTID));
     if (prefs) { 
@@ -290,16 +312,24 @@ ContentParent::ActorDestroy(ActorDestroy
 
     nsCOMPtr<nsIThreadInternal>
         threadInt(do_QueryInterface(NS_GetCurrentThread()));
     if (threadInt)
         threadInt->SetObserver(mOldObserver);
     if (mRunToCompletionDepth)
         mRunToCompletionDepth = 0;
 
+    if (gContentParents) {
+        gContentParents->RemoveElement(this);
+        if (!gContentParents->Length()) {
+            delete gContentParents;
+            gContentParents = NULL;
+        }
+    }
+
     mIsAlive = false;
 
     if (obs) {
         nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
         props->Init();
 
         if (AbnormalShutdown == why) {
             props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), PR_TRUE);
@@ -357,38 +387,38 @@ ContentParent::DestroyTestShell(TestShel
 }
 
 ContentParent::ContentParent()
     : mGeolocationWatchID(-1)
     , mRunToCompletionDepth(0)
     , mShouldCallUnblockChild(false)
     , mIsAlive(true)
     , mProcessStartTime(time(NULL))
+    , mSendPermissionUpdates(false)
 {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content);
     mSubprocess->AsyncLaunch();
     Open(mSubprocess->GetChannel(), mSubprocess->GetChildProcessHandle());
 
     nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
     nsChromeRegistryChrome* chromeRegistry =
         static_cast<nsChromeRegistryChrome*>(registrySvc.get());
     chromeRegistry->SendRegisteredChrome(this);
+    mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
 }
 
 ContentParent::~ContentParent()
 {
     if (OtherProcess())
         base::CloseProcessHandle(OtherProcess());
 
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-    //If the previous content process has died, a new one could have
-    //been started since.
-    if (gSingleton == this)
-        gSingleton = nsnull;
+    NS_ASSERTION(!gContentParents || !gContentParents->Contains(this),
+                 "Should have been removed in ActorDestroy");
 }
 
 bool
 ContentParent::IsAlive()
 {
     return mIsAlive;
 }
 
@@ -454,17 +484,17 @@ ContentParent::RecvReadPermissions(Infal
         PRInt64 expireTime;
         perm->GetExpireTime(&expireTime);
 
         aPermissions->AppendElement(IPC::Permission(host, type, capability,
                                                     expireType, expireTime));
     }
 
     // Ask for future changes
-    permissionManager->ChildRequestPermissions();
+    mSendPermissionUpdates = true;
 #endif
 
     return true;
 }
 
 bool
 ContentParent::RecvGetIndexedDBDirectory(nsString* aDirectory)
 {
@@ -1078,28 +1108,28 @@ ContentParent::RecvShowAlertNotification
 
     return true;
 }
 
 bool
 ContentParent::RecvSyncMessage(const nsString& aMsg, const nsString& aJSON,
                                InfallibleTArray<nsString>* aRetvals)
 {
-  nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sParentProcessManager;
+  nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
                         aMsg,PR_TRUE, aJSON, nsnull, aRetvals);
   }
   return true;
 }
 
 bool
 ContentParent::RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON)
 {
-  nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sParentProcessManager;
+  nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
                         aMsg, PR_FALSE, aJSON, nsnull, nsnull);
   }
   return true;
 }
 
 bool
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -50,16 +50,17 @@
 #include "nsNetUtil.h"
 #include "nsIPrefService.h"
 #include "nsIPermissionManager.h"
 #include "nsIDOMGeoPositionCallback.h"
 #include "nsIDeviceMotion.h"
 #include "nsIMemoryReporter.h"
 #include "nsCOMArray.h"
 
+class nsFrameMessageManager;
 namespace mozilla {
 
 namespace ipc {
 class TestShellParent;
 }
 
 namespace dom {
 
@@ -72,22 +73,18 @@ class ContentParent : public PContentPar
                     , public nsIDOMGeoPositionCallback
                     , public nsIDeviceMotionListener
 {
 private:
     typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
     typedef mozilla::ipc::TestShellParent TestShellParent;
 
 public:
-    static ContentParent* GetSingleton(PRBool aForceNew = PR_TRUE);
-
-#if 0
-    // TODO: implement this somewhere!
-    static ContentParent* FreeSingleton();
-#endif
+    static ContentParent* GetNewOrUsed();
+    static void GetAll(nsTArray<ContentParent*>& aArray);
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
     NS_DECL_NSITHREADOBSERVER
     NS_DECL_NSIDOMGEOPOSITIONCALLBACK
     NS_DECL_NSIDEVICEMOTIONLISTENER
 
     TabParent* CreateTab(PRUint32 aChromeFlags);
@@ -97,22 +94,26 @@ public:
 
     void ReportChildAlreadyBlocked();
     bool RequestRunToCompletion();
 
     bool IsAlive();
 
     void SetChildMemoryReporters(const InfallibleTArray<MemoryReport>& report);
 
+    bool NeedsPermissionsUpdate() {
+        return mSendPermissionUpdates;
+    }
+
 protected:
     void OnChannelConnected(int32 pid);
     virtual void ActorDestroy(ActorDestroyReason why);
 
 private:
-    static ContentParent* gSingleton;
+    static nsTArray<ContentParent*>* gContentParents;
 
     // Hide the raw constructor methods since we don't want client code
     // using them.
     using PContentParent::SendPBrowserConstructor;
     using PContentParent::SendPTestShellConstructor;
 
     ContentParent();
     virtual ~ContentParent();
@@ -225,14 +226,18 @@ private:
     // registered in the child process.  To update this, one
     // can broadcast the topic "child-memory-reporter-request" using
     // the nsIObserverService.
     nsCOMArray<nsIMemoryReporter> mMemoryReporters;
 
     bool mIsAlive;
     nsCOMPtr<nsIPrefServiceInternal> mPrefService;
     time_t mProcessStartTime;
+
+    bool mSendPermissionUpdates;
+
+    nsRefPtr<nsFrameMessageManager> mMessageManager;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/ipc/test.xul
+++ b/dom/ipc/test.xul
@@ -101,24 +101,47 @@
         var cpm = Components.classes["@mozilla.org/childprocessmessagemanager;1"]
                             .getService(Components.interfaces.nsISyncMessageSender);  
       } catch (ex) {
         didThrow = true;
       }
       if (!didThrow) {
         alert("One shouldn't be able to create content process message manager in chrome process!");
       }
+      var tppm = ppm.QueryInterface(Components.interfaces.nsITreeItemFrameMessageManager);
+      if (tppm.childCount != 1) {
+        alert("Should have one child process!");
+      }
+      var childprocessmm = tppm.getChildAt(0);
+      
+      childprocessmm.addMessageListener("ppm-sync",
+        function(m) {
+          if (m.target != childprocessmm) alert("Wrong target!");
+          document.getElementById("messageLog").value += "[SYNC1 PPM]"; 
+        }
+      );
+      
       ppm.addMessageListener("ppm-sync",
         function(m) {
-          document.getElementById("messageLog").value += "[SYNC PPM]"; 
+          // Check that global process message manager gets the per-process mm as target.
+          if (m.target != childprocessmm) alert("Wrong target!");
+          document.getElementById("messageLog").value += "[SYNC2 PPM]"; 
+        }
+      );
+      childprocessmm.addMessageListener("ppm-async",
+        function(m) {
+          if (m.target != childprocessmm) alert("Wrong target!");
+          document.getElementById("messageLog").value += "[ASYNC1 PPM]"; 
         }
       );
       ppm.addMessageListener("ppm-async",
         function(m) {
-          document.getElementById("messageLog").value += "[ASYNC PPM]"; 
+          // Check that global process message manager gets the per-process mm as target.
+          if (m.target != childprocessmm) alert("Wrong target!");
+          document.getElementById("messageLog").value += "[ASYNC2 PPM]"; 
         }
       );
       messageManager.loadFrameScript("chrome://global/content/remote-test-ipc.js", true);
       ppm.sendAsyncMessage("cpm-async");
 
       // 2. Test that adding message listener works, and that receiving a sync message works.
       messageManager.addMessageListener("linkclick",
         function(m) {
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -84,33 +84,16 @@ ChildProcess()
       NS_RUNTIMEABORT("Content Process is NULL!");
     return cpc;
   }
 
   return nsnull;
 }
 
 
-/**
- * @returns The parent process object, or if we are not in the parent
- *          process, nsnull.
- */
-static ContentParent*
-ParentProcess()
-{
-  if (!IsChildProcess()) {
-    ContentParent* cpc = ContentParent::GetSingleton();
-    if (!cpc)
-      NS_RUNTIMEABORT("Content Process is NULL!");
-    return cpc;
-  }
-
-  return nsnull;
-}
-
 #define ENSURE_NOT_CHILD_PROCESS_(onError) \
   PR_BEGIN_MACRO \
   if (IsChildProcess()) { \
     NS_ERROR("Cannot perform action in content process!"); \
     onError \
   } \
   PR_END_MACRO
 
@@ -165,17 +148,16 @@ static const char kPermissionsFileName[]
 static const char kHostpermFileName[] = "hostperm.1";
 
 static const char kPermissionChangeNotification[] = PERM_CHANGE_NOTIFICATION;
 
 NS_IMPL_ISUPPORTS3(nsPermissionManager, nsIPermissionManager, nsIObserver, nsISupportsWeakReference)
 
 nsPermissionManager::nsPermissionManager()
  : mLargestID(0)
- , mUpdateChildProcess(PR_FALSE)
 {
 }
 
 nsPermissionManager::~nsPermissionManager()
 {
   RemoveAllFromMemory();
 }
 
@@ -462,22 +444,26 @@ nsPermissionManager::AddInternal(const n
                                  PRUint32              aPermission,
                                  PRInt64               aID,
                                  PRUint32              aExpireType,
                                  PRInt64               aExpireTime,
                                  NotifyOperationType   aNotifyOperation,
                                  DBOperationType       aDBOperation)
 {
   if (!IsChildProcess()) {
-    // In the parent, send the update now, if the child is ready
-    if (mUpdateChildProcess) {
-      IPC::Permission permission((aHost),
-                                 (aType),
-                                 aPermission, aExpireType, aExpireTime);
-      unused << ParentProcess()->SendAddPermission(permission);
+    IPC::Permission permission((aHost),
+                               (aType),
+                               aPermission, aExpireType, aExpireTime);
+
+    nsTArray<ContentParent*> cplist;
+    ContentParent::GetAll(cplist);
+    for (PRUint32 i = 0; i < cplist.Length(); ++i) {
+      ContentParent* cp = cplist[i];
+      if (cp->NeedsPermissionsUpdate())
+        unused << cp->SendAddPermission(permission);
     }
   }
 
   if (!gHostArena) {
     gHostArena = new PLArenaPool;
     if (!gHostArena)
       return NS_ERROR_OUT_OF_MEMORY;    
     PL_INIT_ARENA_POOL(gHostArena, "PermissionHostArena", HOST_ARENA_SIZE);
--- a/extensions/cookie/nsPermissionManager.h
+++ b/extensions/cookie/nsPermissionManager.h
@@ -245,26 +245,15 @@ private:
   nsCOMPtr<mozIStorageStatement> mStmtUpdate;
 
   nsTHashtable<nsHostEntry>    mHostTable;
   // a unique, monotonically increasing id used to identify each database entry
   PRInt64                      mLargestID;
 
   // An array to store the strings identifying the different types.
   nsTArray<nsCString>          mTypeArray;
-
-  // Whether we should update the child process with every change to a
-  // permission. This is set to true once the child is ready to receive
-  // such updates.
-  PRBool                       mUpdateChildProcess;
-
-public:
-  void ChildRequestPermissions()
-  {
-    mUpdateChildProcess = PR_TRUE;
-  }
 };
 
 // {4F6B5E00-0C36-11d5-A535-0010A401EB10}
 #define NS_PERMISSIONMANAGER_CID \
 { 0x4f6b5e00, 0xc36, 0x11d5, { 0xa5, 0x35, 0x0, 0x10, 0xa4, 0x1, 0xeb, 0x10 } }
 
 #endif /* nsPermissionManager_h__ */
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1477,16 +1477,18 @@ pref("dom.ipc.plugins.java.enabled", fal
 // Linux plugins using Xt instead of Xembed don't work out-of-process yet.
 pref("dom.ipc.plugins.enabled.libvlcplugin.so", false);
 pref("dom.ipc.plugins.enabled.nppdf.so", false);
 pref("dom.ipc.plugins.enabled.602plugin.so", false);
 #endif
 #endif
 #endif
 
+pref("dom.ipc.processCount", 1);
+
 pref("svg.smil.enabled", true);
 
 pref("font.minimum-size.ar", 0);
 pref("font.minimum-size.x-armn", 0);
 pref("font.minimum-size.x-beng", 0);
 pref("font.minimum-size.x-baltic", 0);
 pref("font.minimum-size.x-central-euro", 0);
 pref("font.minimum-size.zh-CN", 0);
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -51,26 +51,28 @@
 
 #include "mozilla/storage.h"
 #include "mozilla/dom/Link.h"
 #include "nsDocShellCID.h"
 #include "mozilla/Services.h"
 #include "nsThreadUtils.h"
 #include "nsNetUtil.h"
 #include "nsIXPConnect.h"
+#include "mozilla/unused.h"
 #include "mozilla/Util.h"
 #include "nsContentUtils.h"
 
 // Initial size for the cache holding visited status observers.
 #define VISIT_OBSERVERS_INITIAL_CACHE_SIZE 128
 
 // Topic used to notify that work in mozIAsyncHistory::updatePlaces is done.
 #define TOPIC_UPDATEPLACES_COMPLETE "places-updatePlaces-complete"
 
 using namespace mozilla::dom;
+using mozilla::unused;
 
 namespace mozilla {
 namespace places {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Global Defines
 
 #define URI_VISITED "visited"
@@ -1283,20 +1285,21 @@ History::~History()
 void
 History::NotifyVisited(nsIURI* aURI)
 {
   NS_ASSERTION(aURI, "Ruh-roh!  A NULL URI was passed to us!");
 
   nsAutoScriptBlocker scriptBlocker;
 
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
-    mozilla::dom::ContentParent* cpp = 
-      mozilla::dom::ContentParent::GetSingleton(PR_FALSE);
-    if (cpp)
-      (void)cpp->SendNotifyVisited(aURI);
+    nsTArray<ContentParent*> cplist;
+    ContentParent::GetAll(cplist);
+    for (PRUint32 i = 0; i < cplist.Length(); ++i) {
+      unused << cplist[i]->SendNotifyVisited(aURI);
+    }
   }
 
   // If the hash table has not been initialized, then we have nothing to notify
   // about.
   if (!mObservers.IsInitialized()) {
     return;
   }
 
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -116,16 +116,19 @@
 #include "nsIXULRuntime.h"
 #include "nsPIDOMWindow.h"
 #include "nsIBaseWindow.h"
 #include "nsIWidget.h"
 #include "nsIDocShell.h"
 #include "nsAppShellCID.h"
 
 #include "mozilla/FunctionTimer.h"
+#include "mozilla/unused.h"
+
+using mozilla::unused;
 
 #ifdef XP_WIN
 #include "nsIWinAppHelper.h"
 #include <windows.h>
 #include "cairo/cairo-features.h"
 
 #ifndef PROCESS_DEP_ENABLE
 #define PROCESS_DEP_ENABLE 0x1
@@ -746,19 +749,17 @@ nsXULAppInfo::GetProcessType(PRUint32* a
 }
 
 NS_IMETHODIMP
 nsXULAppInfo::EnsureContentProcess()
 {
   if (XRE_GetProcessType() != GeckoProcessType_Default)
     return NS_ERROR_NOT_AVAILABLE;
 
-  ContentParent* c = ContentParent::GetSingleton();
-  if (!c)
-    return NS_ERROR_NOT_AVAILABLE;
+  unused << ContentParent::GetNewOrUsed();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULAppInfo::InvalidateCachesOnRestart()
 {
   nsCOMPtr<nsIFile> file;
   nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP, 
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -707,17 +707,17 @@ XRE_ShutdownChildProcess()
 #endif // XP_MACOSX
 }
 
 namespace {
 TestShellParent* gTestShellParent = nsnull;
 TestShellParent* GetOrCreateTestShellParent()
 {
     if (!gTestShellParent) {
-        ContentParent* parent = ContentParent::GetSingleton();
+        ContentParent* parent = ContentParent::GetNewOrUsed();
         NS_ENSURE_TRUE(parent, nsnull);
         gTestShellParent = parent->CreateTestShell();
         NS_ENSURE_TRUE(gTestShellParent, nsnull);
     }
     return gTestShellParent;
 }
 }
 
@@ -753,17 +753,18 @@ XRE_GetChildGlobalObject(JSContext* aCx,
     return tsp && tsp->GetGlobalJSObject(aCx, aGlobalP);
 }
 
 bool
 XRE_ShutdownTestShell()
 {
   if (!gTestShellParent)
     return true;
-  return ContentParent::GetSingleton()->DestroyTestShell(gTestShellParent);
+  return static_cast<ContentParent*>(gTestShellParent->Manager())->
+    DestroyTestShell(gTestShellParent);
 }
 
 #ifdef MOZ_X11
 void
 XRE_InstallX11ErrorHandler()
 {
   InstallX11ErrorHandler();
 }
--- a/widget/src/android/nsWindow.cpp
+++ b/widget/src/android/nsWindow.cpp
@@ -90,18 +90,18 @@ class ContentCreationNotifier : public n
 {
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD Observe(nsISupports* aSubject,
                        const char* aTopic,
                        const PRUnichar* aData)
     {
         if (!strcmp(aTopic, "ipc:content-created")) {
-            ContentParent *cp = ContentParent::GetSingleton(PR_FALSE);
-            NS_ABORT_IF_FALSE(cp, "Must have content process if notified of its creation");
+            nsCOMPtr<nsIObserver> cpo = do_QueryInterface(aSubject);
+            ContentParent* cp = static_cast<ContentParent*>(cpo.get());
             unused << cp->SendScreenSizeChanged(gAndroidScreenBounds);
         } else if (!strcmp(aTopic, "xpcom-shutdown")) {
             nsCOMPtr<nsIObserverService>
                 obs(do_GetService("@mozilla.org/observer-service;1"));
             if (obs) {
                 obs->RemoveObserver(static_cast<nsIObserver*>(this),
                                     "xpcom-shutdown");
                 obs->RemoveObserver(static_cast<nsIObserver*>(this),
@@ -769,19 +769,20 @@ nsWindow::OnGlobalAndroidEvent(AndroidGe
 
             gAndroidScreenBounds.width = newScreenWidth;
             gAndroidScreenBounds.height = newScreenHeight;
 
             if (XRE_GetProcessType() != GeckoProcessType_Default)
                 break;
 
             // Tell the content process the new screen size.
-            ContentParent *cp = ContentParent::GetSingleton(PR_FALSE);
-            if (cp)
-                unused << cp->SendScreenSizeChanged(gAndroidScreenBounds);
+            nsTArray<ContentParent*> cplist;
+            ContentParent::GetAll(cplist);
+            for (PRUint32 i = 0; i < cplist.Length(); ++i)
+                unused << cplist[i]->SendScreenSizeChanged(gAndroidScreenBounds);
 
             if (gContentCreationNotifier)
                 break;
 
             // If the content process is not created yet, wait until it's
             // created and then tell it the screen size.
             nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1");
             if (!obs)