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