Merge the electrolysis branch to mozilla-central.
authorBenjamin Smedberg <benjamin@smedbergs.us>
Fri, 19 Aug 2011 10:15:52 -0400
changeset 75531 d963476cbf67a6a4e10223806842fa8af28ff03d
parent 75530 1881f9b5f8b50fa29a6b4f9885948e9ce632d22b (current diff)
parent 73690 0ecd5149132ccd658fa372f95f51c1f244ec2f50 (diff)
child 75532 53cbb774bab3d4386eb0d004160e07c838f6550f
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone9.0a1
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)