Bug 585173 - Process message manager. r=dougt a=blocking-fennec

This commit is contained in:
Olli Pettay 2010-08-31 11:58:35 -07:00
parent 250583af1b
commit 37754ca52c
15 changed files with 271 additions and 14 deletions

View File

@ -315,6 +315,20 @@
#define NS_GLOBALMESSAGEMANAGER_CONTRACTID \
"@mozilla.org/globalmessagemanager;1"
#define NS_PARENTPROCESSMESSAGEMANAGER_CID \
{ /* 2a058404-fb85-44ec-8cfd-e8cbdc988dc1 */ \
0x2a058404, 0xfb85, 0x44ec, \
{ 0x8c, 0xfd, 0xe8, 0xcb, 0xdc, 0x98, 0x8d, 0xc1 } }
#define NS_PARENTPROCESSMESSAGEMANAGER_CONTRACTID \
"@mozilla.org/parentprocessmessagemanager;1"
#define NS_CHILDPROCESSMESSAGEMANAGER_CID \
{ /* fe0ff7c3-8e97-448b-9a8a-86afdb9fbbb6 */ \
0xfe0ff7c3, 0x8e97, 0x448b, \
{ 0x9a, 0x8a, 0x86, 0xaf, 0xdb, 0x9f, 0xbb, 0xb6 } }
#define NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID \
"@mozilla.org/childprocessmessagemanager;1"
// {f96f5ec9-755b-447e-b1f3-717d1a84bb41}
#define NS_PLUGINDOCUMENT_CID \
{ 0xf96f5ec9, 0x755b, 0x447e, { 0xb1, 0xf3, 0x71, 0x7d, 0x1a, 0x84, 0xbb, 0x41 } }

View File

@ -72,16 +72,18 @@ interface nsIFrameMessageManager : nsISupports
void sendAsyncMessage(/*in messageName, in JSON*/);
};
[scriptable, uuid(c56e85b8-6736-4ae2-ae90-66bcef952a82)]
interface nsIContentFrameMessageManager : nsIFrameMessageManager
[scriptable, uuid(cdb1a40b-9862-426c-ae8a-f5ab84e20e32)]
interface nsISyncMessageSender : nsIFrameMessageManager
{
/**
* @note sending JS objects isn't implemented yet.
*
* Returns an array of JSON objects.
*/
void sendSyncMessage(/*in messageName, in JSON, in an array of JS objects,*/);
void sendSyncMessage(/*in messageName, in JSON*/);
};
[scriptable, uuid(c56e85b8-6736-4ae2-ae90-66bcef952a82)]
interface nsIContentFrameMessageManager : nsISyncMessageSender
{
/**
* The current top level window in the frame or null.
*/

View File

@ -35,6 +35,10 @@
*
* ***** END LICENSE BLOCK ***** */
#ifdef MOZ_IPC
#include "ContentChild.h"
#include "ContentParent.h"
#endif
#include "jscntxt.h"
#include "nsFrameMessageManager.h"
#include "nsContentUtils.h"
@ -46,6 +50,17 @@
#include "nsNetUtil.h"
#include "nsScriptLoader.h"
#include "nsIJSContextStack.h"
#include "nsIXULRuntime.h"
static PRBool
IsChromeProcess()
{
nsCOMPtr<nsIXULRuntime> rt = do_GetService("@mozilla.org/xre/runtime;1");
NS_ABORT_IF_FALSE(rt, "We must have a xre runtime");
PRUint32 type;
rt->GetProcessType(&type);
return type == nsIXULRuntime::PROCESS_TYPE_DEFAULT;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameMessageManager)
@ -76,8 +91,14 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameMessageManager)
static_cast<nsIChromeFrameMessageManager*>(this)) :
static_cast<nsIFrameMessageManager*>(
static_cast<nsIContentFrameMessageManager*>(this))))
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIContentFrameMessageManager, !mChrome)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIChromeFrameMessageManager, mChrome)
/* 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)
/* Process message manager doesn't support nsIChromeFrameMessageManager. */
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIChromeFrameMessageManager,
mChrome && !mIsProcessManager)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsFrameMessageManager,
@ -307,6 +328,9 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
JSContext* aContext)
{
JSContext* ctx = mContext ? mContext : aContext;
if (!ctx) {
nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&ctx);
}
if (mListeners.Length()) {
nsCOMPtr<nsIAtom> name = do_GetAtom(aMessage);
nsRefPtr<nsFrameMessageManager> kungfuDeathGrip(this);
@ -496,6 +520,7 @@ nsFrameMessageManager::Disconnect(PRBool aRemoveFromParent)
nsresult
NS_NewGlobalMessageManager(nsIChromeFrameMessageManager** aResult)
{
NS_ENSURE_TRUE(IsChromeProcess(), NS_ERROR_NOT_AVAILABLE);
nsFrameMessageManager* mm = new nsFrameMessageManager(PR_TRUE,
nsnull,
nsnull,
@ -681,3 +706,96 @@ nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL)
NS_IMPL_ISUPPORTS1(nsScriptCacheCleaner, nsIObserver)
nsFrameMessageManager* nsFrameMessageManager::sChildProcessManager = nsnull;
nsFrameMessageManager* nsFrameMessageManager::sParentProcessManager = nsnull;
#ifdef MOZ_IPC
bool SendAsyncMessageToChildProcess(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON)
{
mozilla::dom::ContentParent* cp =
mozilla::dom::ContentParent::GetSingleton(PR_FALSE);
NS_WARN_IF_FALSE(cp, "No child process!");
if (cp) {
return cp->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
}
return true;
}
bool SendSyncMessageToParentProcess(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON,
nsTArray<nsString>* aJSONRetVal)
{
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
if (cc) {
return
cc->SendSyncMessage(nsString(aMessage), nsString(aJSON), aJSONRetVal);
}
return true;
}
bool SendAsyncMessageToParentProcess(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON)
{
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
if (cc) {
return cc->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
}
return true;
}
#endif
nsresult
NS_NewParentProcessMessageManager(nsIFrameMessageManager** aResult)
{
NS_ASSERTION(!nsFrameMessageManager::sParentProcessManager,
"Re-creating sParentProcessManager");
#ifdef MOZ_IPC
NS_ENSURE_TRUE(IsChromeProcess(), NS_ERROR_NOT_AVAILABLE);
nsFrameMessageManager* mm = new nsFrameMessageManager(PR_TRUE,
nsnull,
SendAsyncMessageToChildProcess,
nsnull,
&nsFrameMessageManager::sParentProcessManager,
nsnull,
nsnull,
PR_FALSE,
PR_TRUE);
NS_ENSURE_TRUE(mm, NS_ERROR_OUT_OF_MEMORY);
nsFrameMessageManager::sParentProcessManager = mm;
return CallQueryInterface(mm, aResult);
#else
return NS_ERROR_NOT_AVAILABLE;
#endif
}
nsresult
NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
{
NS_ASSERTION(!nsFrameMessageManager::sChildProcessManager,
"Re-creating sChildProcessManager");
#ifdef MOZ_IPC
NS_ENSURE_TRUE(!IsChromeProcess(), NS_ERROR_NOT_AVAILABLE);
nsFrameMessageManager* mm = new nsFrameMessageManager(PR_FALSE,
SendSyncMessageToParentProcess,
SendAsyncMessageToParentProcess,
nsnull,
&nsFrameMessageManager::sChildProcessManager,
nsnull,
nsnull,
PR_FALSE,
PR_TRUE);
NS_ENSURE_TRUE(mm, NS_ERROR_OUT_OF_MEMORY);
nsFrameMessageManager::sChildProcessManager = mm;
return CallQueryInterface(mm, aResult);
#else
return NS_ERROR_NOT_AVAILABLE;
#endif
}

View File

@ -82,14 +82,16 @@ public:
void* aCallbackData,
nsFrameMessageManager* aParentManager,
JSContext* aContext,
PRBool aGlobal = PR_FALSE)
: mChrome(aChrome), mGlobal(aGlobal), mParentManager(aParentManager),
PRBool aGlobal = PR_FALSE,
PRBool aProcessManager = PR_FALSE)
: mChrome(aChrome), mGlobal(aGlobal), mIsProcessManager(aProcessManager),
mParentManager(aParentManager),
mSyncCallback(aSyncCallback), mAsyncCallback(aAsyncCallback),
mLoadScriptCallback(aLoadScriptCallback), mCallbackData(aCallbackData),
mContext(aContext)
{
NS_ASSERTION(mContext || (aChrome && !aParentManager),
"Should have mContext in non-global manager!");
NS_ASSERTION(mContext || (aChrome && !aParentManager) || aProcessManager,
"Should have mContext in non-global/non-process manager!");
NS_ASSERTION(aChrome || !aParentManager, "Should not set parent manager!");
// This is a bit hackish. When parent manager is global, we want
// to attach the window message manager to it immediately.
@ -106,12 +108,21 @@ public:
static_cast<nsFrameMessageManager*>(mChildManagers[i - 1])->
Disconnect(PR_FALSE);
}
if (mIsProcessManager) {
if (this == sParentProcessManager) {
sParentProcessManager = nsnull;
}
if (this == sChildProcessManager) {
sChildProcessManager = nsnull;
}
}
}
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
@ -142,11 +153,21 @@ public:
}
PRBool IsGlobal() { return mGlobal; }
PRBool IsWindowLevel() { return mParentManager && mParentManager->IsGlobal(); }
static nsFrameMessageManager* GetParentProcessManager()
{
return sParentProcessManager;
}
static nsFrameMessageManager* GetChildProcessManager()
{
return sChildProcessManager;
}
protected:
nsTArray<nsMessageListenerInfo> mListeners;
nsCOMArray<nsIContentFrameMessageManager> mChildManagers;
PRPackedBool mChrome;
PRPackedBool mGlobal;
PRPackedBool mIsProcessManager;
nsFrameMessageManager* mParentManager;
nsSyncMessageCallback mSyncCallback;
nsAsyncMessageCallback mAsyncCallback;
@ -154,6 +175,9 @@ protected:
void* mCallbackData;
JSContext* mContext;
nsTArray<nsString> mPendingScripts;
public:
static nsFrameMessageManager* sParentProcessManager;
static nsFrameMessageManager* sChildProcessManager;
};
class nsScriptCacheCleaner;

View File

@ -153,6 +153,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsInProcessTabChildGlobal)
NS_INTERFACE_MAP_ENTRY(nsIFrameMessageManager)
NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender)
NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager)
NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager)
NS_INTERFACE_MAP_ENTRY(nsIScriptContextPrincipal)

View File

@ -4035,6 +4035,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIFrameMessageManager)
DOM_CLASSINFO_MAP_ENTRY(nsISyncMessageSender)
DOM_CLASSINFO_MAP_ENTRY(nsIContentFrameMessageManager)
DOM_CLASSINFO_MAP_END

View File

@ -63,6 +63,7 @@
#include "nsChromeRegistryContent.h"
#include "mozilla/chrome/RegistryMessageUtils.h"
#include "nsFrameMessageManager.h"
using namespace mozilla::ipc;
using namespace mozilla::net;
@ -356,5 +357,17 @@ ContentChild::RecvNotifyVisited(const IPC::URI& aURI)
return true;
}
bool
ContentChild::RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON)
{
nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
if (cpm) {
cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
aMsg, PR_FALSE, aJSON, nsnull, nsnull);
}
return true;
}
} // namespace dom
} // namespace mozilla

View File

@ -101,8 +101,9 @@ public:
const nsCString& aPrefRoot,
nsIObserver* aObserver);
virtual bool RecvNotifyRemotePrefObserver(
const nsCString& aDomain);
virtual bool RecvNotifyRemotePrefObserver(const nsCString& aDomain);
virtual bool RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON);
private:
NS_OVERRIDE

View File

@ -55,6 +55,7 @@
#include "nsChromeRegistryChrome.h"
#include "nsExternalHelperAppService.h"
#include "nsCExternalHandlerService.h"
#include "nsFrameMessageManager.h"
#ifdef ANDROID
#include "AndroidBridge.h"
@ -556,6 +557,31 @@ ContentParent::RecvNotifyIME(const int& aType, const int& aStatus)
return false;
#endif
}
bool
ContentParent::RecvSyncMessage(const nsString& aMsg, const nsString& aJSON,
nsTArray<nsString>* aRetvals)
{
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sParentProcessManager;
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;
if (ppm) {
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg, PR_FALSE, aJSON, nsnull, nsnull);
}
return true;
}
} // namespace dom
} // namespace mozilla

View File

@ -164,6 +164,10 @@ private:
virtual bool RecvLoadURIExternal(const IPC::URI& uri);
virtual bool RecvSyncMessage(const nsString& aMsg, const nsString& aJSON,
nsTArray<nsString>* aRetvals);
virtual bool RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON);
mozilla::Monitor mMonitor;
GeckoChildProcessHost* mSubprocess;

View File

@ -98,6 +98,13 @@ parent:
NotifyIME(int aType, int aState);
NotifyIMEChange(nsString aText, PRUint32 aTextLen,
int aStart, int aEnd, int aNewEnd);
sync SyncMessage(nsString aMessage, nsString aJSON)
returns (nsString[] retval);
both:
AsyncMessage(nsString aMessage, nsString aJSON);
};
}

View File

@ -1193,6 +1193,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TabChildGlobal)
NS_INTERFACE_MAP_ENTRY(nsIFrameMessageManager)
NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender)
NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager)
NS_INTERFACE_MAP_ENTRY(nsIScriptContextPrincipal)
NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)

View File

@ -1,6 +1,15 @@
dump("Loading remote script!\n");
dump(content + "\n");
var cpm = Components.classes["@mozilla.org/childprocessmessagemanager;1"]
.getService(Components.interfaces.nsISyncMessageSender);
cpm.addMessageListener("cpm-async",
function(m) {
cpm.sendSyncMessage("ppm-sync");
dump(content.document.documentElement);
cpm.sendAsyncMessage("ppm-async");
});
var Cc = Components.classes;
var Ci = Components.interfaces;
var dshell = content.QueryInterface(Ci.nsIInterfaceRequestor)

View File

@ -92,8 +92,34 @@
}
function initRemoteFrameScript() {
// 1. Test that loading a script works
// 1. Test that loading a script works, and that accessing process level mm and
// global mm works.
var ppm = Components.classes["@mozilla.org/parentprocessmessagemanager;1"]
.getService(Components.interfaces.nsIFrameMessageManager);
var gm = Components.classes["@mozilla.org/globalmessagemanager;1"]
.getService(Components.interfaces.nsIChromeFrameMessageManager);
var didThrow = false;
try {
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!");
}
ppm.addMessageListener("ppm-sync",
function(m) {
document.getElementById("messageLog").value += "[SYNC PPM]";
}
);
ppm.addMessageListener("ppm-async",
function(m) {
document.getElementById("messageLog").value += "[ASYNC 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",

View File

@ -463,6 +463,8 @@ nsresult NS_NewDOMEventGroup(nsIDOMEventGroup** aResult);
nsresult NS_NewEventListenerService(nsIEventListenerService** aResult);
nsresult NS_NewGlobalMessageManager(nsIChromeFrameMessageManager** aResult);
nsresult NS_NewParentProcessMessageManager(nsIFrameMessageManager** aResult);
nsresult NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult);
nsresult NS_NewXULControllers(nsISupports* aOuter, REFNSIID aIID, void** aResult);
@ -562,6 +564,8 @@ MAKE_CTOR(CreateXMLContentBuilder, nsIXMLContentBuilder, NS_NewXML
MAKE_CTOR(CreateContentDLF, nsIDocumentLoaderFactory, NS_NewContentDocumentLoaderFactory)
MAKE_CTOR(CreateEventListenerService, nsIEventListenerService, NS_NewEventListenerService)
MAKE_CTOR(CreateGlobalMessageManager, nsIChromeFrameMessageManager,NS_NewGlobalMessageManager)
MAKE_CTOR(CreateParentMessageManager, nsIFrameMessageManager,NS_NewParentProcessMessageManager)
MAKE_CTOR(CreateChildMessageManager, nsISyncMessageSender,NS_NewChildProcessMessageManager)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWyciwygProtocolHandler)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDataDocumentContentPolicy)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsNoDataProtocolContentPolicy)
@ -868,6 +872,8 @@ NS_DEFINE_NAMED_CID(NS_ICONTENTUTILS_CID);
NS_DEFINE_NAMED_CID(CSPSERVICE_CID);
NS_DEFINE_NAMED_CID(NS_EVENTLISTENERSERVICE_CID);
NS_DEFINE_NAMED_CID(NS_GLOBALMESSAGEMANAGER_CID);
NS_DEFINE_NAMED_CID(NS_PARENTPROCESSMESSAGEMANAGER_CID);
NS_DEFINE_NAMED_CID(NS_CHILDPROCESSMESSAGEMANAGER_CID);
NS_DEFINE_NAMED_CID(NSCHANNELPOLICY_CID);
NS_DEFINE_NAMED_CID(NS_SCRIPTSECURITYMANAGER_CID);
NS_DEFINE_NAMED_CID(NS_PRINCIPAL_CID);
@ -1016,6 +1022,8 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
{ &kCSPSERVICE_CID, false, NULL, CSPServiceConstructor },
{ &kNS_EVENTLISTENERSERVICE_CID, false, NULL, CreateEventListenerService },
{ &kNS_GLOBALMESSAGEMANAGER_CID, false, NULL, CreateGlobalMessageManager },
{ &kNS_PARENTPROCESSMESSAGEMANAGER_CID, false, NULL, CreateParentMessageManager },
{ &kNS_CHILDPROCESSMESSAGEMANAGER_CID, false, NULL, CreateChildMessageManager },
{ &kNSCHANNELPOLICY_CID, false, NULL, nsChannelPolicyConstructor },
{ &kNS_SCRIPTSECURITYMANAGER_CID, false, NULL, Construct_nsIScriptSecurityManager },
{ &kNS_PRINCIPAL_CID, false, NULL, nsPrincipalConstructor },
@ -1158,6 +1166,8 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
{ CSPSERVICE_CONTRACTID, &kCSPSERVICE_CID },
{ NS_EVENTLISTENERSERVICE_CONTRACTID, &kNS_EVENTLISTENERSERVICE_CID },
{ NS_GLOBALMESSAGEMANAGER_CONTRACTID, &kNS_GLOBALMESSAGEMANAGER_CID },
{ NS_PARENTPROCESSMESSAGEMANAGER_CONTRACTID, &kNS_PARENTPROCESSMESSAGEMANAGER_CID },
{ NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID, &kNS_CHILDPROCESSMESSAGEMANAGER_CID },
{ NSCHANNELPOLICY_CONTRACTID, &kNSCHANNELPOLICY_CID },
{ NS_SCRIPTSECURITYMANAGER_CONTRACTID, &kNS_SCRIPTSECURITYMANAGER_CID },
{ NS_GLOBAL_CHANNELEVENTSINK_CONTRACTID, &kNS_SCRIPTSECURITYMANAGER_CID },