content/base/src/nsFrameMessageManager.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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*)&params);
   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);
  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);
  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;
  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);
  1061       JS::Rooted<JS::Value> rval(cx, JSVAL_VOID);
  1062       JS::Rooted<JS::Value> argv(cx, JS::ObjectValue(*param));
  1065         JS::Rooted<JSObject*> thisObject(cx, thisValue.toObjectOrNull());
  1067         JSAutoCompartment tac(cx, thisObject);
  1068         if (!JS_WrapValue(cx, &argv)) {
  1069           return NS_ERROR_UNEXPECTED;
  1072         if (!JS_CallFunctionValue(cx, thisObject, funval, argv, &rval)) {
  1073           nsJSUtils::ReportPendingException(cx);
  1074           continue;
  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;
  1083           aJSONRetVal->AppendElement(json);
  1088   nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = mParentManager;
  1089   return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
  1090                                                          aIsSync, aCloneData,
  1091                                                          aCpows, aPrincipal,
  1092                                                          aJSONRetVal) : NS_OK;
  1095 void
  1096 nsFrameMessageManager::AddChildManager(nsFrameMessageManager* aManager)
  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]);
  1112   for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
  1113     aManager->LoadFrameScript(mPendingScripts[i], false,
  1114                               mPendingScriptsGlobalStates[i]);
  1118 void
  1119 nsFrameMessageManager::SetCallback(MessageManagerCallback* aCallback)
  1121   MOZ_ASSERT(!mIsBroadcaster || !mCallback,
  1122              "Broadcasters cannot have callbacks!");
  1123   if (aCallback && mCallback != aCallback) {
  1124     mCallback = aCallback;
  1125     if (mOwnsCallback) {
  1126       mOwnedCallback = aCallback;
  1131 void
  1132 nsFrameMessageManager::InitWithCallback(MessageManagerCallback* aCallback)
  1134   if (mCallback) {
  1135     // Initialization should only happen once.
  1136     return;
  1139   SetCallback(aCallback);
  1141   // First load global scripts by adding this to parent manager.
  1142   if (mParentManager) {
  1143     mParentManager->AddChildManager(this);
  1146   for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
  1147     LoadFrameScript(mPendingScripts[i], false, mPendingScriptsGlobalStates[i]);
  1151 void
  1152 nsFrameMessageManager::RemoveFromParent()
  1154   if (mParentManager) {
  1155     mParentManager->RemoveChildManager(this);
  1157   mParentManager = nullptr;
  1158   mCallback = nullptr;
  1159   mOwnedCallback = nullptr;
  1162 void
  1163 nsFrameMessageManager::Disconnect(bool aRemoveFromParent)
  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);
  1172   if (mParentManager && aRemoveFromParent) {
  1173     mParentManager->RemoveChildManager(this);
  1175   mDisconnected = true;
  1176   mParentManager = nullptr;
  1177   mCallback = nullptr;
  1178   mOwnedCallback = nullptr;
  1179   if (!mHandlingMessage) {
  1180     mListeners.Clear();
  1184 namespace {
  1186 struct MessageManagerReferentCount
  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
  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)
  1220   MessageManagerReferentCount* referentCount =
  1221     static_cast<MessageManagerReferentCount*>(aData);
  1223   uint32_t listenerCount = aListeners->Length();
  1224   if (!listenerCount) {
  1225     return PL_DHASH_NEXT;
  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);
  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++;
  1251     } else {
  1252       referentCount->mStrong++;
  1255   return PL_DHASH_NEXT;
  1258 void
  1259 MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager,
  1260                                        MessageManagerReferentCount* aReferentCount)
  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);
  1274 static nsresult
  1275 ReportReferentCount(const char* aManagerType,
  1276                     const MessageManagerReferentCount& aReferentCount,
  1277                     nsIMemoryReporterCallback* aCb,
  1278                     nsISupports* aClosure)
  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));
  1317 #undef REPORT
  1319   return NS_OK;
  1322 NS_IMETHODIMP
  1323 MessageManagerReporter::CollectReports(nsIMemoryReporterCallback* aCb,
  1324                                        nsISupports* aClosure)
  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);
  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);
  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);
  1355   return NS_OK;
  1358 } // namespace dom
  1359 } // namespace mozilla
  1361 nsresult
  1362 NS_NewGlobalMessageManager(nsIMessageBroadcaster** aResult)
  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);
  1373 nsDataHashtable<nsStringHashKey, nsFrameScriptObjectExecutorHolder*>*
  1374   nsFrameScriptExecutor::sCachedScripts = nullptr;
  1375 nsScriptCacheCleaner* nsFrameScriptExecutor::sScriptCacheCleaner = nullptr;
  1377 void
  1378 nsFrameScriptExecutor::DidCreateGlobal()
  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);
  1391 static PLDHashOperator
  1392 RemoveCachedScriptEntry(const nsAString& aKey,
  1393                         nsFrameScriptObjectExecutorHolder*& aData,
  1394                         void* aUserArg)
  1396   delete aData;
  1397   return PL_DHASH_REMOVE;
  1400 // static
  1401 void
  1402 nsFrameScriptExecutor::Shutdown()
  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);
  1417 void
  1418 nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL,
  1419                                                bool aRunInGlobalScope)
  1421   if (!mGlobal || !sCachedScripts) {
  1422     return;
  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);
  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;
  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);
  1458     if (!ok) {
  1459       nsJSUtils::ReportPendingException(cx);
  1464 void
  1465 nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
  1466                                                     bool aRunInGlobalScope,
  1467                                                     bool aShouldCache,
  1468                                                     JS::MutableHandle<JSScript*> aScriptp,
  1469                                                     JS::MutableHandle<JSObject*> aFunp)
  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;
  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;
  1487   nsCOMPtr<nsIChannel> channel;
  1488   NS_NewChannel(getter_AddRefs(channel), uri);
  1489   if (!channel) {
  1490     return;
  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;
  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;
  1508     nsScriptLoader::ConvertToUTF16(channel, (uint8_t*)buffer.get(), avail,
  1509                                    EmptyString(), nullptr,
  1510                                    dataStringBuf, dataStringLength);
  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;
  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))
  1536           return;
  1538         funobj = JS_GetFunctionObject(fun);
  1541       if (!script && !funobj) {
  1542         return;
  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);
  1560         sCachedScripts->Put(aURL, holder);
  1566 void
  1567 nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
  1568                                                     bool aRunInGlobalScope)
  1570   AutoSafeJSContext cx;
  1571   JS::Rooted<JSScript*> script(cx);
  1572   JS::Rooted<JSObject*> funobj(cx);
  1573   TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope, true, &script, &funobj);
  1576 bool
  1577 nsFrameScriptExecutor::InitTabChildGlobalInternal(nsISupports* aScope,
  1578                                                   const nsACString& aID)
  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;
  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
  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)
  1636   NS_IMETHOD Run()
  1638     nsFrameMessageManager* ppm = nsFrameMessageManager::sChildProcessManager;
  1639     ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), ppm);
  1640     return NS_OK;
  1642 };
  1645 /**
  1646  * Send messages to an imaginary child process in a single-process scenario.
  1647  */
  1648 class SameParentProcessMessageManagerCallback : public MessageManagerCallback
  1650 public:
  1651   SameParentProcessMessageManagerCallback()
  1653     MOZ_COUNT_CTOR(SameParentProcessMessageManagerCallback);
  1655   virtual ~SameParentProcessMessageManagerCallback()
  1657     MOZ_COUNT_DTOR(SameParentProcessMessageManagerCallback);
  1660   virtual bool DoSendAsyncMessage(JSContext* aCx,
  1661                                   const nsAString& aMessage,
  1662                                   const StructuredCloneData& aData,
  1663                                   JS::Handle<JSObject *> aCpows,
  1664                                   nsIPrincipal* aPrincipal)
  1666     nsRefPtr<nsIRunnable> ev =
  1667       new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows,
  1668                                            aPrincipal);
  1669     NS_DispatchToCurrentThread(ev);
  1670     return true;
  1673   bool CheckPermission(const nsAString& aPermission)
  1675     // In a single-process scenario, the child always has all capabilities.
  1676     return true;
  1679   bool CheckManifestURL(const nsAString& aManifestURL)
  1681     // In a single-process scenario, the child always has all capabilities.
  1682     return true;
  1685   bool CheckAppHasPermission(const nsAString& aPermission)
  1687     // In a single-process scenario, the child always has all capabilities.
  1688     return true;
  1691   virtual bool CheckAppHasStatus(unsigned short aStatus)
  1693     // In a single-process scenario, the child always has all capabilities.
  1694     return true;
  1696 };
  1699 /**
  1700  * Send messages to the parent process.
  1701  */
  1702 class ChildProcessMessageManagerCallback : public MessageManagerCallback
  1704 public:
  1705   ChildProcessMessageManagerCallback()
  1707     MOZ_COUNT_CTOR(ChildProcessMessageManagerCallback);
  1709   virtual ~ChildProcessMessageManagerCallback()
  1711     MOZ_COUNT_DTOR(ChildProcessMessageManagerCallback);
  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
  1722     mozilla::dom::ContentChild* cc =
  1723       mozilla::dom::ContentChild::GetSingleton();
  1724     if (!cc) {
  1725       return true;
  1727     ClonedMessageData data;
  1728     if (!BuildClonedMessageDataForChild(cc, aData, data)) {
  1729       return false;
  1731     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
  1732     if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
  1733       return false;
  1735     if (aIsSync) {
  1736       return cc->SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
  1737                                  aPrincipal, aJSONRetVal);
  1739     return cc->CallRpcMessage(PromiseFlatString(aMessage), data, cpows,
  1740                               aPrincipal, aJSONRetVal);
  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
  1749     mozilla::dom::ContentChild* cc =
  1750       mozilla::dom::ContentChild::GetSingleton();
  1751     if (!cc) {
  1752       return true;
  1754     ClonedMessageData data;
  1755     if (!BuildClonedMessageDataForChild(cc, aData, data)) {
  1756       return false;
  1758     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
  1759     if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
  1760       return false;
  1762     return cc->SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
  1763                                 aPrincipal);
  1766 };
  1769 class nsAsyncMessageToSameProcessParent : public nsSameProcessAsyncMessageBase,
  1770                                           public nsRunnable
  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)
  1782   NS_IMETHOD Run()
  1784     if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
  1785       nsFrameMessageManager::sPendingSameProcessAsyncMessages->RemoveElement(this);
  1787     nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager;
  1788     ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), ppm);
  1789     return NS_OK;
  1791 };
  1793 /**
  1794  * Send messages to the imaginary parent process in a single-process scenario.
  1795  */
  1796 class SameChildProcessMessageManagerCallback : public MessageManagerCallback
  1798 public:
  1799   SameChildProcessMessageManagerCallback()
  1801     MOZ_COUNT_CTOR(SameChildProcessMessageManagerCallback);
  1803   virtual ~SameChildProcessMessageManagerCallback()
  1805     MOZ_COUNT_DTOR(SameChildProcessMessageManagerCallback);
  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
  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();
  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);
  1831     return true;
  1834   virtual bool DoSendAsyncMessage(JSContext* aCx,
  1835                                   const nsAString& aMessage,
  1836                                   const mozilla::dom::StructuredCloneData& aData,
  1837                                   JS::Handle<JSObject *> aCpows,
  1838                                   nsIPrincipal* aPrincipal)
  1840     if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
  1841       nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray<nsCOMPtr<nsIRunnable> >;
  1843     nsCOMPtr<nsIRunnable> ev =
  1844       new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows, aPrincipal);
  1845     nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev);
  1846     NS_DispatchToCurrentThread(ev);
  1847     return true;
  1850 };
  1853 // This creates the global parent process message manager.
  1854 nsresult
  1855 NS_NewParentProcessMessageManager(nsIMessageBroadcaster** aResult)
  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);
  1870 nsFrameMessageManager*
  1871 nsFrameMessageManager::NewProcessMessageManager(mozilla::dom::ContentParent* aProcess)
  1873   if (!nsFrameMessageManager::sParentProcessManager) {
  1874      nsCOMPtr<nsIMessageBroadcaster> dummy =
  1875        do_GetService("@mozilla.org/parentprocessmessagemanager;1");
  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;
  1891   return mm;
  1894 nsresult
  1895 NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
  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());
  1907   nsFrameMessageManager* mm = new nsFrameMessageManager(cb,
  1908                                                         nullptr,
  1909                                                         MM_PROCESSMANAGER | MM_OWNSCALLBACK);
  1910   nsFrameMessageManager::sChildProcessManager = mm;
  1911   return CallQueryInterface(mm, aResult);
  1914 static PLDHashOperator
  1915 CycleCollectorMarkListeners(const nsAString& aKey,
  1916                             nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
  1917                             void* aData)
  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);
  1925   return PL_DHASH_NEXT;
  1928 bool
  1929 nsFrameMessageManager::MarkForCC()
  1931   mListeners.EnumerateRead(CycleCollectorMarkListeners, nullptr);
  1933   if (mRefCnt.IsPurple()) {
  1934     mRefCnt.RemovePurple();
  1936   return true;
  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)
  1949   if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
  1950     NS_RUNTIMEABORT("OOM");
  1952   mClosure = aData.mClosure;
  1955 void
  1956 nsSameProcessAsyncMessageBase::ReceiveMessage(nsISupports* aTarget,
  1957                                               nsFrameMessageManager* aManager)
  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);

mercurial