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 "MainThreadUtils.h"
13 #include "base/process_util.h"
14 #include "base/task.h"
15 #include "FileDescriptor.h"
16 #include "GeckoProfiler.h"
17 #include "InputStreamUtils.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/SpinEventLoopUntil.h"
25 #include "mozilla/StaticPtr.h"
26 #include "mozilla/Unused.h"
27 #include "mozilla/dom/ContentChild.h"
28 #include "mozilla/dom/ContentParent.h"
29 #include "mozilla/dom/File.h"
30 #include "mozilla/dom/WorkerPrivate.h"
31 #include "mozilla/dom/WorkerRef.h"
32 #include "mozilla/ipc/BackgroundStarterChild.h"
33 #include "mozilla/ipc/BackgroundStarterParent.h"
34 #include "mozilla/ipc/Endpoint.h"
35 #include "mozilla/ipc/PBackgroundStarter.h"
36 #include "mozilla/ipc/ProtocolTypes.h"
37 #include "mozilla/net/SocketProcessChild.h"
38 #include "mozilla/net/SocketProcessBridgeChild.h"
39 #include "nsCOMPtr.h"
40 #include "nsIEventTarget.h"
41 #include "nsIObserver.h"
42 #include "nsIObserverService.h"
43 #include "nsIRunnable.h"
44 #include "nsISupportsImpl.h"
45 #include "nsIThread.h"
46 #include "nsITimer.h"
47 #include "nsTArray.h"
48 #include "nsThreadUtils.h"
49 #include "nsTraceRefcnt.h"
50 #include "nsXULAppAPI.h"
51 #include "nsXPCOMPrivate.h"
52 #include "prthread.h"
53
54 #include <functional>
55
56 #ifdef RELEASE_OR_BETA
57 # define THREADSAFETY_ASSERT MOZ_ASSERT
58 #else
59 # define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
60 #endif
61
62 #define CRASH_IN_CHILD_PROCESS(_msg) \
63 do { \
64 if (XRE_IsParentProcess()) { \
65 MOZ_ASSERT(false, _msg); \
66 } else { \
67 MOZ_CRASH(_msg); \
68 } \
69 } while (0)
70
71 using namespace mozilla;
72 using namespace mozilla::dom;
73 using namespace mozilla::ipc;
74 using namespace mozilla::net;
75
76 namespace {
77
78 class ChildImpl;
79
80 // -----------------------------------------------------------------------------
81 // Utility Functions
82 // -----------------------------------------------------------------------------
83
AssertIsInMainOrSocketProcess()84 void AssertIsInMainOrSocketProcess() {
85 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
86 }
87
AssertIsOnMainThread()88 void AssertIsOnMainThread() { THREADSAFETY_ASSERT(NS_IsMainThread()); }
89
90 // -----------------------------------------------------------------------------
91 // ParentImpl Declaration
92 // -----------------------------------------------------------------------------
93
94 class ParentImpl final : public BackgroundParentImpl {
95 friend class ChildImpl;
96 friend class mozilla::ipc::BackgroundParent;
97 friend class mozilla::ipc::BackgroundStarterParent;
98
99 private:
100 class ShutdownObserver;
101
102 struct MOZ_STACK_CLASS TimerCallbackClosure {
103 nsIThread* mThread;
104 nsTArray<IToplevelProtocol*>* mLiveActors;
105
TimerCallbackClosure__anonc429a1a90111::ParentImpl::TimerCallbackClosure106 TimerCallbackClosure(nsIThread* aThread,
107 nsTArray<IToplevelProtocol*>* aLiveActors)
108 : mThread(aThread), mLiveActors(aLiveActors) {
109 AssertIsInMainOrSocketProcess();
110 AssertIsOnMainThread();
111 MOZ_ASSERT(aThread);
112 MOZ_ASSERT(aLiveActors);
113 }
114 };
115
116 // The length of time we will wait at shutdown for all actors to clean
117 // themselves up before forcing them to be destroyed.
118 static const uint32_t kShutdownTimerDelayMS = 10000;
119
120 // This is only modified on the main thread. It is null if the thread does not
121 // exist or is shutting down.
122 static StaticRefPtr<nsIThread> sBackgroundThread;
123
124 // This is created and destroyed on the main thread but only modified on the
125 // background thread. It is specific to each instance of sBackgroundThread.
126 static nsTArray<IToplevelProtocol*>* sLiveActorsForBackgroundThread;
127
128 // This is only modified on the main thread.
129 static StaticRefPtr<nsITimer> sShutdownTimer;
130
131 // This exists so that that [Assert]IsOnBackgroundThread() can continue to
132 // work during shutdown.
133 static Atomic<PRThread*> sBackgroundPRThread;
134
135 // Maintains a count of live actors so that the background thread can be shut
136 // down when it is no longer needed.
137 // May be incremented on either the background thread (by an existing actor)
138 // or on the main thread, but must be decremented on the main thread.
139 static Atomic<uint64_t> sLiveActorCount;
140
141 // This is only modified on the main thread. It is true after the shutdown
142 // observer is registered and is never unset thereafter.
143 static bool sShutdownObserverRegistered;
144
145 // This is only modified on the main thread. It prevents us from trying to
146 // create the background thread after application shutdown has started.
147 static bool sShutdownHasStarted;
148
149 // Only touched on the main thread, null if this is a same-process actor.
150 RefPtr<ContentParent> mContent;
151
152 // Set when the actor is opened successfully and used to handle shutdown
153 // hangs. Only touched on the background thread.
154 nsTArray<IToplevelProtocol*>* mLiveActorArray;
155
156 // Set at construction to indicate whether this parent actor corresponds to a
157 // child actor in another process or to a child actor from a different thread
158 // in the same process.
159 const bool mIsOtherProcessActor;
160
161 // Set after ActorDestroy has been called. Only touched on the background
162 // thread.
163 bool mActorDestroyed;
164
165 public:
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 need to be deleted on the main thread, despite IPC
175 // controlling them on a background thread. Use `_WITH_DELETE_ON_MAIN_THREAD`
176 // to force destruction to occur on the desired thread.
177 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(ParentImpl,
178 override)
179
180 void Destroy();
181
182 private:
183 // Forwarded from BackgroundParent.
184 static bool IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
185
186 // Forwarded from BackgroundParent.
187 static already_AddRefed<ContentParent> GetContentParent(
188 PBackgroundParent* aBackgroundActor);
189
190 // Forwarded from BackgroundParent.
191 static intptr_t GetRawContentParentForComparison(
192 PBackgroundParent* aBackgroundActor);
193
194 // Forwarded from BackgroundParent.
195 static uint64_t GetChildID(PBackgroundParent* aBackgroundActor);
196
197 // Forwarded from BackgroundParent.
198 static bool AllocStarter(ContentParent* aContent,
199 Endpoint<PBackgroundStarterParent>&& aEndpoint,
200 bool aCrossProcess = true);
201
202 static bool CreateBackgroundThread();
203
204 static void ShutdownBackgroundThread();
205
206 static void ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
207
208 // NOTE: ParentImpl could be used in 4 cases below.
209 // 1. Within the parent process.
210 // 2. Between parent process and content process.
211 // 3. Between socket process and content process.
212 // 4. Between parent process and socket process.
213 // |aContent| should be not null for case 2. For cases 1, 3 and 4, it's null.
ParentImpl(already_AddRefed<ContentParent> && aContent,bool aIsOtherProcessActor)214 explicit ParentImpl(already_AddRefed<ContentParent>&& aContent,
215 bool aIsOtherProcessActor)
216 : mContent(std::move(aContent)),
217 mLiveActorArray(nullptr),
218 mIsOtherProcessActor(aIsOtherProcessActor),
219 mActorDestroyed(false) {
220 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
221 MOZ_ASSERT_IF(!aIsOtherProcessActor, XRE_IsParentProcess());
222 }
223
~ParentImpl()224 ~ParentImpl() {
225 AssertIsInMainOrSocketProcess();
226 AssertIsOnMainThread();
227 MOZ_ASSERT(!mContent);
228 }
229
230 void MainThreadActorDestroy();
231
SetLiveActorArray(nsTArray<IToplevelProtocol * > * aLiveActorArray)232 void SetLiveActorArray(nsTArray<IToplevelProtocol*>* aLiveActorArray) {
233 AssertIsInMainOrSocketProcess();
234 AssertIsOnBackgroundThread();
235 MOZ_ASSERT(aLiveActorArray);
236 MOZ_ASSERT(!aLiveActorArray->Contains(this));
237 MOZ_ASSERT(!mLiveActorArray);
238 MOZ_ASSERT(mIsOtherProcessActor);
239
240 mLiveActorArray = aLiveActorArray;
241 mLiveActorArray->AppendElement(this);
242 }
243
244 // These methods are only called by IPDL.
245 virtual void ActorDestroy(ActorDestroyReason aWhy) override;
246 };
247
248 // -----------------------------------------------------------------------------
249 // ChildImpl Declaration
250 // -----------------------------------------------------------------------------
251
252 class ChildImpl final : public BackgroundChildImpl {
253 friend class mozilla::ipc::BackgroundChild;
254 friend class mozilla::ipc::BackgroundChildImpl;
255 friend class mozilla::ipc::BackgroundStarterChild;
256
257 typedef base::ProcessId ProcessId;
258
259 class ShutdownObserver;
260
261 public:
262 struct ThreadLocalInfo {
ThreadLocalInfo__anonc429a1a90111::ChildImpl::ThreadLocalInfo263 ThreadLocalInfo()
264 #ifdef DEBUG
265 : mClosed(false)
266 #endif
267 {
268 }
269
270 RefPtr<ChildImpl> mActor;
271 UniquePtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal;
272 #ifdef DEBUG
273 bool mClosed;
274 #endif
275 };
276
277 private:
278 // A thread-local index that is not valid.
279 static constexpr unsigned int kBadThreadLocalIndex =
280 static_cast<unsigned int>(-1);
281
282 // ThreadInfoWrapper encapsulates ThreadLocalInfo and ThreadLocalIndex and
283 // also provides some common functions for creating PBackground IPC actor.
284 class ThreadInfoWrapper final {
285 friend class ChildImpl;
286
287 public:
288 using ActorCreateFunc = void (*)(ThreadLocalInfo*, unsigned int,
289 nsIEventTarget*, ChildImpl**);
290
291 ThreadInfoWrapper() = default;
292
Startup()293 void Startup() {
294 MOZ_ASSERT(mThreadLocalIndex == kBadThreadLocalIndex,
295 "ThreadInfoWrapper::Startup() called more than once!");
296
297 PRStatus status =
298 PR_NewThreadPrivateIndex(&mThreadLocalIndex, ThreadLocalDestructor);
299 MOZ_RELEASE_ASSERT(status == PR_SUCCESS,
300 "PR_NewThreadPrivateIndex failed!");
301
302 MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex);
303 }
304
Shutdown()305 void Shutdown() {
306 if (sShutdownHasStarted) {
307 MOZ_ASSERT_IF(mThreadLocalIndex != kBadThreadLocalIndex,
308 !PR_GetThreadPrivate(mThreadLocalIndex));
309 return;
310 }
311
312 if (mThreadLocalIndex == kBadThreadLocalIndex) {
313 return;
314 }
315
316 RefPtr<BackgroundStarterChild> starter;
317 {
318 auto lock = mStarter.Lock();
319 starter = lock->forget();
320 }
321 if (starter) {
322 CloseStarter(starter);
323 }
324
325 ThreadLocalInfo* threadLocalInfo;
326 #ifdef DEBUG
327 threadLocalInfo =
328 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
329 MOZ_ASSERT(!threadLocalInfo);
330 #endif
331
332 threadLocalInfo = mMainThreadInfo;
333 if (threadLocalInfo) {
334 #ifdef DEBUG
335 MOZ_ASSERT(!threadLocalInfo->mClosed);
336 threadLocalInfo->mClosed = true;
337 #endif
338
339 ThreadLocalDestructor(threadLocalInfo);
340 mMainThreadInfo = nullptr;
341 }
342 }
343
344 template <typename Actor>
InitStarter(Actor * aActor)345 void InitStarter(Actor* aActor) {
346 AssertIsOnMainThread();
347
348 // Create a pair of endpoints and send them to the other process.
349 Endpoint<PBackgroundStarterParent> parent;
350 Endpoint<PBackgroundStarterChild> child;
351 MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints(
352 aActor->OtherPid(), base::GetCurrentProcId(), &parent, &child));
353 MOZ_ALWAYS_TRUE(aActor->SendInitBackground(std::move(parent)));
354
355 InitStarter(std::move(child));
356 }
357
InitStarter(Endpoint<PBackgroundStarterChild> && aEndpoint)358 void InitStarter(Endpoint<PBackgroundStarterChild>&& aEndpoint) {
359 AssertIsOnMainThread();
360
361 base::ProcessId otherPid = aEndpoint.OtherPid();
362
363 nsCOMPtr<nsISerialEventTarget> taskQueue;
364 MOZ_ALWAYS_SUCCEEDS(NS_CreateBackgroundTaskQueue(
365 "PBackgroundStarter Queue", getter_AddRefs(taskQueue)));
366
367 RefPtr<BackgroundStarterChild> starter =
368 new BackgroundStarterChild(otherPid, taskQueue);
369
370 taskQueue->Dispatch(NS_NewRunnableFunction(
371 "PBackgroundStarterChild Init",
372 [starter, endpoint = std::move(aEndpoint)]() mutable {
373 MOZ_ALWAYS_TRUE(endpoint.Bind(starter));
374 }));
375
376 // Swap in the newly initialized `BackgroundStarterChild`, and close the
377 // previous one if we're replacing an existing PBackgroundStarterChild
378 // instance.
379 RefPtr<BackgroundStarterChild> prevStarter;
380 {
381 auto lock = mStarter.Lock();
382 prevStarter = lock->forget();
383 *lock = starter.forget();
384 }
385 if (prevStarter) {
386 CloseStarter(prevStarter);
387 }
388 }
389
CloseForCurrentThread()390 void CloseForCurrentThread() {
391 MOZ_ASSERT(!NS_IsMainThread());
392
393 if (mThreadLocalIndex == kBadThreadLocalIndex) {
394 return;
395 }
396
397 auto* threadLocalInfo =
398 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
399
400 if (!threadLocalInfo) {
401 return;
402 }
403
404 #ifdef DEBUG
405 MOZ_ASSERT(!threadLocalInfo->mClosed);
406 threadLocalInfo->mClosed = true;
407 #endif
408
409 // Clearing the thread local will synchronously close the actor.
410 DebugOnly<PRStatus> status =
411 PR_SetThreadPrivate(mThreadLocalIndex, nullptr);
412 MOZ_ASSERT(status == PR_SUCCESS);
413 }
414
GetOrCreateForCurrentThread()415 PBackgroundChild* GetOrCreateForCurrentThread() {
416 // Processes can be told to do final CC's during shutdown even though
417 // they never finished starting (and thus call this), because they
418 // hadn't gotten far enough to call Startup() before shutdown began.
419 if (mThreadLocalIndex == kBadThreadLocalIndex) {
420 NS_ERROR("BackgroundChild::Startup() was never called");
421 return nullptr;
422 }
423 if (NS_IsMainThread() && ChildImpl::sShutdownHasStarted) {
424 return nullptr;
425 }
426
427 auto* threadLocalInfo = NS_IsMainThread()
428 ? mMainThreadInfo
429 : static_cast<ThreadLocalInfo*>(
430 PR_GetThreadPrivate(mThreadLocalIndex));
431
432 if (!threadLocalInfo) {
433 auto newInfo = MakeUnique<ThreadLocalInfo>();
434
435 if (NS_IsMainThread()) {
436 mMainThreadInfo = newInfo.get();
437 } else {
438 if (PR_SetThreadPrivate(mThreadLocalIndex, newInfo.get()) !=
439 PR_SUCCESS) {
440 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
441 return nullptr;
442 }
443 }
444
445 threadLocalInfo = newInfo.release();
446 }
447
448 if (threadLocalInfo->mActor) {
449 return threadLocalInfo->mActor;
450 }
451
452 RefPtr<BackgroundStarterChild> starter;
453 {
454 auto lock = mStarter.Lock();
455 starter = *lock;
456 }
457 if (!starter) {
458 CRASH_IN_CHILD_PROCESS("No BackgroundStarterChild");
459 return nullptr;
460 }
461
462 Endpoint<PBackgroundParent> parent;
463 Endpoint<PBackgroundChild> child;
464 nsresult rv;
465 rv = PBackground::CreateEndpoints(
466 starter->mOtherPid, base::GetCurrentProcId(), &parent, &child);
467 if (NS_FAILED(rv)) {
468 NS_WARNING("Failed to create top level actor!");
469 return nullptr;
470 }
471
472 RefPtr<ChildImpl> strongActor = new ChildImpl();
473 if (!child.Bind(strongActor)) {
474 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
475 return nullptr;
476 }
477 strongActor->SetActorAlive();
478 threadLocalInfo->mActor = strongActor;
479
480 // Dispatch to the background task queue to create the relevant actor in
481 // the remote process.
482 starter->mTaskQueue->Dispatch(NS_NewRunnableFunction(
483 "PBackground GetOrCreateForCurrentThread",
484 [starter, endpoint = std::move(parent)]() mutable {
485 if (!starter->SendInitBackground(std::move(endpoint))) {
486 NS_WARNING("Failed to create toplevel actor");
487 }
488 }));
489 return strongActor;
490 }
491
492 private:
CloseStarter(BackgroundStarterChild * aStarter)493 static void CloseStarter(BackgroundStarterChild* aStarter) {
494 aStarter->mTaskQueue->Dispatch(NS_NewRunnableFunction(
495 "PBackgroundStarterChild Close",
496 [starter = RefPtr{aStarter}] { starter->Close(); }));
497 }
498
499 // This is only modified on the main thread. It is the thread-local index
500 // that we use to store the BackgroundChild for each thread.
501 unsigned int mThreadLocalIndex = kBadThreadLocalIndex;
502
503 // On the main thread, we store TLS in this global instead of in
504 // mThreadLocalIndex. That way, cooperative main threads all share the same
505 // thread info.
506 ThreadLocalInfo* mMainThreadInfo = nullptr;
507
508 // The starter which will be used to launch PBackground instances of this
509 // type. Only modified on the main thread, but may be read by any thread
510 // wanting to start background actors.
511 StaticDataMutex<StaticRefPtr<BackgroundStarterChild>> mStarter{"mStarter"};
512 };
513
514 // For PBackground between parent and content process.
515 static ThreadInfoWrapper sParentAndContentProcessThreadInfo;
516
517 // For PBackground between socket and content process.
518 static ThreadInfoWrapper sSocketAndContentProcessThreadInfo;
519
520 // For PBackground between socket and parent process.
521 static ThreadInfoWrapper sSocketAndParentProcessThreadInfo;
522
523 // This is only modified on the main thread. It prevents us from trying to
524 // create the background thread after application shutdown has started.
525 static bool sShutdownHasStarted;
526
527 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
528 nsISerialEventTarget* mOwningEventTarget;
529 #endif
530
531 #ifdef DEBUG
532 bool mActorWasAlive;
533 bool mActorDestroyed;
534 #endif
535
536 public:
537 static void Shutdown();
538
AssertIsOnOwningThread()539 void AssertIsOnOwningThread() {
540 THREADSAFETY_ASSERT(mOwningEventTarget);
541
542 #ifdef RELEASE_OR_BETA
543 DebugOnly<bool> current;
544 #else
545 bool current;
546 #endif
547 THREADSAFETY_ASSERT(
548 NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(¤t)));
549 THREADSAFETY_ASSERT(current);
550 }
551
AssertActorDestroyed()552 void AssertActorDestroyed() {
553 MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
554 }
555
ChildImpl()556 explicit ChildImpl()
557 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
558 : mOwningEventTarget(GetCurrentSerialEventTarget())
559 #endif
560 #ifdef DEBUG
561 ,
562 mActorWasAlive(false),
563 mActorDestroyed(false)
564 #endif
565 {
566 AssertIsOnOwningThread();
567 }
568
SetActorAlive()569 void SetActorAlive() {
570 AssertIsOnOwningThread();
571 MOZ_ASSERT(!mActorWasAlive);
572 MOZ_ASSERT(!mActorDestroyed);
573
574 #ifdef DEBUG
575 mActorWasAlive = true;
576 #endif
577 }
578
579 NS_INLINE_DECL_REFCOUNTING(ChildImpl, override)
580
581 private:
582 // Forwarded from BackgroundChild.
583 static void Startup();
584
585 // Forwarded from BackgroundChild.
586 static PBackgroundChild* GetForCurrentThread();
587
588 // Forwarded from BackgroundChild.
589 static PBackgroundChild* GetOrCreateForCurrentThread();
590
591 // Forwarded from BackgroundChild.
592 static PBackgroundChild* GetOrCreateSocketActorForCurrentThread();
593
594 // Forwarded from BackgroundChild.
595 static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread();
596
597 static void CloseForCurrentThread();
598
599 // Forwarded from BackgroundChildImpl.
600 static BackgroundChildImpl::ThreadLocal* GetThreadLocalForCurrentThread();
601
602 // Forwarded from BackgroundChild.
603 static void InitContentStarter(mozilla::dom::ContentChild* aContent);
604
605 // Forwarded from BackgroundChild.
606 static void InitSocketStarter(mozilla::net::SocketProcessChild* aSocket);
607
608 // Forwarded from BackgroundChild.
609 static void InitSocketBridgeStarter(
610 mozilla::net::SocketProcessBridgeChild* aSocketBridge);
611
612 static void ThreadLocalDestructor(void* aThreadLocal);
613
614 // This class is reference counted.
~ChildImpl()615 ~ChildImpl() { MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed); }
616
617 // Only called by IPDL.
618 virtual void ActorDestroy(ActorDestroyReason aWhy) override;
619 };
620
621 // -----------------------------------------------------------------------------
622 // ParentImpl Helper Declarations
623 // -----------------------------------------------------------------------------
624
625 class ParentImpl::ShutdownObserver final : public nsIObserver {
626 public:
ShutdownObserver()627 ShutdownObserver() { AssertIsOnMainThread(); }
628
629 NS_DECL_ISUPPORTS
630 NS_DECL_NSIOBSERVER
631
632 private:
~ShutdownObserver()633 ~ShutdownObserver() { AssertIsOnMainThread(); }
634 };
635
636 // -----------------------------------------------------------------------------
637 // ChildImpl Helper Declarations
638 // -----------------------------------------------------------------------------
639
640 class ChildImpl::ShutdownObserver final : public nsIObserver {
641 public:
ShutdownObserver()642 ShutdownObserver() { AssertIsOnMainThread(); }
643
644 NS_DECL_ISUPPORTS
645 NS_DECL_NSIOBSERVER
646
647 private:
~ShutdownObserver()648 ~ShutdownObserver() { AssertIsOnMainThread(); }
649 };
650
651 } // namespace
652
653 namespace mozilla {
654 namespace ipc {
655
IsOnBackgroundThread()656 bool IsOnBackgroundThread() { return ParentImpl::IsOnBackgroundThread(); }
657
658 #ifdef DEBUG
659
AssertIsOnBackgroundThread()660 void AssertIsOnBackgroundThread() { ParentImpl::AssertIsOnBackgroundThread(); }
661
662 #endif // DEBUG
663
664 } // namespace ipc
665 } // namespace mozilla
666
667 // -----------------------------------------------------------------------------
668 // BackgroundParent Public Methods
669 // -----------------------------------------------------------------------------
670
671 // static
IsOtherProcessActor(PBackgroundParent * aBackgroundActor)672 bool BackgroundParent::IsOtherProcessActor(
673 PBackgroundParent* aBackgroundActor) {
674 return ParentImpl::IsOtherProcessActor(aBackgroundActor);
675 }
676
677 // static
GetContentParent(PBackgroundParent * aBackgroundActor)678 already_AddRefed<ContentParent> BackgroundParent::GetContentParent(
679 PBackgroundParent* aBackgroundActor) {
680 return ParentImpl::GetContentParent(aBackgroundActor);
681 }
682
683 // static
GetRawContentParentForComparison(PBackgroundParent * aBackgroundActor)684 intptr_t BackgroundParent::GetRawContentParentForComparison(
685 PBackgroundParent* aBackgroundActor) {
686 return ParentImpl::GetRawContentParentForComparison(aBackgroundActor);
687 }
688
689 // static
GetChildID(PBackgroundParent * aBackgroundActor)690 uint64_t BackgroundParent::GetChildID(PBackgroundParent* aBackgroundActor) {
691 return ParentImpl::GetChildID(aBackgroundActor);
692 }
693
694 // static
AllocStarter(ContentParent * aContent,Endpoint<PBackgroundStarterParent> && aEndpoint)695 bool BackgroundParent::AllocStarter(
696 ContentParent* aContent, Endpoint<PBackgroundStarterParent>&& aEndpoint) {
697 return ParentImpl::AllocStarter(aContent, std::move(aEndpoint));
698 }
699
700 // -----------------------------------------------------------------------------
701 // BackgroundChild Public Methods
702 // -----------------------------------------------------------------------------
703
704 // static
Startup()705 void BackgroundChild::Startup() { ChildImpl::Startup(); }
706
707 // static
GetForCurrentThread()708 PBackgroundChild* BackgroundChild::GetForCurrentThread() {
709 return ChildImpl::GetForCurrentThread();
710 }
711
712 // static
GetOrCreateForCurrentThread()713 PBackgroundChild* BackgroundChild::GetOrCreateForCurrentThread() {
714 return ChildImpl::GetOrCreateForCurrentThread();
715 }
716
717 // static
GetOrCreateSocketActorForCurrentThread()718 PBackgroundChild* BackgroundChild::GetOrCreateSocketActorForCurrentThread() {
719 return ChildImpl::GetOrCreateSocketActorForCurrentThread();
720 }
721
722 // static
723 PBackgroundChild*
GetOrCreateForSocketParentBridgeForCurrentThread()724 BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread() {
725 return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread();
726 }
727
728 // static
CloseForCurrentThread()729 void BackgroundChild::CloseForCurrentThread() {
730 ChildImpl::CloseForCurrentThread();
731 }
732
733 // static
InitContentStarter(ContentChild * aContent)734 void BackgroundChild::InitContentStarter(ContentChild* aContent) {
735 ChildImpl::InitContentStarter(aContent);
736 }
737
738 // static
InitSocketStarter(net::SocketProcessChild * aSocket)739 void BackgroundChild::InitSocketStarter(net::SocketProcessChild* aSocket) {
740 ChildImpl::InitSocketStarter(aSocket);
741 }
742
743 // static
InitSocketBridgeStarter(net::SocketProcessBridgeChild * aSocketBridge)744 void BackgroundChild::InitSocketBridgeStarter(
745 net::SocketProcessBridgeChild* aSocketBridge) {
746 ChildImpl::InitSocketBridgeStarter(aSocketBridge);
747 }
748
749 // -----------------------------------------------------------------------------
750 // BackgroundChildImpl Public Methods
751 // -----------------------------------------------------------------------------
752
753 // static
754 BackgroundChildImpl::ThreadLocal*
GetThreadLocalForCurrentThread()755 BackgroundChildImpl::GetThreadLocalForCurrentThread() {
756 return ChildImpl::GetThreadLocalForCurrentThread();
757 }
758
759 // -----------------------------------------------------------------------------
760 // ParentImpl Static Members
761 // -----------------------------------------------------------------------------
762
763 StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread;
764
765 nsTArray<IToplevelProtocol*>* ParentImpl::sLiveActorsForBackgroundThread;
766
767 StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer;
768
769 Atomic<PRThread*> ParentImpl::sBackgroundPRThread;
770
771 Atomic<uint64_t> ParentImpl::sLiveActorCount;
772
773 bool ParentImpl::sShutdownObserverRegistered = false;
774
775 bool ParentImpl::sShutdownHasStarted = false;
776
777 // -----------------------------------------------------------------------------
778 // ChildImpl Static Members
779 // -----------------------------------------------------------------------------
780
781 ChildImpl::ThreadInfoWrapper ChildImpl::sParentAndContentProcessThreadInfo;
782
783 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndContentProcessThreadInfo;
784
785 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndParentProcessThreadInfo;
786
787 bool ChildImpl::sShutdownHasStarted = false;
788
789 // -----------------------------------------------------------------------------
790 // ParentImpl Implementation
791 // -----------------------------------------------------------------------------
792
793 // static
IsOtherProcessActor(PBackgroundParent * aBackgroundActor)794 bool ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor) {
795 AssertIsOnBackgroundThread();
796 MOZ_ASSERT(aBackgroundActor);
797
798 return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
799 }
800
801 // static
GetContentParent(PBackgroundParent * aBackgroundActor)802 already_AddRefed<ContentParent> ParentImpl::GetContentParent(
803 PBackgroundParent* aBackgroundActor) {
804 AssertIsOnBackgroundThread();
805 MOZ_ASSERT(aBackgroundActor);
806
807 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
808 if (actor->mActorDestroyed) {
809 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
810 return nullptr;
811 }
812
813 if (actor->mContent) {
814 // We need to hand out a reference to our ContentParent but we also need to
815 // keep the one we have. We can't call AddRef here because ContentParent is
816 // not threadsafe so instead we dispatch a runnable to the main thread to do
817 // it for us. This is safe since we are guaranteed that our AddRef runnable
818 // will run before the reference we hand out can be released, and the
819 // ContentParent can't die as long as the existing reference is maintained.
820 //
821 // XXX: Why can't we use `nsMainThreadPtrHandle` here instead?
822 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewNonOwningRunnableMethod(
823 "ContentParent::AddRef", actor->mContent, &ContentParent::AddRef)));
824 }
825
826 return already_AddRefed<ContentParent>(actor->mContent.get());
827 }
828
829 // static
GetRawContentParentForComparison(PBackgroundParent * aBackgroundActor)830 intptr_t ParentImpl::GetRawContentParentForComparison(
831 PBackgroundParent* aBackgroundActor) {
832 AssertIsOnBackgroundThread();
833 MOZ_ASSERT(aBackgroundActor);
834
835 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
836 if (actor->mActorDestroyed) {
837 MOZ_ASSERT(false,
838 "GetRawContentParentForComparison called after ActorDestroy was "
839 "called!");
840 return intptr_t(-1);
841 }
842
843 return intptr_t(static_cast<ContentParent*>(actor->mContent.get()));
844 }
845
846 // static
GetChildID(PBackgroundParent * aBackgroundActor)847 uint64_t ParentImpl::GetChildID(PBackgroundParent* aBackgroundActor) {
848 AssertIsOnBackgroundThread();
849 MOZ_ASSERT(aBackgroundActor);
850
851 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
852 if (actor->mActorDestroyed) {
853 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
854 return 0;
855 }
856
857 if (actor->mContent) {
858 return actor->mContent->ChildID();
859 }
860
861 return 0;
862 }
863
864 // static
AllocStarter(ContentParent * aContent,Endpoint<PBackgroundStarterParent> && aEndpoint,bool aCrossProcess)865 bool ParentImpl::AllocStarter(ContentParent* aContent,
866 Endpoint<PBackgroundStarterParent>&& aEndpoint,
867 bool aCrossProcess) {
868 AssertIsInMainOrSocketProcess();
869 AssertIsOnMainThread();
870
871 MOZ_ASSERT(aEndpoint.IsValid());
872
873 if (!sBackgroundThread && !CreateBackgroundThread()) {
874 NS_WARNING("Failed to create background thread!");
875 return false;
876 }
877
878 sLiveActorCount++;
879
880 RefPtr<BackgroundStarterParent> actor =
881 new BackgroundStarterParent(aContent, aCrossProcess);
882
883 if (NS_FAILED(sBackgroundThread->Dispatch(NS_NewRunnableFunction(
884 "BackgroundStarterParent::ConnectActorRunnable",
885 [actor = std::move(actor), endpoint = std::move(aEndpoint),
886 liveActorArray = sLiveActorsForBackgroundThread]() mutable {
887 MOZ_ASSERT(endpoint.IsValid());
888 MOZ_ALWAYS_TRUE(endpoint.Bind(actor));
889 actor->SetLiveActorArray(liveActorArray);
890 })))) {
891 NS_WARNING("Failed to dispatch connect runnable!");
892
893 MOZ_ASSERT(sLiveActorCount);
894 sLiveActorCount--;
895 }
896
897 return true;
898 }
899
900 // static
CreateBackgroundThread()901 bool ParentImpl::CreateBackgroundThread() {
902 AssertIsInMainOrSocketProcess();
903 AssertIsOnMainThread();
904 MOZ_ASSERT(!sBackgroundThread);
905 MOZ_ASSERT(!sLiveActorsForBackgroundThread);
906
907 if (sShutdownHasStarted) {
908 NS_WARNING(
909 "Trying to create background thread after shutdown has "
910 "already begun!");
911 return false;
912 }
913
914 nsCOMPtr<nsITimer> newShutdownTimer;
915
916 if (!sShutdownTimer) {
917 newShutdownTimer = NS_NewTimer();
918 if (!newShutdownTimer) {
919 return false;
920 }
921 }
922
923 if (!sShutdownObserverRegistered) {
924 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
925 if (NS_WARN_IF(!obs)) {
926 return false;
927 }
928
929 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
930
931 nsresult rv = obs->AddObserver(
932 observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
933 if (NS_WARN_IF(NS_FAILED(rv))) {
934 return false;
935 }
936
937 sShutdownObserverRegistered = true;
938 }
939
940 nsCOMPtr<nsIThread> thread;
941 if (NS_FAILED(NS_NewNamedThread(
942 "IPDL Background", getter_AddRefs(thread),
943 NS_NewRunnableFunction(
944 "Background::ParentImpl::CreateBackgroundThreadRunnable", []() {
945 DebugOnly<PRThread*> oldBackgroundThread =
946 sBackgroundPRThread.exchange(PR_GetCurrentThread());
947
948 MOZ_ASSERT_IF(oldBackgroundThread,
949 PR_GetCurrentThread() != oldBackgroundThread);
950 })))) {
951 NS_WARNING("NS_NewNamedThread failed!");
952 return false;
953 }
954
955 sBackgroundThread = thread.forget();
956
957 sLiveActorsForBackgroundThread = new nsTArray<IToplevelProtocol*>(1);
958
959 if (!sShutdownTimer) {
960 MOZ_ASSERT(newShutdownTimer);
961 sShutdownTimer = newShutdownTimer;
962 }
963
964 return true;
965 }
966
967 // static
ShutdownBackgroundThread()968 void ParentImpl::ShutdownBackgroundThread() {
969 AssertIsInMainOrSocketProcess();
970 AssertIsOnMainThread();
971 MOZ_ASSERT(sShutdownHasStarted);
972 MOZ_ASSERT_IF(!sBackgroundThread, !sLiveActorCount);
973 MOZ_ASSERT_IF(sBackgroundThread, sShutdownTimer);
974
975 nsCOMPtr<nsITimer> shutdownTimer = sShutdownTimer.get();
976 sShutdownTimer = nullptr;
977
978 if (sBackgroundThread) {
979 nsCOMPtr<nsIThread> thread = sBackgroundThread.get();
980 sBackgroundThread = nullptr;
981
982 UniquePtr<nsTArray<IToplevelProtocol*>> liveActors(
983 sLiveActorsForBackgroundThread);
984 sLiveActorsForBackgroundThread = nullptr;
985
986 MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
987
988 if (sLiveActorCount) {
989 // We need to spin the event loop while we wait for all the actors to be
990 // cleaned up. We also set a timeout to force-kill any hanging actors.
991 TimerCallbackClosure closure(thread, liveActors.get());
992
993 MOZ_ALWAYS_SUCCEEDS(shutdownTimer->InitWithNamedFuncCallback(
994 &ShutdownTimerCallback, &closure, kShutdownTimerDelayMS,
995 nsITimer::TYPE_ONE_SHOT, "ParentImpl::ShutdownTimerCallback"));
996
997 SpinEventLoopUntil("ParentImpl::ShutdownBackgroundThread"_ns,
998 [&]() { return !sLiveActorCount; });
999
1000 MOZ_ASSERT(liveActors->IsEmpty());
1001
1002 MOZ_ALWAYS_SUCCEEDS(shutdownTimer->Cancel());
1003 }
1004
1005 // Dispatch this runnable to unregister the PR thread from the profiler.
1006 MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(NS_NewRunnableFunction(
1007 "Background::ParentImpl::ShutdownBackgroundThreadRunnable", []() {
1008 // It is possible that another background thread was created while
1009 // this thread was shutting down. In that case we can't assert
1010 // anything about sBackgroundPRThread and we should not modify it
1011 // here.
1012 sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
1013 })));
1014
1015 MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
1016 }
1017 }
1018
1019 // static
ShutdownTimerCallback(nsITimer * aTimer,void * aClosure)1020 void ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure) {
1021 AssertIsInMainOrSocketProcess();
1022 AssertIsOnMainThread();
1023 MOZ_ASSERT(sShutdownHasStarted);
1024 MOZ_ASSERT(sLiveActorCount);
1025
1026 auto closure = static_cast<TimerCallbackClosure*>(aClosure);
1027 MOZ_ASSERT(closure);
1028
1029 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
1030 // finished.
1031 sLiveActorCount++;
1032
1033 InvokeAsync(
1034 closure->mThread, __func__,
1035 [liveActors = closure->mLiveActors]() {
1036 MOZ_ASSERT(liveActors);
1037
1038 if (!liveActors->IsEmpty()) {
1039 // Copy the array since calling Close() could mutate the
1040 // actual array.
1041 nsTArray<IToplevelProtocol*> actorsToClose(liveActors->Clone());
1042 for (IToplevelProtocol* actor : actorsToClose) {
1043 actor->Close();
1044 }
1045 }
1046 return GenericPromise::CreateAndResolve(true, __func__);
1047 })
1048 ->Then(GetCurrentSerialEventTarget(), __func__, []() {
1049 MOZ_ASSERT(sLiveActorCount);
1050 sLiveActorCount--;
1051 });
1052 }
1053
Destroy()1054 void ParentImpl::Destroy() {
1055 // May be called on any thread!
1056
1057 AssertIsInMainOrSocketProcess();
1058
1059 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1060 NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy", this,
1061 &ParentImpl::MainThreadActorDestroy)));
1062 }
1063
MainThreadActorDestroy()1064 void ParentImpl::MainThreadActorDestroy() {
1065 AssertIsInMainOrSocketProcess();
1066 AssertIsOnMainThread();
1067 MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
1068
1069 mContent = nullptr;
1070
1071 MOZ_ASSERT(sLiveActorCount);
1072 sLiveActorCount--;
1073
1074 // This may be the last reference!
1075 Release();
1076 }
1077
ActorDestroy(ActorDestroyReason aWhy)1078 void ParentImpl::ActorDestroy(ActorDestroyReason aWhy) {
1079 AssertIsInMainOrSocketProcess();
1080 AssertIsOnBackgroundThread();
1081 MOZ_ASSERT(!mActorDestroyed);
1082 MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
1083
1084 BackgroundParentImpl::ActorDestroy(aWhy);
1085
1086 mActorDestroyed = true;
1087
1088 if (mLiveActorArray) {
1089 MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1090 mLiveActorArray = nullptr;
1091 }
1092
1093 // This is tricky. We should be able to call Destroy() here directly because
1094 // we're not going to touch 'this' or our MessageChannel any longer on this
1095 // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1096 // it runs it will destroy 'this' and our associated MessageChannel. However,
1097 // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1098 // racing with the main thread we must ensure that the MessageChannel lives
1099 // long enough to be cleared in this call stack.
1100
1101 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(
1102 "ParentImpl::Destroy", this, &ParentImpl::Destroy)));
1103 }
1104
NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver,nsIObserver)1105 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver)
1106
1107 NS_IMETHODIMP
1108 ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1109 const char16_t* aData) {
1110 AssertIsInMainOrSocketProcess();
1111 AssertIsOnMainThread();
1112 MOZ_ASSERT(!sShutdownHasStarted);
1113 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1114
1115 sShutdownHasStarted = true;
1116
1117 // Do this first before calling (and spinning the event loop in)
1118 // ShutdownBackgroundThread().
1119 ChildImpl::Shutdown();
1120
1121 ShutdownBackgroundThread();
1122
1123 return NS_OK;
1124 }
1125
BackgroundStarterParent(ContentParent * aContent,bool aCrossProcess)1126 BackgroundStarterParent::BackgroundStarterParent(ContentParent* aContent,
1127 bool aCrossProcess)
1128 : mCrossProcess(aCrossProcess), mContent(aContent) {
1129 AssertIsOnMainThread();
1130 AssertIsInMainOrSocketProcess();
1131 MOZ_ASSERT_IF(!mCrossProcess, !mContent);
1132 MOZ_ASSERT_IF(!mCrossProcess, XRE_IsParentProcess());
1133 }
1134
SetLiveActorArray(nsTArray<IToplevelProtocol * > * aLiveActorArray)1135 void BackgroundStarterParent::SetLiveActorArray(
1136 nsTArray<IToplevelProtocol*>* aLiveActorArray) {
1137 AssertIsInMainOrSocketProcess();
1138 AssertIsOnBackgroundThread();
1139 MOZ_ASSERT(aLiveActorArray);
1140 MOZ_ASSERT(!aLiveActorArray->Contains(this));
1141 MOZ_ASSERT(!mLiveActorArray);
1142 MOZ_ASSERT_IF(!mCrossProcess, OtherPid() == base::GetCurrentProcId());
1143
1144 mLiveActorArray = aLiveActorArray;
1145 mLiveActorArray->AppendElement(this);
1146 }
1147
RecvInitBackground(Endpoint<PBackgroundParent> && aEndpoint)1148 IPCResult BackgroundStarterParent::RecvInitBackground(
1149 Endpoint<PBackgroundParent>&& aEndpoint) {
1150 AssertIsOnBackgroundThread();
1151
1152 if (!aEndpoint.IsValid()) {
1153 return IPC_FAIL(this,
1154 "Cannot initialize PBackground with invalid endpoint");
1155 }
1156
1157 if (mContent) {
1158 // We need to hand out a reference to our ContentParent for the new
1159 // ParentImpl actor, but we also need to keep the one we have. We can't call
1160 // AddRef here because ContentParent is not threadsafe so instead we
1161 // dispatch a runnable to the main thread to do it for us. This is safe
1162 // since we are guaranteed that our AddRef runnable will run before the
1163 // reference we hand out can be released, and the ContentParent can't die as
1164 // long as the existing reference is maintained.
1165 //
1166 // XXX: Why can't we use `nsMainThreadPtrHandle` here?
1167 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewNonOwningRunnableMethod(
1168 "ContentParent::AddRef", mContent, &ContentParent::AddRef)));
1169 }
1170
1171 ParentImpl* actor = new ParentImpl(
1172 already_AddRefed<ContentParent>(mContent.get()), mCrossProcess);
1173
1174 // Take a reference on this thread. If Open() fails then we will release this
1175 // reference in Destroy.
1176 NS_ADDREF(actor);
1177
1178 ParentImpl::sLiveActorCount++;
1179
1180 if (!aEndpoint.Bind(actor)) {
1181 actor->Destroy();
1182 return IPC_OK();
1183 }
1184
1185 if (mCrossProcess) {
1186 actor->SetLiveActorArray(mLiveActorArray);
1187 }
1188 return IPC_OK();
1189 }
1190
ActorDestroy(ActorDestroyReason aReason)1191 void BackgroundStarterParent::ActorDestroy(ActorDestroyReason aReason) {
1192 AssertIsOnBackgroundThread();
1193
1194 if (mLiveActorArray) {
1195 MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1196 mLiveActorArray = nullptr;
1197 }
1198
1199 // Make sure to decrement `sLiveActorCount` on the main thread.
1200 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NS_NewRunnableFunction(
1201 "BackgroundStarterParent::MainThreadDestroy", [self = RefPtr{this}] {
1202 self->mContent = nullptr;
1203 ParentImpl::sLiveActorCount--;
1204 })));
1205 }
1206
1207 // -----------------------------------------------------------------------------
1208 // ChildImpl Implementation
1209 // -----------------------------------------------------------------------------
1210
1211 // static
Startup()1212 void ChildImpl::Startup() {
1213 // This happens on the main thread but before XPCOM has started so we can't
1214 // assert that we're being called on the main thread here.
1215
1216 sParentAndContentProcessThreadInfo.Startup();
1217 sSocketAndContentProcessThreadInfo.Startup();
1218 sSocketAndParentProcessThreadInfo.Startup();
1219
1220 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1221 MOZ_RELEASE_ASSERT(observerService);
1222
1223 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1224
1225 nsresult rv = observerService->AddObserver(
1226 observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1227 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
1228
1229 // Initialize a starter actor to allow starting PBackground within the parent
1230 // process.
1231 if (XRE_IsParentProcess()) {
1232 Endpoint<PBackgroundStarterParent> parent;
1233 Endpoint<PBackgroundStarterChild> child;
1234 MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints(
1235 base::GetCurrentProcId(), base::GetCurrentProcId(), &parent, &child));
1236
1237 MOZ_ALWAYS_TRUE(ParentImpl::AllocStarter(nullptr, std::move(parent),
1238 /* aCrossProcess */ false));
1239 sParentAndContentProcessThreadInfo.InitStarter(std::move(child));
1240 }
1241 }
1242
1243 // static
Shutdown()1244 void ChildImpl::Shutdown() {
1245 AssertIsOnMainThread();
1246
1247 sParentAndContentProcessThreadInfo.Shutdown();
1248 sSocketAndContentProcessThreadInfo.Shutdown();
1249 sSocketAndParentProcessThreadInfo.Shutdown();
1250
1251 sShutdownHasStarted = true;
1252 }
1253
1254 // static
GetForCurrentThread()1255 PBackgroundChild* ChildImpl::GetForCurrentThread() {
1256 MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1257 kBadThreadLocalIndex);
1258
1259 auto threadLocalInfo =
1260 NS_IsMainThread()
1261 ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1262 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1263 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1264
1265 if (!threadLocalInfo) {
1266 return nullptr;
1267 }
1268
1269 return threadLocalInfo->mActor;
1270 }
1271
1272 /* static */
GetOrCreateForCurrentThread()1273 PBackgroundChild* ChildImpl::GetOrCreateForCurrentThread() {
1274 return sParentAndContentProcessThreadInfo.GetOrCreateForCurrentThread();
1275 }
1276
1277 /* static */
GetOrCreateSocketActorForCurrentThread()1278 PBackgroundChild* ChildImpl::GetOrCreateSocketActorForCurrentThread() {
1279 return sSocketAndContentProcessThreadInfo.GetOrCreateForCurrentThread();
1280 }
1281
1282 /* static */
1283 PBackgroundChild*
GetOrCreateForSocketParentBridgeForCurrentThread()1284 ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread() {
1285 return sSocketAndParentProcessThreadInfo.GetOrCreateForCurrentThread();
1286 }
1287
1288 // static
CloseForCurrentThread()1289 void ChildImpl::CloseForCurrentThread() {
1290 MOZ_ASSERT(!NS_IsMainThread(),
1291 "PBackground for the main thread should be shut down via "
1292 "ChildImpl::Shutdown().");
1293
1294 sParentAndContentProcessThreadInfo.CloseForCurrentThread();
1295 sSocketAndContentProcessThreadInfo.CloseForCurrentThread();
1296 sSocketAndParentProcessThreadInfo.CloseForCurrentThread();
1297 }
1298
1299 // static
GetThreadLocalForCurrentThread()1300 BackgroundChildImpl::ThreadLocal* ChildImpl::GetThreadLocalForCurrentThread() {
1301 MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1302 kBadThreadLocalIndex,
1303 "BackgroundChild::Startup() was never called!");
1304
1305 auto threadLocalInfo =
1306 NS_IsMainThread()
1307 ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1308 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1309 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1310
1311 if (!threadLocalInfo) {
1312 return nullptr;
1313 }
1314
1315 if (!threadLocalInfo->mConsumerThreadLocal) {
1316 threadLocalInfo->mConsumerThreadLocal =
1317 MakeUnique<BackgroundChildImpl::ThreadLocal>();
1318 }
1319
1320 return threadLocalInfo->mConsumerThreadLocal.get();
1321 }
1322
1323 // static
InitContentStarter(mozilla::dom::ContentChild * aContent)1324 void ChildImpl::InitContentStarter(mozilla::dom::ContentChild* aContent) {
1325 sParentAndContentProcessThreadInfo.InitStarter(aContent);
1326 }
1327
1328 // static
InitSocketStarter(mozilla::net::SocketProcessChild * aSocket)1329 void ChildImpl::InitSocketStarter(mozilla::net::SocketProcessChild* aSocket) {
1330 sSocketAndParentProcessThreadInfo.InitStarter(aSocket);
1331 }
1332
1333 // static
InitSocketBridgeStarter(mozilla::net::SocketProcessBridgeChild * aSocketBridge)1334 void ChildImpl::InitSocketBridgeStarter(
1335 mozilla::net::SocketProcessBridgeChild* aSocketBridge) {
1336 sSocketAndContentProcessThreadInfo.InitStarter(aSocketBridge);
1337 }
1338
1339 // static
ThreadLocalDestructor(void * aThreadLocal)1340 void ChildImpl::ThreadLocalDestructor(void* aThreadLocal) {
1341 auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
1342
1343 if (threadLocalInfo) {
1344 MOZ_ASSERT(threadLocalInfo->mClosed);
1345
1346 if (threadLocalInfo->mActor) {
1347 threadLocalInfo->mActor->Close();
1348 threadLocalInfo->mActor->AssertActorDestroyed();
1349 }
1350
1351 delete threadLocalInfo;
1352 }
1353 }
1354
ActorDestroy(ActorDestroyReason aWhy)1355 void ChildImpl::ActorDestroy(ActorDestroyReason aWhy) {
1356 AssertIsOnOwningThread();
1357
1358 #ifdef DEBUG
1359 MOZ_ASSERT(!mActorDestroyed);
1360 mActorDestroyed = true;
1361 #endif
1362
1363 BackgroundChildImpl::ActorDestroy(aWhy);
1364 }
1365
NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver,nsIObserver)1366 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
1367
1368 NS_IMETHODIMP
1369 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1370 const char16_t* aData) {
1371 AssertIsOnMainThread();
1372 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1373
1374 ChildImpl::Shutdown();
1375
1376 return NS_OK;
1377 }
1378