Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/nsFrameMessageManager.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "base/basictypes.h"
8
9
#include "nsFrameMessageManager.h"
10
11
#include "ContentChild.h"
12
#include "GeckoProfiler.h"
13
#include "nsASCIIMask.h"
14
#include "nsContentUtils.h"
15
#include "nsError.h"
16
#include "nsIXPConnect.h"
17
#include "jsapi.h"
18
#include "jsfriendapi.h"
19
#include "nsJSUtils.h"
20
#include "nsJSPrincipals.h"
21
#include "nsNetUtil.h"
22
#include "mozilla/dom/ScriptLoader.h"
23
#include "nsFrameLoader.h"
24
#include "nsIInputStream.h"
25
#include "nsIXULRuntime.h"
26
#include "nsIScriptError.h"
27
#include "nsIConsoleService.h"
28
#include "nsIMemoryReporter.h"
29
#include "nsIProtocolHandler.h"
30
#include "nsIScriptSecurityManager.h"
31
#include "xpcpublic.h"
32
#include "js/CompilationAndEvaluation.h"
33
#include "js/JSON.h"
34
#include "js/SourceBufferHolder.h"
35
#include "mozilla/ClearOnShutdown.h"
36
#include "mozilla/CycleCollectedJSContext.h"
37
#include "mozilla/Preferences.h"
38
#include "mozilla/ScriptPreloader.h"
39
#include "mozilla/Telemetry.h"
40
#include "mozilla/dom/ChildProcessMessageManager.h"
41
#include "mozilla/dom/ChromeMessageBroadcaster.h"
42
#include "mozilla/dom/File.h"
43
#include "mozilla/dom/MessageManagerBinding.h"
44
#include "mozilla/dom/MessagePort.h"
45
#include "mozilla/dom/ContentParent.h"
46
#include "mozilla/dom/ContentProcessMessageManager.h"
47
#include "mozilla/dom/ParentProcessMessageManager.h"
48
#include "mozilla/dom/PermissionMessageUtils.h"
49
#include "mozilla/dom/ProcessMessageManager.h"
50
#include "mozilla/dom/ResolveSystemBinding.h"
51
#include "mozilla/dom/SameProcessMessageQueue.h"
52
#include "mozilla/dom/ScriptSettings.h"
53
#include "mozilla/dom/ToJSValue.h"
54
#include "mozilla/dom/ipc/SharedMap.h"
55
#include "mozilla/dom/ipc/StructuredCloneData.h"
56
#include "mozilla/dom/DOMStringList.h"
57
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
58
#include "mozilla/recordreplay/ParentIPC.h"
59
#include "nsPrintfCString.h"
60
#include "nsXULAppAPI.h"
61
#include "nsQueryObject.h"
62
#include "xpcprivate.h"
63
#include <algorithm>
64
#include "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize
65
66
#ifdef XP_WIN
67
# if defined(SendMessage)
68
#  undef SendMessage
69
# endif
70
#endif
71
72
#ifdef FUZZING
73
#include "MessageManagerFuzzer.h"
74
#endif
75
76
using namespace mozilla;
77
using namespace mozilla::dom;
78
using namespace mozilla::dom::ipc;
79
80
nsFrameMessageManager::nsFrameMessageManager(MessageManagerCallback* aCallback,
81
                                             MessageManagerFlags aFlags)
82
 : mChrome(aFlags & MessageManagerFlags::MM_CHROME),
83
   mGlobal(aFlags & MessageManagerFlags::MM_GLOBAL),
84
   mIsProcessManager(aFlags & MessageManagerFlags::MM_PROCESSMANAGER),
85
   mIsBroadcaster(aFlags & MessageManagerFlags::MM_BROADCASTER),
86
   mOwnsCallback(aFlags & MessageManagerFlags::MM_OWNSCALLBACK),
87
   mHandlingMessage(false),
88
   mClosed(false),
89
   mDisconnected(false),
90
   mCallback(aCallback)
91
0
{
92
0
  NS_ASSERTION(!mIsBroadcaster || !mCallback,
93
0
               "Broadcasters cannot have callbacks!");
94
0
  if (mOwnsCallback) {
95
0
    mOwnedCallback = aCallback;
96
0
  }
97
0
}
98
99
nsFrameMessageManager::~nsFrameMessageManager()
100
0
{
101
0
  for (int32_t i = mChildManagers.Length(); i > 0; --i) {
102
0
    mChildManagers[i - 1]->Disconnect(false);
103
0
  }
104
0
  if (mIsProcessManager) {
105
0
    if (this == sParentProcessManager) {
106
0
      sParentProcessManager = nullptr;
107
0
    }
108
0
    if (this == sChildProcessManager) {
109
0
      sChildProcessManager = nullptr;
110
0
      delete mozilla::dom::SameProcessMessageQueue::Get();
111
0
    }
112
0
    if (this == sSameProcessParentManager) {
113
0
      sSameProcessParentManager = nullptr;
114
0
    }
115
0
  }
116
0
}
117
118
inline void
119
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
120
                            nsMessageListenerInfo& aField,
121
                            const char* aName,
122
                            uint32_t aFlags = 0)
123
0
{
124
0
  ImplCycleCollectionTraverse(aCallback, aField.mStrongListener, aName, aFlags);
125
0
  ImplCycleCollectionTraverse(aCallback, aField.mWeakListener, aName, aFlags);
126
0
}
127
128
NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameMessageManager)
129
130
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager)
131
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListeners)
132
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildManagers)
133
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedData)
134
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
135
136
0
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsFrameMessageManager)
137
0
  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mInitialProcessData)
138
0
NS_IMPL_CYCLE_COLLECTION_TRACE_END
139
140
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFrameMessageManager)
141
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mListeners)
142
0
  for (int32_t i = tmp->mChildManagers.Length(); i > 0; --i) {
143
0
    tmp->mChildManagers[i - 1]->Disconnect(false);
144
0
  }
145
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildManagers)
146
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSharedData)
147
0
  tmp->mInitialProcessData.setNull();
148
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
149
150
151
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameMessageManager)
152
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
153
0
154
0
  /* Message managers in child process implement nsIMessageSender.
155
0
     Message managers in the chrome process are
156
0
     either broadcasters (if they have subordinate/child message
157
0
     managers) or they're simple message senders. */
158
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMessageSender, !mChrome || !mIsBroadcaster)
159
0
160
0
NS_INTERFACE_MAP_END
161
162
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameMessageManager)
163
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameMessageManager)
164
165
void
166
MessageManagerCallback::DoGetRemoteType(nsAString& aRemoteType,
167
                                        ErrorResult& aError) const
168
0
{
169
0
  aRemoteType.Truncate();
170
0
  mozilla::dom::ProcessMessageManager* parent = GetProcessMessageManager();
171
0
  if (!parent) {
172
0
    return;
173
0
  }
174
0
175
0
  parent->GetRemoteType(aRemoteType, aError);
176
0
}
177
178
bool
179
MessageManagerCallback::BuildClonedMessageDataForParent(nsIContentParent* aParent,
180
                                                        StructuredCloneData& aData,
181
                                                        ClonedMessageData& aClonedData)
182
0
{
183
0
  return aData.BuildClonedMessageDataForParent(aParent, aClonedData);
184
0
}
185
186
bool
187
MessageManagerCallback::BuildClonedMessageDataForChild(nsIContentChild* aChild,
188
                                                       StructuredCloneData& aData,
189
                                                       ClonedMessageData& aClonedData)
190
0
{
191
0
  return aData.BuildClonedMessageDataForChild(aChild, aClonedData);
192
0
}
193
194
void
195
mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aClonedData,
196
                                                    StructuredCloneData& aData)
197
0
{
198
0
  aData.BorrowFromClonedMessageDataForParent(aClonedData);
199
0
}
200
201
void
202
mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aClonedData,
203
                                                   StructuredCloneData& aData)
204
0
{
205
0
  aData.BorrowFromClonedMessageDataForChild(aClonedData);
206
0
}
207
208
bool
209
SameProcessCpowHolder::ToObject(JSContext* aCx,
210
                                JS::MutableHandle<JSObject*> aObjp)
211
0
{
212
0
  if (!mObj) {
213
0
    return true;
214
0
  }
215
0
216
0
  aObjp.set(mObj);
217
0
  return JS_WrapObject(aCx, aObjp);
218
0
}
219
220
void
221
nsFrameMessageManager::AddMessageListener(const nsAString& aMessageName,
222
                                          MessageListener& aListener,
223
                                          bool aListenWhenClosed,
224
                                          ErrorResult& aError)
225
0
{
226
0
  auto listeners = mListeners.LookupForAdd(aMessageName).OrInsert([]() {
227
0
      return new nsAutoTObserverArray<nsMessageListenerInfo, 1>();
228
0
    });
229
0
  uint32_t len = listeners->Length();
230
0
  for (uint32_t i = 0; i < len; ++i) {
231
0
    MessageListener* strongListener = listeners->ElementAt(i).mStrongListener;
232
0
    if (strongListener && *strongListener == aListener) {
233
0
      return;
234
0
    }
235
0
  }
236
0
237
0
  nsMessageListenerInfo* entry = listeners->AppendElement();
238
0
  entry->mStrongListener = &aListener;
239
0
  entry->mListenWhenClosed = aListenWhenClosed;
240
0
}
241
242
void
243
nsFrameMessageManager::RemoveMessageListener(const nsAString& aMessageName,
244
                                             MessageListener& aListener,
245
                                             ErrorResult& aError)
246
0
{
247
0
  nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
248
0
    mListeners.Get(aMessageName);
249
0
  if (listeners) {
250
0
    uint32_t len = listeners->Length();
251
0
    for (uint32_t i = 0; i < len; ++i) {
252
0
      MessageListener* strongListener = listeners->ElementAt(i).mStrongListener;
253
0
      if (strongListener && *strongListener == aListener) {
254
0
        listeners->RemoveElementAt(i);
255
0
        return;
256
0
      }
257
0
    }
258
0
  }
259
0
}
260
261
static already_AddRefed<nsISupports>
262
ToXPCOMMessageListener(MessageListener& aListener)
263
0
{
264
0
  return CallbackObjectHolder<mozilla::dom::MessageListener,
265
0
                              nsISupports>(&aListener).ToXPCOMCallback();
266
0
}
267
268
void
269
nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessageName,
270
                                              MessageListener& aListener,
271
                                              ErrorResult& aError)
272
0
{
273
0
  nsCOMPtr<nsISupports> listener(ToXPCOMMessageListener(aListener));
274
0
  nsWeakPtr weak = do_GetWeakReference(listener);
275
0
  if (!weak) {
276
0
    aError.Throw(NS_ERROR_NO_INTERFACE);
277
0
    return;
278
0
  }
279
0
280
#ifdef DEBUG
281
  // It's technically possible that one object X could give two different
282
  // nsIWeakReference*'s when you do_GetWeakReference(X).  We really don't want
283
  // this to happen; it will break e.g. RemoveWeakMessageListener.  So let's
284
  // check that we're not getting ourselves into that situation.
285
  nsCOMPtr<nsISupports> canonical = do_QueryInterface(listener);
286
  for (auto iter = mListeners.Iter(); !iter.Done(); iter.Next()) {
287
    nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners = iter.UserData();
288
    uint32_t count = listeners->Length();
289
    for (uint32_t i = 0; i < count; i++) {
290
      nsWeakPtr weakListener = listeners->ElementAt(i).mWeakListener;
291
      if (weakListener) {
292
        nsCOMPtr<nsISupports> otherCanonical = do_QueryReferent(weakListener);
293
        MOZ_ASSERT((canonical == otherCanonical) == (weak == weakListener));
294
      }
295
    }
296
  }
297
#endif
298
299
0
  auto listeners = mListeners.LookupForAdd(aMessageName).OrInsert([]() {
300
0
      return new nsAutoTObserverArray<nsMessageListenerInfo, 1>();
301
0
    });
302
0
  uint32_t len = listeners->Length();
303
0
  for (uint32_t i = 0; i < len; ++i) {
304
0
    if (listeners->ElementAt(i).mWeakListener == weak) {
305
0
      return;
306
0
    }
307
0
  }
308
0
309
0
  nsMessageListenerInfo* entry = listeners->AppendElement();
310
0
  entry->mWeakListener = weak;
311
0
  entry->mListenWhenClosed = false;
312
0
}
313
314
void
315
nsFrameMessageManager::RemoveWeakMessageListener(const nsAString& aMessageName,
316
                                                 MessageListener& aListener,
317
                                                 ErrorResult& aError)
318
0
{
319
0
  nsCOMPtr<nsISupports> listener(ToXPCOMMessageListener(aListener));
320
0
  nsWeakPtr weak = do_GetWeakReference(listener);
321
0
  if (!weak) {
322
0
    aError.Throw(NS_ERROR_NO_INTERFACE);
323
0
    return;
324
0
  }
325
0
326
0
  nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
327
0
    mListeners.Get(aMessageName);
328
0
  if (!listeners) {
329
0
    return;
330
0
  }
331
0
332
0
  uint32_t len = listeners->Length();
333
0
  for (uint32_t i = 0; i < len; ++i) {
334
0
    if (listeners->ElementAt(i).mWeakListener == weak) {
335
0
      listeners->RemoveElementAt(i);
336
0
      return;
337
0
    }
338
0
  }
339
0
}
340
341
void
342
nsFrameMessageManager::LoadScript(const nsAString& aURL,
343
                                  bool aAllowDelayedLoad,
344
                                  bool aRunInGlobalScope,
345
                                  ErrorResult& aError)
346
0
{
347
0
  if (aAllowDelayedLoad) {
348
0
    // Cache for future windows or frames
349
0
    mPendingScripts.AppendElement(aURL);
350
0
    mPendingScriptsGlobalStates.AppendElement(aRunInGlobalScope);
351
0
  }
352
0
353
0
  if (mCallback) {
354
#ifdef DEBUG_smaug
355
    printf("Will load %s \n", NS_ConvertUTF16toUTF8(aURL).get());
356
#endif
357
0
    if (!mCallback->DoLoadMessageManagerScript(aURL, aRunInGlobalScope)) {
358
0
      aError.Throw(NS_ERROR_FAILURE);
359
0
      return;
360
0
    }
361
0
  }
362
0
363
0
  for (uint32_t i = 0; i < mChildManagers.Length(); ++i) {
364
0
    RefPtr<nsFrameMessageManager> mm = mChildManagers[i];
365
0
    if (mm) {
366
0
      // Use false here, so that child managers don't cache the script, which
367
0
      // is already cached in the parent.
368
0
      mm->LoadScript(aURL, false, aRunInGlobalScope, IgnoreErrors());
369
0
    }
370
0
  }
371
0
}
372
373
void
374
nsFrameMessageManager::RemoveDelayedScript(const nsAString& aURL)
375
0
{
376
0
  for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
377
0
    if (mPendingScripts[i] == aURL) {
378
0
      mPendingScripts.RemoveElementAt(i);
379
0
      mPendingScriptsGlobalStates.RemoveElementAt(i);
380
0
      break;
381
0
    }
382
0
  }
383
0
}
384
385
void
386
nsFrameMessageManager::GetDelayedScripts(JSContext* aCx,
387
                                         nsTArray<nsTArray<JS::Value>>& aList,
388
                                         ErrorResult& aError)
389
0
{
390
0
  // Frame message managers may return an incomplete list because scripts
391
0
  // that were loaded after it was connected are not added to the list.
392
0
  if (!IsGlobal() && !IsBroadcaster()) {
393
0
    NS_WARNING("Cannot retrieve list of pending frame scripts for frame"
394
0
               "message managers as it may be incomplete");
395
0
    aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
396
0
    return;
397
0
  }
398
0
399
0
  aError.MightThrowJSException();
400
0
401
0
  aList.SetCapacity(mPendingScripts.Length());
402
0
  for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
403
0
    JS::Rooted<JS::Value> url(aCx);
404
0
    if (!ToJSValue(aCx, mPendingScripts[i], &url)) {
405
0
      aError.NoteJSContextException(aCx);
406
0
      return;
407
0
    }
408
0
409
0
    nsTArray<JS::Value>* array = aList.AppendElement(2);
410
0
    array->AppendElement(url);
411
0
    array->AppendElement(JS::BooleanValue(mPendingScriptsGlobalStates[i]));
412
0
  }
413
0
}
414
415
static bool
416
GetParamsForMessage(JSContext* aCx,
417
                    const JS::Value& aValue,
418
                    const JS::Value& aTransfer,
419
                    StructuredCloneData& aData)
420
0
{
421
0
  // First try to use structured clone on the whole thing.
422
0
  JS::RootedValue v(aCx, aValue);
423
0
  JS::RootedValue t(aCx, aTransfer);
424
0
  ErrorResult rv;
425
0
  aData.Write(aCx, v, t, rv);
426
0
  if (!rv.Failed()) {
427
0
    return true;
428
0
  }
429
0
430
0
  rv.SuppressException();
431
0
  JS_ClearPendingException(aCx);
432
0
433
0
  nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
434
0
  if (console) {
435
0
    nsAutoString filename;
436
0
    uint32_t lineno = 0, column = 0;
437
0
    nsJSUtils::GetCallingLocation(aCx, filename, &lineno, &column);
438
0
    nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
439
0
    error->Init(NS_LITERAL_STRING("Sending message that cannot be cloned. Are you trying to send an XPCOM object?"),
440
0
                filename, EmptyString(), lineno, column,
441
0
                nsIScriptError::warningFlag, "chrome javascript",
442
0
                false /* from private window */);
443
0
    console->LogMessage(error);
444
0
  }
445
0
446
0
  // Not clonable, try JSON
447
0
  //XXX This is ugly but currently structured cloning doesn't handle
448
0
  //    properly cases when interface is implemented in JS and used
449
0
  //    as a dictionary.
450
0
  nsAutoString json;
451
0
  NS_ENSURE_TRUE(nsContentUtils::StringifyJSON(aCx, &v, json), false);
452
0
  NS_ENSURE_TRUE(!json.IsEmpty(), false);
453
0
454
0
  JS::Rooted<JS::Value> val(aCx, JS::NullValue());
455
0
  NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast<const char16_t*>(json.get()),
456
0
                              json.Length(), &val), false);
457
0
458
0
  aData.Write(aCx, val, rv);
459
0
  if (NS_WARN_IF(rv.Failed())) {
460
0
    rv.SuppressException();
461
0
    return false;
462
0
  }
463
0
464
0
  return true;
465
0
}
466
467
468
static bool sSendingSyncMessage = false;
469
470
static bool
471
AllowMessage(size_t aDataLength, const nsAString& aMessageName)
472
0
{
473
0
  // A message includes more than structured clone data, so subtract
474
0
  // 20KB to make it more likely that a message within this bound won't
475
0
  // result in an overly large IPC message.
476
0
  static const size_t kMaxMessageSize = IPC::Channel::kMaximumMessageSize - 20 * 1024;
477
0
  if (aDataLength < kMaxMessageSize) {
478
0
    return true;
479
0
  }
480
0
481
0
  NS_ConvertUTF16toUTF8 messageName(aMessageName);
482
0
  messageName.StripTaggedASCII(ASCIIMask::Mask0to9());
483
0
484
0
  Telemetry::Accumulate(Telemetry::REJECTED_MESSAGE_MANAGER_MESSAGE,
485
0
                        messageName);
486
0
487
0
  return false;
488
0
}
489
490
void
491
nsFrameMessageManager::SendMessage(JSContext* aCx,
492
                                   const nsAString& aMessageName,
493
                                   JS::Handle<JS::Value> aObj,
494
                                   JS::Handle<JSObject*> aObjects,
495
                                   nsIPrincipal* aPrincipal,
496
                                   bool aIsSync,
497
                                   nsTArray<JS::Value>& aResult,
498
                                   ErrorResult& aError)
499
0
{
500
0
  NS_ASSERTION(!IsGlobal(), "Should not call SendSyncMessage in chrome");
501
0
  NS_ASSERTION(!IsBroadcaster(), "Should not call SendSyncMessage in chrome");
502
0
  NS_ASSERTION(!GetParentManager(),
503
0
               "Should not have parent manager in content!");
504
0
505
0
  AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
506
0
    "nsFrameMessageManager::SendMessage", OTHER, aMessageName);
507
0
508
0
  if (sSendingSyncMessage && aIsSync) {
509
0
    // No kind of blocking send should be issued on top of a sync message.
510
0
    aError.Throw(NS_ERROR_UNEXPECTED);
511
0
    return;
512
0
  }
513
0
514
0
  StructuredCloneData data;
515
0
  if (!aObj.isUndefined() &&
516
0
      !GetParamsForMessage(aCx, aObj, JS::UndefinedHandleValue, data)) {
517
0
    aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
518
0
    return;
519
0
  }
520
0
521
0
#ifdef FUZZING
522
0
  if (data.DataLength() > 0) {
523
0
    MessageManagerFuzzer::TryMutate(
524
0
      aCx,
525
0
      aMessageName,
526
0
      &data,
527
0
      JS::UndefinedHandleValue);
528
0
  }
529
0
#endif
530
0
531
0
  if (!AllowMessage(data.DataLength(), aMessageName)) {
532
0
    aError.Throw(NS_ERROR_FAILURE);
533
0
    return;
534
0
  }
535
0
536
0
  if (!mCallback) {
537
0
    aError.Throw(NS_ERROR_NOT_INITIALIZED);
538
0
    return;
539
0
  }
540
0
541
0
  nsTArray<StructuredCloneData> retval;
542
0
543
0
  TimeStamp start = TimeStamp::Now();
544
0
  sSendingSyncMessage |= aIsSync;
545
0
  bool ok = mCallback->DoSendBlockingMessage(aCx, aMessageName, data, aObjects,
546
0
                                             aPrincipal, &retval, aIsSync);
547
0
  if (aIsSync) {
548
0
    sSendingSyncMessage = false;
549
0
  }
550
0
551
0
  uint32_t latencyMs = round((TimeStamp::Now() - start).ToMilliseconds());
552
0
  if (latencyMs >= kMinTelemetrySyncMessageManagerLatencyMs) {
553
0
    NS_ConvertUTF16toUTF8 messageName(aMessageName);
554
0
    // NOTE: We need to strip digit characters from the message name in order to
555
0
    // avoid a large number of buckets due to generated names from addons (such
556
0
    // as "ublock:sb:{N}"). See bug 1348113 comment 10.
557
0
    messageName.StripTaggedASCII(ASCIIMask::Mask0to9());
558
0
    Telemetry::Accumulate(Telemetry::IPC_SYNC_MESSAGE_MANAGER_LATENCY_MS,
559
0
                          messageName, latencyMs);
560
0
  }
561
0
562
0
  if (!ok) {
563
0
    return;
564
0
  }
565
0
566
0
  uint32_t len = retval.Length();
567
0
  aResult.SetCapacity(len);
568
0
  for (uint32_t i = 0; i < len; ++i) {
569
0
    JS::Rooted<JS::Value> ret(aCx);
570
0
    retval[i].Read(aCx, &ret, aError);
571
0
    if (aError.Failed()) {
572
0
      MOZ_ASSERT(false, "Unable to read structured clone in SendMessage");
573
0
      return;
574
0
    }
575
0
    aResult.AppendElement(ret);
576
0
  }
577
0
}
578
579
nsresult
580
nsFrameMessageManager::DispatchAsyncMessageInternal(JSContext* aCx,
581
                                                    const nsAString& aMessage,
582
                                                    StructuredCloneData& aData,
583
                                                    JS::Handle<JSObject *> aCpows,
584
                                                    nsIPrincipal* aPrincipal)
585
0
{
586
0
  if (mIsBroadcaster) {
587
0
    uint32_t len = mChildManagers.Length();
588
0
    for (uint32_t i = 0; i < len; ++i) {
589
0
      mChildManagers[i]->
590
0
         DispatchAsyncMessageInternal(aCx, aMessage, aData, aCpows, aPrincipal);
591
0
    }
592
0
    return NS_OK;
593
0
  }
594
0
595
0
  if (!mCallback) {
596
0
    return NS_ERROR_NOT_INITIALIZED;
597
0
  }
598
0
599
0
  nsresult rv = mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows, aPrincipal);
600
0
  if (NS_FAILED(rv)) {
601
0
    return rv;
602
0
  }
603
0
  return NS_OK;
604
0
}
605
606
void
607
nsFrameMessageManager::DispatchAsyncMessage(JSContext* aCx,
608
                                            const nsAString& aMessageName,
609
                                            JS::Handle<JS::Value> aObj,
610
                                            JS::Handle<JSObject*> aObjects,
611
                                            nsIPrincipal* aPrincipal,
612
                                            JS::Handle<JS::Value> aTransfers,
613
                                            ErrorResult& aError)
614
0
{
615
0
  StructuredCloneData data;
616
0
  if (!aObj.isUndefined() && !GetParamsForMessage(aCx, aObj, aTransfers, data)) {
617
0
    aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
618
0
    return;
619
0
  }
620
0
621
0
#ifdef FUZZING
622
0
  if (data.DataLength()) {
623
0
    MessageManagerFuzzer::TryMutate(aCx, aMessageName, &data, aTransfers);
624
0
  }
625
0
#endif
626
0
627
0
  if (!AllowMessage(data.DataLength(), aMessageName)) {
628
0
    aError.Throw(NS_ERROR_FAILURE);
629
0
    return;
630
0
  }
631
0
632
0
  aError = DispatchAsyncMessageInternal(aCx, aMessageName, data, aObjects,
633
0
                                        aPrincipal);
634
0
}
635
636
class MMListenerRemover
637
{
638
public:
639
  explicit MMListenerRemover(nsFrameMessageManager* aMM)
640
    : mWasHandlingMessage(aMM->mHandlingMessage)
641
    , mMM(aMM)
642
0
  {
643
0
    mMM->mHandlingMessage = true;
644
0
  }
645
  ~MMListenerRemover()
646
0
  {
647
0
    if (!mWasHandlingMessage) {
648
0
      mMM->mHandlingMessage = false;
649
0
      if (mMM->mDisconnected) {
650
0
        mMM->mListeners.Clear();
651
0
      }
652
0
    }
653
0
  }
654
655
  bool mWasHandlingMessage;
656
  RefPtr<nsFrameMessageManager> mMM;
657
};
658
659
// When recording or replaying, return whether a message should be received in
660
// the middleman process instead of the recording/replaying process.
661
static bool
662
DirectMessageToMiddleman(const nsAString& aMessage)
663
0
{
664
0
  // Middleman processes run developer tools server code and need to receive
665
0
  // debugger related messages. The session store flush message needs to be
666
0
  // received in order to cleanly shutdown the process.
667
0
  return (StringBeginsWith(aMessage, NS_LITERAL_STRING("debug:")) &&
668
0
          recordreplay::parent::DebuggerRunsInMiddleman())
669
0
      || aMessage.EqualsLiteral("SessionStore:flush");
670
0
}
671
672
void
673
nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
674
                                      nsFrameLoader* aTargetFrameLoader,
675
                                      bool aTargetClosed,
676
                                      const nsAString& aMessage,
677
                                      bool aIsSync,
678
                                      StructuredCloneData* aCloneData,
679
                                      mozilla::jsipc::CpowHolder* aCpows,
680
                                      nsIPrincipal* aPrincipal,
681
                                      nsTArray<StructuredCloneData>* aRetVal,
682
                                      ErrorResult& aError)
683
0
{
684
0
  // If we are recording or replaying, we will end up here in both the
685
0
  // middleman process and the recording/replaying process. Ignore the message
686
0
  // in one of the processes, so that it is only received in one place.
687
0
  if (recordreplay::IsRecordingOrReplaying()) {
688
0
    if (DirectMessageToMiddleman(aMessage)) {
689
0
      return;
690
0
    }
691
0
  } else if (recordreplay::IsMiddleman()) {
692
0
    if (!DirectMessageToMiddleman(aMessage)) {
693
0
      return;
694
0
    }
695
0
  }
696
0
697
0
  MOZ_ASSERT(aTarget);
698
0
699
0
  nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
700
0
    mListeners.Get(aMessage);
701
0
  if (listeners) {
702
0
703
0
    MMListenerRemover lr(this);
704
0
705
0
    nsAutoTObserverArray<nsMessageListenerInfo, 1>::EndLimitedIterator
706
0
      iter(*listeners);
707
0
    while(iter.HasMore()) {
708
0
      nsMessageListenerInfo& listener = iter.GetNext();
709
0
      // Remove mListeners[i] if it's an expired weak listener.
710
0
      nsCOMPtr<nsISupports> weakListener;
711
0
      if (listener.mWeakListener) {
712
0
        weakListener = do_QueryReferent(listener.mWeakListener);
713
0
        if (!weakListener) {
714
0
          listeners->RemoveElement(listener);
715
0
          continue;
716
0
        }
717
0
      }
718
0
719
0
      if (!listener.mListenWhenClosed && aTargetClosed) {
720
0
        continue;
721
0
      }
722
0
723
0
      JS::RootingContext* rcx = RootingCx();
724
0
      JS::Rooted<JSObject*> object(rcx);
725
0
      JS::Rooted<JSObject*> objectGlobal(rcx);
726
0
727
0
      RefPtr<MessageListener> webIDLListener;
728
0
      if (!weakListener) {
729
0
        webIDLListener = listener.mStrongListener;
730
0
        object = webIDLListener->CallbackOrNull();
731
0
        objectGlobal = webIDLListener->CallbackGlobalOrNull();
732
0
      } else {
733
0
        nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(weakListener);
734
0
        if (!wrappedJS) {
735
0
          continue;
736
0
        }
737
0
738
0
        object = wrappedJS->GetJSObject();
739
0
        objectGlobal = wrappedJS->GetJSObjectGlobal();
740
0
      }
741
0
742
0
      if (!object) {
743
0
        continue;
744
0
      }
745
0
746
0
      AutoEntryScript aes(js::UncheckedUnwrap(object), "message manager handler");
747
0
      JSContext* cx = aes.cx();
748
0
749
0
      // We passed the unwrapped object to AutoEntryScript so we now need to
750
0
      // enter the realm of the global object that represents the realm of our
751
0
      // callback.
752
0
      JSAutoRealm ar(cx, objectGlobal);
753
0
754
0
      RootedDictionary<ReceiveMessageArgument> argument(cx);
755
0
756
0
      JS::Rooted<JSObject*> cpows(cx);
757
0
      if (aCpows && !aCpows->ToObject(cx, &cpows)) {
758
0
        aError.Throw(NS_ERROR_UNEXPECTED);
759
0
        return;
760
0
      }
761
0
762
0
      if (!cpows) {
763
0
        cpows = JS_NewPlainObject(cx);
764
0
        if (!cpows) {
765
0
          aError.Throw(NS_ERROR_UNEXPECTED);
766
0
          return;
767
0
        }
768
0
      }
769
0
      argument.mObjects = cpows;
770
0
771
0
      JS::Rooted<JS::Value> json(cx, JS::NullValue());
772
0
      if (aCloneData && aCloneData->DataLength()) {
773
0
        aCloneData->Read(cx, &json, aError);
774
0
        if (NS_WARN_IF(aError.Failed())) {
775
0
          aError.SuppressException();
776
0
          JS_ClearPendingException(cx);
777
0
          return;
778
0
        }
779
0
      }
780
0
      argument.mData = json;
781
0
      argument.mJson = json;
782
0
783
0
      // Get cloned MessagePort from StructuredCloneData.
784
0
      if (aCloneData) {
785
0
        Sequence<OwningNonNull<MessagePort>> ports;
786
0
        if (!aCloneData->TakeTransferredPortsAsSequence(ports)) {
787
0
          aError.Throw(NS_ERROR_FAILURE);
788
0
          return;
789
0
        }
790
0
        argument.mPorts.Construct(std::move(ports));
791
0
      }
792
0
793
0
      argument.mName = aMessage;
794
0
      argument.mPrincipal = aPrincipal;
795
0
      argument.mSync = aIsSync;
796
0
      argument.mTarget = aTarget;
797
0
      if (aTargetFrameLoader) {
798
0
        argument.mTargetFrameLoader.Construct(*aTargetFrameLoader);
799
0
      }
800
0
801
0
      JS::Rooted<JS::Value> thisValue(cx, JS::UndefinedValue());
802
0
803
0
      if (JS::IsCallable(object)) {
804
0
        // A small hack to get 'this' value right on content side where
805
0
        // messageManager is wrapped in TabChildMessageManager's global.
806
0
        nsCOMPtr<nsISupports> defaultThisValue;
807
0
        if (mChrome) {
808
0
          defaultThisValue = do_QueryObject(this);
809
0
        } else {
810
0
          defaultThisValue = aTarget;
811
0
        }
812
0
        js::AssertSameCompartment(cx, object);
813
0
        aError = nsContentUtils::WrapNative(cx, defaultThisValue, &thisValue);
814
0
        if (aError.Failed()) {
815
0
          return;
816
0
        }
817
0
      }
818
0
819
0
      JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());
820
0
      if (webIDLListener) {
821
0
        webIDLListener->ReceiveMessage(thisValue, argument, &rval, aError);
822
0
        if (aError.Failed()) {
823
0
          // At this point the call to ReceiveMessage will have reported any exceptions
824
0
          // (we kept the default of eReportExceptions). We suppress the failure in the
825
0
          // ErrorResult and continue.
826
0
          aError.SuppressException();
827
0
          continue;
828
0
        }
829
0
      } else {
830
0
        JS::Rooted<JS::Value> funval(cx);
831
0
        if (JS::IsCallable(object)) {
832
0
          // If the listener is a JS function:
833
0
          funval.setObject(*object);
834
0
        } else {
835
0
          // If the listener is a JS object which has receiveMessage function:
836
0
          if (!JS_GetProperty(cx, object, "receiveMessage", &funval) ||
837
0
              !funval.isObject()) {
838
0
            aError.Throw(NS_ERROR_UNEXPECTED);
839
0
            return;
840
0
          }
841
0
842
0
          // Check if the object is even callable.
843
0
          if (!JS::IsCallable(&funval.toObject())) {
844
0
            aError.Throw(NS_ERROR_UNEXPECTED);
845
0
            return;
846
0
          }
847
0
          thisValue.setObject(*object);
848
0
        }
849
0
850
0
        JS::Rooted<JS::Value> argv(cx);
851
0
        if (!ToJSValue(cx, argument, &argv)) {
852
0
          aError.Throw(NS_ERROR_UNEXPECTED);
853
0
          return;
854
0
        }
855
0
856
0
        {
857
0
          JS::Rooted<JSObject*> thisObject(cx, thisValue.toObjectOrNull());
858
0
          js::AssertSameCompartment(cx, thisObject);
859
0
          if (!JS_CallFunctionValue(cx, thisObject, funval,
860
0
                                    JS::HandleValueArray(argv), &rval)) {
861
0
            // Because the AutoEntryScript is inside the loop this continue will make us
862
0
            // report any exceptions (after which we'll move on to the next listener).
863
0
            continue;
864
0
          }
865
0
        }
866
0
      }
867
0
868
0
      if (aRetVal) {
869
0
        StructuredCloneData* data = aRetVal->AppendElement();
870
0
        data->InitScope(JS::StructuredCloneScope::DifferentProcess);
871
0
        data->Write(cx, rval, aError);
872
0
        if (NS_WARN_IF(aError.Failed())) {
873
0
          aRetVal->RemoveLastElement();
874
0
          nsString msg = aMessage + NS_LITERAL_STRING(": message reply cannot be cloned. Are you trying to send an XPCOM object?");
875
0
876
0
          nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
877
0
          if (console) {
878
0
            nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
879
0
            error->Init(msg, EmptyString(), EmptyString(),
880
0
                        0, 0, nsIScriptError::warningFlag, "chrome javascript",
881
0
                        false /* from private window */);
882
0
            console->LogMessage(error);
883
0
          }
884
0
885
0
          JS_ClearPendingException(cx);
886
0
          continue;
887
0
        }
888
0
      }
889
0
    }
890
0
  }
891
0
892
0
  RefPtr<nsFrameMessageManager> kungFuDeathGrip = GetParentManager();
893
0
  if (kungFuDeathGrip) {
894
0
    kungFuDeathGrip->ReceiveMessage(aTarget, aTargetFrameLoader, aTargetClosed, aMessage,
895
0
                                    aIsSync, aCloneData, aCpows, aPrincipal, aRetVal,
896
0
                                    aError);
897
0
  }
898
0
}
899
900
void
901
nsFrameMessageManager::LoadPendingScripts(nsFrameMessageManager* aManager,
902
                                          nsFrameMessageManager* aChildMM)
903
0
{
904
0
  // We have parent manager if we're a message broadcaster.
905
0
  // In that case we want to load the pending scripts from all parent
906
0
  // message managers in the hierarchy. Process the parent first so
907
0
  // that pending scripts higher up in the hierarchy are loaded before others.
908
0
  nsFrameMessageManager* parentManager = aManager->GetParentManager();
909
0
  if (parentManager) {
910
0
    LoadPendingScripts(parentManager, aChildMM);
911
0
  }
912
0
913
0
  for (uint32_t i = 0; i < aManager->mPendingScripts.Length(); ++i) {
914
0
    aChildMM->LoadScript(aManager->mPendingScripts[i],
915
0
                         false,
916
0
                         aManager->mPendingScriptsGlobalStates[i],
917
0
                         IgnoreErrors());
918
0
  }
919
0
}
920
921
void
922
nsFrameMessageManager::LoadPendingScripts()
923
0
{
924
0
  RefPtr<nsFrameMessageManager> kungfuDeathGrip = this;
925
0
  LoadPendingScripts(this, this);
926
0
}
927
928
void
929
nsFrameMessageManager::SetCallback(MessageManagerCallback* aCallback)
930
0
{
931
0
  MOZ_ASSERT(!mIsBroadcaster || !mCallback,
932
0
             "Broadcasters cannot have callbacks!");
933
0
  if (aCallback && mCallback != aCallback) {
934
0
    mCallback = aCallback;
935
0
    if (mOwnsCallback) {
936
0
      mOwnedCallback = aCallback;
937
0
    }
938
0
  }
939
0
}
940
941
void
942
nsFrameMessageManager::Close()
943
0
{
944
0
  if (!mClosed) {
945
0
    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
946
0
    if (obs) {
947
0
      obs->NotifyObservers(this, "message-manager-close", nullptr);
948
0
    }
949
0
  }
950
0
  mClosed = true;
951
0
  mCallback = nullptr;
952
0
  mOwnedCallback = nullptr;
953
0
}
954
955
void
956
nsFrameMessageManager::Disconnect(bool aRemoveFromParent)
957
0
{
958
0
  // Notify message-manager-close if we haven't already.
959
0
  Close();
960
0
961
0
  if (!mDisconnected) {
962
0
    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
963
0
    if (obs) {
964
0
       obs->NotifyObservers(this, "message-manager-disconnect", nullptr);
965
0
    }
966
0
  }
967
0
968
0
  ClearParentManager(aRemoveFromParent);
969
0
970
0
  mDisconnected = true;
971
0
  if (!mHandlingMessage) {
972
0
    mListeners.Clear();
973
0
  }
974
0
}
975
976
void
977
nsFrameMessageManager::SetInitialProcessData(JS::HandleValue aInitialData)
978
0
{
979
0
  MOZ_ASSERT(!mChrome);
980
0
  MOZ_ASSERT(mIsProcessManager);
981
0
  MOZ_ASSERT(aInitialData.isObject());
982
0
  mInitialProcessData = aInitialData;
983
0
}
984
985
void
986
nsFrameMessageManager::GetInitialProcessData(JSContext* aCx,
987
                                             JS::MutableHandle<JS::Value> aInitialProcessData,
988
                                             ErrorResult& aError)
989
0
{
990
0
  MOZ_ASSERT(mIsProcessManager);
991
0
  MOZ_ASSERT_IF(mChrome, IsBroadcaster());
992
0
993
0
  JS::RootedValue init(aCx, mInitialProcessData);
994
0
  if (mChrome && init.isUndefined()) {
995
0
    // We create the initial object in the junk scope. If we created it in a
996
0
    // normal realm, that realm would leak until shutdown.
997
0
    JS::RootedObject global(aCx, xpc::PrivilegedJunkScope());
998
0
    JSAutoRealm ar(aCx, global);
999
0
1000
0
    JS::RootedObject obj(aCx, JS_NewPlainObject(aCx));
1001
0
    if (!obj) {
1002
0
      aError.NoteJSContextException(aCx);
1003
0
      return;
1004
0
    }
1005
0
1006
0
    mInitialProcessData.setObject(*obj);
1007
0
    init.setObject(*obj);
1008
0
  }
1009
0
1010
0
  if (!mChrome && XRE_IsParentProcess()) {
1011
0
    // This is the cpmm in the parent process. We should use the same object as the ppmm.
1012
0
    // Create it first through do_GetService and use the cached pointer in
1013
0
    // sParentProcessManager.
1014
0
    nsCOMPtr<nsISupports> ppmm = do_GetService("@mozilla.org/parentprocessmessagemanager;1");
1015
0
    sParentProcessManager->GetInitialProcessData(aCx, &init, aError);
1016
0
    if (aError.Failed()) {
1017
0
      return;
1018
0
    }
1019
0
    mInitialProcessData = init;
1020
0
  }
1021
0
1022
0
  if (!JS_WrapValue(aCx, &init)) {
1023
0
    aError.NoteJSContextException(aCx);
1024
0
    return;
1025
0
  }
1026
0
  aInitialProcessData.set(init);
1027
0
}
1028
1029
WritableSharedMap*
1030
nsFrameMessageManager::SharedData()
1031
0
{
1032
0
  if (!mChrome || !mIsProcessManager) {
1033
0
    MOZ_ASSERT(false, "Should only call this binding method on ppmm");
1034
0
    return nullptr;
1035
0
  }
1036
0
  if (!mSharedData) {
1037
0
    mSharedData = new WritableSharedMap();
1038
0
  }
1039
0
  return mSharedData;
1040
0
}
1041
1042
already_AddRefed<ProcessMessageManager>
1043
nsFrameMessageManager::GetProcessMessageManager(ErrorResult& aError)
1044
0
{
1045
0
  RefPtr<ProcessMessageManager> pmm;
1046
0
  if (mCallback) {
1047
0
    pmm = mCallback->GetProcessMessageManager();
1048
0
  }
1049
0
  return pmm.forget();
1050
0
}
1051
1052
void
1053
nsFrameMessageManager::GetRemoteType(nsAString& aRemoteType, ErrorResult& aError) const
1054
0
{
1055
0
  aRemoteType.Truncate();
1056
0
  if (mCallback) {
1057
0
    mCallback->DoGetRemoteType(aRemoteType, aError);
1058
0
  }
1059
0
}
1060
1061
namespace {
1062
1063
struct MessageManagerReferentCount
1064
{
1065
0
  MessageManagerReferentCount() : mStrong(0), mWeakAlive(0), mWeakDead(0) {}
1066
  size_t mStrong;
1067
  size_t mWeakAlive;
1068
  size_t mWeakDead;
1069
  nsTArray<nsString> mSuspectMessages;
1070
  nsDataHashtable<nsStringHashKey, uint32_t> mMessageCounter;
1071
};
1072
1073
} // namespace
1074
1075
namespace mozilla {
1076
namespace dom {
1077
1078
class MessageManagerReporter final : public nsIMemoryReporter
1079
{
1080
  ~MessageManagerReporter() = default;
1081
1082
public:
1083
  NS_DECL_ISUPPORTS
1084
  NS_DECL_NSIMEMORYREPORTER
1085
1086
  static const size_t kSuspectReferentCount = 300;
1087
protected:
1088
  void CountReferents(nsFrameMessageManager* aMessageManager,
1089
                      MessageManagerReferentCount* aReferentCount);
1090
};
1091
1092
NS_IMPL_ISUPPORTS(MessageManagerReporter, nsIMemoryReporter)
1093
1094
void
1095
MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager,
1096
                                       MessageManagerReferentCount* aReferentCount)
1097
0
{
1098
0
  for (auto it = aMessageManager->mListeners.Iter(); !it.Done(); it.Next()) {
1099
0
    nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
1100
0
      it.UserData();
1101
0
    uint32_t listenerCount = listeners->Length();
1102
0
    if (listenerCount == 0) {
1103
0
      continue;
1104
0
    }
1105
0
1106
0
    nsString key(it.Key());
1107
0
    uint32_t oldCount = 0;
1108
0
    aReferentCount->mMessageCounter.Get(key, &oldCount);
1109
0
    uint32_t currentCount = oldCount + listenerCount;
1110
0
    aReferentCount->mMessageCounter.Put(key, currentCount);
1111
0
1112
0
    // Keep track of messages that have a suspiciously large
1113
0
    // number of referents (symptom of leak).
1114
0
    if (currentCount == MessageManagerReporter::kSuspectReferentCount) {
1115
0
      aReferentCount->mSuspectMessages.AppendElement(key);
1116
0
    }
1117
0
1118
0
    for (uint32_t i = 0; i < listenerCount; ++i) {
1119
0
      const nsMessageListenerInfo& listenerInfo = listeners->ElementAt(i);
1120
0
      if (listenerInfo.mWeakListener) {
1121
0
        nsCOMPtr<nsISupports> referent =
1122
0
          do_QueryReferent(listenerInfo.mWeakListener);
1123
0
        if (referent) {
1124
0
          aReferentCount->mWeakAlive++;
1125
0
        } else {
1126
0
          aReferentCount->mWeakDead++;
1127
0
        }
1128
0
      } else {
1129
0
        aReferentCount->mStrong++;
1130
0
      }
1131
0
    }
1132
0
  }
1133
0
1134
0
  // Add referent count in child managers because the listeners
1135
0
  // participate in messages dispatched from parent message manager.
1136
0
  for (uint32_t i = 0; i < aMessageManager->mChildManagers.Length(); ++i) {
1137
0
    RefPtr<nsFrameMessageManager> mm = aMessageManager->mChildManagers[i];
1138
0
    CountReferents(mm, aReferentCount);
1139
0
  }
1140
0
}
1141
1142
static void
1143
ReportReferentCount(const char* aManagerType,
1144
                    const MessageManagerReferentCount& aReferentCount,
1145
                    nsIHandleReportCallback* aHandleReport,
1146
                    nsISupports* aData)
1147
0
{
1148
0
#define REPORT(_path, _amount, _desc) \
1149
0
    do { \
1150
0
      aHandleReport->Callback(EmptyCString(), _path, \
1151
0
                              nsIMemoryReporter::KIND_OTHER, \
1152
0
                              nsIMemoryReporter::UNITS_COUNT, _amount, \
1153
0
                              _desc, aData); \
1154
0
    } while (0)
1155
0
1156
0
  REPORT(nsPrintfCString("message-manager/referent/%s/strong", aManagerType),
1157
0
         aReferentCount.mStrong,
1158
0
         nsPrintfCString("The number of strong referents held by the message "
1159
0
                         "manager in the %s manager.", aManagerType));
1160
0
  REPORT(nsPrintfCString("message-manager/referent/%s/weak/alive", aManagerType),
1161
0
         aReferentCount.mWeakAlive,
1162
0
         nsPrintfCString("The number of weak referents that are still alive "
1163
0
                         "held by the message manager in the %s manager.",
1164
0
                         aManagerType));
1165
0
  REPORT(nsPrintfCString("message-manager/referent/%s/weak/dead", aManagerType),
1166
0
         aReferentCount.mWeakDead,
1167
0
         nsPrintfCString("The number of weak referents that are dead "
1168
0
                         "held by the message manager in the %s manager.",
1169
0
                         aManagerType));
1170
0
1171
0
  for (uint32_t i = 0; i < aReferentCount.mSuspectMessages.Length(); i++) {
1172
0
    uint32_t totalReferentCount = 0;
1173
0
    aReferentCount.mMessageCounter.Get(aReferentCount.mSuspectMessages[i],
1174
0
                                       &totalReferentCount);
1175
0
    NS_ConvertUTF16toUTF8 suspect(aReferentCount.mSuspectMessages[i]);
1176
0
    REPORT(nsPrintfCString("message-manager-suspect/%s/referent(message=%s)",
1177
0
                           aManagerType, suspect.get()), totalReferentCount,
1178
0
           nsPrintfCString("A message in the %s message manager with a "
1179
0
                           "suspiciously large number of referents (symptom "
1180
0
                           "of a leak).", aManagerType));
1181
0
  }
1182
0
1183
0
#undef REPORT
1184
0
}
1185
1186
static StaticRefPtr<ChromeMessageBroadcaster> sGlobalMessageManager;
1187
1188
NS_IMETHODIMP
1189
MessageManagerReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
1190
                                       nsISupports* aData, bool aAnonymize)
1191
0
{
1192
0
  if (XRE_IsParentProcess() && sGlobalMessageManager) {
1193
0
    MessageManagerReferentCount count;
1194
0
    CountReferents(sGlobalMessageManager, &count);
1195
0
    ReportReferentCount("global-manager", count, aHandleReport, aData);
1196
0
  }
1197
0
1198
0
  if (nsFrameMessageManager::sParentProcessManager) {
1199
0
    MessageManagerReferentCount count;
1200
0
    CountReferents(nsFrameMessageManager::sParentProcessManager, &count);
1201
0
    ReportReferentCount("parent-process-manager", count, aHandleReport, aData);
1202
0
  }
1203
0
1204
0
  if (nsFrameMessageManager::sChildProcessManager) {
1205
0
    MessageManagerReferentCount count;
1206
0
    CountReferents(nsFrameMessageManager::sChildProcessManager, &count);
1207
0
    ReportReferentCount("child-process-manager", count, aHandleReport, aData);
1208
0
  }
1209
0
1210
0
  return NS_OK;
1211
0
}
1212
1213
} // namespace dom
1214
} // namespace mozilla
1215
1216
already_AddRefed<ChromeMessageBroadcaster>
1217
nsFrameMessageManager::GetGlobalMessageManager()
1218
0
{
1219
0
  RefPtr<ChromeMessageBroadcaster> mm;
1220
0
  if (sGlobalMessageManager) {
1221
0
    mm = sGlobalMessageManager;
1222
0
  } else {
1223
0
    sGlobalMessageManager = mm =
1224
0
      new ChromeMessageBroadcaster(MessageManagerFlags::MM_GLOBAL);
1225
0
    ClearOnShutdown(&sGlobalMessageManager);
1226
0
    RegisterStrongMemoryReporter(new MessageManagerReporter());
1227
0
  }
1228
0
  return mm.forget();
1229
0
}
1230
1231
nsresult
1232
NS_NewGlobalMessageManager(nsISupports** aResult)
1233
0
{
1234
0
  *aResult = nsFrameMessageManager::GetGlobalMessageManager().take();
1235
0
  return NS_OK;
1236
0
}
1237
1238
nsDataHashtable<nsStringHashKey, nsMessageManagerScriptHolder*>*
1239
  nsMessageManagerScriptExecutor::sCachedScripts = nullptr;
1240
StaticRefPtr<nsScriptCacheCleaner> nsMessageManagerScriptExecutor::sScriptCacheCleaner;
1241
1242
void
1243
nsMessageManagerScriptExecutor::DidCreateScriptLoader()
1244
0
{
1245
0
  if (!sCachedScripts) {
1246
0
    sCachedScripts =
1247
0
      new nsDataHashtable<nsStringHashKey, nsMessageManagerScriptHolder*>;
1248
0
    sScriptCacheCleaner = new nsScriptCacheCleaner();
1249
0
  }
1250
0
}
1251
1252
// static
1253
void
1254
nsMessageManagerScriptExecutor::PurgeCache()
1255
0
{
1256
0
  if (sCachedScripts) {
1257
0
    NS_ASSERTION(sCachedScripts != nullptr, "Need cached scripts");
1258
0
    for (auto iter = sCachedScripts->Iter(); !iter.Done(); iter.Next()) {
1259
0
      delete iter.Data();
1260
0
      iter.Remove();
1261
0
    }
1262
0
  }
1263
0
}
1264
1265
// static
1266
void
1267
nsMessageManagerScriptExecutor::Shutdown()
1268
0
{
1269
0
  if (sCachedScripts) {
1270
0
    PurgeCache();
1271
0
1272
0
    delete sCachedScripts;
1273
0
    sCachedScripts = nullptr;
1274
0
    sScriptCacheCleaner = nullptr;
1275
0
  }
1276
0
}
1277
1278
void
1279
nsMessageManagerScriptExecutor::LoadScriptInternal(JS::Handle<JSObject*> aMessageManager,
1280
                                                   const nsAString& aURL,
1281
                                                   bool aRunInUniqueScope)
1282
0
{
1283
0
  AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
1284
0
    "nsMessageManagerScriptExecutor::LoadScriptInternal", OTHER, aURL);
1285
0
1286
0
  if (!sCachedScripts) {
1287
0
    return;
1288
0
  }
1289
0
1290
0
  JS::RootingContext* rcx = RootingCx();
1291
0
  JS::Rooted<JSScript*> script(rcx);
1292
0
1293
0
  nsMessageManagerScriptHolder* holder = sCachedScripts->Get(aURL);
1294
0
  if (holder) {
1295
0
    script = holder->mScript;
1296
0
  } else {
1297
0
    TryCacheLoadAndCompileScript(aURL, aRunInUniqueScope, true,
1298
0
                                 aMessageManager, &script);
1299
0
  }
1300
0
1301
0
  AutoEntryScript aes(aMessageManager, "message manager script load");
1302
0
  JSContext* cx = aes.cx();
1303
0
  if (script) {
1304
0
    if (aRunInUniqueScope) {
1305
0
      JS::Rooted<JSObject*> scope(cx);
1306
0
      bool ok = js::ExecuteInFrameScriptEnvironment(cx, aMessageManager, script, &scope);
1307
0
      if (ok) {
1308
0
        // Force the scope to stay alive.
1309
0
        mAnonymousGlobalScopes.AppendElement(scope);
1310
0
      }
1311
0
    } else {
1312
0
      JS::RootedValue rval(cx);
1313
0
      JS::AutoObjectVector envChain(cx);
1314
0
      if (!envChain.append(aMessageManager)) {
1315
0
        return;
1316
0
      }
1317
0
      JS::CloneAndExecuteScript(cx, envChain, script, &rval);
1318
0
    }
1319
0
  }
1320
0
}
1321
1322
void
1323
nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
1324
  const nsAString& aURL,
1325
  bool aRunInUniqueScope,
1326
  bool aShouldCache,
1327
  JS::Handle<JSObject*> aMessageManager,
1328
  JS::MutableHandle<JSScript*> aScriptp)
1329
0
{
1330
0
  nsCString url = NS_ConvertUTF16toUTF8(aURL);
1331
0
  nsCOMPtr<nsIURI> uri;
1332
0
  nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
1333
0
  if (NS_FAILED(rv)) {
1334
0
    return;
1335
0
  }
1336
0
1337
0
  bool hasFlags;
1338
0
  rv = NS_URIChainHasFlags(uri,
1339
0
                           nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
1340
0
                           &hasFlags);
1341
0
  if (NS_FAILED(rv) || !hasFlags) {
1342
0
    NS_WARNING("Will not load a frame script!");
1343
0
    return;
1344
0
  }
1345
0
1346
0
  // If this script won't be cached, or there is only one of this type of
1347
0
  // message manager per process, treat this script as run-once. Run-once
1348
0
  // scripts can be compiled directly for the target global, and will be dropped
1349
0
  // from the preloader cache after they're executed and serialized.
1350
0
  bool isRunOnce = !aShouldCache || IsProcessScoped();
1351
0
1352
0
  // If the script will be reused in this session, compile it in the compilation
1353
0
  // scope instead of the current global to avoid keeping the current
1354
0
  // compartment alive.
1355
0
  AutoJSAPI jsapi;
1356
0
  if (!jsapi.Init(isRunOnce ? aMessageManager : xpc::CompilationScope())) {
1357
0
    return;
1358
0
  }
1359
0
  JSContext* cx = jsapi.cx();
1360
0
  JS::Rooted<JSScript*> script(cx);
1361
0
1362
0
  script = ScriptPreloader::GetChildSingleton().GetCachedScript(cx, url);
1363
0
1364
0
  if (!script) {
1365
0
    nsCOMPtr<nsIChannel> channel;
1366
0
    NS_NewChannel(getter_AddRefs(channel),
1367
0
                  uri,
1368
0
                  nsContentUtils::GetSystemPrincipal(),
1369
0
                  nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
1370
0
                  nsIContentPolicy::TYPE_OTHER);
1371
0
1372
0
    if (!channel) {
1373
0
      return;
1374
0
    }
1375
0
1376
0
    nsCOMPtr<nsIInputStream> input;
1377
0
    rv = channel->Open2(getter_AddRefs(input));
1378
0
    NS_ENSURE_SUCCESS_VOID(rv);
1379
0
    nsString dataString;
1380
0
    char16_t* dataStringBuf = nullptr;
1381
0
    size_t dataStringLength = 0;
1382
0
    if (input) {
1383
0
      nsCString buffer;
1384
0
      uint64_t written;
1385
0
      if (NS_FAILED(NS_ReadInputStreamToString(input, buffer, -1, &written))) {
1386
0
        return;
1387
0
      }
1388
0
1389
0
      uint32_t size = (uint32_t)std::min(written, (uint64_t)UINT32_MAX);
1390
0
      ScriptLoader::ConvertToUTF16(channel, (uint8_t*)buffer.get(), size,
1391
0
                                   EmptyString(), nullptr,
1392
0
                                   dataStringBuf, dataStringLength);
1393
0
    }
1394
0
1395
0
    JS::SourceBufferHolder srcBuf(dataStringBuf, dataStringLength,
1396
0
                                  JS::SourceBufferHolder::GiveOwnership);
1397
0
1398
0
    if (!dataStringBuf || dataStringLength == 0) {
1399
0
      return;
1400
0
    }
1401
0
1402
0
    JS::CompileOptions options(cx);
1403
0
    options.setFileAndLine(url.get(), 1);
1404
0
    options.setNoScriptRval(true);
1405
0
1406
0
    if (!JS::CompileForNonSyntacticScope(cx, options, srcBuf, &script)) {
1407
0
      return;
1408
0
    }
1409
0
  }
1410
0
1411
0
  MOZ_ASSERT(script);
1412
0
  aScriptp.set(script);
1413
0
1414
0
  nsAutoCString scheme;
1415
0
  uri->GetScheme(scheme);
1416
0
  // We don't cache data: scripts!
1417
0
  if (aShouldCache && !scheme.EqualsLiteral("data")) {
1418
0
    ScriptPreloader::GetChildSingleton().NoteScript(url, url, script, isRunOnce);
1419
0
1420
0
    // If this script will only run once per process, only cache it in the
1421
0
    // preloader cache, not the session cache.
1422
0
    if (!isRunOnce) {
1423
0
      // Root the object also for caching.
1424
0
      auto* holder = new nsMessageManagerScriptHolder(cx, script);
1425
0
      sCachedScripts->Put(aURL, holder);
1426
0
    }
1427
0
  }
1428
0
}
1429
1430
void
1431
nsMessageManagerScriptExecutor::Trace(const TraceCallbacks& aCallbacks, void* aClosure)
1432
0
{
1433
0
  for (size_t i = 0, length = mAnonymousGlobalScopes.Length(); i < length; ++i) {
1434
0
    aCallbacks.Trace(&mAnonymousGlobalScopes[i], "mAnonymousGlobalScopes[i]", aClosure);
1435
0
  }
1436
0
}
1437
1438
void
1439
nsMessageManagerScriptExecutor::Unlink()
1440
0
{
1441
0
  ImplCycleCollectionUnlink(mAnonymousGlobalScopes);
1442
0
}
1443
1444
bool
1445
nsMessageManagerScriptExecutor::Init()
1446
0
{
1447
0
  DidCreateScriptLoader();
1448
0
  return true;
1449
0
}
1450
1451
void
1452
nsMessageManagerScriptExecutor::MarkScopesForCC()
1453
0
{
1454
0
  for (uint32_t i = 0; i < mAnonymousGlobalScopes.Length(); ++i) {
1455
0
    mAnonymousGlobalScopes[i].exposeToActiveJS();
1456
0
  }
1457
0
}
1458
1459
NS_IMPL_ISUPPORTS(nsScriptCacheCleaner, nsIObserver)
1460
1461
ChildProcessMessageManager* nsFrameMessageManager::sChildProcessManager = nullptr;
1462
ParentProcessMessageManager* nsFrameMessageManager::sParentProcessManager = nullptr;
1463
nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr;
1464
1465
class nsAsyncMessageToSameProcessChild : public nsSameProcessAsyncMessageBase,
1466
                                         public Runnable
1467
{
1468
public:
1469
  nsAsyncMessageToSameProcessChild(JS::RootingContext* aRootingCx,
1470
                                   JS::Handle<JSObject*> aCpows)
1471
    : nsSameProcessAsyncMessageBase(aRootingCx, aCpows)
1472
    , mozilla::Runnable("nsAsyncMessageToSameProcessChild")
1473
0
  { }
1474
  NS_IMETHOD Run() override
1475
0
  {
1476
0
    nsFrameMessageManager* ppm = nsFrameMessageManager::GetChildProcessManager();
1477
0
    ReceiveMessage(ppm, nullptr, ppm);
1478
0
    return NS_OK;
1479
0
  }
1480
};
1481
1482
1483
/**
1484
 * Send messages to an imaginary child process in a single-process scenario.
1485
 */
1486
class SameParentProcessMessageManagerCallback : public MessageManagerCallback
1487
{
1488
public:
1489
  SameParentProcessMessageManagerCallback()
1490
0
  {
1491
0
    MOZ_COUNT_CTOR(SameParentProcessMessageManagerCallback);
1492
0
  }
1493
  ~SameParentProcessMessageManagerCallback() override
1494
0
  {
1495
0
    MOZ_COUNT_DTOR(SameParentProcessMessageManagerCallback);
1496
0
  }
1497
1498
  bool DoLoadMessageManagerScript(const nsAString& aURL,
1499
                                  bool aRunInGlobalScope) override
1500
0
  {
1501
0
    auto* global = ContentProcessMessageManager::Get();
1502
0
    MOZ_ASSERT(!aRunInGlobalScope);
1503
0
    global->LoadScript(aURL);
1504
0
    return true;
1505
0
  }
1506
1507
  nsresult DoSendAsyncMessage(JSContext* aCx,
1508
                              const nsAString& aMessage,
1509
                              StructuredCloneData& aData,
1510
                              JS::Handle<JSObject *> aCpows,
1511
                              nsIPrincipal* aPrincipal) override
1512
0
  {
1513
0
    JS::RootingContext* rcx = JS::RootingContext::get(aCx);
1514
0
    RefPtr<nsAsyncMessageToSameProcessChild> ev =
1515
0
      new nsAsyncMessageToSameProcessChild(rcx, aCpows);
1516
0
1517
0
    nsresult rv = ev->Init(aMessage, aData, aPrincipal);
1518
0
    if (NS_FAILED(rv)) {
1519
0
      return rv;
1520
0
    }
1521
0
    rv = NS_DispatchToCurrentThread(ev);
1522
0
    if (NS_FAILED(rv)) {
1523
0
      return rv;
1524
0
    }
1525
0
    return NS_OK;
1526
0
  }
1527
};
1528
1529
1530
/**
1531
 * Send messages to the parent process.
1532
 */
1533
class ChildProcessMessageManagerCallback : public MessageManagerCallback
1534
{
1535
public:
1536
  ChildProcessMessageManagerCallback()
1537
0
  {
1538
0
    MOZ_COUNT_CTOR(ChildProcessMessageManagerCallback);
1539
0
  }
1540
  ~ChildProcessMessageManagerCallback() override
1541
0
  {
1542
0
    MOZ_COUNT_DTOR(ChildProcessMessageManagerCallback);
1543
0
  }
1544
1545
  bool DoSendBlockingMessage(JSContext* aCx,
1546
                             const nsAString& aMessage,
1547
                             StructuredCloneData& aData,
1548
                             JS::Handle<JSObject *> aCpows,
1549
                             nsIPrincipal* aPrincipal,
1550
                             nsTArray<StructuredCloneData>* aRetVal,
1551
                             bool aIsSync) override
1552
0
  {
1553
0
    mozilla::dom::ContentChild* cc =
1554
0
      mozilla::dom::ContentChild::GetSingleton();
1555
0
    if (!cc) {
1556
0
      return true;
1557
0
    }
1558
0
    ClonedMessageData data;
1559
0
    if (!BuildClonedMessageDataForChild(cc, aData, data)) {
1560
0
      return false;
1561
0
    }
1562
0
    InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
1563
0
    if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
1564
0
      return false;
1565
0
    }
1566
0
    if (aIsSync) {
1567
0
      return cc->SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
1568
0
                                 IPC::Principal(aPrincipal), aRetVal);
1569
0
    }
1570
0
    return cc->SendRpcMessage(PromiseFlatString(aMessage), data, cpows,
1571
0
                              IPC::Principal(aPrincipal), aRetVal);
1572
0
  }
1573
1574
  nsresult DoSendAsyncMessage(JSContext* aCx,
1575
                              const nsAString& aMessage,
1576
                              StructuredCloneData& aData,
1577
                              JS::Handle<JSObject *> aCpows,
1578
                              nsIPrincipal* aPrincipal) override
1579
0
  {
1580
0
    mozilla::dom::ContentChild* cc =
1581
0
      mozilla::dom::ContentChild::GetSingleton();
1582
0
    if (!cc) {
1583
0
      return NS_OK;
1584
0
    }
1585
0
    ClonedMessageData data;
1586
0
    if (!BuildClonedMessageDataForChild(cc, aData, data)) {
1587
0
      return NS_ERROR_DOM_DATA_CLONE_ERR;
1588
0
    }
1589
0
    InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
1590
0
    if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
1591
0
      return NS_ERROR_UNEXPECTED;
1592
0
    }
1593
0
    if (!cc->SendAsyncMessage(PromiseFlatString(aMessage), cpows,
1594
0
                              IPC::Principal(aPrincipal), data)) {
1595
0
      return NS_ERROR_UNEXPECTED;
1596
0
    }
1597
0
1598
0
    return NS_OK;
1599
0
  }
1600
};
1601
1602
1603
class nsAsyncMessageToSameProcessParent : public nsSameProcessAsyncMessageBase,
1604
                                          public SameProcessMessageQueue::Runnable
1605
{
1606
public:
1607
  nsAsyncMessageToSameProcessParent(JS::RootingContext* aRootingCx,
1608
                                    JS::Handle<JSObject*> aCpows)
1609
    : nsSameProcessAsyncMessageBase(aRootingCx, aCpows)
1610
0
  { }
1611
  nsresult HandleMessage() override
1612
0
  {
1613
0
    nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager;
1614
0
    ReceiveMessage(ppm, nullptr, ppm);
1615
0
    return NS_OK;
1616
0
  }
1617
};
1618
1619
/**
1620
 * Send messages to the imaginary parent process in a single-process scenario.
1621
 */
1622
class SameChildProcessMessageManagerCallback : public MessageManagerCallback
1623
{
1624
public:
1625
  SameChildProcessMessageManagerCallback()
1626
0
  {
1627
0
    MOZ_COUNT_CTOR(SameChildProcessMessageManagerCallback);
1628
0
  }
1629
  ~SameChildProcessMessageManagerCallback() override
1630
0
  {
1631
0
    MOZ_COUNT_DTOR(SameChildProcessMessageManagerCallback);
1632
0
  }
1633
1634
  bool DoSendBlockingMessage(JSContext* aCx,
1635
                             const nsAString& aMessage,
1636
                             StructuredCloneData& aData,
1637
                             JS::Handle<JSObject *> aCpows,
1638
                             nsIPrincipal* aPrincipal,
1639
                             nsTArray<StructuredCloneData>* aRetVal,
1640
                             bool aIsSync) override
1641
0
  {
1642
0
    SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
1643
0
    queue->Flush();
1644
0
1645
0
    if (nsFrameMessageManager::sSameProcessParentManager) {
1646
0
      SameProcessCpowHolder cpows(JS::RootingContext::get(aCx), aCpows);
1647
0
      RefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
1648
0
      ppm->ReceiveMessage(ppm, nullptr, aMessage, true, &aData, &cpows, aPrincipal,
1649
0
                          aRetVal, IgnoreErrors());
1650
0
    }
1651
0
    return true;
1652
0
  }
1653
1654
  nsresult DoSendAsyncMessage(JSContext* aCx,
1655
                              const nsAString& aMessage,
1656
                              StructuredCloneData& aData,
1657
                              JS::Handle<JSObject *> aCpows,
1658
                              nsIPrincipal* aPrincipal) override
1659
0
  {
1660
0
    SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
1661
0
    JS::RootingContext* rcx = JS::RootingContext::get(aCx);
1662
0
    RefPtr<nsAsyncMessageToSameProcessParent> ev =
1663
0
      new nsAsyncMessageToSameProcessParent(rcx, aCpows);
1664
0
    nsresult rv = ev->Init(aMessage, aData, aPrincipal);
1665
0
1666
0
    if (NS_FAILED(rv)) {
1667
0
      return rv;
1668
0
    }
1669
0
    queue->Push(ev);
1670
0
    return NS_OK;
1671
0
  }
1672
1673
};
1674
1675
1676
// This creates the global parent process message manager.
1677
nsresult
1678
NS_NewParentProcessMessageManager(nsISupports** aResult)
1679
0
{
1680
0
  NS_ASSERTION(!nsFrameMessageManager::sParentProcessManager,
1681
0
               "Re-creating sParentProcessManager");
1682
0
  RefPtr<ParentProcessMessageManager> mm = new ParentProcessMessageManager();
1683
0
  nsFrameMessageManager::sParentProcessManager = mm;
1684
0
  nsFrameMessageManager::NewProcessMessageManager(false); // Create same process message manager.
1685
0
  mm.forget(aResult);
1686
0
  return NS_OK;
1687
0
}
1688
1689
1690
ProcessMessageManager*
1691
nsFrameMessageManager::NewProcessMessageManager(bool aIsRemote)
1692
0
{
1693
0
  if (!nsFrameMessageManager::sParentProcessManager) {
1694
0
     nsCOMPtr<nsISupports> dummy =
1695
0
       do_GetService("@mozilla.org/parentprocessmessagemanager;1");
1696
0
  }
1697
0
1698
0
  MOZ_ASSERT(nsFrameMessageManager::sParentProcessManager,
1699
0
             "parent process manager not created");
1700
0
  ProcessMessageManager* mm;
1701
0
  if (aIsRemote) {
1702
0
    // Callback is set in ContentParent::InitInternal so that the process has
1703
0
    // already started when we send pending scripts.
1704
0
    mm = new ProcessMessageManager(nullptr,
1705
0
                                   nsFrameMessageManager::sParentProcessManager);
1706
0
  } else {
1707
0
    mm = new ProcessMessageManager(new SameParentProcessMessageManagerCallback(),
1708
0
                                   nsFrameMessageManager::sParentProcessManager,
1709
0
                                   MessageManagerFlags::MM_OWNSCALLBACK);
1710
0
    sSameProcessParentManager = mm;
1711
0
  }
1712
0
  return mm;
1713
0
}
1714
1715
nsresult
1716
NS_NewChildProcessMessageManager(nsISupports** aResult)
1717
0
{
1718
0
  NS_ASSERTION(!nsFrameMessageManager::GetChildProcessManager(),
1719
0
               "Re-creating sChildProcessManager");
1720
0
1721
0
  MessageManagerCallback* cb;
1722
0
  if (XRE_IsParentProcess()) {
1723
0
    cb = new SameChildProcessMessageManagerCallback();
1724
0
  } else {
1725
0
    cb = new ChildProcessMessageManagerCallback();
1726
0
    RegisterStrongMemoryReporter(new MessageManagerReporter());
1727
0
  }
1728
0
  auto* mm = new ChildProcessMessageManager(cb);
1729
0
  nsFrameMessageManager::SetChildProcessManager(mm);
1730
0
  auto global = MakeRefPtr<ContentProcessMessageManager>(mm);
1731
0
  NS_ENSURE_TRUE(global->Init(), NS_ERROR_UNEXPECTED);
1732
0
  return CallQueryInterface(global, aResult);
1733
0
}
1734
1735
void
1736
nsFrameMessageManager::MarkForCC()
1737
0
{
1738
0
  for (auto iter = mListeners.Iter(); !iter.Done(); iter.Next()) {
1739
0
    nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners = iter.UserData();
1740
0
    uint32_t count = listeners->Length();
1741
0
    for (uint32_t i = 0; i < count; i++) {
1742
0
      MessageListener* strongListener = listeners->ElementAt(i).mStrongListener;
1743
0
      if (strongListener) {
1744
0
        strongListener->MarkForCC();
1745
0
      }
1746
0
    }
1747
0
  }
1748
0
1749
0
  if (mRefCnt.IsPurple()) {
1750
0
    mRefCnt.RemovePurple();
1751
0
  }
1752
0
}
1753
1754
nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JS::RootingContext* aRootingCx,
1755
                                                             JS::Handle<JSObject*> aCpows)
1756
  : mCpows(aRootingCx, aCpows)
1757
#ifdef DEBUG
1758
  , mCalledInit(false)
1759
#endif
1760
0
{ }
1761
1762
1763
nsresult
1764
nsSameProcessAsyncMessageBase::Init(const nsAString& aMessage,
1765
                                    StructuredCloneData& aData,
1766
                                    nsIPrincipal* aPrincipal)
1767
0
{
1768
0
  if (!mData.Copy(aData)) {
1769
0
    Telemetry::Accumulate(Telemetry::IPC_SAME_PROCESS_MESSAGE_COPY_OOM_KB, aData.DataLength());
1770
0
    return NS_ERROR_OUT_OF_MEMORY;
1771
0
  }
1772
0
1773
0
  mMessage = aMessage;
1774
0
  mPrincipal = aPrincipal;
1775
#ifdef DEBUG
1776
  mCalledInit = true;
1777
#endif
1778
1779
0
  return NS_OK;
1780
0
}
1781
1782
void
1783
nsSameProcessAsyncMessageBase::ReceiveMessage(nsISupports* aTarget,
1784
                                              nsFrameLoader* aTargetFrameLoader,
1785
                                              nsFrameMessageManager* aManager)
1786
0
{
1787
0
  // Make sure that we have called Init() and it has succeeded.
1788
0
  MOZ_ASSERT(mCalledInit);
1789
0
  if (aManager) {
1790
0
    SameProcessCpowHolder cpows(RootingCx(), mCpows);
1791
0
1792
0
    RefPtr<nsFrameMessageManager> mm = aManager;
1793
0
    mm->ReceiveMessage(aTarget, aTargetFrameLoader, mMessage, false, &mData,
1794
0
                       &cpows, mPrincipal, nullptr, IgnoreErrors());
1795
0
  }
1796
0
}