content/base/src/nsFrameMessageManager.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

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

mercurial