Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "base/basictypes.h"
8 #include "nsFrameMessageManager.h"
10 #include "AppProcessChecker.h"
11 #include "ContentChild.h"
12 #include "ContentParent.h"
13 #include "nsContentUtils.h"
14 #include "nsCxPusher.h"
15 #include "nsError.h"
16 #include "nsIXPConnect.h"
17 #include "jsapi.h"
18 #include "nsJSUtils.h"
19 #include "nsJSPrincipals.h"
20 #include "nsNetUtil.h"
21 #include "nsScriptLoader.h"
22 #include "nsFrameLoader.h"
23 #include "nsIXULRuntime.h"
24 #include "nsIScriptError.h"
25 #include "nsIConsoleService.h"
26 #include "nsIMemoryReporter.h"
27 #include "nsIProtocolHandler.h"
28 #include "nsIScriptSecurityManager.h"
29 #include "nsIJSRuntimeService.h"
30 #include "nsIDOMClassInfo.h"
31 #include "nsIDOMFile.h"
32 #include "xpcpublic.h"
33 #include "mozilla/Preferences.h"
34 #include "mozilla/dom/StructuredCloneUtils.h"
35 #include "mozilla/dom/PBlobChild.h"
36 #include "mozilla/dom/PBlobParent.h"
37 #include "JavaScriptChild.h"
38 #include "JavaScriptParent.h"
39 #include "mozilla/dom/DOMStringList.h"
40 #include "nsPrintfCString.h"
41 #include <algorithm>
43 #ifdef ANDROID
44 #include <android/log.h>
45 #endif
46 #ifdef XP_WIN
47 #include <windows.h>
48 # if defined(SendMessage)
49 # undef SendMessage
50 # endif
51 #endif
53 using namespace mozilla;
54 using namespace mozilla::dom;
55 using namespace mozilla::dom::ipc;
57 static PLDHashOperator
58 CycleCollectorTraverseListeners(const nsAString& aKey,
59 nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
60 void* aCb)
61 {
62 nsCycleCollectionTraversalCallback* cb =
63 static_cast<nsCycleCollectionTraversalCallback*> (aCb);
64 uint32_t count = aListeners->Length();
65 for (uint32_t i = 0; i < count; ++i) {
66 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "listeners[i] mStrongListener");
67 cb->NoteXPCOMChild(aListeners->ElementAt(i).mStrongListener.get());
68 }
69 return PL_DHASH_NEXT;
70 }
72 NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameMessageManager)
74 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager)
75 tmp->mListeners.EnumerateRead(CycleCollectorTraverseListeners,
76 static_cast<void*>(&cb));
77 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildManagers)
78 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
80 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFrameMessageManager)
81 tmp->mListeners.Clear();
82 for (int32_t i = tmp->mChildManagers.Count(); i > 0; --i) {
83 static_cast<nsFrameMessageManager*>(tmp->mChildManagers[i - 1])->
84 Disconnect(false);
85 }
86 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildManagers)
87 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
90 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameMessageManager)
91 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentFrameMessageManager)
93 /* nsFrameMessageManager implements nsIMessageSender and nsIMessageBroadcaster,
94 * both of which descend from nsIMessageListenerManager. QI'ing to
95 * nsIMessageListenerManager is therefore ambiguous and needs explicit casts
96 * depending on which child interface applies. */
97 NS_INTERFACE_MAP_ENTRY_AGGREGATED(nsIMessageListenerManager,
98 (mIsBroadcaster ?
99 static_cast<nsIMessageListenerManager*>(
100 static_cast<nsIMessageBroadcaster*>(this)) :
101 static_cast<nsIMessageListenerManager*>(
102 static_cast<nsIMessageSender*>(this))))
104 /* Message managers in child process implement nsIMessageSender and
105 nsISyncMessageSender. Message managers in the chrome process are
106 either broadcasters (if they have subordinate/child message
107 managers) or they're simple message senders. */
108 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISyncMessageSender, !mChrome)
109 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMessageSender, !mChrome || !mIsBroadcaster)
110 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMessageBroadcaster, mChrome && mIsBroadcaster)
112 /* nsIContentFrameMessageManager is accessible only in TabChildGlobal. */
113 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIContentFrameMessageManager,
114 !mChrome && !mIsProcessManager)
116 /* Frame message managers (non-process message managers) support nsIFrameScriptLoader. */
117 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFrameScriptLoader,
118 mChrome && !mIsProcessManager)
120 /* Message senders in the chrome process support nsIProcessChecker. */
121 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIProcessChecker,
122 mChrome && !mIsBroadcaster)
124 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageBroadcaster,
125 mChrome && mIsBroadcaster)
126 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageSender,
127 mChrome && !mIsBroadcaster)
128 NS_INTERFACE_MAP_END
130 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameMessageManager)
131 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameMessageManager)
133 enum ActorFlavorEnum {
134 Parent = 0,
135 Child
136 };
138 template <ActorFlavorEnum>
139 struct BlobTraits
140 { };
142 template <>
143 struct BlobTraits<Parent>
144 {
145 typedef mozilla::dom::BlobParent BlobType;
146 typedef mozilla::dom::PBlobParent ProtocolType;
147 typedef mozilla::dom::ContentParent ConcreteContentManagerType;
148 };
150 template <>
151 struct BlobTraits<Child>
152 {
153 typedef mozilla::dom::BlobChild BlobType;
154 typedef mozilla::dom::PBlobChild ProtocolType;
155 typedef mozilla::dom::ContentChild ConcreteContentManagerType;
156 };
158 template<ActorFlavorEnum>
159 struct DataBlobs
160 { };
162 template<>
163 struct DataBlobs<Parent>
164 {
165 typedef BlobTraits<Parent>::ProtocolType ProtocolType;
167 static InfallibleTArray<ProtocolType*>& Blobs(ClonedMessageData& aData)
168 {
169 return aData.blobsParent();
170 }
172 static const InfallibleTArray<ProtocolType*>& Blobs(const ClonedMessageData& aData)
173 {
174 return aData.blobsParent();
175 }
176 };
178 template<>
179 struct DataBlobs<Child>
180 {
181 typedef BlobTraits<Child>::ProtocolType ProtocolType;
183 static InfallibleTArray<ProtocolType*>& Blobs(ClonedMessageData& aData)
184 {
185 return aData.blobsChild();
186 }
188 static const InfallibleTArray<ProtocolType*>& Blobs(const ClonedMessageData& aData)
189 {
190 return aData.blobsChild();
191 }
192 };
194 template<ActorFlavorEnum Flavor>
195 static bool
196 BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType* aManager,
197 const StructuredCloneData& aData,
198 ClonedMessageData& aClonedData)
199 {
200 SerializedStructuredCloneBuffer& buffer = aClonedData.data();
201 buffer.data = aData.mData;
202 buffer.dataLength = aData.mDataLength;
203 const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
204 if (!blobs.IsEmpty()) {
205 typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
206 InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
207 uint32_t length = blobs.Length();
208 blobList.SetCapacity(length);
209 for (uint32_t i = 0; i < length; ++i) {
210 typename BlobTraits<Flavor>::BlobType* protocolActor =
211 aManager->GetOrCreateActorForBlob(blobs[i]);
212 if (!protocolActor) {
213 return false;
214 }
215 blobList.AppendElement(protocolActor);
216 }
217 }
218 return true;
219 }
221 bool
222 MessageManagerCallback::BuildClonedMessageDataForParent(ContentParent* aParent,
223 const StructuredCloneData& aData,
224 ClonedMessageData& aClonedData)
225 {
226 return BuildClonedMessageData<Parent>(aParent, aData, aClonedData);
227 }
229 bool
230 MessageManagerCallback::BuildClonedMessageDataForChild(ContentChild* aChild,
231 const StructuredCloneData& aData,
232 ClonedMessageData& aClonedData)
233 {
234 return BuildClonedMessageData<Child>(aChild, aData, aClonedData);
235 }
237 template<ActorFlavorEnum Flavor>
238 static StructuredCloneData
239 UnpackClonedMessageData(const ClonedMessageData& aData)
240 {
241 const SerializedStructuredCloneBuffer& buffer = aData.data();
242 typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
243 const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aData);
244 StructuredCloneData cloneData;
245 cloneData.mData = buffer.data;
246 cloneData.mDataLength = buffer.dataLength;
247 if (!blobs.IsEmpty()) {
248 uint32_t length = blobs.Length();
249 cloneData.mClosure.mBlobs.SetCapacity(length);
250 for (uint32_t i = 0; i < length; ++i) {
251 auto* blob =
252 static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
253 MOZ_ASSERT(blob);
254 nsCOMPtr<nsIDOMBlob> domBlob = blob->GetBlob();
255 MOZ_ASSERT(domBlob);
256 cloneData.mClosure.mBlobs.AppendElement(domBlob);
257 }
258 }
259 return cloneData;
260 }
262 StructuredCloneData
263 mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aData)
264 {
265 return UnpackClonedMessageData<Parent>(aData);
266 }
268 StructuredCloneData
269 mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aData)
270 {
271 return UnpackClonedMessageData<Child>(aData);
272 }
274 bool
275 SameProcessCpowHolder::ToObject(JSContext* aCx,
276 JS::MutableHandle<JSObject*> aObjp)
277 {
278 if (!mObj) {
279 return true;
280 }
282 aObjp.set(mObj);
283 return JS_WrapObject(aCx, aObjp);
284 }
286 // nsIMessageListenerManager
288 NS_IMETHODIMP
289 nsFrameMessageManager::AddMessageListener(const nsAString& aMessage,
290 nsIMessageListener* aListener)
291 {
292 nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
293 mListeners.Get(aMessage);
294 if (!listeners) {
295 listeners = new nsAutoTObserverArray<nsMessageListenerInfo, 1>();
296 mListeners.Put(aMessage, listeners);
297 } else {
298 uint32_t len = listeners->Length();
299 for (uint32_t i = 0; i < len; ++i) {
300 if (listeners->ElementAt(i).mStrongListener == aListener) {
301 return NS_OK;
302 }
303 }
304 }
306 nsMessageListenerInfo* entry = listeners->AppendElement();
307 NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
308 entry->mStrongListener = aListener;
309 return NS_OK;
310 }
312 NS_IMETHODIMP
313 nsFrameMessageManager::RemoveMessageListener(const nsAString& aMessage,
314 nsIMessageListener* aListener)
315 {
316 nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
317 mListeners.Get(aMessage);
318 if (!listeners) {
319 return NS_OK;
320 }
322 uint32_t len = listeners->Length();
323 for (uint32_t i = 0; i < len; ++i) {
324 if (listeners->ElementAt(i).mStrongListener == aListener) {
325 listeners->RemoveElementAt(i);
326 return NS_OK;
327 }
328 }
329 return NS_OK;
330 }
332 #ifdef DEBUG
333 typedef struct
334 {
335 nsCOMPtr<nsISupports> mCanonical;
336 nsWeakPtr mWeak;
337 } CanonicalCheckerParams;
339 static PLDHashOperator
340 CanonicalChecker(const nsAString& aKey,
341 nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
342 void* aParams)
343 {
344 CanonicalCheckerParams* params =
345 static_cast<CanonicalCheckerParams*> (aParams);
347 uint32_t count = aListeners->Length();
348 for (uint32_t i = 0; i < count; i++) {
349 if (!aListeners->ElementAt(i).mWeakListener) {
350 continue;
351 }
352 nsCOMPtr<nsISupports> otherCanonical =
353 do_QueryReferent(aListeners->ElementAt(i).mWeakListener);
354 MOZ_ASSERT((params->mCanonical == otherCanonical) ==
355 (params->mWeak == aListeners->ElementAt(i).mWeakListener));
356 }
357 return PL_DHASH_NEXT;
358 }
359 #endif
361 NS_IMETHODIMP
362 nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage,
363 nsIMessageListener* aListener)
364 {
365 nsWeakPtr weak = do_GetWeakReference(aListener);
366 NS_ENSURE_TRUE(weak, NS_ERROR_NO_INTERFACE);
368 #ifdef DEBUG
369 // It's technically possible that one object X could give two different
370 // nsIWeakReference*'s when you do_GetWeakReference(X). We really don't want
371 // this to happen; it will break e.g. RemoveWeakMessageListener. So let's
372 // check that we're not getting ourselves into that situation.
373 nsCOMPtr<nsISupports> canonical = do_QueryInterface(aListener);
374 CanonicalCheckerParams params;
375 params.mCanonical = canonical;
376 params.mWeak = weak;
377 mListeners.EnumerateRead(CanonicalChecker, (void*)¶ms);
378 #endif
380 nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
381 mListeners.Get(aMessage);
382 if (!listeners) {
383 listeners = new nsAutoTObserverArray<nsMessageListenerInfo, 1>();
384 mListeners.Put(aMessage, listeners);
385 } else {
386 uint32_t len = listeners->Length();
387 for (uint32_t i = 0; i < len; ++i) {
388 if (listeners->ElementAt(i).mWeakListener == weak) {
389 return NS_OK;
390 }
391 }
392 }
394 nsMessageListenerInfo* entry = listeners->AppendElement();
395 entry->mWeakListener = weak;
396 return NS_OK;
397 }
399 NS_IMETHODIMP
400 nsFrameMessageManager::RemoveWeakMessageListener(const nsAString& aMessage,
401 nsIMessageListener* aListener)
402 {
403 nsWeakPtr weak = do_GetWeakReference(aListener);
404 NS_ENSURE_TRUE(weak, NS_OK);
406 nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
407 mListeners.Get(aMessage);
408 if (!listeners) {
409 return NS_OK;
410 }
412 uint32_t len = listeners->Length();
413 for (uint32_t i = 0; i < len; ++i) {
414 if (listeners->ElementAt(i).mWeakListener == weak) {
415 listeners->RemoveElementAt(i);
416 return NS_OK;
417 }
418 }
420 return NS_OK;
421 }
423 // nsIFrameScriptLoader
425 NS_IMETHODIMP
426 nsFrameMessageManager::LoadFrameScript(const nsAString& aURL,
427 bool aAllowDelayedLoad,
428 bool aRunInGlobalScope)
429 {
430 // FIXME: Bug 673569 is currently disabled.
431 aRunInGlobalScope = true;
433 if (aAllowDelayedLoad) {
434 if (IsGlobal() || IsWindowLevel()) {
435 // Cache for future windows or frames
436 mPendingScripts.AppendElement(aURL);
437 mPendingScriptsGlobalStates.AppendElement(aRunInGlobalScope);
438 } else if (!mCallback) {
439 // We're frame message manager, which isn't connected yet.
440 mPendingScripts.AppendElement(aURL);
441 mPendingScriptsGlobalStates.AppendElement(aRunInGlobalScope);
442 return NS_OK;
443 }
444 }
446 if (mCallback) {
447 #ifdef DEBUG_smaug
448 printf("Will load %s \n", NS_ConvertUTF16toUTF8(aURL).get());
449 #endif
450 NS_ENSURE_TRUE(mCallback->DoLoadFrameScript(aURL, aRunInGlobalScope),
451 NS_ERROR_FAILURE);
452 }
454 for (int32_t i = 0; i < mChildManagers.Count(); ++i) {
455 nsRefPtr<nsFrameMessageManager> mm =
456 static_cast<nsFrameMessageManager*>(mChildManagers[i]);
457 if (mm) {
458 // Use false here, so that child managers don't cache the script, which
459 // is already cached in the parent.
460 mm->LoadFrameScript(aURL, false, aRunInGlobalScope);
461 }
462 }
463 return NS_OK;
464 }
466 NS_IMETHODIMP
467 nsFrameMessageManager::RemoveDelayedFrameScript(const nsAString& aURL)
468 {
469 for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
470 if (mPendingScripts[i] == aURL) {
471 mPendingScripts.RemoveElementAt(i);
472 mPendingScriptsGlobalStates.RemoveElementAt(i);
473 break;
474 }
475 }
476 return NS_OK;
477 }
479 NS_IMETHODIMP
480 nsFrameMessageManager::GetDelayedFrameScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList)
481 {
482 // Frame message managers may return an incomplete list because scripts
483 // that were loaded after it was connected are not added to the list.
484 if (!IsGlobal() && !IsWindowLevel()) {
485 NS_WARNING("Cannot retrieve list of pending frame scripts for frame"
486 "message managers as it may be incomplete");
487 return NS_ERROR_NOT_IMPLEMENTED;
488 }
490 JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, mPendingScripts.Length()));
491 NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
493 JS::Rooted<JSString*> url(aCx);
494 JS::Rooted<JSObject*> pair(aCx);
495 for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
496 url = JS_NewUCStringCopyN(aCx, mPendingScripts[i].get(), mPendingScripts[i].Length());
497 NS_ENSURE_TRUE(url, NS_ERROR_OUT_OF_MEMORY);
499 JS::AutoValueArray<2> pairElts(aCx);
500 pairElts[0].setString(url);
501 pairElts[1].setBoolean(mPendingScriptsGlobalStates[i]);
503 pair = JS_NewArrayObject(aCx, pairElts);
504 NS_ENSURE_TRUE(pair, NS_ERROR_OUT_OF_MEMORY);
506 NS_ENSURE_TRUE(JS_SetElement(aCx, array, i, pair),
507 NS_ERROR_OUT_OF_MEMORY);
508 }
510 aList.setObject(*array);
511 return NS_OK;
512 }
514 static bool
515 JSONCreator(const jschar* aBuf, uint32_t aLen, void* aData)
516 {
517 nsAString* result = static_cast<nsAString*>(aData);
518 result->Append(static_cast<const char16_t*>(aBuf),
519 static_cast<uint32_t>(aLen));
520 return true;
521 }
523 static bool
524 GetParamsForMessage(JSContext* aCx,
525 const JS::Value& aJSON,
526 JSAutoStructuredCloneBuffer& aBuffer,
527 StructuredCloneClosure& aClosure)
528 {
529 JS::Rooted<JS::Value> v(aCx, aJSON);
530 if (WriteStructuredClone(aCx, v, aBuffer, aClosure)) {
531 return true;
532 }
533 JS_ClearPendingException(aCx);
535 // Not clonable, try JSON
536 //XXX This is ugly but currently structured cloning doesn't handle
537 // properly cases when interface is implemented in JS and used
538 // as a dictionary.
539 nsAutoString json;
540 NS_ENSURE_TRUE(JS_Stringify(aCx, &v, JS::NullPtr(), JS::NullHandleValue,
541 JSONCreator, &json), false);
542 NS_ENSURE_TRUE(!json.IsEmpty(), false);
544 JS::Rooted<JS::Value> val(aCx, JS::NullValue());
545 NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast<const jschar*>(json.get()),
546 json.Length(), &val), false);
548 return WriteStructuredClone(aCx, val, aBuffer, aClosure);
549 }
552 // nsISyncMessageSender
554 static bool sSendingSyncMessage = false;
556 NS_IMETHODIMP
557 nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
558 JS::Handle<JS::Value> aJSON,
559 JS::Handle<JS::Value> aObjects,
560 nsIPrincipal* aPrincipal,
561 JSContext* aCx,
562 uint8_t aArgc,
563 JS::MutableHandle<JS::Value> aRetval)
564 {
565 return SendMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx, aArgc,
566 aRetval, true);
567 }
569 NS_IMETHODIMP
570 nsFrameMessageManager::SendRpcMessage(const nsAString& aMessageName,
571 JS::Handle<JS::Value> aJSON,
572 JS::Handle<JS::Value> aObjects,
573 nsIPrincipal* aPrincipal,
574 JSContext* aCx,
575 uint8_t aArgc,
576 JS::MutableHandle<JS::Value> aRetval)
577 {
578 return SendMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx, aArgc,
579 aRetval, false);
580 }
582 nsresult
583 nsFrameMessageManager::SendMessage(const nsAString& aMessageName,
584 JS::Handle<JS::Value> aJSON,
585 JS::Handle<JS::Value> aObjects,
586 nsIPrincipal* aPrincipal,
587 JSContext* aCx,
588 uint8_t aArgc,
589 JS::MutableHandle<JS::Value> aRetval,
590 bool aIsSync)
591 {
592 NS_ASSERTION(!IsGlobal(), "Should not call SendSyncMessage in chrome");
593 NS_ASSERTION(!IsWindowLevel(), "Should not call SendSyncMessage in chrome");
594 NS_ASSERTION(!mParentManager, "Should not have parent manager in content!");
596 aRetval.setUndefined();
597 NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
599 if (sSendingSyncMessage && aIsSync) {
600 // No kind of blocking send should be issued on top of a sync message.
601 return NS_ERROR_UNEXPECTED;
602 }
604 StructuredCloneData data;
605 JSAutoStructuredCloneBuffer buffer;
606 if (aArgc >= 2 &&
607 !GetParamsForMessage(aCx, aJSON, buffer, data.mClosure)) {
608 return NS_ERROR_DOM_DATA_CLONE_ERR;
609 }
610 data.mData = buffer.data();
611 data.mDataLength = buffer.nbytes();
613 JS::Rooted<JSObject*> objects(aCx);
614 if (aArgc >= 3 && aObjects.isObject()) {
615 objects = &aObjects.toObject();
616 }
618 InfallibleTArray<nsString> retval;
620 sSendingSyncMessage |= aIsSync;
621 bool rv = mCallback->DoSendBlockingMessage(aCx, aMessageName, data, objects,
622 aPrincipal, &retval, aIsSync);
623 if (aIsSync) {
624 sSendingSyncMessage = false;
625 }
627 if (!rv) {
628 return NS_OK;
629 }
631 uint32_t len = retval.Length();
632 JS::Rooted<JSObject*> dataArray(aCx, JS_NewArrayObject(aCx, len));
633 NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY);
635 for (uint32_t i = 0; i < len; ++i) {
636 if (retval[i].IsEmpty()) {
637 continue;
638 }
640 JS::Rooted<JS::Value> ret(aCx);
641 if (!JS_ParseJSON(aCx, static_cast<const jschar*>(retval[i].get()),
642 retval[i].Length(), &ret)) {
643 return NS_ERROR_UNEXPECTED;
644 }
645 NS_ENSURE_TRUE(JS_SetElement(aCx, dataArray, i, ret),
646 NS_ERROR_OUT_OF_MEMORY);
647 }
649 aRetval.setObject(*dataArray);
650 return NS_OK;
651 }
653 nsresult
654 nsFrameMessageManager::DispatchAsyncMessageInternal(JSContext* aCx,
655 const nsAString& aMessage,
656 const StructuredCloneData& aData,
657 JS::Handle<JSObject *> aCpows,
658 nsIPrincipal* aPrincipal)
659 {
660 if (mIsBroadcaster) {
661 int32_t len = mChildManagers.Count();
662 for (int32_t i = 0; i < len; ++i) {
663 static_cast<nsFrameMessageManager*>(mChildManagers[i])->
664 DispatchAsyncMessageInternal(aCx, aMessage, aData, aCpows, aPrincipal);
665 }
666 return NS_OK;
667 }
669 NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
670 if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows, aPrincipal)) {
671 return NS_ERROR_FAILURE;
672 }
673 return NS_OK;
674 }
676 nsresult
677 nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
678 const JS::Value& aJSON,
679 const JS::Value& aObjects,
680 nsIPrincipal* aPrincipal,
681 JSContext* aCx,
682 uint8_t aArgc)
683 {
684 StructuredCloneData data;
685 JSAutoStructuredCloneBuffer buffer;
687 if (aArgc >= 2 &&
688 !GetParamsForMessage(aCx, aJSON, buffer, data.mClosure)) {
689 return NS_ERROR_DOM_DATA_CLONE_ERR;
690 }
692 JS::Rooted<JSObject*> objects(aCx);
693 if (aArgc >= 3 && aObjects.isObject()) {
694 objects = &aObjects.toObject();
695 }
697 data.mData = buffer.data();
698 data.mDataLength = buffer.nbytes();
700 return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects,
701 aPrincipal);
702 }
705 // nsIMessageSender
707 NS_IMETHODIMP
708 nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
709 JS::Handle<JS::Value> aJSON,
710 JS::Handle<JS::Value> aObjects,
711 nsIPrincipal* aPrincipal,
712 JSContext* aCx,
713 uint8_t aArgc)
714 {
715 return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx,
716 aArgc);
717 }
720 // nsIMessageBroadcaster
722 NS_IMETHODIMP
723 nsFrameMessageManager::BroadcastAsyncMessage(const nsAString& aMessageName,
724 JS::Handle<JS::Value> aJSON,
725 JS::Handle<JS::Value> aObjects,
726 JSContext* aCx,
727 uint8_t aArgc)
728 {
729 return DispatchAsyncMessage(aMessageName, aJSON, aObjects, nullptr, aCx,
730 aArgc);
731 }
733 NS_IMETHODIMP
734 nsFrameMessageManager::GetChildCount(uint32_t* aChildCount)
735 {
736 *aChildCount = static_cast<uint32_t>(mChildManagers.Count());
737 return NS_OK;
738 }
740 NS_IMETHODIMP
741 nsFrameMessageManager::GetChildAt(uint32_t aIndex,
742 nsIMessageListenerManager** aMM)
743 {
744 *aMM = nullptr;
745 nsCOMPtr<nsIMessageListenerManager> mm =
746 do_QueryInterface(mChildManagers.SafeObjectAt(static_cast<uint32_t>(aIndex)));
747 mm.swap(*aMM);
748 return NS_OK;
749 }
752 // nsIContentFrameMessageManager
754 NS_IMETHODIMP
755 nsFrameMessageManager::Dump(const nsAString& aStr)
756 {
757 #ifdef ANDROID
758 __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", NS_ConvertUTF16toUTF8(aStr).get());
759 #endif
760 #ifdef XP_WIN
761 if (IsDebuggerPresent()) {
762 OutputDebugStringW(PromiseFlatString(aStr).get());
763 }
764 #endif
765 fputs(NS_ConvertUTF16toUTF8(aStr).get(), stdout);
766 fflush(stdout);
767 return NS_OK;
768 }
770 NS_IMETHODIMP
771 nsFrameMessageManager::PrivateNoteIntentionalCrash()
772 {
773 return NS_ERROR_NOT_IMPLEMENTED;
774 }
776 NS_IMETHODIMP
777 nsFrameMessageManager::GetContent(nsIDOMWindow** aContent)
778 {
779 *aContent = nullptr;
780 return NS_OK;
781 }
783 NS_IMETHODIMP
784 nsFrameMessageManager::GetDocShell(nsIDocShell** aDocShell)
785 {
786 *aDocShell = nullptr;
787 return NS_OK;
788 }
790 NS_IMETHODIMP
791 nsFrameMessageManager::Btoa(const nsAString& aBinaryData,
792 nsAString& aAsciiBase64String)
793 {
794 return NS_OK;
795 }
797 NS_IMETHODIMP
798 nsFrameMessageManager::Atob(const nsAString& aAsciiString,
799 nsAString& aBinaryData)
800 {
801 return NS_OK;
802 }
804 // nsIProcessChecker
806 nsresult
807 nsFrameMessageManager::AssertProcessInternal(ProcessCheckerType aType,
808 const nsAString& aCapability,
809 bool* aValid)
810 {
811 *aValid = false;
813 // This API is only supported for message senders in the chrome process.
814 if (!mChrome || mIsBroadcaster) {
815 return NS_ERROR_NOT_IMPLEMENTED;
816 }
817 if (!mCallback) {
818 return NS_ERROR_NOT_AVAILABLE;
819 }
820 switch (aType) {
821 case PROCESS_CHECKER_PERMISSION:
822 *aValid = mCallback->CheckPermission(aCapability);
823 break;
824 case PROCESS_CHECKER_MANIFEST_URL:
825 *aValid = mCallback->CheckManifestURL(aCapability);
826 break;
827 case ASSERT_APP_HAS_PERMISSION:
828 *aValid = mCallback->CheckAppHasPermission(aCapability);
829 break;
830 default:
831 break;
832 }
833 return NS_OK;
834 }
836 NS_IMETHODIMP
837 nsFrameMessageManager::AssertPermission(const nsAString& aPermission,
838 bool* aHasPermission)
839 {
840 return AssertProcessInternal(PROCESS_CHECKER_PERMISSION,
841 aPermission,
842 aHasPermission);
843 }
845 NS_IMETHODIMP
846 nsFrameMessageManager::AssertContainApp(const nsAString& aManifestURL,
847 bool* aHasManifestURL)
848 {
849 return AssertProcessInternal(PROCESS_CHECKER_MANIFEST_URL,
850 aManifestURL,
851 aHasManifestURL);
852 }
854 NS_IMETHODIMP
855 nsFrameMessageManager::AssertAppHasPermission(const nsAString& aPermission,
856 bool* aHasPermission)
857 {
858 return AssertProcessInternal(ASSERT_APP_HAS_PERMISSION,
859 aPermission,
860 aHasPermission);
861 }
863 NS_IMETHODIMP
864 nsFrameMessageManager::AssertAppHasStatus(unsigned short aStatus,
865 bool* aHasStatus)
866 {
867 *aHasStatus = false;
869 // This API is only supported for message senders in the chrome process.
870 if (!mChrome || mIsBroadcaster) {
871 return NS_ERROR_NOT_IMPLEMENTED;
872 }
873 if (!mCallback) {
874 return NS_ERROR_NOT_AVAILABLE;
875 }
876 *aHasStatus = mCallback->CheckAppHasStatus(aStatus);
878 return NS_OK;
879 }
881 class MMListenerRemover
882 {
883 public:
884 MMListenerRemover(nsFrameMessageManager* aMM)
885 : mWasHandlingMessage(aMM->mHandlingMessage)
886 , mMM(aMM)
887 {
888 mMM->mHandlingMessage = true;
889 }
890 ~MMListenerRemover()
891 {
892 if (!mWasHandlingMessage) {
893 mMM->mHandlingMessage = false;
894 if (mMM->mDisconnected) {
895 mMM->mListeners.Clear();
896 }
897 }
898 }
900 bool mWasHandlingMessage;
901 nsRefPtr<nsFrameMessageManager> mMM;
902 };
905 // nsIMessageListener
907 nsresult
908 nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
909 const nsAString& aMessage,
910 bool aIsSync,
911 const StructuredCloneData* aCloneData,
912 CpowHolder* aCpows,
913 nsIPrincipal* aPrincipal,
914 InfallibleTArray<nsString>* aJSONRetVal)
915 {
916 AutoSafeJSContext cx;
917 nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
918 mListeners.Get(aMessage);
919 if (listeners) {
921 MMListenerRemover lr(this);
923 nsAutoTObserverArray<nsMessageListenerInfo, 1>::EndLimitedIterator
924 iter(*listeners);
925 while(iter.HasMore()) {
926 nsMessageListenerInfo& listener = iter.GetNext();
927 // Remove mListeners[i] if it's an expired weak listener.
928 nsCOMPtr<nsISupports> weakListener;
929 if (listener.mWeakListener) {
930 weakListener = do_QueryReferent(listener.mWeakListener);
931 if (!weakListener) {
932 listeners->RemoveElement(listener);
933 continue;
934 }
935 }
937 nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS;
938 if (weakListener) {
939 wrappedJS = do_QueryInterface(weakListener);
940 } else {
941 wrappedJS = do_QueryInterface(listener.mStrongListener);
942 }
944 if (!wrappedJS) {
945 continue;
946 }
947 JS::Rooted<JSObject*> object(cx, wrappedJS->GetJSObject());
948 if (!object) {
949 continue;
950 }
951 JSAutoCompartment ac(cx, object);
953 // The parameter for the listener function.
954 JS::Rooted<JSObject*> param(cx,
955 JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
956 NS_ENSURE_TRUE(param, NS_ERROR_OUT_OF_MEMORY);
958 JS::Rooted<JS::Value> targetv(cx);
959 js::AssertSameCompartment(cx, object);
960 nsresult rv = nsContentUtils::WrapNative(cx, aTarget, &targetv);
961 NS_ENSURE_SUCCESS(rv, rv);
963 JS::Rooted<JSObject*> cpows(cx);
964 if (aCpows) {
965 if (!aCpows->ToObject(cx, &cpows)) {
966 return NS_ERROR_UNEXPECTED;
967 }
968 }
970 if (!cpows) {
971 cpows = JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr());
972 if (!cpows) {
973 return NS_ERROR_UNEXPECTED;
974 }
975 }
977 JS::Rooted<JS::Value> cpowsv(cx, JS::ObjectValue(*cpows));
979 JS::Rooted<JS::Value> json(cx, JS::NullValue());
980 if (aCloneData && aCloneData->mDataLength &&
981 !ReadStructuredClone(cx, *aCloneData, &json)) {
982 JS_ClearPendingException(cx);
983 return NS_OK;
984 }
985 JS::Rooted<JSString*> jsMessage(cx,
986 JS_NewUCStringCopyN(cx,
987 static_cast<const jschar*>(aMessage.BeginReading()),
988 aMessage.Length()));
989 NS_ENSURE_TRUE(jsMessage, NS_ERROR_OUT_OF_MEMORY);
990 JS::Rooted<JS::Value> syncv(cx, JS::BooleanValue(aIsSync));
991 JS_DefineProperty(cx, param, "target", targetv, JSPROP_ENUMERATE);
992 JS_DefineProperty(cx, param, "name", jsMessage, JSPROP_ENUMERATE);
993 JS_DefineProperty(cx, param, "sync", syncv, JSPROP_ENUMERATE);
994 JS_DefineProperty(cx, param, "json", json, JSPROP_ENUMERATE); // deprecated
995 JS_DefineProperty(cx, param, "data", json, JSPROP_ENUMERATE);
996 JS_DefineProperty(cx, param, "objects", cpowsv, JSPROP_ENUMERATE);
998 // message.principal == null
999 if (!aPrincipal) {
1000 JS_DefineProperty(cx, param, "principal", JS::UndefinedHandleValue, JSPROP_ENUMERATE);
1001 }
1003 // message.principal = { appId: <id>, origin: <origin>, isInBrowserElement: <something> }
1004 else {
1005 JS::Rooted<JSObject*> principalObj(cx,
1006 JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
1008 uint32_t appId;
1009 nsresult rv = aPrincipal->GetAppId(&appId);
1010 NS_ENSURE_SUCCESS(rv, rv);
1012 JS_DefineProperty(cx, principalObj, "appId", appId, JSPROP_ENUMERATE);
1014 nsCString origin;
1015 rv = aPrincipal->GetOrigin(getter_Copies(origin));
1016 NS_ENSURE_SUCCESS(rv, rv);
1018 JS::Rooted<JSString*> originStr(cx, JS_NewStringCopyN(cx, origin.get(), origin.Length()));
1019 NS_ENSURE_TRUE(originStr, NS_ERROR_OUT_OF_MEMORY);
1020 JS_DefineProperty(cx, principalObj, "origin", originStr, JSPROP_ENUMERATE);
1022 bool browser;
1023 rv = aPrincipal->GetIsInBrowserElement(&browser);
1024 NS_ENSURE_SUCCESS(rv, rv);
1026 JS::Rooted<JS::Value> browserValue(cx, JS::BooleanValue(browser));
1027 JS_DefineProperty(cx, principalObj, "isInBrowserElement", browserValue, JSPROP_ENUMERATE);
1029 JS_DefineProperty(cx, param, "principal", principalObj, JSPROP_ENUMERATE);
1030 }
1032 JS::Rooted<JS::Value> thisValue(cx, JS::UndefinedValue());
1034 JS::Rooted<JS::Value> funval(cx);
1035 if (JS_ObjectIsCallable(cx, object)) {
1036 // If the listener is a JS function:
1037 funval.setObject(*object);
1039 // A small hack to get 'this' value right on content side where
1040 // messageManager is wrapped in TabChildGlobal.
1041 nsCOMPtr<nsISupports> defaultThisValue;
1042 if (mChrome) {
1043 defaultThisValue = do_QueryObject(this);
1044 } else {
1045 defaultThisValue = aTarget;
1046 }
1047 js::AssertSameCompartment(cx, object);
1048 nsresult rv = nsContentUtils::WrapNative(cx, defaultThisValue, &thisValue);
1049 NS_ENSURE_SUCCESS(rv, rv);
1050 } else {
1051 // If the listener is a JS object which has receiveMessage function:
1052 if (!JS_GetProperty(cx, object, "receiveMessage", &funval) ||
1053 !funval.isObject())
1054 return NS_ERROR_UNEXPECTED;
1056 // Check if the object is even callable.
1057 NS_ENSURE_STATE(JS_ObjectIsCallable(cx, &funval.toObject()));
1058 thisValue.setObject(*object);
1059 }
1061 JS::Rooted<JS::Value> rval(cx, JSVAL_VOID);
1062 JS::Rooted<JS::Value> argv(cx, JS::ObjectValue(*param));
1064 {
1065 JS::Rooted<JSObject*> thisObject(cx, thisValue.toObjectOrNull());
1067 JSAutoCompartment tac(cx, thisObject);
1068 if (!JS_WrapValue(cx, &argv)) {
1069 return NS_ERROR_UNEXPECTED;
1070 }
1072 if (!JS_CallFunctionValue(cx, thisObject, funval, argv, &rval)) {
1073 nsJSUtils::ReportPendingException(cx);
1074 continue;
1075 }
1076 if (aJSONRetVal) {
1077 nsString json;
1078 if (!JS_Stringify(cx, &rval, JS::NullPtr(), JS::NullHandleValue,
1079 JSONCreator, &json)) {
1080 nsJSUtils::ReportPendingException(cx);
1081 continue;
1082 }
1083 aJSONRetVal->AppendElement(json);
1084 }
1085 }
1086 }
1087 }
1088 nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = mParentManager;
1089 return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
1090 aIsSync, aCloneData,
1091 aCpows, aPrincipal,
1092 aJSONRetVal) : NS_OK;
1093 }
1095 void
1096 nsFrameMessageManager::AddChildManager(nsFrameMessageManager* aManager)
1097 {
1098 mChildManagers.AppendObject(aManager);
1100 nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = this;
1101 nsRefPtr<nsFrameMessageManager> kungfuDeathGrip2 = aManager;
1102 // We have parent manager if we're a window message manager.
1103 // In that case we want to load the pending scripts from global
1104 // message manager.
1105 if (mParentManager) {
1106 nsRefPtr<nsFrameMessageManager> globalMM = mParentManager;
1107 for (uint32_t i = 0; i < globalMM->mPendingScripts.Length(); ++i) {
1108 aManager->LoadFrameScript(globalMM->mPendingScripts[i], false,
1109 globalMM->mPendingScriptsGlobalStates[i]);
1110 }
1111 }
1112 for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
1113 aManager->LoadFrameScript(mPendingScripts[i], false,
1114 mPendingScriptsGlobalStates[i]);
1115 }
1116 }
1118 void
1119 nsFrameMessageManager::SetCallback(MessageManagerCallback* aCallback)
1120 {
1121 MOZ_ASSERT(!mIsBroadcaster || !mCallback,
1122 "Broadcasters cannot have callbacks!");
1123 if (aCallback && mCallback != aCallback) {
1124 mCallback = aCallback;
1125 if (mOwnsCallback) {
1126 mOwnedCallback = aCallback;
1127 }
1128 }
1129 }
1131 void
1132 nsFrameMessageManager::InitWithCallback(MessageManagerCallback* aCallback)
1133 {
1134 if (mCallback) {
1135 // Initialization should only happen once.
1136 return;
1137 }
1139 SetCallback(aCallback);
1141 // First load global scripts by adding this to parent manager.
1142 if (mParentManager) {
1143 mParentManager->AddChildManager(this);
1144 }
1146 for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
1147 LoadFrameScript(mPendingScripts[i], false, mPendingScriptsGlobalStates[i]);
1148 }
1149 }
1151 void
1152 nsFrameMessageManager::RemoveFromParent()
1153 {
1154 if (mParentManager) {
1155 mParentManager->RemoveChildManager(this);
1156 }
1157 mParentManager = nullptr;
1158 mCallback = nullptr;
1159 mOwnedCallback = nullptr;
1160 }
1162 void
1163 nsFrameMessageManager::Disconnect(bool aRemoveFromParent)
1164 {
1165 if (!mDisconnected) {
1166 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
1167 if (obs) {
1168 obs->NotifyObservers(NS_ISUPPORTS_CAST(nsIContentFrameMessageManager*, this),
1169 "message-manager-disconnect", nullptr);
1170 }
1171 }
1172 if (mParentManager && aRemoveFromParent) {
1173 mParentManager->RemoveChildManager(this);
1174 }
1175 mDisconnected = true;
1176 mParentManager = nullptr;
1177 mCallback = nullptr;
1178 mOwnedCallback = nullptr;
1179 if (!mHandlingMessage) {
1180 mListeners.Clear();
1181 }
1182 }
1184 namespace {
1186 struct MessageManagerReferentCount
1187 {
1188 MessageManagerReferentCount() : mStrong(0), mWeakAlive(0), mWeakDead(0) {}
1189 size_t mStrong;
1190 size_t mWeakAlive;
1191 size_t mWeakDead;
1192 nsTArray<nsString> mSuspectMessages;
1193 nsDataHashtable<nsStringHashKey, uint32_t> mMessageCounter;
1194 };
1196 } // anonymous namespace
1198 namespace mozilla {
1199 namespace dom {
1201 class MessageManagerReporter MOZ_FINAL : public nsIMemoryReporter
1202 {
1203 public:
1204 NS_DECL_ISUPPORTS
1205 NS_DECL_NSIMEMORYREPORTER
1207 static const size_t kSuspectReferentCount = 300;
1208 protected:
1209 void CountReferents(nsFrameMessageManager* aMessageManager,
1210 MessageManagerReferentCount* aReferentCount);
1211 };
1213 NS_IMPL_ISUPPORTS(MessageManagerReporter, nsIMemoryReporter)
1215 static PLDHashOperator
1216 CollectMessageListenerData(const nsAString& aKey,
1217 nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
1218 void* aData)
1219 {
1220 MessageManagerReferentCount* referentCount =
1221 static_cast<MessageManagerReferentCount*>(aData);
1223 uint32_t listenerCount = aListeners->Length();
1224 if (!listenerCount) {
1225 return PL_DHASH_NEXT;
1226 }
1228 nsString key(aKey);
1229 uint32_t oldCount = 0;
1230 referentCount->mMessageCounter.Get(key, &oldCount);
1231 uint32_t currentCount = oldCount + listenerCount;
1232 referentCount->mMessageCounter.Put(key, currentCount);
1234 // Keep track of messages that have a suspiciously large
1235 // number of referents (symptom of leak).
1236 if (currentCount == MessageManagerReporter::kSuspectReferentCount) {
1237 referentCount->mSuspectMessages.AppendElement(key);
1238 }
1240 for (uint32_t i = 0; i < listenerCount; ++i) {
1241 const nsMessageListenerInfo& listenerInfo =
1242 aListeners->ElementAt(i);
1243 if (listenerInfo.mWeakListener) {
1244 nsCOMPtr<nsISupports> referent =
1245 do_QueryReferent(listenerInfo.mWeakListener);
1246 if (referent) {
1247 referentCount->mWeakAlive++;
1248 } else {
1249 referentCount->mWeakDead++;
1250 }
1251 } else {
1252 referentCount->mStrong++;
1253 }
1254 }
1255 return PL_DHASH_NEXT;
1256 }
1258 void
1259 MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager,
1260 MessageManagerReferentCount* aReferentCount)
1261 {
1262 aMessageManager->mListeners.EnumerateRead(CollectMessageListenerData,
1263 aReferentCount);
1265 // Add referent count in child managers because the listeners
1266 // participate in messages dispatched from parent message manager.
1267 for (uint32_t i = 0; i < aMessageManager->mChildManagers.Length(); ++i) {
1268 nsRefPtr<nsFrameMessageManager> mm =
1269 static_cast<nsFrameMessageManager*>(aMessageManager->mChildManagers[i]);
1270 CountReferents(mm, aReferentCount);
1271 }
1272 }
1274 static nsresult
1275 ReportReferentCount(const char* aManagerType,
1276 const MessageManagerReferentCount& aReferentCount,
1277 nsIMemoryReporterCallback* aCb,
1278 nsISupports* aClosure)
1279 {
1280 #define REPORT(_path, _amount, _desc) \
1281 do { \
1282 nsresult rv; \
1283 rv = aCb->Callback(EmptyCString(), _path, \
1284 nsIMemoryReporter::KIND_OTHER, \
1285 nsIMemoryReporter::UNITS_COUNT, _amount, \
1286 _desc, aClosure); \
1287 NS_ENSURE_SUCCESS(rv, rv); \
1288 } while (0)
1290 REPORT(nsPrintfCString("message-manager/referent/%s/strong", aManagerType),
1291 aReferentCount.mStrong,
1292 nsPrintfCString("The number of strong referents held by the message "
1293 "manager in the %s manager.", aManagerType));
1294 REPORT(nsPrintfCString("message-manager/referent/%s/weak/alive", aManagerType),
1295 aReferentCount.mWeakAlive,
1296 nsPrintfCString("The number of weak referents that are still alive "
1297 "held by the message manager in the %s manager.",
1298 aManagerType));
1299 REPORT(nsPrintfCString("message-manager/referent/%s/weak/dead", aManagerType),
1300 aReferentCount.mWeakDead,
1301 nsPrintfCString("The number of weak referents that are dead "
1302 "held by the message manager in the %s manager.",
1303 aManagerType));
1305 for (uint32_t i = 0; i < aReferentCount.mSuspectMessages.Length(); i++) {
1306 uint32_t totalReferentCount = 0;
1307 aReferentCount.mMessageCounter.Get(aReferentCount.mSuspectMessages[i],
1308 &totalReferentCount);
1309 NS_ConvertUTF16toUTF8 suspect(aReferentCount.mSuspectMessages[i]);
1310 REPORT(nsPrintfCString("message-manager-suspect/%s/referent(message=%s)",
1311 aManagerType, suspect.get()), totalReferentCount,
1312 nsPrintfCString("A message in the %s message manager with a "
1313 "suspiciously large number of referents (symptom "
1314 "of a leak).", aManagerType));
1315 }
1317 #undef REPORT
1319 return NS_OK;
1320 }
1322 NS_IMETHODIMP
1323 MessageManagerReporter::CollectReports(nsIMemoryReporterCallback* aCb,
1324 nsISupports* aClosure)
1325 {
1326 nsresult rv;
1328 if (XRE_GetProcessType() == GeckoProcessType_Default) {
1329 nsCOMPtr<nsIMessageBroadcaster> globalmm =
1330 do_GetService("@mozilla.org/globalmessagemanager;1");
1331 if (globalmm) {
1332 nsRefPtr<nsFrameMessageManager> mm =
1333 static_cast<nsFrameMessageManager*>(globalmm.get());
1334 MessageManagerReferentCount count;
1335 CountReferents(mm, &count);
1336 rv = ReportReferentCount("global-manager", count, aCb, aClosure);
1337 NS_ENSURE_SUCCESS(rv, rv);
1338 }
1339 }
1341 if (nsFrameMessageManager::sParentProcessManager) {
1342 MessageManagerReferentCount count;
1343 CountReferents(nsFrameMessageManager::sParentProcessManager, &count);
1344 rv = ReportReferentCount("parent-process-manager", count, aCb, aClosure);
1345 NS_ENSURE_SUCCESS(rv, rv);
1346 }
1348 if (nsFrameMessageManager::sChildProcessManager) {
1349 MessageManagerReferentCount count;
1350 CountReferents(nsFrameMessageManager::sChildProcessManager, &count);
1351 rv = ReportReferentCount("child-process-manager", count, aCb, aClosure);
1352 NS_ENSURE_SUCCESS(rv, rv);
1353 }
1355 return NS_OK;
1356 }
1358 } // namespace dom
1359 } // namespace mozilla
1361 nsresult
1362 NS_NewGlobalMessageManager(nsIMessageBroadcaster** aResult)
1363 {
1364 NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default,
1365 NS_ERROR_NOT_AVAILABLE);
1366 nsFrameMessageManager* mm = new nsFrameMessageManager(nullptr,
1367 nullptr,
1368 MM_CHROME | MM_GLOBAL | MM_BROADCASTER);
1369 RegisterStrongMemoryReporter(new MessageManagerReporter());
1370 return CallQueryInterface(mm, aResult);
1371 }
1373 nsDataHashtable<nsStringHashKey, nsFrameScriptObjectExecutorHolder*>*
1374 nsFrameScriptExecutor::sCachedScripts = nullptr;
1375 nsScriptCacheCleaner* nsFrameScriptExecutor::sScriptCacheCleaner = nullptr;
1377 void
1378 nsFrameScriptExecutor::DidCreateGlobal()
1379 {
1380 NS_ASSERTION(mGlobal, "Should have mGlobal!");
1381 if (!sCachedScripts) {
1382 sCachedScripts =
1383 new nsDataHashtable<nsStringHashKey, nsFrameScriptObjectExecutorHolder*>;
1385 nsRefPtr<nsScriptCacheCleaner> scriptCacheCleaner =
1386 new nsScriptCacheCleaner();
1387 scriptCacheCleaner.forget(&sScriptCacheCleaner);
1388 }
1389 }
1391 static PLDHashOperator
1392 RemoveCachedScriptEntry(const nsAString& aKey,
1393 nsFrameScriptObjectExecutorHolder*& aData,
1394 void* aUserArg)
1395 {
1396 delete aData;
1397 return PL_DHASH_REMOVE;
1398 }
1400 // static
1401 void
1402 nsFrameScriptExecutor::Shutdown()
1403 {
1404 if (sCachedScripts) {
1405 AutoSafeJSContext cx;
1406 NS_ASSERTION(sCachedScripts != nullptr, "Need cached scripts");
1407 sCachedScripts->Enumerate(RemoveCachedScriptEntry, nullptr);
1409 delete sCachedScripts;
1410 sCachedScripts = nullptr;
1412 nsRefPtr<nsScriptCacheCleaner> scriptCacheCleaner;
1413 scriptCacheCleaner.swap(sScriptCacheCleaner);
1414 }
1415 }
1417 void
1418 nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL,
1419 bool aRunInGlobalScope)
1420 {
1421 if (!mGlobal || !sCachedScripts) {
1422 return;
1423 }
1425 AutoSafeJSContext cx;
1426 JS::Rooted<JSScript*> script(cx);
1427 JS::Rooted<JSObject*> funobj(cx);
1429 nsFrameScriptObjectExecutorHolder* holder = sCachedScripts->Get(aURL);
1430 if (holder && holder->WillRunInGlobalScope() == aRunInGlobalScope) {
1431 script = holder->mScript;
1432 funobj = holder->mFunction;
1433 } else {
1434 // Don't put anything in the cache if we already have an entry
1435 // with a different WillRunInGlobalScope() value.
1436 bool shouldCache = !holder;
1437 TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope,
1438 shouldCache, &script, &funobj);
1439 }
1441 JS::Rooted<JSObject*> global(cx, mGlobal->GetJSObject());
1442 if (global) {
1443 JSAutoCompartment ac(cx, global);
1444 bool ok = true;
1445 if (funobj) {
1446 JS::Rooted<JSObject*> method(cx, JS_CloneFunctionObject(cx, funobj, global));
1447 if (!method) {
1448 return;
1449 }
1450 JS::Rooted<JS::Value> rval(cx);
1451 JS::Rooted<JS::Value> methodVal(cx, JS::ObjectValue(*method));
1452 ok = JS_CallFunctionValue(cx, global, methodVal,
1453 JS::HandleValueArray::empty(), &rval);
1454 } else if (script) {
1455 ok = JS::CloneAndExecuteScript(cx, global, script);
1456 }
1458 if (!ok) {
1459 nsJSUtils::ReportPendingException(cx);
1460 }
1461 }
1462 }
1464 void
1465 nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
1466 bool aRunInGlobalScope,
1467 bool aShouldCache,
1468 JS::MutableHandle<JSScript*> aScriptp,
1469 JS::MutableHandle<JSObject*> aFunp)
1470 {
1471 nsCString url = NS_ConvertUTF16toUTF8(aURL);
1472 nsCOMPtr<nsIURI> uri;
1473 nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
1474 if (NS_FAILED(rv)) {
1475 return;
1476 }
1478 bool hasFlags;
1479 rv = NS_URIChainHasFlags(uri,
1480 nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
1481 &hasFlags);
1482 if (NS_FAILED(rv) || !hasFlags) {
1483 NS_WARNING("Will not load a frame script!");
1484 return;
1485 }
1487 nsCOMPtr<nsIChannel> channel;
1488 NS_NewChannel(getter_AddRefs(channel), uri);
1489 if (!channel) {
1490 return;
1491 }
1493 nsCOMPtr<nsIInputStream> input;
1494 channel->Open(getter_AddRefs(input));
1495 nsString dataString;
1496 jschar* dataStringBuf = nullptr;
1497 size_t dataStringLength = 0;
1498 uint64_t avail64 = 0;
1499 if (input && NS_SUCCEEDED(input->Available(&avail64)) && avail64) {
1500 if (avail64 > UINT32_MAX) {
1501 return;
1502 }
1503 nsCString buffer;
1504 uint32_t avail = (uint32_t)std::min(avail64, (uint64_t)UINT32_MAX);
1505 if (NS_FAILED(NS_ReadInputStreamToString(input, buffer, avail))) {
1506 return;
1507 }
1508 nsScriptLoader::ConvertToUTF16(channel, (uint8_t*)buffer.get(), avail,
1509 EmptyString(), nullptr,
1510 dataStringBuf, dataStringLength);
1511 }
1513 JS::SourceBufferHolder srcBuf(dataStringBuf, dataStringLength,
1514 JS::SourceBufferHolder::GiveOwnership);
1516 if (dataStringBuf && dataStringLength > 0) {
1517 AutoSafeJSContext cx;
1518 JS::Rooted<JSObject*> global(cx, mGlobal->GetJSObject());
1519 if (global) {
1520 JSAutoCompartment ac(cx, global);
1521 JS::CompileOptions options(cx);
1522 options.setFileAndLine(url.get(), 1);
1523 JS::Rooted<JSScript*> script(cx);
1524 JS::Rooted<JSObject*> funobj(cx);
1525 if (aRunInGlobalScope) {
1526 options.setNoScriptRval(true);
1527 if (!JS::Compile(cx, JS::NullPtr(), options, srcBuf, &script)) {
1528 return;
1529 }
1530 } else {
1531 JS::Rooted<JSFunction *> fun(cx);
1532 if (!JS::CompileFunction(cx, JS::NullPtr(), options,
1533 nullptr, 0, nullptr, /* name, nargs, args */
1534 srcBuf, &fun))
1535 {
1536 return;
1537 }
1538 funobj = JS_GetFunctionObject(fun);
1539 }
1541 if (!script && !funobj) {
1542 return;
1543 }
1545 aScriptp.set(script);
1546 aFunp.set(funobj);
1548 nsAutoCString scheme;
1549 uri->GetScheme(scheme);
1550 // We don't cache data: scripts!
1551 if (aShouldCache && !scheme.EqualsLiteral("data")) {
1552 nsFrameScriptObjectExecutorHolder* holder;
1554 // Root the object also for caching.
1555 if (script) {
1556 holder = new nsFrameScriptObjectExecutorHolder(cx, script);
1557 } else {
1558 holder = new nsFrameScriptObjectExecutorHolder(cx, funobj);
1559 }
1560 sCachedScripts->Put(aURL, holder);
1561 }
1562 }
1563 }
1564 }
1566 void
1567 nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
1568 bool aRunInGlobalScope)
1569 {
1570 AutoSafeJSContext cx;
1571 JS::Rooted<JSScript*> script(cx);
1572 JS::Rooted<JSObject*> funobj(cx);
1573 TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope, true, &script, &funobj);
1574 }
1576 bool
1577 nsFrameScriptExecutor::InitTabChildGlobalInternal(nsISupports* aScope,
1578 const nsACString& aID)
1579 {
1581 nsCOMPtr<nsIJSRuntimeService> runtimeSvc =
1582 do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
1583 NS_ENSURE_TRUE(runtimeSvc, false);
1585 JSRuntime* rt = nullptr;
1586 runtimeSvc->GetRuntime(&rt);
1587 NS_ENSURE_TRUE(rt, false);
1589 AutoSafeJSContext cx;
1590 nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
1592 nsIXPConnect* xpc = nsContentUtils::XPConnect();
1593 const uint32_t flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES;
1595 JS::CompartmentOptions options;
1596 options.setZone(JS::SystemZone)
1597 .setVersion(JSVERSION_LATEST);
1599 nsresult rv =
1600 xpc->InitClassesWithNewWrappedGlobal(cx, aScope, mPrincipal,
1601 flags, options, getter_AddRefs(mGlobal));
1602 NS_ENSURE_SUCCESS(rv, false);
1605 JS::Rooted<JSObject*> global(cx, mGlobal->GetJSObject());
1606 NS_ENSURE_TRUE(global, false);
1608 // Set the location information for the new global, so that tools like
1609 // about:memory may use that information.
1610 xpc::SetLocationForGlobal(global, aID);
1612 DidCreateGlobal();
1613 return true;
1614 }
1616 NS_IMPL_ISUPPORTS(nsScriptCacheCleaner, nsIObserver)
1618 nsFrameMessageManager* nsFrameMessageManager::sChildProcessManager = nullptr;
1619 nsFrameMessageManager* nsFrameMessageManager::sParentProcessManager = nullptr;
1620 nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr;
1621 nsTArray<nsCOMPtr<nsIRunnable> >* nsFrameMessageManager::sPendingSameProcessAsyncMessages = nullptr;
1623 class nsAsyncMessageToSameProcessChild : public nsSameProcessAsyncMessageBase,
1624 public nsRunnable
1625 {
1626 public:
1627 nsAsyncMessageToSameProcessChild(JSContext* aCx,
1628 const nsAString& aMessage,
1629 const StructuredCloneData& aData,
1630 JS::Handle<JSObject *> aCpows,
1631 nsIPrincipal* aPrincipal)
1632 : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
1633 {
1634 }
1636 NS_IMETHOD Run()
1637 {
1638 nsFrameMessageManager* ppm = nsFrameMessageManager::sChildProcessManager;
1639 ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), ppm);
1640 return NS_OK;
1641 }
1642 };
1645 /**
1646 * Send messages to an imaginary child process in a single-process scenario.
1647 */
1648 class SameParentProcessMessageManagerCallback : public MessageManagerCallback
1649 {
1650 public:
1651 SameParentProcessMessageManagerCallback()
1652 {
1653 MOZ_COUNT_CTOR(SameParentProcessMessageManagerCallback);
1654 }
1655 virtual ~SameParentProcessMessageManagerCallback()
1656 {
1657 MOZ_COUNT_DTOR(SameParentProcessMessageManagerCallback);
1658 }
1660 virtual bool DoSendAsyncMessage(JSContext* aCx,
1661 const nsAString& aMessage,
1662 const StructuredCloneData& aData,
1663 JS::Handle<JSObject *> aCpows,
1664 nsIPrincipal* aPrincipal)
1665 {
1666 nsRefPtr<nsIRunnable> ev =
1667 new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows,
1668 aPrincipal);
1669 NS_DispatchToCurrentThread(ev);
1670 return true;
1671 }
1673 bool CheckPermission(const nsAString& aPermission)
1674 {
1675 // In a single-process scenario, the child always has all capabilities.
1676 return true;
1677 }
1679 bool CheckManifestURL(const nsAString& aManifestURL)
1680 {
1681 // In a single-process scenario, the child always has all capabilities.
1682 return true;
1683 }
1685 bool CheckAppHasPermission(const nsAString& aPermission)
1686 {
1687 // In a single-process scenario, the child always has all capabilities.
1688 return true;
1689 }
1691 virtual bool CheckAppHasStatus(unsigned short aStatus)
1692 {
1693 // In a single-process scenario, the child always has all capabilities.
1694 return true;
1695 }
1696 };
1699 /**
1700 * Send messages to the parent process.
1701 */
1702 class ChildProcessMessageManagerCallback : public MessageManagerCallback
1703 {
1704 public:
1705 ChildProcessMessageManagerCallback()
1706 {
1707 MOZ_COUNT_CTOR(ChildProcessMessageManagerCallback);
1708 }
1709 virtual ~ChildProcessMessageManagerCallback()
1710 {
1711 MOZ_COUNT_DTOR(ChildProcessMessageManagerCallback);
1712 }
1714 virtual bool DoSendBlockingMessage(JSContext* aCx,
1715 const nsAString& aMessage,
1716 const mozilla::dom::StructuredCloneData& aData,
1717 JS::Handle<JSObject *> aCpows,
1718 nsIPrincipal* aPrincipal,
1719 InfallibleTArray<nsString>* aJSONRetVal,
1720 bool aIsSync) MOZ_OVERRIDE
1721 {
1722 mozilla::dom::ContentChild* cc =
1723 mozilla::dom::ContentChild::GetSingleton();
1724 if (!cc) {
1725 return true;
1726 }
1727 ClonedMessageData data;
1728 if (!BuildClonedMessageDataForChild(cc, aData, data)) {
1729 return false;
1730 }
1731 InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
1732 if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
1733 return false;
1734 }
1735 if (aIsSync) {
1736 return cc->SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
1737 aPrincipal, aJSONRetVal);
1738 }
1739 return cc->CallRpcMessage(PromiseFlatString(aMessage), data, cpows,
1740 aPrincipal, aJSONRetVal);
1741 }
1743 virtual bool DoSendAsyncMessage(JSContext* aCx,
1744 const nsAString& aMessage,
1745 const mozilla::dom::StructuredCloneData& aData,
1746 JS::Handle<JSObject *> aCpows,
1747 nsIPrincipal* aPrincipal) MOZ_OVERRIDE
1748 {
1749 mozilla::dom::ContentChild* cc =
1750 mozilla::dom::ContentChild::GetSingleton();
1751 if (!cc) {
1752 return true;
1753 }
1754 ClonedMessageData data;
1755 if (!BuildClonedMessageDataForChild(cc, aData, data)) {
1756 return false;
1757 }
1758 InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
1759 if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
1760 return false;
1761 }
1762 return cc->SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
1763 aPrincipal);
1764 }
1766 };
1769 class nsAsyncMessageToSameProcessParent : public nsSameProcessAsyncMessageBase,
1770 public nsRunnable
1771 {
1772 public:
1773 nsAsyncMessageToSameProcessParent(JSContext* aCx,
1774 const nsAString& aMessage,
1775 const StructuredCloneData& aData,
1776 JS::Handle<JSObject *> aCpows,
1777 nsIPrincipal* aPrincipal)
1778 : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
1779 {
1780 }
1782 NS_IMETHOD Run()
1783 {
1784 if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
1785 nsFrameMessageManager::sPendingSameProcessAsyncMessages->RemoveElement(this);
1786 }
1787 nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager;
1788 ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), ppm);
1789 return NS_OK;
1790 }
1791 };
1793 /**
1794 * Send messages to the imaginary parent process in a single-process scenario.
1795 */
1796 class SameChildProcessMessageManagerCallback : public MessageManagerCallback
1797 {
1798 public:
1799 SameChildProcessMessageManagerCallback()
1800 {
1801 MOZ_COUNT_CTOR(SameChildProcessMessageManagerCallback);
1802 }
1803 virtual ~SameChildProcessMessageManagerCallback()
1804 {
1805 MOZ_COUNT_DTOR(SameChildProcessMessageManagerCallback);
1806 }
1808 virtual bool DoSendBlockingMessage(JSContext* aCx,
1809 const nsAString& aMessage,
1810 const mozilla::dom::StructuredCloneData& aData,
1811 JS::Handle<JSObject *> aCpows,
1812 nsIPrincipal* aPrincipal,
1813 InfallibleTArray<nsString>* aJSONRetVal,
1814 bool aIsSync) MOZ_OVERRIDE
1815 {
1816 nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
1817 if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
1818 asyncMessages.SwapElements(*nsFrameMessageManager::sPendingSameProcessAsyncMessages);
1819 uint32_t len = asyncMessages.Length();
1820 for (uint32_t i = 0; i < len; ++i) {
1821 nsCOMPtr<nsIRunnable> async = asyncMessages[i];
1822 async->Run();
1823 }
1824 }
1825 if (nsFrameMessageManager::sSameProcessParentManager) {
1826 SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
1827 nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
1828 ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), aMessage,
1829 true, &aData, &cpows, aPrincipal, aJSONRetVal);
1830 }
1831 return true;
1832 }
1834 virtual bool DoSendAsyncMessage(JSContext* aCx,
1835 const nsAString& aMessage,
1836 const mozilla::dom::StructuredCloneData& aData,
1837 JS::Handle<JSObject *> aCpows,
1838 nsIPrincipal* aPrincipal)
1839 {
1840 if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
1841 nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray<nsCOMPtr<nsIRunnable> >;
1842 }
1843 nsCOMPtr<nsIRunnable> ev =
1844 new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows, aPrincipal);
1845 nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev);
1846 NS_DispatchToCurrentThread(ev);
1847 return true;
1848 }
1850 };
1853 // This creates the global parent process message manager.
1854 nsresult
1855 NS_NewParentProcessMessageManager(nsIMessageBroadcaster** aResult)
1856 {
1857 NS_ASSERTION(!nsFrameMessageManager::sParentProcessManager,
1858 "Re-creating sParentProcessManager");
1859 NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default,
1860 NS_ERROR_NOT_AVAILABLE);
1861 nsRefPtr<nsFrameMessageManager> mm = new nsFrameMessageManager(nullptr,
1862 nullptr,
1863 MM_CHROME | MM_PROCESSMANAGER | MM_BROADCASTER);
1864 nsFrameMessageManager::sParentProcessManager = mm;
1865 nsFrameMessageManager::NewProcessMessageManager(nullptr); // Create same process message manager.
1866 return CallQueryInterface(mm, aResult);
1867 }
1870 nsFrameMessageManager*
1871 nsFrameMessageManager::NewProcessMessageManager(mozilla::dom::ContentParent* aProcess)
1872 {
1873 if (!nsFrameMessageManager::sParentProcessManager) {
1874 nsCOMPtr<nsIMessageBroadcaster> dummy =
1875 do_GetService("@mozilla.org/parentprocessmessagemanager;1");
1876 }
1878 MOZ_ASSERT(nsFrameMessageManager::sParentProcessManager,
1879 "parent process manager not created");
1880 nsFrameMessageManager* mm;
1881 if (aProcess) {
1882 mm = new nsFrameMessageManager(aProcess,
1883 nsFrameMessageManager::sParentProcessManager,
1884 MM_CHROME | MM_PROCESSMANAGER);
1885 } else {
1886 mm = new nsFrameMessageManager(new SameParentProcessMessageManagerCallback(),
1887 nsFrameMessageManager::sParentProcessManager,
1888 MM_CHROME | MM_PROCESSMANAGER | MM_OWNSCALLBACK);
1889 sSameProcessParentManager = mm;
1890 }
1891 return mm;
1892 }
1894 nsresult
1895 NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
1896 {
1897 NS_ASSERTION(!nsFrameMessageManager::sChildProcessManager,
1898 "Re-creating sChildProcessManager");
1900 MessageManagerCallback* cb;
1901 if (XRE_GetProcessType() == GeckoProcessType_Default) {
1902 cb = new SameChildProcessMessageManagerCallback();
1903 } else {
1904 cb = new ChildProcessMessageManagerCallback();
1905 RegisterStrongMemoryReporter(new MessageManagerReporter());
1906 }
1907 nsFrameMessageManager* mm = new nsFrameMessageManager(cb,
1908 nullptr,
1909 MM_PROCESSMANAGER | MM_OWNSCALLBACK);
1910 nsFrameMessageManager::sChildProcessManager = mm;
1911 return CallQueryInterface(mm, aResult);
1912 }
1914 static PLDHashOperator
1915 CycleCollectorMarkListeners(const nsAString& aKey,
1916 nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
1917 void* aData)
1918 {
1919 uint32_t count = aListeners->Length();
1920 for (uint32_t i = 0; i < count; i++) {
1921 if (aListeners->ElementAt(i).mStrongListener) {
1922 xpc_TryUnmarkWrappedGrayObject(aListeners->ElementAt(i).mStrongListener);
1923 }
1924 }
1925 return PL_DHASH_NEXT;
1926 }
1928 bool
1929 nsFrameMessageManager::MarkForCC()
1930 {
1931 mListeners.EnumerateRead(CycleCollectorMarkListeners, nullptr);
1933 if (mRefCnt.IsPurple()) {
1934 mRefCnt.RemovePurple();
1935 }
1936 return true;
1937 }
1939 nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JSContext* aCx,
1940 const nsAString& aMessage,
1941 const StructuredCloneData& aData,
1942 JS::Handle<JSObject*> aCpows,
1943 nsIPrincipal* aPrincipal)
1944 : mRuntime(js::GetRuntime(aCx)),
1945 mMessage(aMessage),
1946 mCpows(aCx, aCpows),
1947 mPrincipal(aPrincipal)
1948 {
1949 if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
1950 NS_RUNTIMEABORT("OOM");
1951 }
1952 mClosure = aData.mClosure;
1953 }
1955 void
1956 nsSameProcessAsyncMessageBase::ReceiveMessage(nsISupports* aTarget,
1957 nsFrameMessageManager* aManager)
1958 {
1959 if (aManager) {
1960 StructuredCloneData data;
1961 data.mData = mData.data();
1962 data.mDataLength = mData.nbytes();
1963 data.mClosure = mClosure;
1965 SameProcessCpowHolder cpows(mRuntime, mCpows);
1967 nsRefPtr<nsFrameMessageManager> mm = aManager;
1968 mm->ReceiveMessage(aTarget, mMessage, false, &data, &cpows,
1969 mPrincipal, nullptr);
1970 }
1971 }