/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
void nsFrameMessageManager::RemoveMessageListener(const nsAString& aMessageName,
MessageListener& aListener,
ErrorResult& aError) {
nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
mListeners.Get(aMessageName); if (listeners) {
uint32_t len = listeners->Length(); for (uint32_t i = 0; i < len; ++i) {
MessageListener* strongListener = listeners->ElementAt(i).mListener; if (strongListener && *strongListener == aListener) {
listeners->RemoveElementAt(i); return;
}
}
}
}
void nsFrameMessageManager::LoadScript(const nsAString& aURL, bool aAllowDelayedLoad, bool aRunInGlobalScope,
ErrorResult& aError) { if (aAllowDelayedLoad) { // Cache for future windows or frames
mPendingScripts.AppendElement(aURL);
mPendingScriptsGlobalStates.AppendElement(aRunInGlobalScope);
}
if (mCallback) { #ifdef DEBUG_smaug
printf("Will load %s \n", NS_ConvertUTF16toUTF8(aURL).get()); #endif if (!mCallback->DoLoadMessageManagerScript(aURL, aRunInGlobalScope)) {
aError.Throw(NS_ERROR_FAILURE); return;
}
}
for (uint32_t i = 0; i < mChildManagers.Length(); ++i) {
RefPtr<nsFrameMessageManager> mm = mChildManagers[i]; if (mm) { // Use false here, so that child managers don't cache the script, which // is already cached in the parent.
mm->LoadScript(aURL, false, aRunInGlobalScope, IgnoreErrors());
}
}
}
void nsFrameMessageManager::RemoveDelayedScript(const nsAString& aURL) { for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) { if (mPendingScripts[i] == aURL) {
mPendingScripts.RemoveElementAt(i);
mPendingScriptsGlobalStates.RemoveElementAt(i); break;
}
}
}
void nsFrameMessageManager::GetDelayedScripts(
JSContext* aCx, nsTArray<nsTArray<JS::Value>>& aList, ErrorResult& aError) { // 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() && !IsBroadcaster()) {
NS_WARNING( "Cannot retrieve list of pending frame scripts for frame" "message managers as it may be incomplete");
aError.Throw(NS_ERROR_NOT_IMPLEMENTED); return;
}
aError.MightThrowJSException();
aList.SetCapacity(mPendingScripts.Length()); for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
JS::Rooted<JS::Value> url(aCx); if (!ToJSValue(aCx, mPendingScripts[i], &url)) {
aError.NoteJSContextException(aCx); return;
}
/* static */ bool nsFrameMessageManager::GetParamsForMessage(
JSContext* aCx, const JS::Value& aValue, const JS::Value& aTransfer,
NotNull<StructuredCloneData*> aData) { // First try to use structured clone on the whole thing.
JS::Rooted<JS::Value> v(aCx, aValue);
JS::Rooted<JS::Value> t(aCx, aTransfer);
IgnoredErrorResult rv;
aData->Write(aCx, v, t, JS::CloneDataPolicy(), rv); if (!rv.Failed()) { return true;
}
rv.SuppressException();
nsCOMPtr<nsIConsoleService> console(
do_GetService(NS_CONSOLESERVICE_CONTRACTID)); if (console) { auto location = JSCallingLocation::Get(aCx);
nsCOMPtr<nsIScriptError> error(
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
error->Init(
u"Sending message that cannot be cloned. Are " "you trying to send an XPCOM object?"_ns,
location.FileName(), location.mLine, location.mColumn,
nsIScriptError::warningFlag, "chrome javascript"_ns, false/* from private window */, true /* from chrome context */);
console->LogMessage(error);
}
// Not clonable, try JSON // Bug 1749037 - 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; if (!nsContentUtils::StringifyJSON(aCx, v, json,
UndefinedIsNullStringLiteral)) {
NS_WARNING("nsContentUtils::StringifyJSON() failed");
JS_ClearPendingException(aCx); returnfalse;
}
NS_ENSURE_TRUE(!json.IsEmpty(), false);
aData->Write(aCx, val, rv); if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException(); returnfalse;
}
return true;
}
staticbool sSendingSyncMessage = false;
void nsFrameMessageManager::SendSyncMessage(JSContext* aCx, const nsAString& aMessageName,
JS::Handle<JS::Value> aObj,
nsTArray<JS::Value>& aResult,
ErrorResult& aError) {
NS_ASSERTION(!IsGlobal(), "Should not call SendSyncMessage in chrome");
NS_ASSERTION(!IsBroadcaster(), "Should not call SendSyncMessage in chrome");
NS_ASSERTION(!GetParentManager(), "Should not have parent manager in content!");
if (sSendingSyncMessage) { // No kind of blocking send should be issued on top of a sync message.
aError.Throw(NS_ERROR_UNEXPECTED); return;
}
auto data = MakeNotNull<RefPtr<StructuredCloneData>>(
JS::StructuredCloneScope::DifferentProcess,
StructuredCloneHolder::TransferringNotSupported); if (!GetParamsForMessage(aCx, aObj, JS::UndefinedHandleValue, data)) {
aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return;
}
// Enter the shared module global. // All serialization/deserialization will be performed from this global.
AutoEntryScript aes(xpc::PrivilegedJunkScope(), "message manager receive");
JSContext* cx = aes.cx();
// Initialize the argument.{mData, mJson, mPorts} members. if (aCloneData->HasData()) { // aCloneData may contain transferrables (which can only be received once), // yet can have multiple distinct listeners. Deserialize the data structure // up-front, and use the same value for all callbacks. This is OK as all // listeners are system code.
if (aCloneData->SupportsTransferring() &&
!aCloneData->TakeTransferredPortsAsSequence(argument.mPorts)) {
NS_WARNING("OOM taking transferred ports from StructuredCloneData");
JS_ReportOutOfMemory(cx); return;
}
}
for (RefPtr<nsFrameMessageManager> current = this; current;
current = current->GetParentManager()) { // A small hack to get `this` right on the content side where messageManager // is wrapped in BrowserChildMessageManager's global. // XXX(January 2026): We no longer use a separate global for // BrowserChildMessageManager, so this may no longer be relevant?
nsCOMPtr<nsISupports> thisValue; if (mChrome) {
thisValue = do_QueryObject(current);
} else {
thisValue = aTarget;
}
nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
current->mListeners.Get(aMessage); if (listeners) {
MMListenerRemover lr(this);
// NOTE: This is intentionally accessing `mClosed` not // `current->mClosed`, as we only care about whether the explicit target // of the nsFrameMessageManager call was closed. if (!listener || (!listenerInfo.mListenWhenClosed && mClosed)) { continue;
}
if (aRetVal) { auto data = MakeNotNull<RefPtr<StructuredCloneData>>(
JS::StructuredCloneScope::DifferentProcess,
StructuredCloneHolder::TransferringNotSupported);
data->Write(cx, rval, error); if (NS_WARN_IF(error.Failed())) {
nsString msg = aMessage +
u": message reply cannot be cloned. Are " "you trying to send an XPCOM object?"_ns;
void nsFrameMessageManager::LoadPendingScripts(
nsFrameMessageManager* aManager, nsFrameMessageManager* aChildMM) { // We have parent manager if we're a message broadcaster. // In that case we want to load the pending scripts from all parent // message managers in the hierarchy. Process the parent first so // that pending scripts higher up in the hierarchy are loaded before others.
nsFrameMessageManager* parentManager = aManager->GetParentManager(); if (parentManager) {
LoadPendingScripts(parentManager, aChildMM);
}
for (uint32_t i = 0; i < aManager->mPendingScripts.Length(); ++i) {
aChildMM->LoadScript(aManager->mPendingScripts[i], false,
aManager->mPendingScriptsGlobalStates[i],
IgnoreErrors());
}
}
JS::Rooted<JS::Value> init(aCx, mInitialProcessData); if (mChrome && init.isUndefined()) { // We create the initial object in the junk scope. If we created it in a // normal realm, that realm would leak until shutdown.
JS::Rooted<JSObject*> global(aCx, xpc::PrivilegedJunkScope());
JSAutoRealm ar(aCx, global);
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx)); if (!obj) {
aError.NoteJSContextException(aCx); return;
}
if (!mChrome && XRE_IsParentProcess()) { // This is the cpmm in the parent process. We should use the same object // as the ppmm. Create it first through do_GetService and use the cached // pointer in sParentProcessManager.
nsCOMPtr<nsISupports> ppmm =
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
sParentProcessManager->GetInitialProcessData(aCx, &init, aError); if (aError.Failed()) { return;
}
mInitialProcessData = init;
}
if (!JS_WrapValue(aCx, &init)) {
aError.NoteJSContextException(aCx); return;
}
aInitialProcessData.set(init);
}
WritableSharedMap* nsFrameMessageManager::SharedData() { if (!mChrome || !mIsProcessManager) {
MOZ_ASSERT(false, "Should only call this binding method on ppmm"); return nullptr;
} if (!mSharedData) {
mSharedData = new WritableSharedMap();
} return mSharedData;
}
// Keep track of messages that have a suspiciously large // number of referents (symptom of leak). if (currentCount >= MessageManagerReporter::kSuspectReferentCount) {
aReferentCount->mSuspectMessages.AppendElement(key);
}
aReferentCount->mStrong += listenerCount;
}
// 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) {
RefPtr<nsFrameMessageManager> mm = aMessageManager->mChildManagers[i];
CountReferents(mm, aReferentCount);
}
}
REPORT(nsPrintfCString("message-manager/referent/%s/strong", aManagerType),
aReferentCount.mStrong,
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.mWeakAlive,
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.mWeakDead,
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.mSuspectMessages.Length(); i++) { const uint32_t totalReferentCount =
aReferentCount.mMessageCounter.Get(aReferentCount.mSuspectMessages[i]);
NS_ConvertUTF16toUTF8 suspect(aReferentCount.mSuspectMessages[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));
}
bool hasFlags;
rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
&hasFlags); if (NS_FAILED(rv) || !hasFlags) {
NS_WARNING("Will not load a frame script!"); return nullptr;
}
// If this script won't be cached, or there is only one of this type of // message manager per process, treat this script as run-once. Run-once // scripts can be compiled directly for the target global, and will be // dropped from the preloader cache after they're executed and serialized. // // NOTE: This does not affect the JS::CompileOptions. We generate the same // bytecode as though it were run multiple times. This is required for the // batch decoding from ScriptPreloader to work. bool isRunOnce = IsProcessScoped();
// We don't cache data: scripts, and we also don't cache scripts not from // omni.ja to avoid serving stale bytecode when JAR files from built-in // add-ons installed in the profile directory are updated.
nsAutoCString scheme;
uri->GetScheme(scheme); bool isCacheable = !scheme.EqualsLiteral("data");
// If the script will be reused in this session, compile it in the // compilation scope instead of the current global to avoid keeping the // current compartment alive.
AutoJSAPI jsapi; if (!jsapi.Init(isRunOnce ? aMessageManager : xpc::CompilationScope())) { return nullptr;
}
JSContext* cx = jsapi.cx();
// If we are not encoding to the ScriptPreloader cache, we can now relax // the compile options and use the JS syntax-parser for lower latency. if (!useScriptPreloader || !ScriptPreloader::GetChildSingleton().Active()) {
options.setSourceIsLazy(false);
}
JS::SourceText<Utf8Unit> srcBuf; if (!srcBuf.init(cx, std::move(dataStringBuf), dataStringLength)) { return nullptr;
}
if (isCacheable && !isRunOnce) { // Store into our cache only when we compile it here. auto* holder = new nsMessageManagerScriptHolder(stencil);
sCachedScripts->InsertOrUpdate(aURL, holder);
}
#ifdef DEBUG // The above shouldn't touch any options for instantiation.
JS::InstantiateOptions instantiateOptions(options);
instantiateOptions.assertDefault(); #endif
}
MOZ_ASSERT(stencil);
if (useScriptPreloader) {
MOZ_ASSERT(!cachePath.IsEmpty());
ScriptPreloader::GetChildSingleton().NoteStencil(url, cachePath, stencil,
isRunOnce);
}
return stencil.forget();
}
void nsMessageManagerScriptExecutor::Trace(const TraceCallbacks& aCallbacks, void* aClosure) { for (size_t i = 0, length = mAnonymousGlobalScopes.Length(); i < length;
++i) {
aCallbacks.Trace(&mAnonymousGlobalScopes[i], "mAnonymousGlobalScopes[i]",
aClosure);
}
}
// This creates the global parent process message manager.
nsresult NS_NewParentProcessMessageManager(nsISupports** aResult) {
NS_ASSERTION(!nsFrameMessageManager::sParentProcessManager, "Re-creating sParentProcessManager");
RefPtr<ParentProcessMessageManager> mm = new ParentProcessMessageManager();
nsFrameMessageManager::sParentProcessManager = mm;
nsFrameMessageManager::NewProcessMessageManager( false); // Create same process message manager.
mm.forget(aResult); return NS_OK;
}
MOZ_ASSERT(nsFrameMessageManager::sParentProcessManager, "parent process manager not created");
ProcessMessageManager* mm; if (aIsRemote) { // Callback is set in ContentParent::InitInternal so that the process has // already started when we send pending scripts.
mm = new ProcessMessageManager(
nullptr, nsFrameMessageManager::sParentProcessManager);
} else {
mm = new ProcessMessageManager(new SameParentProcessMessageManagerCallback(),
nsFrameMessageManager::sParentProcessManager,
MessageManagerFlags::MM_OWNSCALLBACK);
mm->SetOsPid(base::GetCurrentProcId());
sSameProcessParentManager = mm;
} return mm;
}
MessageManagerCallback* cb; if (XRE_IsParentProcess()) {
cb = new SameChildProcessMessageManagerCallback();
} else {
cb = new ChildProcessMessageManagerCallback();
RegisterStrongMemoryReporter(MakeAndAddRef<MessageManagerReporter>());
} auto* mm = new ChildProcessMessageManager(cb);
nsFrameMessageManager::SetChildProcessManager(mm); auto global = MakeRefPtr<ContentProcessMessageManager>(mm);
NS_ENSURE_TRUE(global->Init(), NS_ERROR_UNEXPECTED); return CallQueryInterface(global, aResult);
}
void nsFrameMessageManager::MarkForCC() { for (constauto& entry : mListeners) {
nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners = entry.GetWeak();
uint32_t count = listeners->Length(); for (uint32_t i = 0; i < count; i++) {
listeners->ElementAt(i).mListener->MarkForCC();
}
}
if (mRefCnt.IsPurple()) {
mRefCnt.RemovePurple();
}
}
void nsSameProcessAsyncMessageBase::ReceiveMessage(
nsISupports* aTarget, nsFrameLoader* aTargetFrameLoader,
nsFrameMessageManager* aManager) { // Make sure that we have called Init() and it has succeeded.
MOZ_ASSERT(mCalledInit); if (aManager) {
RefPtr<nsFrameMessageManager> mm = aManager;
mm->ReceiveMessage(aTarget, aTargetFrameLoader, mMessage, false,
WrapNotNull(mData.get()), nullptr);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.