2011-10-01 16:14:36 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 11:12:37 +00:00
|
|
|
/* 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/. */
|
2010-05-18 12:28:37 +00:00
|
|
|
|
2012-08-02 06:02:29 +00:00
|
|
|
#include "base/basictypes.h"
|
|
|
|
|
|
|
|
#include "nsFrameMessageManager.h"
|
|
|
|
|
2012-12-22 11:53:38 +00:00
|
|
|
#include "AppProcessChecker.h"
|
2010-08-31 18:58:35 +00:00
|
|
|
#include "ContentChild.h"
|
|
|
|
#include "ContentParent.h"
|
2010-05-18 12:28:37 +00:00
|
|
|
#include "nsContentUtils.h"
|
2013-05-22 16:05:26 +00:00
|
|
|
#include "nsCxPusher.h"
|
2012-07-27 14:03:27 +00:00
|
|
|
#include "nsError.h"
|
2010-05-18 12:28:37 +00:00
|
|
|
#include "nsIXPConnect.h"
|
|
|
|
#include "jsapi.h"
|
|
|
|
#include "nsJSUtils.h"
|
2012-03-09 09:48:50 +00:00
|
|
|
#include "nsJSPrincipals.h"
|
2010-08-10 17:18:26 +00:00
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsScriptLoader.h"
|
2012-09-28 05:43:12 +00:00
|
|
|
#include "nsFrameLoader.h"
|
2010-08-31 18:58:35 +00:00
|
|
|
#include "nsIXULRuntime.h"
|
2011-03-18 04:08:18 +00:00
|
|
|
#include "nsIScriptError.h"
|
|
|
|
#include "nsIConsoleService.h"
|
2011-05-19 14:48:17 +00:00
|
|
|
#include "nsIProtocolHandler.h"
|
2011-11-30 15:51:40 +00:00
|
|
|
#include "nsIScriptSecurityManager.h"
|
|
|
|
#include "nsIJSRuntimeService.h"
|
2012-08-27 14:13:02 +00:00
|
|
|
#include "nsIDOMClassInfo.h"
|
2012-08-02 06:02:29 +00:00
|
|
|
#include "nsIDOMFile.h"
|
2011-11-30 15:51:40 +00:00
|
|
|
#include "xpcpublic.h"
|
2012-06-07 02:52:14 +00:00
|
|
|
#include "mozilla/Preferences.h"
|
2012-08-02 06:02:29 +00:00
|
|
|
#include "mozilla/dom/StructuredCloneUtils.h"
|
2013-07-10 22:05:39 +00:00
|
|
|
#include "JavaScriptChild.h"
|
|
|
|
#include "JavaScriptParent.h"
|
2013-08-09 02:36:37 +00:00
|
|
|
#include "nsDOMLists.h"
|
2013-10-11 23:07:15 +00:00
|
|
|
#include "nsPrintfCString.h"
|
2013-01-15 12:22:03 +00:00
|
|
|
#include <algorithm>
|
2010-08-31 18:58:35 +00:00
|
|
|
|
2011-11-10 00:27:08 +00:00
|
|
|
#ifdef ANDROID
|
|
|
|
#include <android/log.h>
|
|
|
|
#endif
|
2012-08-06 20:41:40 +00:00
|
|
|
#ifdef XP_WIN
|
|
|
|
#include <windows.h>
|
2013-10-01 16:15:06 +00:00
|
|
|
# if defined(SendMessage)
|
|
|
|
# undef SendMessage
|
|
|
|
# endif
|
2012-08-06 20:41:40 +00:00
|
|
|
#endif
|
2011-11-10 00:27:08 +00:00
|
|
|
|
2012-06-07 02:52:14 +00:00
|
|
|
using namespace mozilla;
|
2012-08-02 06:02:29 +00:00
|
|
|
using namespace mozilla::dom;
|
2012-09-28 05:43:12 +00:00
|
|
|
using namespace mozilla::dom::ipc;
|
|
|
|
|
2013-08-02 01:29:05 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameMessageManager)
|
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager)
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t count = tmp->mListeners.Length();
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
2013-08-08 18:36:56 +00:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mListeners[i] mStrongListener");
|
|
|
|
cb.NoteXPCOMChild(tmp->mListeners[i].mStrongListener.get());
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
2012-11-15 07:32:40 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildManagers)
|
2010-05-18 12:28:37 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFrameMessageManager)
|
|
|
|
tmp->mListeners.Clear();
|
2012-08-27 16:28:11 +00:00
|
|
|
for (int32_t i = tmp->mChildManagers.Count(); i > 0; --i) {
|
2010-05-18 12:28:37 +00:00
|
|
|
static_cast<nsFrameMessageManager*>(tmp->mChildManagers[i - 1])->
|
2011-10-17 14:59:28 +00:00
|
|
|
Disconnect(false);
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
2012-11-15 07:32:40 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildManagers)
|
2010-05-18 12:28:37 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameMessageManager)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentFrameMessageManager)
|
2012-08-27 14:13:02 +00:00
|
|
|
|
|
|
|
/* nsFrameMessageManager implements nsIMessageSender and nsIMessageBroadcaster,
|
|
|
|
* both of which descend from nsIMessageListenerManager. QI'ing to
|
|
|
|
* nsIMessageListenerManager is therefore ambiguous and needs explicit casts
|
|
|
|
* depending on which child interface applies. */
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AGGREGATED(nsIMessageListenerManager,
|
|
|
|
(mIsBroadcaster ?
|
|
|
|
static_cast<nsIMessageListenerManager*>(
|
|
|
|
static_cast<nsIMessageBroadcaster*>(this)) :
|
|
|
|
static_cast<nsIMessageListenerManager*>(
|
|
|
|
static_cast<nsIMessageSender*>(this))))
|
|
|
|
|
|
|
|
/* Message managers in child process implement nsIMessageSender and
|
|
|
|
nsISyncMessageSender. Message managers in the chrome process are
|
|
|
|
either broadcasters (if they have subordinate/child message
|
|
|
|
managers) or they're simple message senders. */
|
|
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISyncMessageSender, !mChrome)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMessageSender, !mChrome || !mIsBroadcaster)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMessageBroadcaster, mChrome && mIsBroadcaster)
|
|
|
|
|
2010-08-31 18:58:35 +00:00
|
|
|
/* nsIContentFrameMessageManager is accessible only in TabChildGlobal. */
|
|
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIContentFrameMessageManager,
|
|
|
|
!mChrome && !mIsProcessManager)
|
2012-08-27 14:13:02 +00:00
|
|
|
|
|
|
|
/* Frame message managers (non-process message managers) support nsIFrameScriptLoader. */
|
|
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFrameScriptLoader,
|
2010-08-31 18:58:35 +00:00
|
|
|
mChrome && !mIsProcessManager)
|
2012-08-27 14:13:02 +00:00
|
|
|
|
2012-12-22 12:00:10 +00:00
|
|
|
/* Message senders in the chrome process support nsIProcessChecker. */
|
|
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIProcessChecker,
|
2012-09-28 05:43:12 +00:00
|
|
|
mChrome && !mIsBroadcaster)
|
|
|
|
|
2012-08-27 14:13:02 +00:00
|
|
|
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageBroadcaster,
|
|
|
|
mChrome && mIsBroadcaster)
|
|
|
|
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageSender,
|
|
|
|
mChrome && !mIsBroadcaster)
|
2010-05-18 12:28:37 +00:00
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
2011-03-06 11:11:31 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameMessageManager)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameMessageManager)
|
2010-05-18 12:28:37 +00:00
|
|
|
|
2013-01-24 02:39:27 +00:00
|
|
|
template<ActorFlavorEnum>
|
|
|
|
struct DataBlobs
|
|
|
|
{ };
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct DataBlobs<Parent>
|
|
|
|
{
|
|
|
|
typedef BlobTraits<Parent>::ProtocolType ProtocolType;
|
|
|
|
|
|
|
|
static InfallibleTArray<ProtocolType*>& Blobs(ClonedMessageData& aData)
|
|
|
|
{
|
|
|
|
return aData.blobsParent();
|
|
|
|
}
|
2013-01-24 16:24:19 +00:00
|
|
|
|
|
|
|
static const InfallibleTArray<ProtocolType*>& Blobs(const ClonedMessageData& aData)
|
|
|
|
{
|
|
|
|
return aData.blobsParent();
|
|
|
|
}
|
2013-01-24 02:39:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct DataBlobs<Child>
|
|
|
|
{
|
|
|
|
typedef BlobTraits<Child>::ProtocolType ProtocolType;
|
|
|
|
|
|
|
|
static InfallibleTArray<ProtocolType*>& Blobs(ClonedMessageData& aData)
|
|
|
|
{
|
|
|
|
return aData.blobsChild();
|
|
|
|
}
|
2013-01-24 16:24:19 +00:00
|
|
|
|
|
|
|
static const InfallibleTArray<ProtocolType*>& Blobs(const ClonedMessageData& aData)
|
|
|
|
{
|
|
|
|
return aData.blobsChild();
|
|
|
|
}
|
2013-01-24 02:39:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template<ActorFlavorEnum Flavor>
|
|
|
|
static bool
|
|
|
|
BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType* aManager,
|
|
|
|
const StructuredCloneData& aData,
|
|
|
|
ClonedMessageData& aClonedData)
|
|
|
|
{
|
|
|
|
SerializedStructuredCloneBuffer& buffer = aClonedData.data();
|
|
|
|
buffer.data = aData.mData;
|
|
|
|
buffer.dataLength = aData.mDataLength;
|
|
|
|
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
|
|
|
|
if (!blobs.IsEmpty()) {
|
|
|
|
typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
|
|
|
|
InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
|
|
|
|
uint32_t length = blobs.Length();
|
|
|
|
blobList.SetCapacity(length);
|
|
|
|
for (uint32_t i = 0; i < length; ++i) {
|
|
|
|
Blob<Flavor>* protocolActor = aManager->GetOrCreateActorForBlob(blobs[i]);
|
|
|
|
if (!protocolActor) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
blobList.AppendElement(protocolActor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MessageManagerCallback::BuildClonedMessageDataForParent(ContentParent* aParent,
|
|
|
|
const StructuredCloneData& aData,
|
|
|
|
ClonedMessageData& aClonedData)
|
|
|
|
{
|
|
|
|
return BuildClonedMessageData<Parent>(aParent, aData, aClonedData);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MessageManagerCallback::BuildClonedMessageDataForChild(ContentChild* aChild,
|
|
|
|
const StructuredCloneData& aData,
|
|
|
|
ClonedMessageData& aClonedData)
|
|
|
|
{
|
|
|
|
return BuildClonedMessageData<Child>(aChild, aData, aClonedData);
|
|
|
|
}
|
|
|
|
|
2013-01-24 16:24:19 +00:00
|
|
|
template<ActorFlavorEnum Flavor>
|
|
|
|
static StructuredCloneData
|
|
|
|
UnpackClonedMessageData(const ClonedMessageData& aData)
|
|
|
|
{
|
|
|
|
const SerializedStructuredCloneBuffer& buffer = aData.data();
|
|
|
|
typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
|
|
|
|
const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aData);
|
|
|
|
StructuredCloneData cloneData;
|
|
|
|
cloneData.mData = buffer.data;
|
|
|
|
cloneData.mDataLength = buffer.dataLength;
|
|
|
|
if (!blobs.IsEmpty()) {
|
|
|
|
uint32_t length = blobs.Length();
|
|
|
|
cloneData.mClosure.mBlobs.SetCapacity(length);
|
|
|
|
for (uint32_t i = 0; i < length; ++i) {
|
|
|
|
Blob<Flavor>* blob = static_cast<Blob<Flavor>*>(blobs[i]);
|
|
|
|
MOZ_ASSERT(blob);
|
|
|
|
nsCOMPtr<nsIDOMBlob> domBlob = blob->GetBlob();
|
|
|
|
MOZ_ASSERT(domBlob);
|
|
|
|
cloneData.mClosure.mBlobs.AppendElement(domBlob);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cloneData;
|
|
|
|
}
|
|
|
|
|
|
|
|
StructuredCloneData
|
|
|
|
mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aData)
|
|
|
|
{
|
|
|
|
return UnpackClonedMessageData<Parent>(aData);
|
|
|
|
}
|
|
|
|
|
|
|
|
StructuredCloneData
|
|
|
|
mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aData)
|
|
|
|
{
|
|
|
|
return UnpackClonedMessageData<Child>(aData);
|
|
|
|
}
|
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
bool
|
|
|
|
SameProcessCpowHolder::ToObject(JSContext* aCx, JSObject** aObjp)
|
|
|
|
{
|
|
|
|
*aObjp = mObj;
|
|
|
|
|
|
|
|
if (!mObj) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_WrapObject(aCx, aObjp);
|
|
|
|
}
|
|
|
|
|
2012-08-27 14:13:02 +00:00
|
|
|
// nsIMessageListenerManager
|
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::AddMessageListener(const nsAString& aMessage,
|
2012-08-27 14:13:02 +00:00
|
|
|
nsIMessageListener* aListener)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAtom> message = do_GetAtom(aMessage);
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t len = mListeners.Length();
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
2010-05-18 12:28:37 +00:00
|
|
|
if (mListeners[i].mMessage == message &&
|
2013-08-08 18:36:56 +00:00
|
|
|
mListeners[i].mStrongListener == aListener) {
|
2010-05-18 12:28:37 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nsMessageListenerInfo* entry = mListeners.AppendElement();
|
|
|
|
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
entry->mMessage = message;
|
2013-08-08 18:36:56 +00:00
|
|
|
entry->mStrongListener = aListener;
|
2010-05-18 12:28:37 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::RemoveMessageListener(const nsAString& aMessage,
|
2012-08-27 14:13:02 +00:00
|
|
|
nsIMessageListener* aListener)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAtom> message = do_GetAtom(aMessage);
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t len = mListeners.Length();
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
2010-05-18 12:28:37 +00:00
|
|
|
if (mListeners[i].mMessage == message &&
|
2013-08-08 18:36:56 +00:00
|
|
|
mListeners[i].mStrongListener == aListener) {
|
2010-05-18 12:28:37 +00:00
|
|
|
mListeners.RemoveElementAt(i);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-08-08 18:36:56 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage,
|
|
|
|
nsIMessageListener* aListener)
|
|
|
|
{
|
|
|
|
nsWeakPtr weak = do_GetWeakReference(aListener);
|
|
|
|
NS_ENSURE_TRUE(weak, NS_ERROR_NO_INTERFACE);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
// It's technically possible that one object X could give two different
|
|
|
|
// nsIWeakReference*'s when you do_GetWeakReference(X). We really don't want
|
|
|
|
// this to happen; it will break e.g. RemoveWeakMessageListener. So let's
|
|
|
|
// check that we're not getting ourselves into that situation.
|
|
|
|
nsCOMPtr<nsISupports> canonical = do_QueryInterface(aListener);
|
|
|
|
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
|
|
|
if (!mListeners[i].mWeakListener) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupports> otherCanonical =
|
|
|
|
do_QueryReferent(mListeners[i].mWeakListener);
|
|
|
|
MOZ_ASSERT((canonical == otherCanonical) ==
|
|
|
|
(weak == mListeners[i].mWeakListener));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> message = do_GetAtom(aMessage);
|
|
|
|
uint32_t len = mListeners.Length();
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
|
|
|
if (mListeners[i].mMessage == message &&
|
|
|
|
mListeners[i].mWeakListener == weak) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsMessageListenerInfo* entry = mListeners.AppendElement();
|
|
|
|
entry->mMessage = message;
|
|
|
|
entry->mWeakListener = weak;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::RemoveWeakMessageListener(const nsAString& aMessage,
|
|
|
|
nsIMessageListener* aListener)
|
|
|
|
{
|
|
|
|
nsWeakPtr weak = do_GetWeakReference(aListener);
|
|
|
|
NS_ENSURE_TRUE(weak, NS_OK);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> message = do_GetAtom(aMessage);
|
|
|
|
uint32_t len = mListeners.Length();
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
|
|
|
if (mListeners[i].mMessage == message &&
|
|
|
|
mListeners[i].mWeakListener == weak) {
|
|
|
|
mListeners.RemoveElementAt(i);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-08-27 14:13:02 +00:00
|
|
|
// nsIFrameScriptLoader
|
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::LoadFrameScript(const nsAString& aURL,
|
2011-09-29 06:19:26 +00:00
|
|
|
bool aAllowDelayedLoad)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
2010-06-10 09:26:19 +00:00
|
|
|
if (aAllowDelayedLoad) {
|
|
|
|
if (IsGlobal() || IsWindowLevel()) {
|
|
|
|
// Cache for future windows or frames
|
|
|
|
mPendingScripts.AppendElement(aURL);
|
2012-09-28 05:43:12 +00:00
|
|
|
} else if (!mCallback) {
|
2010-06-10 09:26:19 +00:00
|
|
|
// We're frame message manager, which isn't connected yet.
|
|
|
|
mPendingScripts.AppendElement(aURL);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
|
2012-09-28 05:43:12 +00:00
|
|
|
if (mCallback) {
|
2010-05-18 12:28:37 +00:00
|
|
|
#ifdef DEBUG_smaug
|
|
|
|
printf("Will load %s \n", NS_ConvertUTF16toUTF8(aURL).get());
|
|
|
|
#endif
|
2012-09-28 05:43:12 +00:00
|
|
|
NS_ENSURE_TRUE(mCallback->DoLoadFrameScript(aURL), NS_ERROR_FAILURE);
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
|
2012-08-27 16:28:11 +00:00
|
|
|
for (int32_t i = 0; i < mChildManagers.Count(); ++i) {
|
2010-06-10 09:26:19 +00:00
|
|
|
nsRefPtr<nsFrameMessageManager> mm =
|
|
|
|
static_cast<nsFrameMessageManager*>(mChildManagers[i]);
|
2010-05-18 12:28:37 +00:00
|
|
|
if (mm) {
|
2011-10-17 14:59:28 +00:00
|
|
|
// Use false here, so that child managers don't cache the script, which
|
2010-06-10 09:26:19 +00:00
|
|
|
// is already cached in the parent.
|
2011-10-17 14:59:28 +00:00
|
|
|
mm->LoadFrameScript(aURL, false);
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-08-24 10:16:29 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::RemoveDelayedFrameScript(const nsAString& aURL)
|
|
|
|
{
|
|
|
|
mPendingScripts.RemoveElement(aURL);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-08-09 02:36:37 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::GetDelayedFrameScripts(nsIDOMDOMStringList** aList)
|
|
|
|
{
|
|
|
|
// Frame message managers may return an incomplete list because scripts
|
|
|
|
// that were loaded after it was connected are not added to the list.
|
|
|
|
if (!IsGlobal() && !IsWindowLevel()) {
|
|
|
|
NS_WARNING("Cannot retrieve list of pending frame scripts for frame"
|
|
|
|
"message managers as it may be incomplete");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRefPtr<nsDOMStringList> scripts = new nsDOMStringList();
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
|
|
|
|
scripts->Add(mPendingScripts[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
scripts.forget(aList);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-08-08 22:53:04 +00:00
|
|
|
static bool
|
2012-06-06 07:22:06 +00:00
|
|
|
JSONCreator(const jschar* aBuf, uint32_t aLen, void* aData)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
|
|
|
nsAString* result = static_cast<nsAString*>(aData);
|
2011-10-01 16:14:36 +00:00
|
|
|
result->Append(static_cast<const PRUnichar*>(aBuf),
|
2012-08-22 15:56:38 +00:00
|
|
|
static_cast<uint32_t>(aLen));
|
2011-10-01 16:14:36 +00:00
|
|
|
return true;
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
|
2012-08-02 06:02:29 +00:00
|
|
|
static bool
|
|
|
|
GetParamsForMessage(JSContext* aCx,
|
2013-07-10 22:05:39 +00:00
|
|
|
const JS::Value& aJSON,
|
2012-08-02 06:02:29 +00:00
|
|
|
JSAutoStructuredCloneBuffer& aBuffer,
|
|
|
|
StructuredCloneClosure& aClosure)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
2013-07-10 22:05:39 +00:00
|
|
|
if (WriteStructuredClone(aCx, aJSON, aBuffer, aClosure)) {
|
2012-08-02 06:02:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
JS_ClearPendingException(aCx);
|
|
|
|
|
|
|
|
// Not clonable, try JSON
|
|
|
|
//XXX This is ugly but currently structured cloning doesn't handle
|
|
|
|
// properly cases when interface is implemented in JS and used
|
|
|
|
// as a dictionary.
|
|
|
|
nsAutoString json;
|
2013-07-10 22:05:39 +00:00
|
|
|
JS::Rooted<JS::Value> v(aCx, aJSON);
|
2013-09-17 01:33:40 +00:00
|
|
|
NS_ENSURE_TRUE(JS_Stringify(aCx, &v, JS::NullPtr(), JS::NullHandleValue,
|
2013-05-30 21:46:48 +00:00
|
|
|
JSONCreator, &json), false);
|
2012-08-02 06:02:29 +00:00
|
|
|
NS_ENSURE_TRUE(!json.IsEmpty(), false);
|
|
|
|
|
2013-05-06 12:30:46 +00:00
|
|
|
JS::Rooted<JS::Value> val(aCx, JS::NullValue());
|
2012-12-22 20:40:37 +00:00
|
|
|
NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast<const jschar*>(json.get()),
|
2013-05-29 08:29:39 +00:00
|
|
|
json.Length(), &val), false);
|
2012-08-02 06:02:29 +00:00
|
|
|
|
|
|
|
return WriteStructuredClone(aCx, val, aBuffer, aClosure);
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
|
2012-08-27 14:13:02 +00:00
|
|
|
|
|
|
|
// nsISyncMessageSender
|
|
|
|
|
2013-10-01 16:15:06 +00:00
|
|
|
static bool sSendingSyncMessage = false;
|
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
NS_IMETHODIMP
|
2011-10-01 16:14:36 +00:00
|
|
|
nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
|
2013-07-10 22:05:39 +00:00
|
|
|
const JS::Value& aJSON,
|
|
|
|
const JS::Value& aObjects,
|
2011-10-01 16:14:36 +00:00
|
|
|
JSContext* aCx,
|
2012-08-22 15:56:38 +00:00
|
|
|
uint8_t aArgc,
|
2013-03-23 05:11:52 +00:00
|
|
|
JS::Value* aRetval)
|
2013-10-01 16:15:06 +00:00
|
|
|
{
|
|
|
|
return SendMessage(aMessageName, aJSON, aObjects, aCx, aArgc, aRetval, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::SendRpcMessage(const nsAString& aMessageName,
|
|
|
|
const JS::Value& aJSON,
|
|
|
|
const JS::Value& aObjects,
|
|
|
|
JSContext* aCx,
|
|
|
|
uint8_t aArgc,
|
|
|
|
JS::Value* aRetval)
|
|
|
|
{
|
|
|
|
return SendMessage(aMessageName, aJSON, aObjects, aCx, aArgc, aRetval, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsFrameMessageManager::SendMessage(const nsAString& aMessageName,
|
|
|
|
const JS::Value& aJSON,
|
|
|
|
const JS::Value& aObjects,
|
|
|
|
JSContext* aCx,
|
|
|
|
uint8_t aArgc,
|
|
|
|
JS::Value* aRetval,
|
|
|
|
bool aIsSync)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
2010-06-10 09:26:19 +00:00
|
|
|
NS_ASSERTION(!IsGlobal(), "Should not call SendSyncMessage in chrome");
|
|
|
|
NS_ASSERTION(!IsWindowLevel(), "Should not call SendSyncMessage in chrome");
|
|
|
|
NS_ASSERTION(!mParentManager, "Should not have parent manager in content!");
|
2012-09-28 05:43:12 +00:00
|
|
|
|
2011-10-01 16:14:36 +00:00
|
|
|
*aRetval = JSVAL_VOID;
|
2012-09-28 05:43:12 +00:00
|
|
|
NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
|
2012-08-02 06:02:29 +00:00
|
|
|
|
2013-10-01 16:15:06 +00:00
|
|
|
if (sSendingSyncMessage && aIsSync) {
|
|
|
|
// No kind of blocking send should be issued on top of a sync message.
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
2012-09-28 05:43:12 +00:00
|
|
|
StructuredCloneData data;
|
|
|
|
JSAutoStructuredCloneBuffer buffer;
|
|
|
|
if (aArgc >= 2 &&
|
2013-07-10 22:05:39 +00:00
|
|
|
!GetParamsForMessage(aCx, aJSON, buffer, data.mClosure)) {
|
2012-09-28 05:43:12 +00:00
|
|
|
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
|
|
|
}
|
|
|
|
data.mData = buffer.data();
|
|
|
|
data.mDataLength = buffer.nbytes();
|
2010-05-18 12:28:37 +00:00
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
JS::RootedObject objects(aCx);
|
|
|
|
if (aArgc >= 3 && aObjects.isObject()) {
|
|
|
|
objects = &aObjects.toObject();
|
|
|
|
}
|
|
|
|
|
2012-09-28 05:43:12 +00:00
|
|
|
InfallibleTArray<nsString> retval;
|
2010-05-18 12:28:37 +00:00
|
|
|
|
2013-10-01 16:15:06 +00:00
|
|
|
sSendingSyncMessage |= aIsSync;
|
|
|
|
bool rv = mCallback->DoSendBlockingMessage(aCx, aMessageName, data, objects, &retval, aIsSync);
|
|
|
|
if (aIsSync) {
|
|
|
|
sSendingSyncMessage = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rv) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t len = retval.Length();
|
|
|
|
JS::Rooted<JSObject*> dataArray(aCx, JS_NewArrayObject(aCx, len, nullptr));
|
|
|
|
NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
|
|
|
if (retval[i].IsEmpty()) {
|
|
|
|
continue;
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
2012-09-28 05:43:12 +00:00
|
|
|
|
2013-10-01 16:15:06 +00:00
|
|
|
JS::Rooted<JS::Value> ret(aCx);
|
|
|
|
if (!JS_ParseJSON(aCx, static_cast<const jschar*>(retval[i].get()),
|
|
|
|
retval[i].Length(), &ret)) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
NS_ENSURE_TRUE(JS_SetElement(aCx, dataArray, i, &ret),
|
|
|
|
NS_ERROR_OUT_OF_MEMORY);
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
2013-10-01 16:15:06 +00:00
|
|
|
|
|
|
|
*aRetval = OBJECT_TO_JSVAL(dataArray);
|
2010-05-18 12:28:37 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2013-07-10 22:05:39 +00:00
|
|
|
nsFrameMessageManager::DispatchAsyncMessageInternal(JSContext* aCx,
|
|
|
|
const nsAString& aMessage,
|
|
|
|
const StructuredCloneData& aData,
|
|
|
|
JS::Handle<JSObject *> aCpows)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
2012-09-28 05:43:12 +00:00
|
|
|
if (mIsBroadcaster) {
|
2012-08-27 16:28:11 +00:00
|
|
|
int32_t len = mChildManagers.Count();
|
|
|
|
for (int32_t i = 0; i < len; ++i) {
|
2012-08-27 14:13:02 +00:00
|
|
|
static_cast<nsFrameMessageManager*>(mChildManagers[i])->
|
2013-07-10 22:05:39 +00:00
|
|
|
DispatchAsyncMessageInternal(aCx, aMessage, aData, aCpows);
|
2012-08-27 14:13:02 +00:00
|
|
|
}
|
2012-09-28 05:43:12 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
|
2013-07-10 22:05:39 +00:00
|
|
|
if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows)) {
|
2012-09-28 05:43:12 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-08-27 14:13:02 +00:00
|
|
|
nsresult
|
|
|
|
nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
|
2013-07-10 22:05:39 +00:00
|
|
|
const JS::Value& aJSON,
|
|
|
|
const JS::Value& aObjects,
|
2012-08-27 14:13:02 +00:00
|
|
|
JSContext* aCx,
|
2012-09-28 05:43:12 +00:00
|
|
|
uint8_t aArgc)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
2012-08-02 06:02:29 +00:00
|
|
|
StructuredCloneData data;
|
|
|
|
JSAutoStructuredCloneBuffer buffer;
|
|
|
|
|
|
|
|
if (aArgc >= 2 &&
|
2013-07-10 22:05:39 +00:00
|
|
|
!GetParamsForMessage(aCx, aJSON, buffer, data.mClosure)) {
|
2012-08-02 06:02:29 +00:00
|
|
|
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
2011-10-01 16:14:36 +00:00
|
|
|
}
|
2012-08-02 06:02:29 +00:00
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
JS::RootedObject objects(aCx);
|
|
|
|
if (aArgc >= 3 && aObjects.isObject()) {
|
|
|
|
objects = &aObjects.toObject();
|
|
|
|
}
|
|
|
|
|
2012-08-02 06:02:29 +00:00
|
|
|
data.mData = buffer.data();
|
|
|
|
data.mDataLength = buffer.nbytes();
|
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects);
|
2012-08-27 14:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// nsIMessageSender
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
|
2013-07-10 22:05:39 +00:00
|
|
|
const JS::Value& aJSON,
|
|
|
|
const JS::Value& aObjects,
|
2012-08-27 14:13:02 +00:00
|
|
|
JSContext* aCx,
|
|
|
|
uint8_t aArgc)
|
|
|
|
{
|
2013-07-10 22:05:39 +00:00
|
|
|
return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aCx, aArgc);
|
2012-08-27 14:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// nsIMessageBroadcaster
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::BroadcastAsyncMessage(const nsAString& aMessageName,
|
2013-07-10 22:05:39 +00:00
|
|
|
const JS::Value& aJSON,
|
|
|
|
const JS::Value& aObjects,
|
2012-08-27 14:13:02 +00:00
|
|
|
JSContext* aCx,
|
|
|
|
uint8_t aArgc)
|
|
|
|
{
|
2013-07-10 22:05:39 +00:00
|
|
|
return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aCx, aArgc);
|
2012-08-27 14:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::GetChildCount(uint32_t* aChildCount)
|
|
|
|
{
|
|
|
|
*aChildCount = static_cast<uint32_t>(mChildManagers.Count());
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::GetChildAt(uint32_t aIndex,
|
|
|
|
nsIMessageListenerManager** aMM)
|
|
|
|
{
|
|
|
|
*aMM = nullptr;
|
|
|
|
nsCOMPtr<nsIMessageListenerManager> mm =
|
|
|
|
do_QueryInterface(mChildManagers.SafeObjectAt(static_cast<uint32_t>(aIndex)));
|
|
|
|
mm.swap(*aMM);
|
|
|
|
return NS_OK;
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
|
2012-08-27 14:13:02 +00:00
|
|
|
|
|
|
|
// nsIContentFrameMessageManager
|
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::Dump(const nsAString& aStr)
|
|
|
|
{
|
2011-11-10 00:27:08 +00:00
|
|
|
#ifdef ANDROID
|
2012-06-28 14:14:11 +00:00
|
|
|
__android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", NS_ConvertUTF16toUTF8(aStr).get());
|
2012-08-06 20:41:40 +00:00
|
|
|
#endif
|
|
|
|
#ifdef XP_WIN
|
|
|
|
if (IsDebuggerPresent()) {
|
|
|
|
OutputDebugStringW(PromiseFlatString(aStr).get());
|
|
|
|
}
|
2011-11-10 00:27:08 +00:00
|
|
|
#endif
|
2010-05-18 12:28:37 +00:00
|
|
|
fputs(NS_ConvertUTF16toUTF8(aStr).get(), stdout);
|
|
|
|
fflush(stdout);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-11-24 13:58:21 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::PrivateNoteIntentionalCrash()
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::GetContent(nsIDOMWindow** aContent)
|
|
|
|
{
|
2012-07-30 14:20:58 +00:00
|
|
|
*aContent = nullptr;
|
2010-05-18 12:28:37 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::GetDocShell(nsIDocShell** aDocShell)
|
|
|
|
{
|
2012-07-30 14:20:58 +00:00
|
|
|
*aDocShell = nullptr;
|
2010-05-18 12:28:37 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-06-25 09:52:00 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::Btoa(const nsAString& aBinaryData,
|
|
|
|
nsAString& aAsciiBase64String)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::Atob(const nsAString& aAsciiString,
|
|
|
|
nsAString& aBinaryData)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-12-22 12:00:10 +00:00
|
|
|
// nsIProcessChecker
|
2012-09-28 05:43:12 +00:00
|
|
|
|
2012-12-22 12:00:10 +00:00
|
|
|
nsresult
|
|
|
|
nsFrameMessageManager::AssertProcessInternal(ProcessCheckerType aType,
|
|
|
|
const nsAString& aCapability,
|
|
|
|
bool* aValid)
|
2012-09-28 05:43:12 +00:00
|
|
|
{
|
2012-12-22 12:00:10 +00:00
|
|
|
*aValid = false;
|
2012-09-28 05:43:12 +00:00
|
|
|
|
|
|
|
// This API is only supported for message senders in the chrome process.
|
|
|
|
if (!mChrome || mIsBroadcaster) {
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
if (!mCallback) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
2012-12-22 12:00:10 +00:00
|
|
|
switch (aType) {
|
|
|
|
case PROCESS_CHECKER_PERMISSION:
|
|
|
|
*aValid = mCallback->CheckPermission(aCapability);
|
|
|
|
break;
|
|
|
|
case PROCESS_CHECKER_MANIFEST_URL:
|
|
|
|
*aValid = mCallback->CheckManifestURL(aCapability);
|
|
|
|
break;
|
2013-01-14 10:08:55 +00:00
|
|
|
case ASSERT_APP_HAS_PERMISSION:
|
|
|
|
*aValid = mCallback->CheckAppHasPermission(aCapability);
|
|
|
|
break;
|
2012-12-22 12:00:10 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2012-09-28 05:43:12 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-08-27 14:13:02 +00:00
|
|
|
|
2012-12-22 12:00:10 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::AssertPermission(const nsAString& aPermission,
|
|
|
|
bool* aHasPermission)
|
|
|
|
{
|
|
|
|
return AssertProcessInternal(PROCESS_CHECKER_PERMISSION,
|
|
|
|
aPermission,
|
|
|
|
aHasPermission);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::AssertContainApp(const nsAString& aManifestURL,
|
|
|
|
bool* aHasManifestURL)
|
|
|
|
{
|
|
|
|
return AssertProcessInternal(PROCESS_CHECKER_MANIFEST_URL,
|
|
|
|
aManifestURL,
|
|
|
|
aHasManifestURL);
|
|
|
|
}
|
|
|
|
|
2013-01-14 10:08:55 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::AssertAppHasPermission(const nsAString& aPermission,
|
|
|
|
bool* aHasPermission)
|
|
|
|
{
|
|
|
|
return AssertProcessInternal(ASSERT_APP_HAS_PERMISSION,
|
|
|
|
aPermission,
|
|
|
|
aHasPermission);
|
|
|
|
}
|
|
|
|
|
2013-06-29 10:52:16 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsFrameMessageManager::CheckAppHasStatus(unsigned short aStatus,
|
|
|
|
bool* aHasStatus)
|
|
|
|
{
|
|
|
|
*aHasStatus = false;
|
|
|
|
|
|
|
|
// This API is only supported for message senders in the chrome process.
|
|
|
|
if (!mChrome || mIsBroadcaster) {
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
if (!mCallback) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
*aHasStatus = mCallback->CheckAppHasStatus(aStatus);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-01-07 19:20:12 +00:00
|
|
|
class MMListenerRemover
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MMListenerRemover(nsFrameMessageManager* aMM)
|
2012-02-21 09:34:01 +00:00
|
|
|
: mWasHandlingMessage(aMM->mHandlingMessage)
|
|
|
|
, mMM(aMM)
|
2012-01-07 19:20:12 +00:00
|
|
|
{
|
|
|
|
mMM->mHandlingMessage = true;
|
|
|
|
}
|
|
|
|
~MMListenerRemover()
|
|
|
|
{
|
|
|
|
if (!mWasHandlingMessage) {
|
|
|
|
mMM->mHandlingMessage = false;
|
|
|
|
if (mMM->mDisconnected) {
|
|
|
|
mMM->mListeners.Clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool mWasHandlingMessage;
|
|
|
|
nsRefPtr<nsFrameMessageManager> mMM;
|
|
|
|
};
|
|
|
|
|
2012-08-27 14:13:02 +00:00
|
|
|
|
|
|
|
// nsIMessageListener
|
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
nsresult
|
|
|
|
nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
|
|
|
const nsAString& aMessage,
|
2013-10-01 16:15:06 +00:00
|
|
|
bool aIsSync,
|
2012-08-02 06:02:29 +00:00
|
|
|
const StructuredCloneData* aCloneData,
|
2013-07-10 22:05:39 +00:00
|
|
|
CpowHolder* aCpows,
|
2013-06-30 15:00:18 +00:00
|
|
|
InfallibleTArray<nsString>* aJSONRetVal)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
2013-06-30 15:00:18 +00:00
|
|
|
AutoSafeJSContext ctx;
|
2013-08-08 18:36:56 +00:00
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
if (mListeners.Length()) {
|
|
|
|
nsCOMPtr<nsIAtom> name = do_GetAtom(aMessage);
|
2012-01-07 19:20:12 +00:00
|
|
|
MMListenerRemover lr(this);
|
2010-05-18 12:28:37 +00:00
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
2013-08-08 18:36:56 +00:00
|
|
|
// Remove mListeners[i] if it's an expired weak listener.
|
2013-09-25 19:08:04 +00:00
|
|
|
nsCOMPtr<nsISupports> weakListener;
|
2013-08-08 18:36:56 +00:00
|
|
|
if (mListeners[i].mWeakListener) {
|
|
|
|
weakListener = do_QueryReferent(mListeners[i].mWeakListener);
|
|
|
|
if (!weakListener) {
|
|
|
|
mListeners.RemoveElementAt(i--);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
if (mListeners[i].mMessage == name) {
|
2013-08-08 18:36:56 +00:00
|
|
|
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS;
|
|
|
|
if (weakListener) {
|
|
|
|
wrappedJS = do_QueryInterface(weakListener);
|
|
|
|
} else {
|
|
|
|
wrappedJS = do_QueryInterface(mListeners[i].mStrongListener);
|
|
|
|
}
|
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
if (!wrappedJS) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-05-20 12:44:18 +00:00
|
|
|
JS::Rooted<JSObject*> object(ctx, wrappedJS->GetJSObject());
|
2010-05-18 12:28:37 +00:00
|
|
|
if (!object) {
|
|
|
|
continue;
|
|
|
|
}
|
2012-08-22 01:42:53 +00:00
|
|
|
JSAutoCompartment ac(ctx, object);
|
2011-05-12 10:26:05 +00:00
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
// The parameter for the listener function.
|
2013-05-02 09:12:45 +00:00
|
|
|
JS::Rooted<JSObject*> param(ctx,
|
|
|
|
JS_NewObject(ctx, nullptr, nullptr, nullptr));
|
2010-05-18 12:28:37 +00:00
|
|
|
NS_ENSURE_TRUE(param, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2013-05-02 09:12:47 +00:00
|
|
|
JS::Rooted<JS::Value> targetv(ctx);
|
2013-05-02 09:12:46 +00:00
|
|
|
JS::Rooted<JSObject*> global(ctx, JS_GetGlobalForObject(ctx, object));
|
2013-05-02 09:12:47 +00:00
|
|
|
nsContentUtils::WrapNative(ctx, global, aTarget, targetv.address(),
|
|
|
|
nullptr, true);
|
2010-05-18 12:28:37 +00:00
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
JS::RootedObject cpows(ctx);
|
|
|
|
if (aCpows) {
|
|
|
|
if (!aCpows->ToObject(ctx, cpows.address())) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
if (!cpows) {
|
|
|
|
cpows = JS_NewObject(ctx, nullptr, nullptr, nullptr);
|
|
|
|
if (!cpows) {
|
2011-06-23 16:46:38 +00:00
|
|
|
return NS_ERROR_UNEXPECTED;
|
2013-07-10 22:05:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::RootedValue cpowsv(ctx, JS::ObjectValue(*cpows));
|
2011-06-23 16:46:38 +00:00
|
|
|
|
2013-05-06 12:30:46 +00:00
|
|
|
JS::Rooted<JS::Value> json(ctx, JS::NullValue());
|
2012-08-02 06:02:29 +00:00
|
|
|
if (aCloneData && aCloneData->mDataLength &&
|
2013-05-06 12:30:46 +00:00
|
|
|
!ReadStructuredClone(ctx, *aCloneData, json.address())) {
|
2012-08-02 06:02:29 +00:00
|
|
|
JS_ClearPendingException(ctx);
|
|
|
|
return NS_OK;
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
2013-05-08 02:34:56 +00:00
|
|
|
JS::Rooted<JSString*> jsMessage(ctx,
|
2010-06-10 09:26:19 +00:00
|
|
|
JS_NewUCStringCopyN(ctx,
|
2012-12-22 20:40:37 +00:00
|
|
|
static_cast<const jschar*>(aMessage.BeginReading()),
|
2013-05-08 02:34:56 +00:00
|
|
|
aMessage.Length()));
|
2010-05-18 12:28:37 +00:00
|
|
|
NS_ENSURE_TRUE(jsMessage, NS_ERROR_OUT_OF_MEMORY);
|
2013-04-03 01:14:24 +00:00
|
|
|
JS_DefineProperty(ctx, param, "target", targetv, nullptr, nullptr, JSPROP_ENUMERATE);
|
2010-06-10 09:26:19 +00:00
|
|
|
JS_DefineProperty(ctx, param, "name",
|
2013-04-03 01:14:24 +00:00
|
|
|
STRING_TO_JSVAL(jsMessage), nullptr, nullptr, JSPROP_ENUMERATE);
|
2010-06-10 09:26:19 +00:00
|
|
|
JS_DefineProperty(ctx, param, "sync",
|
2013-10-01 16:15:06 +00:00
|
|
|
BOOLEAN_TO_JSVAL(aIsSync), nullptr, nullptr, JSPROP_ENUMERATE);
|
2013-04-03 01:14:24 +00:00
|
|
|
JS_DefineProperty(ctx, param, "json", json, nullptr, nullptr, JSPROP_ENUMERATE); // deprecated
|
|
|
|
JS_DefineProperty(ctx, param, "data", json, nullptr, nullptr, JSPROP_ENUMERATE);
|
2013-07-10 22:05:39 +00:00
|
|
|
JS_DefineProperty(ctx, param, "objects", cpowsv, nullptr, nullptr, JSPROP_ENUMERATE);
|
2010-05-18 12:28:37 +00:00
|
|
|
|
2013-05-02 09:12:47 +00:00
|
|
|
JS::Rooted<JS::Value> thisValue(ctx, JS::UndefinedValue());
|
2010-05-18 12:28:37 +00:00
|
|
|
|
2013-05-02 09:12:47 +00:00
|
|
|
JS::Rooted<JS::Value> funval(ctx);
|
2011-07-27 20:21:53 +00:00
|
|
|
if (JS_ObjectIsCallable(ctx, object)) {
|
2010-05-18 12:28:37 +00:00
|
|
|
// If the listener is a JS function:
|
2012-05-11 15:46:26 +00:00
|
|
|
funval.setObject(*object);
|
2010-06-10 09:26:19 +00:00
|
|
|
|
|
|
|
// A small hack to get 'this' value right on content side where
|
|
|
|
// messageManager is wrapped in TabChildGlobal.
|
|
|
|
nsCOMPtr<nsISupports> defaultThisValue;
|
|
|
|
if (mChrome) {
|
2011-08-30 21:45:31 +00:00
|
|
|
defaultThisValue = do_QueryObject(this);
|
2010-06-10 09:26:19 +00:00
|
|
|
} else {
|
|
|
|
defaultThisValue = aTarget;
|
|
|
|
}
|
2013-05-02 09:12:46 +00:00
|
|
|
JS::Rooted<JSObject*> global(ctx, JS_GetGlobalForObject(ctx, object));
|
|
|
|
nsContentUtils::WrapNative(ctx, global, defaultThisValue,
|
|
|
|
thisValue.address(), nullptr, true);
|
2010-05-18 12:28:37 +00:00
|
|
|
} else {
|
|
|
|
// If the listener is a JS object which has receiveMessage function:
|
2013-07-26 09:00:38 +00:00
|
|
|
if (!JS_GetProperty(ctx, object, "receiveMessage", &funval) ||
|
2012-05-11 15:46:26 +00:00
|
|
|
!funval.isObject())
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
// Check if the object is even callable.
|
|
|
|
NS_ENSURE_STATE(JS_ObjectIsCallable(ctx, &funval.toObject()));
|
|
|
|
thisValue.setObject(*object);
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
|
2013-04-27 04:08:15 +00:00
|
|
|
JS::Rooted<JS::Value> rval(ctx, JSVAL_VOID);
|
|
|
|
JS::Rooted<JS::Value> argv(ctx, JS::ObjectValue(*param));
|
2010-05-18 12:28:37 +00:00
|
|
|
|
2010-10-10 22:46:16 +00:00
|
|
|
{
|
2013-05-02 09:12:45 +00:00
|
|
|
JS::Rooted<JSObject*> thisObject(ctx, thisValue.toObjectOrNull());
|
2010-10-10 22:46:16 +00:00
|
|
|
|
2012-08-22 01:42:53 +00:00
|
|
|
JSAutoCompartment tac(ctx, thisObject);
|
2013-10-01 16:15:06 +00:00
|
|
|
if (!JS_WrapValue(ctx, argv.address())) {
|
2010-10-10 22:46:16 +00:00
|
|
|
return NS_ERROR_UNEXPECTED;
|
2013-10-01 16:15:06 +00:00
|
|
|
}
|
2010-10-10 22:46:16 +00:00
|
|
|
|
|
|
|
JS_CallFunctionValue(ctx, thisObject,
|
2013-04-27 04:08:15 +00:00
|
|
|
funval, 1, argv.address(), rval.address());
|
2010-10-10 22:46:16 +00:00
|
|
|
if (aJSONRetVal) {
|
|
|
|
nsString json;
|
2013-09-17 01:33:40 +00:00
|
|
|
if (JS_Stringify(ctx, &rval, JS::NullPtr(), JS::NullHandleValue,
|
2010-10-10 22:46:16 +00:00
|
|
|
JSONCreator, &json)) {
|
|
|
|
aJSONRetVal->AppendElement(json);
|
|
|
|
}
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-16 18:21:08 +00:00
|
|
|
nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = mParentManager;
|
2010-05-18 12:28:37 +00:00
|
|
|
return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
|
2013-10-01 16:15:06 +00:00
|
|
|
aIsSync, aCloneData,
|
2013-07-10 22:05:39 +00:00
|
|
|
aCpows,
|
2013-06-30 15:00:19 +00:00
|
|
|
aJSONRetVal) : NS_OK;
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameMessageManager::AddChildManager(nsFrameMessageManager* aManager,
|
2011-09-29 06:19:26 +00:00
|
|
|
bool aLoadScripts)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
|
|
|
mChildManagers.AppendObject(aManager);
|
|
|
|
if (aLoadScripts) {
|
2010-06-10 09:26:19 +00:00
|
|
|
nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = this;
|
|
|
|
nsRefPtr<nsFrameMessageManager> kungfuDeathGrip2 = aManager;
|
|
|
|
// We have parent manager if we're a window message manager.
|
|
|
|
// In that case we want to load the pending scripts from global
|
|
|
|
// message manager.
|
|
|
|
if (mParentManager) {
|
|
|
|
nsRefPtr<nsFrameMessageManager> globalMM = mParentManager;
|
2012-08-22 15:56:38 +00:00
|
|
|
for (uint32_t i = 0; i < globalMM->mPendingScripts.Length(); ++i) {
|
2011-10-17 14:59:28 +00:00
|
|
|
aManager->LoadFrameScript(globalMM->mPendingScripts[i], false);
|
2010-06-10 09:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
2012-08-22 15:56:38 +00:00
|
|
|
for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
|
2011-10-17 14:59:28 +00:00
|
|
|
aManager->LoadFrameScript(mPendingScripts[i], false);
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-09-28 05:43:12 +00:00
|
|
|
nsFrameMessageManager::SetCallback(MessageManagerCallback* aCallback, bool aLoadScripts)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
2012-09-28 05:43:12 +00:00
|
|
|
NS_ASSERTION(!mIsBroadcaster || !mCallback,
|
|
|
|
"Broadcasters cannot have callbacks!");
|
|
|
|
if (aCallback && mCallback != aCallback) {
|
|
|
|
mCallback = aCallback;
|
|
|
|
if (mOwnsCallback) {
|
|
|
|
mOwnedCallback = aCallback;
|
|
|
|
}
|
2010-05-18 12:28:37 +00:00
|
|
|
// First load global scripts by adding this to parent manager.
|
|
|
|
if (mParentManager) {
|
|
|
|
mParentManager->AddChildManager(this, aLoadScripts);
|
|
|
|
}
|
|
|
|
if (aLoadScripts) {
|
2012-08-22 15:56:38 +00:00
|
|
|
for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
|
2011-10-17 14:59:28 +00:00
|
|
|
LoadFrameScript(mPendingScripts[i], false);
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-07 19:20:26 +00:00
|
|
|
void
|
|
|
|
nsFrameMessageManager::RemoveFromParent()
|
|
|
|
{
|
|
|
|
if (mParentManager) {
|
|
|
|
mParentManager->RemoveChildManager(this);
|
|
|
|
}
|
2012-07-30 14:20:58 +00:00
|
|
|
mParentManager = nullptr;
|
2012-09-28 05:43:12 +00:00
|
|
|
mCallback = nullptr;
|
|
|
|
mOwnedCallback = nullptr;
|
2012-01-07 19:20:26 +00:00
|
|
|
}
|
|
|
|
|
2010-05-18 12:28:37 +00:00
|
|
|
void
|
2011-09-29 06:19:26 +00:00
|
|
|
nsFrameMessageManager::Disconnect(bool aRemoveFromParent)
|
2010-05-18 12:28:37 +00:00
|
|
|
{
|
2013-07-01 13:46:53 +00:00
|
|
|
if (!mDisconnected) {
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->NotifyObservers(NS_ISUPPORTS_CAST(nsIContentFrameMessageManager*, this),
|
|
|
|
"message-manager-disconnect", nullptr);
|
|
|
|
}
|
|
|
|
}
|
2010-05-18 12:28:37 +00:00
|
|
|
if (mParentManager && aRemoveFromParent) {
|
|
|
|
mParentManager->RemoveChildManager(this);
|
|
|
|
}
|
2012-01-07 19:20:12 +00:00
|
|
|
mDisconnected = true;
|
2012-07-30 14:20:58 +00:00
|
|
|
mParentManager = nullptr;
|
2012-09-28 05:43:12 +00:00
|
|
|
mCallback = nullptr;
|
|
|
|
mOwnedCallback = nullptr;
|
2012-01-07 19:20:12 +00:00
|
|
|
if (!mHandlingMessage) {
|
|
|
|
mListeners.Clear();
|
|
|
|
}
|
2010-06-10 09:26:19 +00:00
|
|
|
}
|
|
|
|
|
2013-10-11 23:07:15 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
struct MessageManagerReferentCount {
|
|
|
|
MessageManagerReferentCount() : strong(0), weakAlive(0), weakDead(0) {}
|
|
|
|
size_t strong;
|
|
|
|
size_t weakAlive;
|
|
|
|
size_t weakDead;
|
|
|
|
nsCOMArray<nsIAtom> suspectMessages;
|
|
|
|
nsDataHashtable<nsPtrHashKey<nsIAtom>, uint32_t> messageCounter;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
|
|
|
|
|
|
|
class MessageManagerReporter MOZ_FINAL : public nsIMemoryReporter
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSIMEMORYREPORTER
|
|
|
|
protected:
|
|
|
|
static const size_t kSuspectReferentCount = 300;
|
|
|
|
void CountReferents(nsFrameMessageManager* aMessageManager,
|
|
|
|
MessageManagerReferentCount* aReferentCount);
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS1(MessageManagerReporter, nsIMemoryReporter)
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager,
|
|
|
|
MessageManagerReferentCount* aReferentCount)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < aMessageManager->mListeners.Length(); i++) {
|
|
|
|
const nsMessageListenerInfo& listenerInfo = aMessageManager->mListeners[i];
|
|
|
|
|
|
|
|
if (listenerInfo.mWeakListener) {
|
|
|
|
nsCOMPtr<nsISupports> referent =
|
|
|
|
do_QueryReferent(listenerInfo.mWeakListener);
|
|
|
|
if (referent) {
|
|
|
|
aReferentCount->weakAlive++;
|
|
|
|
} else {
|
|
|
|
aReferentCount->weakDead++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
aReferentCount->strong++;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t oldCount = 0;
|
|
|
|
aReferentCount->messageCounter.Get(listenerInfo.mMessage, &oldCount);
|
|
|
|
uint32_t currentCount = oldCount + 1;
|
|
|
|
aReferentCount->messageCounter.Put(listenerInfo.mMessage, currentCount);
|
|
|
|
|
|
|
|
// Keep track of messages that have a suspiciously large
|
|
|
|
// number of referents (symptom of leak).
|
|
|
|
if (currentCount == kSuspectReferentCount) {
|
|
|
|
aReferentCount->suspectMessages.AppendElement(listenerInfo.mMessage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add referent count in child managers because the listeners
|
|
|
|
// participate in messages dispatched from parent message manager.
|
|
|
|
for (uint32_t i = 0; i < aMessageManager->mChildManagers.Length(); i++) {
|
|
|
|
nsRefPtr<nsFrameMessageManager> mm =
|
|
|
|
static_cast<nsFrameMessageManager*>(aMessageManager->mChildManagers[i]);
|
|
|
|
CountReferents(mm, aReferentCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
MessageManagerReporter::GetName(nsACString& aName)
|
|
|
|
{
|
|
|
|
aName.AssignLiteral("message-manager");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static nsresult
|
|
|
|
ReportReferentCount(const char* aManagerType,
|
|
|
|
const MessageManagerReferentCount& aReferentCount,
|
|
|
|
nsIMemoryReporterCallback* aCb,
|
|
|
|
nsISupports* aClosure)
|
|
|
|
{
|
|
|
|
#define REPORT(_path, _amount, _desc) \
|
|
|
|
do { \
|
|
|
|
nsresult rv; \
|
|
|
|
rv = aCb->Callback(EmptyCString(), _path, \
|
|
|
|
nsIMemoryReporter::KIND_OTHER, \
|
|
|
|
nsIMemoryReporter::UNITS_COUNT, _amount, \
|
|
|
|
_desc, aClosure); \
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
REPORT(nsPrintfCString("message-manager/referent/%s/strong", aManagerType),
|
|
|
|
aReferentCount.strong,
|
|
|
|
nsPrintfCString("The number of strong referents held by the message "
|
|
|
|
"manager in the %s manager.", aManagerType));
|
|
|
|
REPORT(nsPrintfCString("message-manager/referent/%s/weak/alive", aManagerType),
|
|
|
|
aReferentCount.weakAlive,
|
|
|
|
nsPrintfCString("The number of weak referents that are still alive "
|
|
|
|
"held by the message manager in the %s manager.",
|
|
|
|
aManagerType));
|
|
|
|
REPORT(nsPrintfCString("message-manager/referent/%s/weak/dead", aManagerType),
|
|
|
|
aReferentCount.weakDead,
|
|
|
|
nsPrintfCString("The number of weak referents that are dead "
|
|
|
|
"held by the message manager in the %s manager.",
|
|
|
|
aManagerType));
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < aReferentCount.suspectMessages.Length(); i++) {
|
|
|
|
uint32_t totalReferentCount = 0;
|
|
|
|
aReferentCount.messageCounter.Get(aReferentCount.suspectMessages[i],
|
|
|
|
&totalReferentCount);
|
|
|
|
nsAtomCString suspect(aReferentCount.suspectMessages[i]);
|
|
|
|
REPORT(nsPrintfCString("message-manager-suspect/%s/referent(message=%s)",
|
|
|
|
aManagerType, suspect.get()), totalReferentCount,
|
|
|
|
nsPrintfCString("A message in the %s message manager with a "
|
|
|
|
"suspiciously large number of referents (symptom "
|
|
|
|
"of a leak).", aManagerType));
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef REPORT
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
MessageManagerReporter::CollectReports(nsIMemoryReporterCallback* aCb,
|
|
|
|
nsISupports* aClosure)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
|
|
|
nsCOMPtr<nsIMessageBroadcaster> globalmm =
|
|
|
|
do_GetService("@mozilla.org/globalmessagemanager;1");
|
|
|
|
if (globalmm) {
|
|
|
|
nsRefPtr<nsFrameMessageManager> mm =
|
|
|
|
static_cast<nsFrameMessageManager*>(globalmm.get());
|
|
|
|
MessageManagerReferentCount count;
|
|
|
|
CountReferents(mm, &count);
|
|
|
|
rv = ReportReferentCount("global-manager", count, aCb, aClosure);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nsFrameMessageManager::sParentProcessManager) {
|
|
|
|
MessageManagerReferentCount count;
|
|
|
|
CountReferents(nsFrameMessageManager::sParentProcessManager, &count);
|
|
|
|
rv = ReportReferentCount("parent-process-manager", count, aCb, aClosure);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nsFrameMessageManager::sChildProcessManager) {
|
|
|
|
MessageManagerReferentCount count;
|
|
|
|
CountReferents(nsFrameMessageManager::sChildProcessManager, &count);
|
|
|
|
rv = ReportReferentCount("child-process-manager", count, aCb, aClosure);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|
|
|
|
|
2010-06-10 09:26:19 +00:00
|
|
|
nsresult
|
2012-08-27 14:13:02 +00:00
|
|
|
NS_NewGlobalMessageManager(nsIMessageBroadcaster** aResult)
|
2010-06-10 09:26:19 +00:00
|
|
|
{
|
2013-06-15 06:40:22 +00:00
|
|
|
NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default,
|
|
|
|
NS_ERROR_NOT_AVAILABLE);
|
2012-09-28 05:43:12 +00:00
|
|
|
nsFrameMessageManager* mm = new nsFrameMessageManager(nullptr,
|
2012-07-30 14:20:58 +00:00
|
|
|
nullptr,
|
2012-09-28 05:43:12 +00:00
|
|
|
MM_CHROME | MM_GLOBAL | MM_BROADCASTER);
|
2013-10-11 23:07:15 +00:00
|
|
|
NS_RegisterMemoryReporter(new MessageManagerReporter());
|
2010-06-10 09:26:19 +00:00
|
|
|
return CallQueryInterface(mm, aResult);
|
2010-05-18 12:28:37 +00:00
|
|
|
}
|
2010-08-10 17:18:26 +00:00
|
|
|
|
2011-09-02 06:46:00 +00:00
|
|
|
nsDataHashtable<nsStringHashKey, nsFrameJSScriptExecutorHolder*>*
|
2012-07-30 14:20:58 +00:00
|
|
|
nsFrameScriptExecutor::sCachedScripts = nullptr;
|
2012-10-05 19:10:30 +00:00
|
|
|
nsScriptCacheCleaner* nsFrameScriptExecutor::sScriptCacheCleaner = nullptr;
|
2010-08-10 17:18:26 +00:00
|
|
|
|
|
|
|
void
|
2013-06-30 15:00:18 +00:00
|
|
|
nsFrameScriptExecutor::DidCreateGlobal()
|
2010-08-10 17:18:26 +00:00
|
|
|
{
|
2013-06-30 15:00:18 +00:00
|
|
|
NS_ASSERTION(mGlobal, "Should have mGlobal!");
|
2010-08-10 17:18:26 +00:00
|
|
|
if (!sCachedScripts) {
|
|
|
|
sCachedScripts =
|
2011-09-02 06:46:00 +00:00
|
|
|
new nsDataHashtable<nsStringHashKey, nsFrameJSScriptExecutorHolder*>;
|
2010-08-16 20:05:42 +00:00
|
|
|
|
2012-10-05 19:10:30 +00:00
|
|
|
nsRefPtr<nsScriptCacheCleaner> scriptCacheCleaner =
|
|
|
|
new nsScriptCacheCleaner();
|
|
|
|
scriptCacheCleaner.forget(&sScriptCacheCleaner);
|
2010-08-10 17:18:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static PLDHashOperator
|
|
|
|
CachedScriptUnrooter(const nsAString& aKey,
|
2011-09-02 06:46:00 +00:00
|
|
|
nsFrameJSScriptExecutorHolder*& aData,
|
2010-08-10 17:18:26 +00:00
|
|
|
void* aUserArg)
|
|
|
|
{
|
|
|
|
JSContext* cx = static_cast<JSContext*>(aUserArg);
|
2011-09-02 06:46:00 +00:00
|
|
|
JS_RemoveScriptRoot(cx, &(aData->mScript));
|
2011-01-21 22:51:41 +00:00
|
|
|
delete aData;
|
2010-08-10 17:18:26 +00:00
|
|
|
return PL_DHASH_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
void
|
|
|
|
nsFrameScriptExecutor::Shutdown()
|
|
|
|
{
|
|
|
|
if (sCachedScripts) {
|
2013-05-06 13:04:17 +00:00
|
|
|
AutoSafeJSContext cx;
|
2013-04-29 18:16:17 +00:00
|
|
|
NS_ASSERTION(sCachedScripts != nullptr, "Need cached scripts");
|
|
|
|
sCachedScripts->Enumerate(CachedScriptUnrooter, cx);
|
2010-08-10 17:18:26 +00:00
|
|
|
|
|
|
|
delete sCachedScripts;
|
2012-07-30 14:20:58 +00:00
|
|
|
sCachedScripts = nullptr;
|
2010-08-16 20:05:42 +00:00
|
|
|
|
2012-10-05 19:10:30 +00:00
|
|
|
nsRefPtr<nsScriptCacheCleaner> scriptCacheCleaner;
|
|
|
|
scriptCacheCleaner.swap(sScriptCacheCleaner);
|
2010-08-10 17:18:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL)
|
|
|
|
{
|
2013-06-30 15:00:17 +00:00
|
|
|
if (!mGlobal || !sCachedScripts) {
|
2010-08-10 17:18:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-09-02 06:46:00 +00:00
|
|
|
nsFrameJSScriptExecutorHolder* holder = sCachedScripts->Get(aURL);
|
2012-08-29 15:26:18 +00:00
|
|
|
if (!holder) {
|
|
|
|
TryCacheLoadAndCompileScript(aURL, EXECUTE_IF_CANT_CACHE);
|
|
|
|
holder = sCachedScripts->Get(aURL);
|
|
|
|
}
|
|
|
|
|
2010-08-10 17:18:26 +00:00
|
|
|
if (holder) {
|
2013-06-30 15:00:17 +00:00
|
|
|
AutoSafeJSContext cx;
|
|
|
|
JS::Rooted<JSObject*> global(cx, mGlobal->GetJSObject());
|
2013-05-22 16:05:28 +00:00
|
|
|
if (global) {
|
2013-06-30 15:00:17 +00:00
|
|
|
JSAutoCompartment ac(cx, global);
|
|
|
|
(void) JS_ExecuteScript(cx, global, holder->mScript, nullptr);
|
2010-08-10 17:18:26 +00:00
|
|
|
}
|
|
|
|
}
|
2012-08-29 15:26:18 +00:00
|
|
|
}
|
2010-08-10 17:18:26 +00:00
|
|
|
|
2012-08-29 15:26:18 +00:00
|
|
|
void
|
|
|
|
nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
|
|
|
|
CacheFailedBehavior aBehavior)
|
|
|
|
{
|
2010-08-10 17:18:26 +00:00
|
|
|
nsCString url = NS_ConvertUTF16toUTF8(aURL);
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return;
|
|
|
|
}
|
2013-05-09 09:44:19 +00:00
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool hasFlags;
|
2011-05-19 14:48:17 +00:00
|
|
|
rv = NS_URIChainHasFlags(uri,
|
|
|
|
nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
|
|
|
|
&hasFlags);
|
|
|
|
if (NS_FAILED(rv) || !hasFlags) {
|
|
|
|
NS_WARNING("Will not load a frame script!");
|
|
|
|
return;
|
|
|
|
}
|
2013-05-09 09:44:19 +00:00
|
|
|
|
2010-08-10 17:18:26 +00:00
|
|
|
nsCOMPtr<nsIChannel> channel;
|
|
|
|
NS_NewChannel(getter_AddRefs(channel), uri);
|
|
|
|
if (!channel) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInputStream> input;
|
|
|
|
channel->Open(getter_AddRefs(input));
|
|
|
|
nsString dataString;
|
2012-08-22 15:56:38 +00:00
|
|
|
uint64_t avail64 = 0;
|
2012-08-11 02:44:11 +00:00
|
|
|
if (input && NS_SUCCEEDED(input->Available(&avail64)) && avail64) {
|
2012-09-28 06:57:33 +00:00
|
|
|
if (avail64 > UINT32_MAX) {
|
2012-08-11 02:44:11 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-04-07 00:17:56 +00:00
|
|
|
nsCString buffer;
|
2013-01-15 12:22:03 +00:00
|
|
|
uint32_t avail = (uint32_t)std::min(avail64, (uint64_t)UINT32_MAX);
|
2011-04-07 00:17:56 +00:00
|
|
|
if (NS_FAILED(NS_ReadInputStreamToString(input, buffer, avail))) {
|
|
|
|
return;
|
2010-08-10 17:18:26 +00:00
|
|
|
}
|
2012-08-22 15:56:38 +00:00
|
|
|
nsScriptLoader::ConvertToUTF16(channel, (uint8_t*)buffer.get(), avail,
|
2012-07-30 14:20:58 +00:00
|
|
|
EmptyString(), nullptr, dataString);
|
2010-08-10 17:18:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!dataString.IsEmpty()) {
|
2013-06-30 15:00:17 +00:00
|
|
|
AutoSafeJSContext cx;
|
|
|
|
JS::Rooted<JSObject*> global(cx, mGlobal->GetJSObject());
|
2013-05-22 16:05:28 +00:00
|
|
|
if (global) {
|
2013-06-30 15:00:17 +00:00
|
|
|
JSAutoCompartment ac(cx, global);
|
|
|
|
JS::CompileOptions options(cx);
|
2013-05-22 16:05:28 +00:00
|
|
|
options.setNoScriptRval(true)
|
|
|
|
.setFileAndLine(url.get(), 1)
|
|
|
|
.setPrincipals(nsJSPrincipals::get(mPrincipal));
|
2013-06-30 15:00:17 +00:00
|
|
|
JS::RootedObject empty(cx, nullptr);
|
|
|
|
JS::Rooted<JSScript*> script(cx,
|
|
|
|
JS::Compile(cx, empty, options, dataString.get(),
|
2013-05-22 16:05:28 +00:00
|
|
|
dataString.Length()));
|
|
|
|
|
|
|
|
if (script) {
|
|
|
|
nsAutoCString scheme;
|
|
|
|
uri->GetScheme(scheme);
|
|
|
|
// We don't cache data: scripts!
|
|
|
|
if (!scheme.EqualsLiteral("data")) {
|
|
|
|
nsFrameJSScriptExecutorHolder* holder =
|
|
|
|
new nsFrameJSScriptExecutorHolder(script);
|
|
|
|
// Root the object also for caching.
|
2013-06-30 15:00:17 +00:00
|
|
|
JS_AddNamedScriptRoot(cx, &(holder->mScript),
|
2013-05-22 16:05:28 +00:00
|
|
|
"Cached message manager script");
|
|
|
|
sCachedScripts->Put(aURL, holder);
|
|
|
|
} else if (aBehavior == EXECUTE_IF_CANT_CACHE) {
|
2013-06-30 15:00:17 +00:00
|
|
|
(void) JS_ExecuteScript(cx, global, script, nullptr);
|
2010-08-10 17:18:26 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-18 15:36:03 +00:00
|
|
|
}
|
2010-08-10 17:18:26 +00:00
|
|
|
}
|
|
|
|
}
|
2010-08-16 20:05:42 +00:00
|
|
|
|
2011-11-30 15:51:40 +00:00
|
|
|
bool
|
2013-02-20 10:39:59 +00:00
|
|
|
nsFrameScriptExecutor::InitTabChildGlobalInternal(nsISupports* aScope,
|
|
|
|
const nsACString& aID)
|
2011-11-30 15:51:40 +00:00
|
|
|
{
|
2013-05-02 09:12:45 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIJSRuntimeService> runtimeSvc =
|
2011-11-30 15:51:40 +00:00
|
|
|
do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
|
|
|
|
NS_ENSURE_TRUE(runtimeSvc, false);
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
JSRuntime* rt = nullptr;
|
2011-11-30 15:51:40 +00:00
|
|
|
runtimeSvc->GetRuntime(&rt);
|
|
|
|
NS_ENSURE_TRUE(rt, false);
|
|
|
|
|
2013-06-30 15:00:20 +00:00
|
|
|
AutoSafeJSContext cx;
|
2011-11-30 15:51:40 +00:00
|
|
|
nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
|
|
|
|
|
|
|
|
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
2012-09-05 18:32:07 +00:00
|
|
|
const uint32_t flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES;
|
2011-11-30 15:51:40 +00:00
|
|
|
|
2013-06-29 15:11:17 +00:00
|
|
|
JS::CompartmentOptions options;
|
2013-06-29 15:11:18 +00:00
|
|
|
options.setZone(JS::SystemZone)
|
|
|
|
.setVersion(JSVERSION_LATEST);
|
2013-06-30 15:00:20 +00:00
|
|
|
|
2011-11-30 15:51:40 +00:00
|
|
|
nsresult rv =
|
2012-03-05 23:22:44 +00:00
|
|
|
xpc->InitClassesWithNewWrappedGlobal(cx, aScope, mPrincipal,
|
2013-06-29 15:11:17 +00:00
|
|
|
flags, options, getter_AddRefs(mGlobal));
|
2011-11-30 15:51:40 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
|
2013-05-09 09:44:19 +00:00
|
|
|
|
2013-05-20 12:44:18 +00:00
|
|
|
JS::Rooted<JSObject*> global(cx, mGlobal->GetJSObject());
|
|
|
|
NS_ENSURE_TRUE(global, false);
|
2011-11-30 15:51:40 +00:00
|
|
|
|
2013-02-20 10:39:59 +00:00
|
|
|
// Set the location information for the new global, so that tools like
|
|
|
|
// about:memory may use that information.
|
|
|
|
xpc::SetLocationForGlobal(global, aID);
|
|
|
|
|
2013-06-30 15:00:18 +00:00
|
|
|
DidCreateGlobal();
|
2011-11-30 15:51:40 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-24 04:50:40 +00:00
|
|
|
NS_IMPL_ISUPPORTS1(nsScriptCacheCleaner, nsIObserver)
|
2010-08-16 20:05:42 +00:00
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
nsFrameMessageManager* nsFrameMessageManager::sChildProcessManager = nullptr;
|
|
|
|
nsFrameMessageManager* nsFrameMessageManager::sParentProcessManager = nullptr;
|
|
|
|
nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr;
|
|
|
|
nsTArray<nsCOMPtr<nsIRunnable> >* nsFrameMessageManager::sPendingSameProcessAsyncMessages = nullptr;
|
2010-08-31 18:58:35 +00:00
|
|
|
|
2011-10-11 10:28:46 +00:00
|
|
|
class nsAsyncMessageToSameProcessChild : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
2013-07-10 22:05:39 +00:00
|
|
|
nsAsyncMessageToSameProcessChild(JSContext* aCx,
|
|
|
|
const nsAString& aMessage,
|
|
|
|
const StructuredCloneData& aData,
|
|
|
|
JS::Handle<JSObject *> aCpows)
|
|
|
|
: mRuntime(js::GetRuntime(aCx)),
|
|
|
|
mMessage(aMessage),
|
|
|
|
mCpows(aCpows)
|
2012-08-02 06:02:29 +00:00
|
|
|
{
|
|
|
|
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
|
|
|
|
NS_RUNTIMEABORT("OOM");
|
|
|
|
}
|
2013-07-10 22:05:39 +00:00
|
|
|
if (mCpows && !js_AddObjectRoot(mRuntime, &mCpows)) {
|
|
|
|
NS_RUNTIMEABORT("OOM");
|
|
|
|
}
|
2012-08-02 06:02:29 +00:00
|
|
|
mClosure = aData.mClosure;
|
|
|
|
}
|
2011-10-11 10:28:46 +00:00
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
~nsAsyncMessageToSameProcessChild()
|
|
|
|
{
|
|
|
|
if (mCpows) {
|
|
|
|
JS_RemoveObjectRootRT(mRuntime, &mCpows);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-11 10:28:46 +00:00
|
|
|
NS_IMETHOD Run()
|
|
|
|
{
|
|
|
|
if (nsFrameMessageManager::sChildProcessManager) {
|
2012-08-02 06:02:29 +00:00
|
|
|
StructuredCloneData data;
|
|
|
|
data.mData = mData.data();
|
|
|
|
data.mDataLength = mData.nbytes();
|
|
|
|
data.mClosure = mClosure;
|
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
SameProcessCpowHolder cpows(mRuntime, JS::Handle<JSObject *>::fromMarkedLocation(&mCpows));
|
|
|
|
|
2011-10-11 10:28:46 +00:00
|
|
|
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sChildProcessManager;
|
|
|
|
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), mMessage,
|
2013-07-10 22:05:39 +00:00
|
|
|
false, &data, &cpows, nullptr);
|
2011-10-11 10:28:46 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2013-07-10 22:05:39 +00:00
|
|
|
JSRuntime* mRuntime;
|
2011-10-11 10:28:46 +00:00
|
|
|
nsString mMessage;
|
2012-08-02 06:02:29 +00:00
|
|
|
JSAutoStructuredCloneBuffer mData;
|
|
|
|
StructuredCloneClosure mClosure;
|
2013-07-10 22:05:39 +00:00
|
|
|
JSObject* mCpows;
|
2011-10-11 10:28:46 +00:00
|
|
|
};
|
|
|
|
|
2012-09-28 05:43:12 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Send messages to an imaginary child process in a single-process scenario.
|
|
|
|
*/
|
|
|
|
class SameParentProcessMessageManagerCallback : public MessageManagerCallback
|
2011-10-11 10:28:46 +00:00
|
|
|
{
|
2012-09-28 05:43:12 +00:00
|
|
|
public:
|
|
|
|
SameParentProcessMessageManagerCallback()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(SameParentProcessMessageManagerCallback);
|
|
|
|
}
|
|
|
|
virtual ~SameParentProcessMessageManagerCallback()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(SameParentProcessMessageManagerCallback);
|
|
|
|
}
|
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
virtual bool DoSendAsyncMessage(JSContext* aCx,
|
|
|
|
const nsAString& aMessage,
|
|
|
|
const StructuredCloneData& aData,
|
|
|
|
JS::Handle<JSObject *> aCpows)
|
2012-09-28 05:43:12 +00:00
|
|
|
{
|
|
|
|
nsRefPtr<nsIRunnable> ev =
|
2013-07-10 22:05:39 +00:00
|
|
|
new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows);
|
2012-09-28 05:43:12 +00:00
|
|
|
NS_DispatchToCurrentThread(ev);
|
|
|
|
return true;
|
|
|
|
}
|
2012-09-28 05:43:12 +00:00
|
|
|
|
2012-09-28 05:43:12 +00:00
|
|
|
bool CheckPermission(const nsAString& aPermission)
|
|
|
|
{
|
|
|
|
// In a single-process scenario, the child always has all capabilities.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-12-22 12:00:10 +00:00
|
|
|
bool CheckManifestURL(const nsAString& aManifestURL)
|
|
|
|
{
|
|
|
|
// In a single-process scenario, the child always has all capabilities.
|
|
|
|
return true;
|
|
|
|
}
|
2013-01-14 10:08:55 +00:00
|
|
|
|
|
|
|
bool CheckAppHasPermission(const nsAString& aPermission)
|
|
|
|
{
|
|
|
|
// In a single-process scenario, the child always has all capabilities.
|
|
|
|
return true;
|
|
|
|
}
|
2012-09-28 05:43:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send messages to the parent process.
|
|
|
|
*/
|
|
|
|
class ChildProcessMessageManagerCallback : public MessageManagerCallback
|
2010-08-31 18:58:35 +00:00
|
|
|
{
|
2012-09-28 05:43:12 +00:00
|
|
|
public:
|
|
|
|
ChildProcessMessageManagerCallback()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(ChildProcessMessageManagerCallback);
|
|
|
|
}
|
|
|
|
virtual ~ChildProcessMessageManagerCallback()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(ChildProcessMessageManagerCallback);
|
|
|
|
}
|
|
|
|
|
2013-10-01 16:15:06 +00:00
|
|
|
virtual bool DoSendBlockingMessage(JSContext* aCx,
|
|
|
|
const nsAString& aMessage,
|
|
|
|
const mozilla::dom::StructuredCloneData& aData,
|
|
|
|
JS::Handle<JSObject *> aCpows,
|
|
|
|
InfallibleTArray<nsString>* aJSONRetVal,
|
|
|
|
bool aIsSync) MOZ_OVERRIDE
|
2012-09-28 05:43:12 +00:00
|
|
|
{
|
|
|
|
mozilla::dom::ContentChild* cc =
|
|
|
|
mozilla::dom::ContentChild::GetSingleton();
|
|
|
|
if (!cc) {
|
|
|
|
return true;
|
|
|
|
}
|
2012-08-02 06:02:29 +00:00
|
|
|
ClonedMessageData data;
|
2013-01-24 02:39:27 +00:00
|
|
|
if (!BuildClonedMessageDataForChild(cc, aData, data)) {
|
|
|
|
return false;
|
2012-08-02 06:02:29 +00:00
|
|
|
}
|
2013-07-10 22:05:39 +00:00
|
|
|
InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
|
|
|
|
if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-10-01 16:15:06 +00:00
|
|
|
if (aIsSync) {
|
|
|
|
return cc->SendSyncMessage(nsString(aMessage), data, cpows, aJSONRetVal);
|
|
|
|
}
|
|
|
|
return cc->CallRpcMessage(nsString(aMessage), data, cpows, aJSONRetVal);
|
2010-08-31 18:58:35 +00:00
|
|
|
}
|
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
virtual bool DoSendAsyncMessage(JSContext* aCx,
|
|
|
|
const nsAString& aMessage,
|
|
|
|
const mozilla::dom::StructuredCloneData& aData,
|
2013-10-01 16:15:06 +00:00
|
|
|
JS::Handle<JSObject *> aCpows) MOZ_OVERRIDE
|
2012-09-28 05:43:12 +00:00
|
|
|
{
|
|
|
|
mozilla::dom::ContentChild* cc =
|
|
|
|
mozilla::dom::ContentChild::GetSingleton();
|
|
|
|
if (!cc) {
|
|
|
|
return true;
|
2011-10-11 10:28:46 +00:00
|
|
|
}
|
2012-08-02 06:02:29 +00:00
|
|
|
ClonedMessageData data;
|
2013-01-24 02:39:27 +00:00
|
|
|
if (!BuildClonedMessageDataForChild(cc, aData, data)) {
|
|
|
|
return false;
|
2012-08-02 06:02:29 +00:00
|
|
|
}
|
2013-07-10 22:05:39 +00:00
|
|
|
InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
|
|
|
|
if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return cc->SendAsyncMessage(nsString(aMessage), data, cpows);
|
2010-08-31 18:58:35 +00:00
|
|
|
}
|
2012-09-28 05:43:12 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2010-08-31 18:58:35 +00:00
|
|
|
|
2011-10-11 10:28:46 +00:00
|
|
|
class nsAsyncMessageToSameProcessParent : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
2013-07-10 22:05:39 +00:00
|
|
|
nsAsyncMessageToSameProcessParent(JSContext* aCx,
|
|
|
|
const nsAString& aMessage,
|
|
|
|
const StructuredCloneData& aData,
|
|
|
|
JS::Handle<JSObject *> aCpows)
|
|
|
|
: mRuntime(js::GetRuntime(aCx)),
|
|
|
|
mMessage(aMessage),
|
|
|
|
mCpows(aCpows)
|
2012-08-02 06:02:29 +00:00
|
|
|
{
|
|
|
|
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
|
|
|
|
NS_RUNTIMEABORT("OOM");
|
|
|
|
}
|
2013-07-10 22:05:39 +00:00
|
|
|
if (mCpows && !js_AddObjectRoot(mRuntime, &mCpows)) {
|
|
|
|
NS_RUNTIMEABORT("OOM");
|
|
|
|
}
|
2012-08-02 06:02:29 +00:00
|
|
|
mClosure = aData.mClosure;
|
|
|
|
}
|
2011-10-11 10:28:46 +00:00
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
~nsAsyncMessageToSameProcessParent()
|
|
|
|
{
|
|
|
|
if (mCpows) {
|
|
|
|
JS_RemoveObjectRootRT(mRuntime, &mCpows);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-11 10:28:46 +00:00
|
|
|
NS_IMETHOD Run()
|
|
|
|
{
|
|
|
|
if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
|
|
|
|
nsFrameMessageManager::sPendingSameProcessAsyncMessages->RemoveElement(this);
|
|
|
|
}
|
|
|
|
if (nsFrameMessageManager::sSameProcessParentManager) {
|
2012-08-02 06:02:29 +00:00
|
|
|
StructuredCloneData data;
|
|
|
|
data.mData = mData.data();
|
|
|
|
data.mDataLength = mData.nbytes();
|
|
|
|
data.mClosure = mClosure;
|
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
SameProcessCpowHolder cpows(mRuntime, JS::Handle<JSObject *>::fromMarkedLocation(&mCpows));
|
|
|
|
|
2012-08-02 06:02:29 +00:00
|
|
|
nsRefPtr<nsFrameMessageManager> ppm =
|
|
|
|
nsFrameMessageManager::sSameProcessParentManager;
|
|
|
|
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
|
2013-07-10 22:05:39 +00:00
|
|
|
mMessage, false, &data, &cpows, nullptr);
|
2012-08-02 06:02:29 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
2011-10-11 10:28:46 +00:00
|
|
|
}
|
2013-07-10 22:05:39 +00:00
|
|
|
JSRuntime* mRuntime;
|
2011-10-11 10:28:46 +00:00
|
|
|
nsString mMessage;
|
2012-08-02 06:02:29 +00:00
|
|
|
JSAutoStructuredCloneBuffer mData;
|
|
|
|
StructuredCloneClosure mClosure;
|
2013-07-10 22:05:39 +00:00
|
|
|
JSObject* mCpows;
|
2011-10-11 10:28:46 +00:00
|
|
|
};
|
|
|
|
|
2012-09-28 05:43:12 +00:00
|
|
|
/**
|
|
|
|
* Send messages to the imaginary parent process in a single-process scenario.
|
|
|
|
*/
|
|
|
|
class SameChildProcessMessageManagerCallback : public MessageManagerCallback
|
2011-10-11 10:28:46 +00:00
|
|
|
{
|
2012-09-28 05:43:12 +00:00
|
|
|
public:
|
|
|
|
SameChildProcessMessageManagerCallback()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(SameChildProcessMessageManagerCallback);
|
2011-10-11 10:28:46 +00:00
|
|
|
}
|
2012-09-28 05:43:12 +00:00
|
|
|
virtual ~SameChildProcessMessageManagerCallback()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(SameChildProcessMessageManagerCallback);
|
|
|
|
}
|
|
|
|
|
2013-10-01 16:15:06 +00:00
|
|
|
virtual bool DoSendBlockingMessage(JSContext* aCx,
|
|
|
|
const nsAString& aMessage,
|
|
|
|
const mozilla::dom::StructuredCloneData& aData,
|
|
|
|
JS::Handle<JSObject *> aCpows,
|
|
|
|
InfallibleTArray<nsString>* aJSONRetVal,
|
|
|
|
bool aIsSync) MOZ_OVERRIDE
|
2012-09-28 05:43:12 +00:00
|
|
|
{
|
|
|
|
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
|
|
|
|
if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
|
|
|
|
asyncMessages.SwapElements(*nsFrameMessageManager::sPendingSameProcessAsyncMessages);
|
|
|
|
uint32_t len = asyncMessages.Length();
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
|
|
|
nsCOMPtr<nsIRunnable> async = asyncMessages[i];
|
|
|
|
async->Run();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nsFrameMessageManager::sSameProcessParentManager) {
|
2013-07-10 22:05:39 +00:00
|
|
|
SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
|
2012-09-28 05:43:12 +00:00
|
|
|
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
|
|
|
|
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), aMessage,
|
2013-07-10 22:05:39 +00:00
|
|
|
true, &aData, &cpows, aJSONRetVal);
|
2012-09-28 05:43:12 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-10 22:05:39 +00:00
|
|
|
virtual bool DoSendAsyncMessage(JSContext* aCx,
|
|
|
|
const nsAString& aMessage,
|
|
|
|
const mozilla::dom::StructuredCloneData& aData,
|
|
|
|
JS::Handle<JSObject *> aCpows)
|
2012-09-28 05:43:12 +00:00
|
|
|
{
|
|
|
|
if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
|
|
|
|
nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray<nsCOMPtr<nsIRunnable> >;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIRunnable> ev =
|
2013-07-10 22:05:39 +00:00
|
|
|
new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows);
|
2012-09-28 05:43:12 +00:00
|
|
|
nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev);
|
|
|
|
NS_DispatchToCurrentThread(ev);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2011-10-11 10:28:46 +00:00
|
|
|
|
2011-08-02 19:57:48 +00:00
|
|
|
// This creates the global parent process message manager.
|
2010-08-31 18:58:35 +00:00
|
|
|
nsresult
|
2012-08-27 14:13:02 +00:00
|
|
|
NS_NewParentProcessMessageManager(nsIMessageBroadcaster** aResult)
|
2010-08-31 18:58:35 +00:00
|
|
|
{
|
|
|
|
NS_ASSERTION(!nsFrameMessageManager::sParentProcessManager,
|
|
|
|
"Re-creating sParentProcessManager");
|
2013-06-15 06:40:22 +00:00
|
|
|
NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default,
|
|
|
|
NS_ERROR_NOT_AVAILABLE);
|
2012-09-28 05:43:12 +00:00
|
|
|
nsRefPtr<nsFrameMessageManager> mm = new nsFrameMessageManager(nullptr,
|
2012-07-30 14:20:58 +00:00
|
|
|
nullptr,
|
2012-09-28 05:43:12 +00:00
|
|
|
MM_CHROME | MM_PROCESSMANAGER | MM_BROADCASTER);
|
2010-08-31 18:58:35 +00:00
|
|
|
nsFrameMessageManager::sParentProcessManager = mm;
|
2012-07-30 14:20:58 +00:00
|
|
|
nsFrameMessageManager::NewProcessMessageManager(nullptr); // Create same process message manager.
|
2010-08-31 18:58:35 +00:00
|
|
|
return CallQueryInterface(mm, aResult);
|
|
|
|
}
|
|
|
|
|
2012-09-28 05:43:12 +00:00
|
|
|
|
2011-08-02 19:57:48 +00:00
|
|
|
nsFrameMessageManager*
|
|
|
|
nsFrameMessageManager::NewProcessMessageManager(mozilla::dom::ContentParent* aProcess)
|
|
|
|
{
|
|
|
|
if (!nsFrameMessageManager::sParentProcessManager) {
|
2013-05-23 18:17:57 +00:00
|
|
|
nsCOMPtr<nsIMessageBroadcaster> dummy =
|
|
|
|
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
|
2011-08-02 19:57:48 +00:00
|
|
|
}
|
|
|
|
|
2013-05-23 18:17:57 +00:00
|
|
|
MOZ_ASSERT(nsFrameMessageManager::sParentProcessManager,
|
|
|
|
"parent process manager not created");
|
2012-09-28 05:43:12 +00:00
|
|
|
nsFrameMessageManager* mm;
|
|
|
|
if (aProcess) {
|
|
|
|
mm = new nsFrameMessageManager(aProcess,
|
|
|
|
nsFrameMessageManager::sParentProcessManager,
|
|
|
|
MM_CHROME | MM_PROCESSMANAGER);
|
|
|
|
} else {
|
|
|
|
mm = new nsFrameMessageManager(new SameParentProcessMessageManagerCallback(),
|
|
|
|
nsFrameMessageManager::sParentProcessManager,
|
|
|
|
MM_CHROME | MM_PROCESSMANAGER | MM_OWNSCALLBACK);
|
2011-10-11 10:28:46 +00:00
|
|
|
sSameProcessParentManager = mm;
|
|
|
|
}
|
2011-08-02 19:57:48 +00:00
|
|
|
return mm;
|
|
|
|
}
|
2010-08-31 18:58:35 +00:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!nsFrameMessageManager::sChildProcessManager,
|
|
|
|
"Re-creating sChildProcessManager");
|
2012-09-28 05:43:12 +00:00
|
|
|
|
|
|
|
MessageManagerCallback* cb;
|
2013-06-15 06:40:22 +00:00
|
|
|
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
2012-09-28 05:43:12 +00:00
|
|
|
cb = new SameChildProcessMessageManagerCallback();
|
|
|
|
} else {
|
|
|
|
cb = new ChildProcessMessageManagerCallback();
|
2013-10-11 23:07:15 +00:00
|
|
|
NS_RegisterMemoryReporter(new MessageManagerReporter());
|
2012-09-28 05:43:12 +00:00
|
|
|
}
|
|
|
|
nsFrameMessageManager* mm = new nsFrameMessageManager(cb,
|
2012-07-30 14:20:58 +00:00
|
|
|
nullptr,
|
2012-09-28 05:43:12 +00:00
|
|
|
MM_PROCESSMANAGER | MM_OWNSCALLBACK);
|
2010-08-31 18:58:35 +00:00
|
|
|
nsFrameMessageManager::sChildProcessManager = mm;
|
|
|
|
return CallQueryInterface(mm, aResult);
|
|
|
|
}
|
2012-01-26 15:39:23 +00:00
|
|
|
|
|
|
|
bool
|
|
|
|
nsFrameMessageManager::MarkForCC()
|
|
|
|
{
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t len = mListeners.Length();
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
2013-08-08 18:36:56 +00:00
|
|
|
if (mListeners[i].mStrongListener) {
|
|
|
|
xpc_TryUnmarkWrappedGrayObject(mListeners[i].mStrongListener);
|
|
|
|
}
|
2012-01-26 15:39:23 +00:00
|
|
|
}
|
2012-10-17 01:22:02 +00:00
|
|
|
if (mRefCnt.IsPurple()) {
|
|
|
|
mRefCnt.RemovePurple();
|
|
|
|
}
|
2012-01-26 15:39:23 +00:00
|
|
|
return true;
|
2012-08-06 12:02:08 +00:00
|
|
|
}
|