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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "BackgroundChild.h"
8 #include "BackgroundParent.h"
9
10 #include "BackgroundChildImpl.h"
11 #include "BackgroundParentImpl.h"
12 #include "base/process_util.h"
13 #include "base/task.h"
14 #include "FileDescriptor.h"
15 #include "GeckoProfiler.h"
16 #include "InputStreamUtils.h"
17 #include "mozilla/Assertions.h"
18 #include "mozilla/Atomics.h"
19 #include "mozilla/ClearOnShutdown.h"
20 #include "mozilla/DebugOnly.h"
21 #include "mozilla/MozPromise.h"
22 #include "mozilla/Services.h"
23 #include "mozilla/SpinEventLoopUntil.h"
24 #include "mozilla/StaticPtr.h"
25 #include "mozilla/Unused.h"
26 #include "mozilla/dom/ContentChild.h"
27 #include "mozilla/dom/ContentParent.h"
28 #include "mozilla/dom/File.h"
29 #include "mozilla/dom/WorkerPrivate.h"
30 #include "mozilla/dom/WorkerRef.h"
31 #include "mozilla/ipc/Endpoint.h"
32 #include "mozilla/ipc/ProtocolTypes.h"
33 #include "mozilla/net/SocketProcessChild.h"
34 #include "mozilla/net/SocketProcessBridgeChild.h"
35 #include "nsCOMPtr.h"
36 #include "nsIEventTarget.h"
37 #include "nsIObserver.h"
38 #include "nsIObserverService.h"
39 #include "nsIRunnable.h"
40 #include "nsISupportsImpl.h"
41 #include "nsIThread.h"
42 #include "nsITimer.h"
43 #include "nsTArray.h"
44 #include "nsThreadUtils.h"
45 #include "nsTraceRefcnt.h"
46 #include "nsXULAppAPI.h"
47 #include "nsXPCOMPrivate.h"
48 #include "prthread.h"
49
50 #include <functional>
51
52 #ifdef RELEASE_OR_BETA
53 # define THREADSAFETY_ASSERT MOZ_ASSERT
54 #else
55 # define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
56 #endif
57
58 #define CRASH_IN_CHILD_PROCESS(_msg) \
59 do { \
60 if (XRE_IsParentProcess()) { \
61 MOZ_ASSERT(false, _msg); \
62 } else { \
63 MOZ_CRASH(_msg); \
64 } \
65 } while (0)
66
67 using namespace mozilla;
68 using namespace mozilla::dom;
69 using namespace mozilla::ipc;
70 using namespace mozilla::net;
71
72 namespace {
73
74 class ChildImpl;
75
76 // -----------------------------------------------------------------------------
77 // Utility Functions
78 // -----------------------------------------------------------------------------
79
AssertIsInMainProcess()80 void AssertIsInMainProcess() { MOZ_ASSERT(XRE_IsParentProcess()); }
81
AssertIsInMainOrSocketProcess()82 void AssertIsInMainOrSocketProcess() {
83 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
84 }
85
AssertIsOnMainThread()86 void AssertIsOnMainThread() { THREADSAFETY_ASSERT(NS_IsMainThread()); }
87
AssertIsNotOnMainThread()88 void AssertIsNotOnMainThread() { THREADSAFETY_ASSERT(!NS_IsMainThread()); }
89
90 // -----------------------------------------------------------------------------
91 // ParentImpl Declaration
92 // -----------------------------------------------------------------------------
93
94 class ParentImpl final : public BackgroundParentImpl {
95 friend class mozilla::ipc::BackgroundParent;
96
97 private:
98 class ShutdownObserver;
99 class CreateActorHelper;
100
101 struct MOZ_STACK_CLASS TimerCallbackClosure {
102 nsIThread* mThread;
103 nsTArray<ParentImpl*>* mLiveActors;
104
TimerCallbackClosure__anondf7260de0111::ParentImpl::TimerCallbackClosure105 TimerCallbackClosure(nsIThread* aThread, nsTArray<ParentImpl*>* aLiveActors)
106 : mThread(aThread), mLiveActors(aLiveActors) {
107 AssertIsInMainOrSocketProcess();
108 AssertIsOnMainThread();
109 MOZ_ASSERT(aThread);
110 MOZ_ASSERT(aLiveActors);
111 }
112 };
113
114 // The length of time we will wait at shutdown for all actors to clean
115 // themselves up before forcing them to be destroyed.
116 static const uint32_t kShutdownTimerDelayMS = 10000;
117
118 // This is only modified on the main thread. It is null if the thread does not
119 // exist or is shutting down.
120 static StaticRefPtr<nsIThread> sBackgroundThread;
121
122 // This is created and destroyed on the main thread but only modified on the
123 // background thread. It is specific to each instance of sBackgroundThread.
124 static nsTArray<ParentImpl*>* sLiveActorsForBackgroundThread;
125
126 // This is only modified on the main thread.
127 static StaticRefPtr<nsITimer> sShutdownTimer;
128
129 // This exists so that that [Assert]IsOnBackgroundThread() can continue to
130 // work during shutdown.
131 static Atomic<PRThread*> sBackgroundPRThread;
132
133 // This is only modified on the main thread. It maintains a count of live
134 // actors so that the background thread can be shut down when it is no longer
135 // needed.
136 static uint64_t sLiveActorCount;
137
138 // This is only modified on the main thread. It is true after the shutdown
139 // observer is registered and is never unset thereafter.
140 static bool sShutdownObserverRegistered;
141
142 // This is only modified on the main thread. It prevents us from trying to
143 // create the background thread after application shutdown has started.
144 static bool sShutdownHasStarted;
145
146 // Only touched on the main thread, null if this is a same-process actor.
147 RefPtr<ContentParent> mContent;
148
149 // Set when the actor is opened successfully and used to handle shutdown
150 // hangs. Only touched on the background thread.
151 nsTArray<ParentImpl*>* mLiveActorArray;
152
153 // Set at construction to indicate whether this parent actor corresponds to a
154 // child actor in another process or to a child actor from a different thread
155 // in the same process.
156 const bool mIsOtherProcessActor;
157
158 // Set after ActorDestroy has been called. Only touched on the background
159 // thread.
160 bool mActorDestroyed;
161
162 public:
163 static already_AddRefed<ChildImpl> CreateActorForSameProcess(
164 nsIEventTarget* aMainEventTarget);
165
IsOnBackgroundThread()166 static bool IsOnBackgroundThread() {
167 return PR_GetCurrentThread() == sBackgroundPRThread;
168 }
169
AssertIsOnBackgroundThread()170 static void AssertIsOnBackgroundThread() {
171 THREADSAFETY_ASSERT(IsOnBackgroundThread());
172 }
173
174 // `ParentImpl` instances are created and need to be deleted on the main
175 // thread, despite IPC controlling them on a background thread. Use
176 // `_WITH_DELETE_ON_MAIN_THREAD` to force destruction to occur on the desired
177 // thread.
178 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(ParentImpl,
179 override)
180
181 void Destroy();
182
183 private:
184 // Forwarded from BackgroundParent.
185 static bool IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
186
187 // Forwarded from BackgroundParent.
188 static already_AddRefed<ContentParent> GetContentParent(
189 PBackgroundParent* aBackgroundActor);
190
191 // Forwarded from BackgroundParent.
192 static intptr_t GetRawContentParentForComparison(
193 PBackgroundParent* aBackgroundActor);
194
195 // Forwarded from BackgroundParent.
196 static uint64_t GetChildID(PBackgroundParent* aBackgroundActor);
197
198 // Forwarded from BackgroundParent.
199 static bool GetLiveActorArray(PBackgroundParent* aBackgroundActor,
200 nsTArray<PBackgroundParent*>& aLiveActorArray);
201
202 // Forwarded from BackgroundParent.
203 static bool Alloc(ContentParent* aContent,
204 Endpoint<PBackgroundParent>&& aEndpoint);
205
206 static bool CreateBackgroundThread();
207
208 static void ShutdownBackgroundThread();
209
210 static void ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
211
212 // For same-process actors.
ParentImpl()213 ParentImpl()
214 : mLiveActorArray(nullptr),
215 mIsOtherProcessActor(false),
216 mActorDestroyed(false) {
217 AssertIsInMainProcess();
218 AssertIsOnMainThread();
219 }
220
221 // For other-process actors.
222 // NOTE: ParentImpl could be used in 3 cases below.
223 // 1. Between parent process and content process.
224 // 2. Between socket process and content process.
225 // 3. Between parent process and socket process.
226 // |mContent| should be not null for case 1. For case 2 and 3, it's null.
ParentImpl(ContentParent * aContent)227 explicit ParentImpl(ContentParent* aContent)
228 : mContent(aContent),
229 mLiveActorArray(nullptr),
230 mIsOtherProcessActor(true),
231 mActorDestroyed(false) {
232 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
233 AssertIsOnMainThread();
234 }
235
~ParentImpl()236 ~ParentImpl() {
237 AssertIsInMainOrSocketProcess();
238 AssertIsOnMainThread();
239 MOZ_ASSERT(!mContent);
240 }
241
242 void MainThreadActorDestroy();
243
SetLiveActorArray(nsTArray<ParentImpl * > * aLiveActorArray)244 void SetLiveActorArray(nsTArray<ParentImpl*>* aLiveActorArray) {
245 AssertIsInMainOrSocketProcess();
246 AssertIsOnBackgroundThread();
247 MOZ_ASSERT(aLiveActorArray);
248 MOZ_ASSERT(!aLiveActorArray->Contains(this));
249 MOZ_ASSERT(!mLiveActorArray);
250 MOZ_ASSERT(mIsOtherProcessActor);
251
252 mLiveActorArray = aLiveActorArray;
253 mLiveActorArray->AppendElement(this);
254 }
255
256 // These methods are only called by IPDL.
257 virtual void ActorDestroy(ActorDestroyReason aWhy) override;
258 };
259
260 // -----------------------------------------------------------------------------
261 // ChildImpl Declaration
262 // -----------------------------------------------------------------------------
263
264 class ChildImpl final : public BackgroundChildImpl {
265 friend class mozilla::ipc::BackgroundChild;
266 friend class mozilla::ipc::BackgroundChildImpl;
267
268 typedef base::ProcessId ProcessId;
269 typedef mozilla::ipc::Transport Transport;
270
271 class ShutdownObserver;
272
273 public:
274 class SendInitBackgroundRunnable;
275
276 struct ThreadLocalInfo {
ThreadLocalInfo__anondf7260de0111::ChildImpl::ThreadLocalInfo277 ThreadLocalInfo()
278 #ifdef DEBUG
279 : mClosed(false)
280 #endif
281 {
282 }
283
284 RefPtr<ChildImpl> mActor;
285 RefPtr<SendInitBackgroundRunnable> mSendInitBackgroundRunnable;
286 UniquePtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal;
287 #ifdef DEBUG
288 bool mClosed;
289 #endif
290 };
291
292 private:
293 // A thread-local index that is not valid.
294 static constexpr unsigned int kBadThreadLocalIndex =
295 static_cast<unsigned int>(-1);
296
297 // ThreadInfoWrapper encapsulates ThreadLocalInfo and ThreadLocalIndex and
298 // also provides some common functions for creating PBackground IPC actor.
299 class ThreadInfoWrapper final {
300 friend class ChildImpl;
301
302 public:
303 using ActorCreateFunc = void (*)(ThreadLocalInfo*, unsigned int,
304 nsIEventTarget*, ChildImpl**);
305
ThreadInfoWrapper(ActorCreateFunc aFunc)306 constexpr explicit ThreadInfoWrapper(ActorCreateFunc aFunc)
307 : mThreadLocalIndex(kBadThreadLocalIndex),
308 mMainThreadInfo(nullptr),
309 mCreateActorFunc(aFunc) {}
310
Startup()311 void Startup() {
312 MOZ_ASSERT(mThreadLocalIndex == kBadThreadLocalIndex,
313 "ThreadInfoWrapper::Startup() called more than once!");
314
315 PRStatus status =
316 PR_NewThreadPrivateIndex(&mThreadLocalIndex, ThreadLocalDestructor);
317 MOZ_RELEASE_ASSERT(status == PR_SUCCESS,
318 "PR_NewThreadPrivateIndex failed!");
319
320 MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex);
321 }
322
Shutdown()323 void Shutdown() {
324 if (sShutdownHasStarted) {
325 MOZ_ASSERT_IF(mThreadLocalIndex != kBadThreadLocalIndex,
326 !PR_GetThreadPrivate(mThreadLocalIndex));
327 return;
328 }
329
330 if (mThreadLocalIndex == kBadThreadLocalIndex) {
331 return;
332 }
333
334 ThreadLocalInfo* threadLocalInfo;
335 #ifdef DEBUG
336 threadLocalInfo =
337 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
338 MOZ_ASSERT(!threadLocalInfo);
339 #endif
340
341 threadLocalInfo = mMainThreadInfo;
342 if (threadLocalInfo) {
343 #ifdef DEBUG
344 MOZ_ASSERT(!threadLocalInfo->mClosed);
345 threadLocalInfo->mClosed = true;
346 #endif
347
348 ThreadLocalDestructor(threadLocalInfo);
349 mMainThreadInfo = nullptr;
350 }
351 }
352
CloseForCurrentThread()353 void CloseForCurrentThread() {
354 MOZ_ASSERT(!NS_IsMainThread());
355
356 if (mThreadLocalIndex == kBadThreadLocalIndex) {
357 return;
358 }
359
360 auto threadLocalInfo =
361 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
362
363 if (!threadLocalInfo) {
364 return;
365 }
366
367 #ifdef DEBUG
368 MOZ_ASSERT(!threadLocalInfo->mClosed);
369 threadLocalInfo->mClosed = true;
370 #endif
371
372 // Clearing the thread local will synchronously close the actor.
373 DebugOnly<PRStatus> status =
374 PR_SetThreadPrivate(mThreadLocalIndex, nullptr);
375 MOZ_ASSERT(status == PR_SUCCESS);
376 }
377
GetOrCreateForCurrentThread(nsIEventTarget * aMainEventTarget)378 PBackgroundChild* GetOrCreateForCurrentThread(
379 nsIEventTarget* aMainEventTarget) {
380 MOZ_ASSERT_IF(NS_IsMainThread(), !aMainEventTarget);
381
382 MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex,
383 "BackgroundChild::Startup() was never called!");
384
385 if (NS_IsMainThread() && ChildImpl::sShutdownHasStarted) {
386 return nullptr;
387 }
388
389 auto threadLocalInfo = NS_IsMainThread()
390 ? mMainThreadInfo
391 : static_cast<ThreadLocalInfo*>(
392 PR_GetThreadPrivate(mThreadLocalIndex));
393
394 if (!threadLocalInfo) {
395 auto newInfo = MakeUnique<ThreadLocalInfo>();
396
397 if (NS_IsMainThread()) {
398 mMainThreadInfo = newInfo.get();
399 } else {
400 if (PR_SetThreadPrivate(mThreadLocalIndex, newInfo.get()) !=
401 PR_SUCCESS) {
402 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
403 return nullptr;
404 }
405 }
406
407 threadLocalInfo = newInfo.release();
408 }
409
410 PBackgroundChild* bgChild =
411 GetFromThreadInfo(aMainEventTarget, threadLocalInfo);
412 if (bgChild) {
413 return bgChild;
414 }
415
416 RefPtr<ChildImpl> actor;
417 mCreateActorFunc(threadLocalInfo, mThreadLocalIndex, aMainEventTarget,
418 getter_AddRefs(actor));
419 return actor;
420 }
421
422 private:
423 // This is only modified on the main thread. It is the thread-local index
424 // that we use to store the BackgroundChild for each thread.
425 unsigned int mThreadLocalIndex;
426
427 // On the main thread, we store TLS in this global instead of in
428 // mThreadLocalIndex. That way, cooperative main threads all share the same
429 // thread info.
430 ThreadLocalInfo* mMainThreadInfo;
431 ActorCreateFunc mCreateActorFunc;
432 };
433
434 // For PBackground between parent and content process.
435 static ThreadInfoWrapper sParentAndContentProcessThreadInfo;
436
437 // For PBackground between socket and content process.
438 static ThreadInfoWrapper sSocketAndContentProcessThreadInfo;
439
440 // For PBackground between socket and parent process.
441 static ThreadInfoWrapper sSocketAndParentProcessThreadInfo;
442
443 // This is only modified on the main thread. It prevents us from trying to
444 // create the background thread after application shutdown has started.
445 static bool sShutdownHasStarted;
446
447 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
448 nsISerialEventTarget* mOwningEventTarget;
449 #endif
450
451 #ifdef DEBUG
452 bool mActorWasAlive;
453 bool mActorDestroyed;
454 #endif
455
456 public:
457 static void Shutdown();
458
AssertIsOnOwningThread()459 void AssertIsOnOwningThread() {
460 THREADSAFETY_ASSERT(mOwningEventTarget);
461
462 #ifdef RELEASE_OR_BETA
463 DebugOnly<bool> current;
464 #else
465 bool current;
466 #endif
467 THREADSAFETY_ASSERT(
468 NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(¤t)));
469 THREADSAFETY_ASSERT(current);
470 }
471
AssertActorDestroyed()472 void AssertActorDestroyed() {
473 MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
474 }
475
ChildImpl()476 explicit ChildImpl()
477 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
478 : mOwningEventTarget(GetCurrentSerialEventTarget())
479 #endif
480 #ifdef DEBUG
481 ,
482 mActorWasAlive(false),
483 mActorDestroyed(false)
484 #endif
485 {
486 AssertIsOnOwningThread();
487 }
488
SetActorAlive()489 void SetActorAlive() {
490 AssertIsOnOwningThread();
491 MOZ_ASSERT(!mActorWasAlive);
492 MOZ_ASSERT(!mActorDestroyed);
493
494 #ifdef DEBUG
495 mActorWasAlive = true;
496 #endif
497 }
498
499 NS_INLINE_DECL_REFCOUNTING(ChildImpl, override)
500
501 private:
502 // Forwarded from BackgroundChild.
503 static void Startup();
504
505 // Forwarded from BackgroundChild.
506 static PBackgroundChild* GetForCurrentThread();
507
508 // Helper function for getting PBackgroundChild from thread info.
509 static PBackgroundChild* GetFromThreadInfo(nsIEventTarget* aMainEventTarget,
510 ThreadLocalInfo* aThreadLocalInfo);
511
512 // Forwarded from BackgroundChild.
513 static PBackgroundChild* GetOrCreateForCurrentThread(
514 nsIEventTarget* aMainEventTarget);
515
516 // Forwarded from BackgroundChild.
517 static PBackgroundChild* GetOrCreateSocketActorForCurrentThread(
518 nsIEventTarget* aMainEventTarget);
519
520 // Forwarded from BackgroundChild.
521 static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread(
522 nsIEventTarget* aMainEventTarget);
523
524 static void CloseForCurrentThread();
525
526 // Forwarded from BackgroundChildImpl.
527 static BackgroundChildImpl::ThreadLocal* GetThreadLocalForCurrentThread();
528
529 static void ThreadLocalDestructor(void* aThreadLocal);
530
531 // This class is reference counted.
~ChildImpl()532 ~ChildImpl() { MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed); }
533
534 // Only called by IPDL.
535 virtual void ActorDestroy(ActorDestroyReason aWhy) override;
536 };
537
538 // -----------------------------------------------------------------------------
539 // ParentImpl Helper Declarations
540 // -----------------------------------------------------------------------------
541
542 class ParentImpl::ShutdownObserver final : public nsIObserver {
543 public:
ShutdownObserver()544 ShutdownObserver() { AssertIsOnMainThread(); }
545
546 NS_DECL_ISUPPORTS
547 NS_DECL_NSIOBSERVER
548
549 private:
~ShutdownObserver()550 ~ShutdownObserver() { AssertIsOnMainThread(); }
551 };
552
553 class ParentImpl::CreateActorHelper final : public Runnable {
554 mozilla::Monitor mMonitor;
555 RefPtr<ParentImpl> mParentActor;
556 nsCOMPtr<nsIThread> mThread;
557 nsresult mMainThreadResultCode;
558 bool mWaiting;
559
560 public:
CreateActorHelper()561 explicit CreateActorHelper()
562 : Runnable("Background::ParentImpl::CreateActorHelper"),
563 mMonitor("CreateActorHelper::mMonitor"),
564 mMainThreadResultCode(NS_OK),
565 mWaiting(true) {
566 AssertIsInMainOrSocketProcess();
567 AssertIsNotOnMainThread();
568 }
569
570 nsresult BlockAndGetResults(nsIEventTarget* aMainEventTarget,
571 RefPtr<ParentImpl>& aParentActor,
572 nsCOMPtr<nsIThread>& aThread);
573
574 private:
~CreateActorHelper()575 ~CreateActorHelper() { AssertIsInMainOrSocketProcess(); }
576
577 nsresult RunOnMainThread();
578
579 NS_DECL_NSIRUNNABLE
580 };
581
582 // -----------------------------------------------------------------------------
583 // ChildImpl Helper Declarations
584 // -----------------------------------------------------------------------------
585
586 class ChildImpl::ShutdownObserver final : public nsIObserver {
587 public:
ShutdownObserver()588 ShutdownObserver() { AssertIsOnMainThread(); }
589
590 NS_DECL_ISUPPORTS
591 NS_DECL_NSIOBSERVER
592
593 private:
~ShutdownObserver()594 ~ShutdownObserver() { AssertIsOnMainThread(); }
595 };
596
597 class ChildImpl::SendInitBackgroundRunnable final : public DiscardableRunnable {
598 nsCOMPtr<nsISerialEventTarget> mOwningEventTarget;
599 RefPtr<StrongWorkerRef> mWorkerRef;
600 Endpoint<PBackgroundParent> mParent;
601 mozilla::Mutex mMutex;
602 bool mSentInitBackground;
603 std::function<void(Endpoint<PBackgroundParent>&& aParent)> mSendInitfunc;
604 unsigned int mThreadLocalIndex;
605
606 public:
607 static already_AddRefed<SendInitBackgroundRunnable> Create(
608 Endpoint<PBackgroundParent>&& aParent,
609 std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
610 unsigned int aThreadLocalIndex);
611
ClearEventTarget()612 void ClearEventTarget() {
613 mWorkerRef = nullptr;
614
615 mozilla::MutexAutoLock lock(mMutex);
616 mOwningEventTarget = nullptr;
617 }
618
619 private:
SendInitBackgroundRunnable(Endpoint<PBackgroundParent> && aParent,std::function<void (Endpoint<PBackgroundParent> && aParent)> && aFunc,unsigned int aThreadLocalIndex)620 explicit SendInitBackgroundRunnable(
621 Endpoint<PBackgroundParent>&& aParent,
622 std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
623 unsigned int aThreadLocalIndex)
624 : DiscardableRunnable(
625 "Background::ChildImpl::SendInitBackgroundRunnable"),
626 mOwningEventTarget(GetCurrentSerialEventTarget()),
627 mParent(std::move(aParent)),
628 mMutex("SendInitBackgroundRunnable::mMutex"),
629 mSentInitBackground(false),
630 mSendInitfunc(std::move(aFunc)),
631 mThreadLocalIndex(aThreadLocalIndex) {}
632
633 ~SendInitBackgroundRunnable() = default;
634
635 NS_DECL_NSIRUNNABLE
636 };
637
638 } // namespace
639
640 namespace mozilla {
641 namespace ipc {
642
IsOnBackgroundThread()643 bool IsOnBackgroundThread() { return ParentImpl::IsOnBackgroundThread(); }
644
645 #ifdef DEBUG
646
AssertIsOnBackgroundThread()647 void AssertIsOnBackgroundThread() { ParentImpl::AssertIsOnBackgroundThread(); }
648
649 #endif // DEBUG
650
651 } // namespace ipc
652 } // namespace mozilla
653
654 // -----------------------------------------------------------------------------
655 // BackgroundParent Public Methods
656 // -----------------------------------------------------------------------------
657
658 // static
IsOtherProcessActor(PBackgroundParent * aBackgroundActor)659 bool BackgroundParent::IsOtherProcessActor(
660 PBackgroundParent* aBackgroundActor) {
661 return ParentImpl::IsOtherProcessActor(aBackgroundActor);
662 }
663
664 // static
GetContentParent(PBackgroundParent * aBackgroundActor)665 already_AddRefed<ContentParent> BackgroundParent::GetContentParent(
666 PBackgroundParent* aBackgroundActor) {
667 return ParentImpl::GetContentParent(aBackgroundActor);
668 }
669
670 // static
GetRawContentParentForComparison(PBackgroundParent * aBackgroundActor)671 intptr_t BackgroundParent::GetRawContentParentForComparison(
672 PBackgroundParent* aBackgroundActor) {
673 return ParentImpl::GetRawContentParentForComparison(aBackgroundActor);
674 }
675
676 // static
GetChildID(PBackgroundParent * aBackgroundActor)677 uint64_t BackgroundParent::GetChildID(PBackgroundParent* aBackgroundActor) {
678 return ParentImpl::GetChildID(aBackgroundActor);
679 }
680
681 // static
GetLiveActorArray(PBackgroundParent * aBackgroundActor,nsTArray<PBackgroundParent * > & aLiveActorArray)682 bool BackgroundParent::GetLiveActorArray(
683 PBackgroundParent* aBackgroundActor,
684 nsTArray<PBackgroundParent*>& aLiveActorArray) {
685 return ParentImpl::GetLiveActorArray(aBackgroundActor, aLiveActorArray);
686 }
687
688 // static
Alloc(ContentParent * aContent,Endpoint<PBackgroundParent> && aEndpoint)689 bool BackgroundParent::Alloc(ContentParent* aContent,
690 Endpoint<PBackgroundParent>&& aEndpoint) {
691 return ParentImpl::Alloc(aContent, std::move(aEndpoint));
692 }
693
694 // -----------------------------------------------------------------------------
695 // BackgroundChild Public Methods
696 // -----------------------------------------------------------------------------
697
698 // static
Startup()699 void BackgroundChild::Startup() { ChildImpl::Startup(); }
700
701 // static
GetForCurrentThread()702 PBackgroundChild* BackgroundChild::GetForCurrentThread() {
703 return ChildImpl::GetForCurrentThread();
704 }
705
706 // static
GetOrCreateForCurrentThread(nsIEventTarget * aMainEventTarget)707 PBackgroundChild* BackgroundChild::GetOrCreateForCurrentThread(
708 nsIEventTarget* aMainEventTarget) {
709 return ChildImpl::GetOrCreateForCurrentThread(aMainEventTarget);
710 }
711
712 // static
GetOrCreateSocketActorForCurrentThread(nsIEventTarget * aMainEventTarget)713 PBackgroundChild* BackgroundChild::GetOrCreateSocketActorForCurrentThread(
714 nsIEventTarget* aMainEventTarget) {
715 return ChildImpl::GetOrCreateSocketActorForCurrentThread(aMainEventTarget);
716 }
717
718 // static
719 PBackgroundChild*
GetOrCreateForSocketParentBridgeForCurrentThread(nsIEventTarget * aMainEventTarget)720 BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread(
721 nsIEventTarget* aMainEventTarget) {
722 return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
723 aMainEventTarget);
724 }
725
726 // static
CloseForCurrentThread()727 void BackgroundChild::CloseForCurrentThread() {
728 ChildImpl::CloseForCurrentThread();
729 }
730
731 // -----------------------------------------------------------------------------
732 // BackgroundChildImpl Public Methods
733 // -----------------------------------------------------------------------------
734
735 // static
736 BackgroundChildImpl::ThreadLocal*
GetThreadLocalForCurrentThread()737 BackgroundChildImpl::GetThreadLocalForCurrentThread() {
738 return ChildImpl::GetThreadLocalForCurrentThread();
739 }
740
741 // -----------------------------------------------------------------------------
742 // ParentImpl Static Members
743 // -----------------------------------------------------------------------------
744
745 StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread;
746
747 nsTArray<ParentImpl*>* ParentImpl::sLiveActorsForBackgroundThread;
748
749 StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer;
750
751 Atomic<PRThread*> ParentImpl::sBackgroundPRThread;
752
753 uint64_t ParentImpl::sLiveActorCount = 0;
754
755 bool ParentImpl::sShutdownObserverRegistered = false;
756
757 bool ParentImpl::sShutdownHasStarted = false;
758
759 // -----------------------------------------------------------------------------
760 // ChildImpl Static Members
761 // -----------------------------------------------------------------------------
762
ParentContentActorCreateFunc(ChildImpl::ThreadLocalInfo * aThreadLocalInfo,unsigned int aThreadLocalIndex,nsIEventTarget * aMainEventTarget,ChildImpl ** aOutput)763 static void ParentContentActorCreateFunc(
764 ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
765 unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
766 ChildImpl** aOutput) {
767 if (XRE_IsParentProcess()) {
768 RefPtr<ChildImpl> strongActor =
769 ParentImpl::CreateActorForSameProcess(aMainEventTarget);
770 if (NS_WARN_IF(!strongActor)) {
771 return;
772 }
773
774 aThreadLocalInfo->mActor = strongActor;
775 strongActor.forget(aOutput);
776 return;
777 }
778
779 RefPtr<ContentChild> content = ContentChild::GetSingleton();
780 MOZ_ASSERT(content);
781
782 if (content->IsShuttingDown()) {
783 // The transport for ContentChild is shut down and can't be used to open
784 // PBackground.
785 return;
786 }
787
788 Endpoint<PBackgroundParent> parent;
789 Endpoint<PBackgroundChild> child;
790 nsresult rv;
791 rv = PBackground::CreateEndpoints(content->OtherPid(),
792 base::GetCurrentProcId(), &parent, &child);
793 if (NS_FAILED(rv)) {
794 NS_WARNING("Failed to create top level actor!");
795 return;
796 }
797
798 RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
799 if (!NS_IsMainThread()) {
800 runnable = ChildImpl::SendInitBackgroundRunnable::Create(
801 std::move(parent),
802 [](Endpoint<PBackgroundParent>&& aParent) {
803 RefPtr<ContentChild> content = ContentChild::GetSingleton();
804 MOZ_ASSERT(content);
805
806 if (!content->SendInitBackground(std::move(aParent))) {
807 NS_WARNING("Failed to create top level actor!");
808 }
809 },
810 aThreadLocalIndex);
811 if (!runnable) {
812 return;
813 }
814 }
815
816 RefPtr<ChildImpl> strongActor = new ChildImpl();
817
818 if (!child.Bind(strongActor)) {
819 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
820
821 return;
822 }
823
824 strongActor->SetActorAlive();
825
826 if (NS_IsMainThread()) {
827 if (!content->SendInitBackground(std::move(parent))) {
828 NS_WARNING("Failed to create top level actor!");
829 return;
830 }
831 } else {
832 if (aMainEventTarget) {
833 MOZ_ALWAYS_SUCCEEDS(
834 aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
835 } else {
836 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
837 }
838
839 aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
840 }
841
842 aThreadLocalInfo->mActor = strongActor;
843 strongActor.forget(aOutput);
844 }
845
846 ChildImpl::ThreadInfoWrapper ChildImpl::sParentAndContentProcessThreadInfo(
847 ParentContentActorCreateFunc);
848
SocketContentActorCreateFunc(ChildImpl::ThreadLocalInfo * aThreadLocalInfo,unsigned int aThreadLocalIndex,nsIEventTarget * aMainEventTarget,ChildImpl ** aOutput)849 static void SocketContentActorCreateFunc(
850 ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
851 unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
852 ChildImpl** aOutput) {
853 RefPtr<SocketProcessBridgeChild> bridgeChild =
854 SocketProcessBridgeChild::GetSingleton();
855
856 if (!bridgeChild || bridgeChild->IsShuttingDown()) {
857 // The transport for SocketProcessBridgeChild is shut down
858 // and can't be used to open PBackground.
859 return;
860 }
861
862 Endpoint<PBackgroundParent> parent;
863 Endpoint<PBackgroundChild> child;
864 nsresult rv;
865 rv = PBackground::CreateEndpoints(bridgeChild->SocketProcessPid(),
866 base::GetCurrentProcId(), &parent, &child);
867 if (NS_FAILED(rv)) {
868 NS_WARNING("Failed to create top level actor!");
869 return;
870 }
871
872 RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
873 if (!NS_IsMainThread()) {
874 runnable = ChildImpl::SendInitBackgroundRunnable::Create(
875 std::move(parent),
876 [](Endpoint<PBackgroundParent>&& aParent) {
877 RefPtr<SocketProcessBridgeChild> bridgeChild =
878 SocketProcessBridgeChild::GetSingleton();
879
880 if (!bridgeChild->SendInitBackground(std::move(aParent))) {
881 NS_WARNING("Failed to create top level actor!");
882 }
883 },
884 aThreadLocalIndex);
885 if (!runnable) {
886 return;
887 }
888 }
889
890 RefPtr<ChildImpl> strongActor = new ChildImpl();
891
892 if (!child.Bind(strongActor)) {
893 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
894
895 return;
896 }
897
898 strongActor->SetActorAlive();
899
900 if (NS_IsMainThread()) {
901 if (!bridgeChild->SendInitBackground(std::move(parent))) {
902 NS_WARNING("Failed to create top level actor!");
903 // Need to close the IPC channel before ChildImpl getting deleted.
904 strongActor->Close();
905 strongActor->AssertActorDestroyed();
906 return;
907 }
908 } else {
909 if (aMainEventTarget) {
910 MOZ_ALWAYS_SUCCEEDS(
911 aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
912 } else {
913 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
914 }
915
916 aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
917 }
918
919 aThreadLocalInfo->mActor = strongActor;
920 strongActor.forget(aOutput);
921 }
922
923 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndContentProcessThreadInfo(
924 SocketContentActorCreateFunc);
925
SocketParentActorCreateFunc(ChildImpl::ThreadLocalInfo * aThreadLocalInfo,unsigned int aThreadLocalIndex,nsIEventTarget * aMainEventTarget,ChildImpl ** aOutput)926 static void SocketParentActorCreateFunc(
927 ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
928 unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
929 ChildImpl** aOutput) {
930 SocketProcessChild* socketChild = SocketProcessChild::GetSingleton();
931
932 if (!socketChild || socketChild->IsShuttingDown()) {
933 return;
934 }
935
936 Endpoint<PBackgroundParent> parent;
937 Endpoint<PBackgroundChild> child;
938 nsresult rv;
939 rv = PBackground::CreateEndpoints(socketChild->OtherPid(),
940 base::GetCurrentProcId(), &parent, &child);
941 if (NS_FAILED(rv)) {
942 NS_WARNING("Failed to create top level actor!");
943 return;
944 }
945
946 RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
947 if (!NS_IsMainThread()) {
948 runnable = ChildImpl::SendInitBackgroundRunnable::Create(
949 std::move(parent),
950 [](Endpoint<PBackgroundParent>&& aParent) {
951 SocketProcessChild* socketChild = SocketProcessChild::GetSingleton();
952 MOZ_ASSERT(socketChild);
953
954 if (!socketChild->SendInitBackground(std::move(aParent))) {
955 MOZ_CRASH("Failed to create top level actor!");
956 }
957 },
958 aThreadLocalIndex);
959 if (!runnable) {
960 return;
961 }
962 }
963
964 RefPtr<ChildImpl> strongActor = new ChildImpl();
965
966 if (!child.Bind(strongActor)) {
967 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
968 return;
969 }
970
971 strongActor->SetActorAlive();
972
973 if (NS_IsMainThread()) {
974 if (!socketChild->SendInitBackground(std::move(parent))) {
975 NS_WARNING("Failed to create top level actor!");
976 return;
977 }
978 } else {
979 if (aMainEventTarget) {
980 MOZ_ALWAYS_SUCCEEDS(
981 aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
982 } else {
983 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
984 }
985
986 aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
987 }
988
989 aThreadLocalInfo->mActor = strongActor;
990 strongActor.forget(aOutput);
991 }
992
993 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndParentProcessThreadInfo(
994 SocketParentActorCreateFunc);
995
996 bool ChildImpl::sShutdownHasStarted = false;
997
998 // -----------------------------------------------------------------------------
999 // ParentImpl Implementation
1000 // -----------------------------------------------------------------------------
1001
1002 // static
IsOtherProcessActor(PBackgroundParent * aBackgroundActor)1003 bool ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor) {
1004 AssertIsOnBackgroundThread();
1005 MOZ_ASSERT(aBackgroundActor);
1006
1007 return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
1008 }
1009
1010 // static
GetContentParent(PBackgroundParent * aBackgroundActor)1011 already_AddRefed<ContentParent> ParentImpl::GetContentParent(
1012 PBackgroundParent* aBackgroundActor) {
1013 AssertIsOnBackgroundThread();
1014 MOZ_ASSERT(aBackgroundActor);
1015
1016 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1017 if (actor->mActorDestroyed) {
1018 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
1019 return nullptr;
1020 }
1021
1022 if (actor->mContent) {
1023 // We need to hand out a reference to our ContentParent but we also need to
1024 // keep the one we have. We can't call AddRef here because ContentParent is
1025 // not threadsafe so instead we dispatch a runnable to the main thread to do
1026 // it for us. This is safe since we are guaranteed that our AddRef runnable
1027 // will run before the reference we hand out can be released, and the
1028 // ContentParent can't die as long as the existing reference is maintained.
1029 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewNonOwningRunnableMethod(
1030 "ContentParent::AddRef", actor->mContent, &ContentParent::AddRef)));
1031 }
1032
1033 return already_AddRefed<ContentParent>(actor->mContent.get());
1034 }
1035
1036 // static
GetRawContentParentForComparison(PBackgroundParent * aBackgroundActor)1037 intptr_t ParentImpl::GetRawContentParentForComparison(
1038 PBackgroundParent* aBackgroundActor) {
1039 AssertIsOnBackgroundThread();
1040 MOZ_ASSERT(aBackgroundActor);
1041
1042 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1043 if (actor->mActorDestroyed) {
1044 MOZ_ASSERT(false,
1045 "GetRawContentParentForComparison called after ActorDestroy was "
1046 "called!");
1047 return intptr_t(-1);
1048 }
1049
1050 return intptr_t(static_cast<ContentParent*>(actor->mContent.get()));
1051 }
1052
1053 // static
GetChildID(PBackgroundParent * aBackgroundActor)1054 uint64_t ParentImpl::GetChildID(PBackgroundParent* aBackgroundActor) {
1055 AssertIsOnBackgroundThread();
1056 MOZ_ASSERT(aBackgroundActor);
1057
1058 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1059 if (actor->mActorDestroyed) {
1060 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
1061 return 0;
1062 }
1063
1064 if (actor->mContent) {
1065 return actor->mContent->ChildID();
1066 }
1067
1068 return 0;
1069 }
1070
1071 // static
GetLiveActorArray(PBackgroundParent * aBackgroundActor,nsTArray<PBackgroundParent * > & aLiveActorArray)1072 bool ParentImpl::GetLiveActorArray(
1073 PBackgroundParent* aBackgroundActor,
1074 nsTArray<PBackgroundParent*>& aLiveActorArray) {
1075 AssertIsOnBackgroundThread();
1076 MOZ_ASSERT(aBackgroundActor);
1077 MOZ_ASSERT(aLiveActorArray.IsEmpty());
1078
1079 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1080 if (actor->mActorDestroyed) {
1081 MOZ_ASSERT(false,
1082 "GetLiveActorArray called after ActorDestroy was called!");
1083 return false;
1084 }
1085
1086 if (!actor->mLiveActorArray) {
1087 return true;
1088 }
1089
1090 for (ParentImpl* liveActor : *actor->mLiveActorArray) {
1091 aLiveActorArray.AppendElement(liveActor);
1092 }
1093
1094 return true;
1095 }
1096
1097 // static
Alloc(ContentParent * aContent,Endpoint<PBackgroundParent> && aEndpoint)1098 bool ParentImpl::Alloc(ContentParent* aContent,
1099 Endpoint<PBackgroundParent>&& aEndpoint) {
1100 AssertIsInMainOrSocketProcess();
1101 AssertIsOnMainThread();
1102 MOZ_ASSERT(aEndpoint.IsValid());
1103
1104 if (!sBackgroundThread && !CreateBackgroundThread()) {
1105 NS_WARNING("Failed to create background thread!");
1106 return false;
1107 }
1108
1109 MOZ_ASSERT(sLiveActorsForBackgroundThread);
1110
1111 sLiveActorCount++;
1112
1113 RefPtr<ParentImpl> actor = new ParentImpl(aContent);
1114
1115 if (NS_FAILED(sBackgroundThread->Dispatch(NS_NewRunnableFunction(
1116 "Background::ParentImpl::ConnectActorRunnable",
1117 [actor = std::move(actor), endpoint = std::move(aEndpoint),
1118 liveActorArray = sLiveActorsForBackgroundThread]() mutable {
1119 MOZ_ASSERT(endpoint.IsValid());
1120 MOZ_ASSERT(liveActorArray);
1121 // Transfer ownership to this thread. If Open() fails then we will
1122 // release this reference in Destroy.
1123 ParentImpl* actorTmp;
1124 actor.forget(&actorTmp);
1125
1126 if (!endpoint.Bind(actorTmp)) {
1127 actorTmp->Destroy();
1128 return;
1129 }
1130
1131 actorTmp->SetLiveActorArray(liveActorArray);
1132 })))) {
1133 NS_WARNING("Failed to dispatch connect runnable!");
1134
1135 MOZ_ASSERT(sLiveActorCount);
1136 sLiveActorCount--;
1137 }
1138
1139 return true;
1140 }
1141
1142 // static
CreateActorForSameProcess(nsIEventTarget * aMainEventTarget)1143 already_AddRefed<ChildImpl> ParentImpl::CreateActorForSameProcess(
1144 nsIEventTarget* aMainEventTarget) {
1145 AssertIsInMainProcess();
1146
1147 RefPtr<ParentImpl> parentActor;
1148 nsCOMPtr<nsIThread> backgroundThread;
1149
1150 if (NS_IsMainThread()) {
1151 if (!sBackgroundThread && !CreateBackgroundThread()) {
1152 NS_WARNING("Failed to create background thread!");
1153 return nullptr;
1154 }
1155
1156 MOZ_ASSERT(!sShutdownHasStarted);
1157
1158 sLiveActorCount++;
1159
1160 parentActor = new ParentImpl();
1161 backgroundThread = sBackgroundThread.get();
1162 } else {
1163 RefPtr<CreateActorHelper> helper = new CreateActorHelper();
1164
1165 nsresult rv = helper->BlockAndGetResults(aMainEventTarget, parentActor,
1166 backgroundThread);
1167 if (NS_WARN_IF(NS_FAILED(rv))) {
1168 return nullptr;
1169 }
1170 }
1171
1172 RefPtr<ChildImpl> childActor = new ChildImpl();
1173
1174 MessageChannel* parentChannel = parentActor->GetIPCChannel();
1175 MOZ_ASSERT(parentChannel);
1176
1177 if (!childActor->Open(parentChannel, backgroundThread, ChildSide)) {
1178 NS_WARNING("Failed to open ChildImpl!");
1179
1180 // Can't release it here, we will release this reference in Destroy.
1181 ParentImpl* actor;
1182 parentActor.forget(&actor);
1183
1184 actor->Destroy();
1185
1186 return nullptr;
1187 }
1188
1189 childActor->SetActorAlive();
1190
1191 // Make sure the parent knows it is same process.
1192 parentActor->SetOtherProcessId(base::GetCurrentProcId());
1193
1194 // Now that Open() has succeeded transfer the ownership of the actors to IPDL.
1195 Unused << parentActor.forget();
1196
1197 return childActor.forget();
1198 }
1199
1200 // static
CreateBackgroundThread()1201 bool ParentImpl::CreateBackgroundThread() {
1202 AssertIsInMainOrSocketProcess();
1203 AssertIsOnMainThread();
1204 MOZ_ASSERT(!sBackgroundThread);
1205 MOZ_ASSERT(!sLiveActorsForBackgroundThread);
1206
1207 if (sShutdownHasStarted) {
1208 NS_WARNING(
1209 "Trying to create background thread after shutdown has "
1210 "already begun!");
1211 return false;
1212 }
1213
1214 nsCOMPtr<nsITimer> newShutdownTimer;
1215
1216 if (!sShutdownTimer) {
1217 newShutdownTimer = NS_NewTimer();
1218 if (!newShutdownTimer) {
1219 return false;
1220 }
1221 }
1222
1223 if (!sShutdownObserverRegistered) {
1224 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
1225 if (NS_WARN_IF(!obs)) {
1226 return false;
1227 }
1228
1229 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1230
1231 nsresult rv = obs->AddObserver(
1232 observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1233 if (NS_WARN_IF(NS_FAILED(rv))) {
1234 return false;
1235 }
1236
1237 sShutdownObserverRegistered = true;
1238 }
1239
1240 nsCOMPtr<nsIThread> thread;
1241 if (NS_FAILED(NS_NewNamedThread(
1242 "IPDL Background", getter_AddRefs(thread),
1243 NS_NewRunnableFunction(
1244 "Background::ParentImpl::CreateBackgroundThreadRunnable", []() {
1245 DebugOnly<PRThread*> oldBackgroundThread =
1246 sBackgroundPRThread.exchange(PR_GetCurrentThread());
1247
1248 MOZ_ASSERT_IF(oldBackgroundThread,
1249 PR_GetCurrentThread() != oldBackgroundThread);
1250 })))) {
1251 NS_WARNING("NS_NewNamedThread failed!");
1252 return false;
1253 }
1254
1255 sBackgroundThread = thread.forget();
1256
1257 sLiveActorsForBackgroundThread = new nsTArray<ParentImpl*>(1);
1258
1259 if (!sShutdownTimer) {
1260 MOZ_ASSERT(newShutdownTimer);
1261 sShutdownTimer = newShutdownTimer;
1262 }
1263
1264 return true;
1265 }
1266
1267 // static
ShutdownBackgroundThread()1268 void ParentImpl::ShutdownBackgroundThread() {
1269 AssertIsInMainOrSocketProcess();
1270 AssertIsOnMainThread();
1271 MOZ_ASSERT(sShutdownHasStarted);
1272 MOZ_ASSERT_IF(!sBackgroundThread, !sLiveActorCount);
1273 MOZ_ASSERT_IF(sBackgroundThread, sShutdownTimer);
1274
1275 nsCOMPtr<nsITimer> shutdownTimer = sShutdownTimer.get();
1276 sShutdownTimer = nullptr;
1277
1278 if (sBackgroundThread) {
1279 nsCOMPtr<nsIThread> thread = sBackgroundThread.get();
1280 sBackgroundThread = nullptr;
1281
1282 UniquePtr<nsTArray<ParentImpl*>> liveActors(sLiveActorsForBackgroundThread);
1283 sLiveActorsForBackgroundThread = nullptr;
1284
1285 MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
1286
1287 if (sLiveActorCount) {
1288 // We need to spin the event loop while we wait for all the actors to be
1289 // cleaned up. We also set a timeout to force-kill any hanging actors.
1290 TimerCallbackClosure closure(thread, liveActors.get());
1291
1292 MOZ_ALWAYS_SUCCEEDS(shutdownTimer->InitWithNamedFuncCallback(
1293 &ShutdownTimerCallback, &closure, kShutdownTimerDelayMS,
1294 nsITimer::TYPE_ONE_SHOT, "ParentImpl::ShutdownTimerCallback"));
1295
1296 SpinEventLoopUntil([&]() { return !sLiveActorCount; });
1297
1298 MOZ_ASSERT(liveActors->IsEmpty());
1299
1300 MOZ_ALWAYS_SUCCEEDS(shutdownTimer->Cancel());
1301 }
1302
1303 // Dispatch this runnable to unregister the PR thread from the profiler.
1304 MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(NS_NewRunnableFunction(
1305 "Background::ParentImpl::ShutdownBackgroundThreadRunnable", []() {
1306 // It is possible that another background thread was created while
1307 // this thread was shutting down. In that case we can't assert
1308 // anything about sBackgroundPRThread and we should not modify it
1309 // here.
1310 sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
1311 })));
1312
1313 MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
1314 }
1315 }
1316
1317 // static
ShutdownTimerCallback(nsITimer * aTimer,void * aClosure)1318 void ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure) {
1319 AssertIsInMainOrSocketProcess();
1320 AssertIsOnMainThread();
1321 MOZ_ASSERT(sShutdownHasStarted);
1322 MOZ_ASSERT(sLiveActorCount);
1323
1324 auto closure = static_cast<TimerCallbackClosure*>(aClosure);
1325 MOZ_ASSERT(closure);
1326
1327 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
1328 // finished.
1329 sLiveActorCount++;
1330
1331 InvokeAsync(closure->mThread, __func__,
1332 [liveActors = closure->mLiveActors]() {
1333 MOZ_ASSERT(liveActors);
1334
1335 if (!liveActors->IsEmpty()) {
1336 // Copy the array since calling Close() could mutate the
1337 // actual array.
1338 nsTArray<ParentImpl*> actorsToClose(liveActors->Clone());
1339 for (ParentImpl* actor : actorsToClose) {
1340 actor->Close();
1341 }
1342 }
1343 return GenericPromise::CreateAndResolve(true, __func__);
1344 })
1345 ->Then(GetCurrentSerialEventTarget(), __func__, []() {
1346 MOZ_ASSERT(sLiveActorCount);
1347 sLiveActorCount--;
1348 });
1349 }
1350
Destroy()1351 void ParentImpl::Destroy() {
1352 // May be called on any thread!
1353
1354 AssertIsInMainOrSocketProcess();
1355
1356 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1357 NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy", this,
1358 &ParentImpl::MainThreadActorDestroy)));
1359 }
1360
MainThreadActorDestroy()1361 void ParentImpl::MainThreadActorDestroy() {
1362 AssertIsInMainOrSocketProcess();
1363 AssertIsOnMainThread();
1364 MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
1365
1366 mContent = nullptr;
1367
1368 MOZ_ASSERT(sLiveActorCount);
1369 sLiveActorCount--;
1370
1371 // This may be the last reference!
1372 Release();
1373 }
1374
ActorDestroy(ActorDestroyReason aWhy)1375 void ParentImpl::ActorDestroy(ActorDestroyReason aWhy) {
1376 AssertIsInMainOrSocketProcess();
1377 AssertIsOnBackgroundThread();
1378 MOZ_ASSERT(!mActorDestroyed);
1379 MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
1380
1381 BackgroundParentImpl::ActorDestroy(aWhy);
1382
1383 mActorDestroyed = true;
1384
1385 if (mLiveActorArray) {
1386 MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1387 mLiveActorArray = nullptr;
1388 }
1389
1390 // This is tricky. We should be able to call Destroy() here directly because
1391 // we're not going to touch 'this' or our MessageChannel any longer on this
1392 // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1393 // it runs it will destroy 'this' and our associated MessageChannel. However,
1394 // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1395 // racing with the main thread we must ensure that the MessageChannel lives
1396 // long enough to be cleared in this call stack.
1397
1398 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(
1399 "ParentImpl::Destroy", this, &ParentImpl::Destroy)));
1400 }
1401
NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver,nsIObserver)1402 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver)
1403
1404 NS_IMETHODIMP
1405 ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1406 const char16_t* aData) {
1407 AssertIsInMainOrSocketProcess();
1408 AssertIsOnMainThread();
1409 MOZ_ASSERT(!sShutdownHasStarted);
1410 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1411
1412 sShutdownHasStarted = true;
1413
1414 // Do this first before calling (and spinning the event loop in)
1415 // ShutdownBackgroundThread().
1416 ChildImpl::Shutdown();
1417
1418 ShutdownBackgroundThread();
1419
1420 return NS_OK;
1421 }
1422
BlockAndGetResults(nsIEventTarget * aMainEventTarget,RefPtr<ParentImpl> & aParentActor,nsCOMPtr<nsIThread> & aThread)1423 nsresult ParentImpl::CreateActorHelper::BlockAndGetResults(
1424 nsIEventTarget* aMainEventTarget, RefPtr<ParentImpl>& aParentActor,
1425 nsCOMPtr<nsIThread>& aThread) {
1426 AssertIsNotOnMainThread();
1427
1428 if (aMainEventTarget) {
1429 MOZ_ALWAYS_SUCCEEDS(aMainEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
1430 } else {
1431 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1432 }
1433
1434 mozilla::MonitorAutoLock lock(mMonitor);
1435 while (mWaiting) {
1436 lock.Wait();
1437 }
1438
1439 if (NS_WARN_IF(NS_FAILED(mMainThreadResultCode))) {
1440 return mMainThreadResultCode;
1441 }
1442
1443 aParentActor = std::move(mParentActor);
1444 aThread = std::move(mThread);
1445 return NS_OK;
1446 }
1447
RunOnMainThread()1448 nsresult ParentImpl::CreateActorHelper::RunOnMainThread() {
1449 AssertIsOnMainThread();
1450
1451 if (!sBackgroundThread && !CreateBackgroundThread()) {
1452 NS_WARNING("Failed to create background thread!");
1453 return NS_ERROR_FAILURE;
1454 }
1455
1456 MOZ_ASSERT(!sShutdownHasStarted);
1457
1458 sLiveActorCount++;
1459
1460 mParentActor = new ParentImpl();
1461 mThread = sBackgroundThread;
1462
1463 return NS_OK;
1464 }
1465
1466 NS_IMETHODIMP
Run()1467 ParentImpl::CreateActorHelper::Run() {
1468 AssertIsOnMainThread();
1469
1470 nsresult rv = RunOnMainThread();
1471 if (NS_WARN_IF(NS_FAILED(rv))) {
1472 mMainThreadResultCode = rv;
1473 }
1474
1475 mozilla::MonitorAutoLock lock(mMonitor);
1476 MOZ_ASSERT(mWaiting);
1477
1478 mWaiting = false;
1479 lock.Notify();
1480
1481 return NS_OK;
1482 }
1483
1484 // -----------------------------------------------------------------------------
1485 // ChildImpl Implementation
1486 // -----------------------------------------------------------------------------
1487
1488 // static
Startup()1489 void ChildImpl::Startup() {
1490 // This happens on the main thread but before XPCOM has started so we can't
1491 // assert that we're being called on the main thread here.
1492
1493 sParentAndContentProcessThreadInfo.Startup();
1494 sSocketAndContentProcessThreadInfo.Startup();
1495 sSocketAndParentProcessThreadInfo.Startup();
1496
1497 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1498 MOZ_RELEASE_ASSERT(observerService);
1499
1500 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1501
1502 nsresult rv = observerService->AddObserver(
1503 observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1504 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
1505 }
1506
1507 // static
Shutdown()1508 void ChildImpl::Shutdown() {
1509 AssertIsOnMainThread();
1510
1511 sParentAndContentProcessThreadInfo.Shutdown();
1512 sSocketAndContentProcessThreadInfo.Shutdown();
1513 sSocketAndParentProcessThreadInfo.Shutdown();
1514
1515 sShutdownHasStarted = true;
1516 }
1517
1518 // static
GetForCurrentThread()1519 PBackgroundChild* ChildImpl::GetForCurrentThread() {
1520 MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1521 kBadThreadLocalIndex);
1522
1523 auto threadLocalInfo =
1524 NS_IsMainThread()
1525 ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1526 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1527 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1528
1529 if (!threadLocalInfo) {
1530 return nullptr;
1531 }
1532
1533 return threadLocalInfo->mActor;
1534 }
1535
1536 /* static */
GetFromThreadInfo(nsIEventTarget * aMainEventTarget,ThreadLocalInfo * aThreadLocalInfo)1537 PBackgroundChild* ChildImpl::GetFromThreadInfo(
1538 nsIEventTarget* aMainEventTarget, ThreadLocalInfo* aThreadLocalInfo) {
1539 MOZ_ASSERT(aThreadLocalInfo);
1540
1541 if (aThreadLocalInfo->mActor) {
1542 RefPtr<SendInitBackgroundRunnable>& runnable =
1543 aThreadLocalInfo->mSendInitBackgroundRunnable;
1544
1545 if (aMainEventTarget && runnable) {
1546 // The SendInitBackgroundRunnable was already dispatched to the main
1547 // thread to finish initialization of a new background child actor.
1548 // However, the caller passed a custom main event target which indicates
1549 // that synchronous blocking of the main thread is happening (done by
1550 // creating a nested event target and spinning the event loop).
1551 // It can happen that the SendInitBackgroundRunnable didn't have a chance
1552 // to run before the synchronous blocking has occured. Unblocking of the
1553 // main thread can depend on an IPC message received on this thread, so
1554 // we have to dispatch the SendInitBackgroundRunnable to the custom main
1555 // event target too, otherwise IPC will be only queueing messages on this
1556 // thread. The runnable will run twice in the end, but that's a harmless
1557 // race between the main and nested event queue of the main thread.
1558 // There's a guard in the runnable implementation for calling
1559 // SendInitBackground only once.
1560
1561 MOZ_ALWAYS_SUCCEEDS(
1562 aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
1563 }
1564
1565 return aThreadLocalInfo->mActor;
1566 }
1567
1568 return nullptr;
1569 }
1570
1571 /* static */
GetOrCreateForCurrentThread(nsIEventTarget * aMainEventTarget)1572 PBackgroundChild* ChildImpl::GetOrCreateForCurrentThread(
1573 nsIEventTarget* aMainEventTarget) {
1574 return sParentAndContentProcessThreadInfo.GetOrCreateForCurrentThread(
1575 aMainEventTarget);
1576 }
1577
1578 /* static */
GetOrCreateSocketActorForCurrentThread(nsIEventTarget * aMainEventTarget)1579 PBackgroundChild* ChildImpl::GetOrCreateSocketActorForCurrentThread(
1580 nsIEventTarget* aMainEventTarget) {
1581 return sSocketAndContentProcessThreadInfo.GetOrCreateForCurrentThread(
1582 aMainEventTarget);
1583 }
1584
1585 /* static */
GetOrCreateForSocketParentBridgeForCurrentThread(nsIEventTarget * aMainEventTarget)1586 PBackgroundChild* ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
1587 nsIEventTarget* aMainEventTarget) {
1588 return sSocketAndParentProcessThreadInfo.GetOrCreateForCurrentThread(
1589 aMainEventTarget);
1590 }
1591
1592 // static
CloseForCurrentThread()1593 void ChildImpl::CloseForCurrentThread() {
1594 MOZ_ASSERT(!NS_IsMainThread(),
1595 "PBackground for the main thread should be shut down via "
1596 "ChildImpl::Shutdown().");
1597
1598 sParentAndContentProcessThreadInfo.CloseForCurrentThread();
1599 sSocketAndContentProcessThreadInfo.CloseForCurrentThread();
1600 sSocketAndParentProcessThreadInfo.CloseForCurrentThread();
1601 }
1602
1603 // static
GetThreadLocalForCurrentThread()1604 BackgroundChildImpl::ThreadLocal* ChildImpl::GetThreadLocalForCurrentThread() {
1605 MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1606 kBadThreadLocalIndex,
1607 "BackgroundChild::Startup() was never called!");
1608
1609 auto threadLocalInfo =
1610 NS_IsMainThread()
1611 ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1612 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1613 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1614
1615 if (!threadLocalInfo) {
1616 return nullptr;
1617 }
1618
1619 if (!threadLocalInfo->mConsumerThreadLocal) {
1620 threadLocalInfo->mConsumerThreadLocal =
1621 MakeUnique<BackgroundChildImpl::ThreadLocal>();
1622 }
1623
1624 return threadLocalInfo->mConsumerThreadLocal.get();
1625 }
1626
1627 // static
ThreadLocalDestructor(void * aThreadLocal)1628 void ChildImpl::ThreadLocalDestructor(void* aThreadLocal) {
1629 auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
1630
1631 if (threadLocalInfo) {
1632 MOZ_ASSERT(threadLocalInfo->mClosed);
1633
1634 if (threadLocalInfo->mActor) {
1635 threadLocalInfo->mActor->Close();
1636 threadLocalInfo->mActor->AssertActorDestroyed();
1637 }
1638
1639 if (threadLocalInfo->mSendInitBackgroundRunnable) {
1640 threadLocalInfo->mSendInitBackgroundRunnable->ClearEventTarget();
1641 }
1642
1643 delete threadLocalInfo;
1644 }
1645 }
1646
ActorDestroy(ActorDestroyReason aWhy)1647 void ChildImpl::ActorDestroy(ActorDestroyReason aWhy) {
1648 AssertIsOnOwningThread();
1649
1650 #ifdef DEBUG
1651 MOZ_ASSERT(!mActorDestroyed);
1652 mActorDestroyed = true;
1653 #endif
1654
1655 BackgroundChildImpl::ActorDestroy(aWhy);
1656 }
1657
NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver,nsIObserver)1658 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
1659
1660 NS_IMETHODIMP
1661 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1662 const char16_t* aData) {
1663 AssertIsOnMainThread();
1664 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1665
1666 ChildImpl::Shutdown();
1667
1668 return NS_OK;
1669 }
1670
1671 // static
1672 already_AddRefed<ChildImpl::SendInitBackgroundRunnable>
Create(Endpoint<PBackgroundParent> && aParent,std::function<void (Endpoint<PBackgroundParent> && aParent)> && aFunc,unsigned int aThreadLocalIndex)1673 ChildImpl::SendInitBackgroundRunnable::Create(
1674 Endpoint<PBackgroundParent>&& aParent,
1675 std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
1676 unsigned int aThreadLocalIndex) {
1677 MOZ_ASSERT(!NS_IsMainThread());
1678
1679 RefPtr<SendInitBackgroundRunnable> runnable = new SendInitBackgroundRunnable(
1680 std::move(aParent), std::move(aFunc), aThreadLocalIndex);
1681
1682 WorkerPrivate* workerPrivate = mozilla::dom::GetCurrentThreadWorkerPrivate();
1683 if (!workerPrivate) {
1684 return runnable.forget();
1685 }
1686
1687 workerPrivate->AssertIsOnWorkerThread();
1688
1689 runnable->mWorkerRef = StrongWorkerRef::Create(
1690 workerPrivate, "ChildImpl::SendInitBackgroundRunnable");
1691 if (NS_WARN_IF(!runnable->mWorkerRef)) {
1692 return nullptr;
1693 }
1694
1695 return runnable.forget();
1696 }
1697
1698 NS_IMETHODIMP
Run()1699 ChildImpl::SendInitBackgroundRunnable::Run() {
1700 if (NS_IsMainThread()) {
1701 if (mSentInitBackground) {
1702 return NS_OK;
1703 }
1704
1705 mSentInitBackground = true;
1706
1707 mSendInitfunc(std::move(mParent));
1708
1709 nsCOMPtr<nsISerialEventTarget> owningEventTarget;
1710 {
1711 mozilla::MutexAutoLock lock(mMutex);
1712 owningEventTarget = mOwningEventTarget;
1713 }
1714
1715 if (!owningEventTarget) {
1716 return NS_OK;
1717 }
1718
1719 nsresult rv = owningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
1720 if (NS_WARN_IF(NS_FAILED(rv))) {
1721 return rv;
1722 }
1723
1724 return NS_OK;
1725 }
1726
1727 ClearEventTarget();
1728
1729 auto threadLocalInfo =
1730 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
1731
1732 if (!threadLocalInfo) {
1733 return NS_OK;
1734 }
1735
1736 threadLocalInfo->mSendInitBackgroundRunnable = nullptr;
1737
1738 return NS_OK;
1739 }
1740