ipc/glue/BackgroundImpl.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:9dfa26805785
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "base/process_util.h"
6 #include "mozilla/Assertions.h"
7 #include "mozilla/Atomics.h"
8 #include "mozilla/ClearOnShutdown.h"
9 #include "mozilla/DebugOnly.h"
10 #include "mozilla/Services.h"
11 #include "mozilla/StaticPtr.h"
12 #include "mozilla/unused.h"
13 #include "mozilla/dom/ContentChild.h"
14 #include "mozilla/dom/ContentParent.h"
15 #include "mozilla/ipc/ProtocolTypes.h"
16 #include "BackgroundChild.h"
17 #include "BackgroundChildImpl.h"
18 #include "BackgroundParent.h"
19 #include "BackgroundParentImpl.h"
20 #include "GeckoProfiler.h"
21 #include "nsAutoPtr.h"
22 #include "nsCOMPtr.h"
23 #include "nsIEventTarget.h"
24 #include "nsIIPCBackgroundChildCreateCallback.h"
25 #include "nsIObserver.h"
26 #include "nsIObserverService.h"
27 #include "nsIRunnable.h"
28 #include "nsISupportsImpl.h"
29 #include "nsIThread.h"
30 #include "nsITimer.h"
31 #include "nsTArray.h"
32 #include "nsThreadUtils.h"
33 #include "nsTraceRefcnt.h"
34 #include "nsXULAppAPI.h"
35 #include "nsXPCOMPrivate.h"
36 #include "prthread.h"
37
38 #ifdef RELEASE_BUILD
39 #define THREADSAFETY_ASSERT MOZ_ASSERT
40 #else
41 #define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
42 #endif
43
44 #define CRASH_IN_CHILD_PROCESS(_msg) \
45 do { \
46 if (IsMainProcess()) { \
47 MOZ_ASSERT(false, _msg); \
48 } else { \
49 MOZ_CRASH(_msg); \
50 } \
51 } \
52 while (0)
53
54 using namespace mozilla;
55 using namespace mozilla::ipc;
56
57 using mozilla::dom::ContentChild;
58 using mozilla::dom::ContentParent;
59
60 namespace {
61
62 // -----------------------------------------------------------------------------
63 // Utility Functions
64 // -----------------------------------------------------------------------------
65
66 bool
67 IsMainProcess()
68 {
69 static const bool isMainProcess =
70 XRE_GetProcessType() == GeckoProcessType_Default;
71 return isMainProcess;
72 }
73
74 bool
75 IsChildProcess()
76 {
77 return !IsMainProcess();
78 }
79
80 void
81 AssertIsInMainProcess()
82 {
83 MOZ_ASSERT(IsMainProcess());
84 }
85
86 void
87 AssertIsInChildProcess()
88 {
89 MOZ_ASSERT(IsChildProcess());
90 }
91
92 void
93 AssertIsOnMainThread()
94 {
95 THREADSAFETY_ASSERT(NS_IsMainThread());
96 }
97
98 // -----------------------------------------------------------------------------
99 // ParentImpl Declaration
100 // -----------------------------------------------------------------------------
101
102 class ParentImpl MOZ_FINAL : public BackgroundParentImpl
103 {
104 friend class mozilla::ipc::BackgroundParent;
105
106 public:
107 class CreateCallback;
108
109 private:
110 class ShutdownObserver;
111 class RequestMessageLoopRunnable;
112 class ShutdownBackgroundThreadRunnable;
113 class ForceCloseBackgroundActorsRunnable;
114 class CreateCallbackRunnable;
115 class ConnectActorRunnable;
116
117 struct MOZ_STACK_CLASS TimerCallbackClosure
118 {
119 nsIThread* mThread;
120 nsTArray<ParentImpl*>* mLiveActors;
121
122 TimerCallbackClosure(nsIThread* aThread, nsTArray<ParentImpl*>* aLiveActors)
123 : mThread(aThread), mLiveActors(aLiveActors)
124 {
125 AssertIsInMainProcess();
126 AssertIsOnMainThread();
127 MOZ_ASSERT(aThread);
128 MOZ_ASSERT(aLiveActors);
129 }
130 };
131
132 // A handle that is invalid on any platform.
133 static const ProcessHandle kInvalidProcessHandle;
134
135 // The length of time we will wait at shutdown for all actors to clean
136 // themselves up before forcing them to be destroyed.
137 static const uint32_t kShutdownTimerDelayMS = 10000;
138
139 // This is only modified on the main thread. It is null if the thread does not
140 // exist or is shutting down.
141 static StaticRefPtr<nsIThread> sBackgroundThread;
142
143 // This is created and destroyed on the main thread but only modified on the
144 // background thread. It is specific to each instance of sBackgroundThread.
145 static nsTArray<ParentImpl*>* sLiveActorsForBackgroundThread;
146
147 // This is only modified on the main thread.
148 static StaticRefPtr<nsITimer> sShutdownTimer;
149
150 // This exists so that that [Assert]IsOnBackgroundThread() can continue to
151 // work during shutdown.
152 static Atomic<PRThread*> sBackgroundPRThread;
153
154 // This is only modified on the main thread. It is null if the thread does not
155 // exist or is shutting down.
156 static MessageLoop* sBackgroundThreadMessageLoop;
157
158 // This is only modified on the main thread. It maintains a count of live
159 // actors so that the background thread can be shut down when it is no longer
160 // needed.
161 static uint64_t sLiveActorCount;
162
163 // This is only modified on the main thread. It is true after the shutdown
164 // observer is registered and is never unset thereafter.
165 static bool sShutdownObserverRegistered;
166
167 // This is only modified on the main thread. It prevents us from trying to
168 // create the background thread after application shutdown has started.
169 static bool sShutdownHasStarted;
170
171 // This is only modified on the main thread. It is a FIFO queue for callbacks
172 // waiting for the background thread to be created.
173 static StaticAutoPtr<nsTArray<nsRefPtr<CreateCallback>>> sPendingCallbacks;
174
175 // Only touched on the main thread, null if this is a same-process actor.
176 nsRefPtr<ContentParent> mContent;
177
178 // mTransport is "owned" by this object but it must only be released on the
179 // IPC thread. It's left as a raw pointer here to prevent accidentally
180 // deleting it on the wrong thread. Only non-null for other-process actors.
181 Transport* mTransport;
182
183 // Set when the actor is opened successfully and used to handle shutdown
184 // hangs. Only touched on the background thread.
185 nsTArray<ParentImpl*>* mLiveActorArray;
186
187 // Set at construction to indicate whether this parent actor corresponds to a
188 // child actor in another process or to a child actor from a different thread
189 // in the same process.
190 const bool mIsOtherProcessActor;
191
192 // Set after ActorDestroy has been called. Only touched on the background
193 // thread.
194 bool mActorDestroyed;
195
196 public:
197 static bool
198 CreateActorForSameProcess(CreateCallback* aCallback);
199
200 static bool
201 IsOnBackgroundThread()
202 {
203 return PR_GetCurrentThread() == sBackgroundPRThread;
204 }
205
206 static void
207 AssertIsOnBackgroundThread()
208 {
209 THREADSAFETY_ASSERT(IsOnBackgroundThread());
210 }
211
212 NS_INLINE_DECL_REFCOUNTING(ParentImpl)
213
214 void
215 Destroy();
216
217 private:
218 // Forwarded from BackgroundParent.
219 static bool
220 IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
221
222 // Forwarded from BackgroundParent.
223 static already_AddRefed<ContentParent>
224 GetContentParent(PBackgroundParent* aBackgroundActor);
225
226 // Forwarded from BackgroundParent.
227 static PBackgroundParent*
228 Alloc(ContentParent* aContent,
229 Transport* aTransport,
230 ProcessId aOtherProcess);
231
232 static bool
233 CreateBackgroundThread();
234
235 static void
236 ShutdownBackgroundThread();
237
238 static void
239 ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
240
241 // For same-process actors.
242 ParentImpl()
243 : mTransport(nullptr), mLiveActorArray(nullptr), mIsOtherProcessActor(false),
244 mActorDestroyed(false)
245 {
246 AssertIsInMainProcess();
247 AssertIsOnMainThread();
248
249 SetOtherProcess(kInvalidProcessHandle);
250 }
251
252 // For other-process actors.
253 ParentImpl(ContentParent* aContent, Transport* aTransport)
254 : mContent(aContent), mTransport(aTransport), mLiveActorArray(nullptr),
255 mIsOtherProcessActor(true), mActorDestroyed(false)
256 {
257 AssertIsInMainProcess();
258 AssertIsOnMainThread();
259 MOZ_ASSERT(aContent);
260 MOZ_ASSERT(aTransport);
261 }
262
263 ~ParentImpl()
264 {
265 AssertIsInMainProcess();
266 AssertIsOnMainThread();
267 MOZ_ASSERT(!mContent);
268 MOZ_ASSERT(!mTransport);
269 }
270
271 void
272 MainThreadActorDestroy();
273
274 void
275 SetLiveActorArray(nsTArray<ParentImpl*>* aLiveActorArray)
276 {
277 AssertIsInMainProcess();
278 AssertIsOnBackgroundThread();
279 MOZ_ASSERT(aLiveActorArray);
280 MOZ_ASSERT(!aLiveActorArray->Contains(this));
281 MOZ_ASSERT(!mLiveActorArray);
282 MOZ_ASSERT(mIsOtherProcessActor);
283
284 mLiveActorArray = aLiveActorArray;
285 mLiveActorArray->AppendElement(this);
286 }
287
288 // These methods are only called by IPDL.
289 virtual IToplevelProtocol*
290 CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
291 ProcessHandle aPeerProcess,
292 ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
293
294 virtual void
295 ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
296 };
297
298 // -----------------------------------------------------------------------------
299 // ChildImpl Declaration
300 // -----------------------------------------------------------------------------
301
302 class ChildImpl MOZ_FINAL : public BackgroundChildImpl
303 {
304 friend class mozilla::ipc::BackgroundChild;
305 friend class mozilla::ipc::BackgroundChildImpl;
306
307 typedef base::ProcessId ProcessId;
308 typedef mozilla::ipc::Transport Transport;
309
310 class ShutdownObserver;
311 class CreateActorRunnable;
312 class ParentCreateCallback;
313 class CreateCallbackRunnable;
314 class OpenChildProcessActorRunnable;
315 class OpenMainProcessActorRunnable;
316
317 // A thread-local index that is not valid.
318 static const unsigned int kBadThreadLocalIndex =
319 static_cast<unsigned int>(-1);
320
321 // This is only modified on the main thread. It is the thread-local index that
322 // we use to store the BackgroundChild for each thread.
323 static unsigned int sThreadLocalIndex;
324
325 struct ThreadLocalInfo
326 {
327 ThreadLocalInfo(nsIIPCBackgroundChildCreateCallback* aCallback)
328 {
329 mCallbacks.AppendElement(aCallback);
330 }
331
332 nsRefPtr<ChildImpl> mActor;
333 nsTArray<nsCOMPtr<nsIIPCBackgroundChildCreateCallback>> mCallbacks;
334 nsAutoPtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal;
335 };
336
337 // This is only modified on the main thread. It is a FIFO queue for actors
338 // that are in the process of construction.
339 static StaticAutoPtr<nsTArray<nsCOMPtr<nsIEventTarget>>> sPendingTargets;
340
341 // This is only modified on the main thread. It prevents us from trying to
342 // create the background thread after application shutdown has started.
343 static bool sShutdownHasStarted;
344
345 #ifdef RELEASE_BUILD
346 DebugOnly<nsIThread*> mBoundThread;
347 #else
348 nsIThread* mBoundThread;
349 #endif
350
351 public:
352 static bool
353 OpenProtocolOnMainThread(nsIEventTarget* aEventTarget);
354
355 static void
356 Shutdown();
357
358 void
359 AssertIsOnBoundThread()
360 {
361 THREADSAFETY_ASSERT(mBoundThread);
362
363 #ifdef RELEASE_BUILD
364 DebugOnly<bool> current;
365 #else
366 bool current;
367 #endif
368 THREADSAFETY_ASSERT(
369 NS_SUCCEEDED(mBoundThread->IsOnCurrentThread(&current)));
370 THREADSAFETY_ASSERT(current);
371 }
372
373 ChildImpl()
374 : mBoundThread(nullptr)
375 {
376 AssertIsOnMainThread();
377 }
378
379 NS_INLINE_DECL_REFCOUNTING(ChildImpl)
380
381 private:
382 // Forwarded from BackgroundChild.
383 static void
384 Startup();
385
386 // Forwarded from BackgroundChild.
387 static PBackgroundChild*
388 Alloc(Transport* aTransport, ProcessId aOtherProcess);
389
390 // Forwarded from BackgroundChild.
391 static PBackgroundChild*
392 GetForCurrentThread();
393
394 // Forwarded from BackgroundChild.
395 static bool
396 GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
397
398 // Forwarded from BackgroundChildImpl.
399 static BackgroundChildImpl::ThreadLocal*
400 GetThreadLocalForCurrentThread();
401
402 static void
403 ThreadLocalDestructor(void* aThreadLocal)
404 {
405 auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
406
407 if (threadLocalInfo) {
408 if (threadLocalInfo->mActor) {
409 threadLocalInfo->mActor->Close();
410 }
411 delete threadLocalInfo;
412 }
413 }
414
415 static void
416 DispatchFailureCallback(nsIEventTarget* aEventTarget);
417
418 // This class is reference counted.
419 ~ChildImpl()
420 { }
421
422 void
423 SetBoundThread()
424 {
425 THREADSAFETY_ASSERT(!mBoundThread);
426
427 #if defined(DEBUG) || !defined(RELEASE_BUILD)
428 mBoundThread = NS_GetCurrentThread();
429 #endif
430
431 THREADSAFETY_ASSERT(mBoundThread);
432 }
433
434 // Only called by IPDL.
435 virtual void
436 ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
437 };
438
439 // -----------------------------------------------------------------------------
440 // ParentImpl Helper Declarations
441 // -----------------------------------------------------------------------------
442
443 class ParentImpl::ShutdownObserver MOZ_FINAL : public nsIObserver
444 {
445 public:
446 ShutdownObserver()
447 {
448 AssertIsOnMainThread();
449 }
450
451 NS_DECL_ISUPPORTS
452 NS_DECL_NSIOBSERVER
453
454 private:
455 ~ShutdownObserver()
456 {
457 AssertIsOnMainThread();
458 }
459 };
460
461 class ParentImpl::RequestMessageLoopRunnable MOZ_FINAL :
462 public nsRunnable
463 {
464 nsCOMPtr<nsIThread> mTargetThread;
465 MessageLoop* mMessageLoop;
466
467 public:
468 RequestMessageLoopRunnable(nsIThread* aTargetThread)
469 : mTargetThread(aTargetThread), mMessageLoop(nullptr)
470 {
471 AssertIsInMainProcess();
472 AssertIsOnMainThread();
473 MOZ_ASSERT(aTargetThread);
474 }
475
476 NS_DECL_ISUPPORTS_INHERITED
477
478 private:
479 ~RequestMessageLoopRunnable()
480 { }
481
482 NS_DECL_NSIRUNNABLE
483 };
484
485 class ParentImpl::ShutdownBackgroundThreadRunnable MOZ_FINAL : public nsRunnable
486 {
487 public:
488 ShutdownBackgroundThreadRunnable()
489 {
490 AssertIsInMainProcess();
491 AssertIsOnMainThread();
492 }
493
494 NS_DECL_ISUPPORTS_INHERITED
495
496 private:
497 ~ShutdownBackgroundThreadRunnable()
498 { }
499
500 NS_DECL_NSIRUNNABLE
501 };
502
503 class ParentImpl::ForceCloseBackgroundActorsRunnable MOZ_FINAL : public nsRunnable
504 {
505 nsTArray<ParentImpl*>* mActorArray;
506
507 public:
508 ForceCloseBackgroundActorsRunnable(nsTArray<ParentImpl*>* aActorArray)
509 : mActorArray(aActorArray)
510 {
511 AssertIsInMainProcess();
512 AssertIsOnMainThread();
513 MOZ_ASSERT(aActorArray);
514 }
515
516 NS_DECL_ISUPPORTS_INHERITED
517
518 private:
519 ~ForceCloseBackgroundActorsRunnable()
520 { }
521
522 NS_DECL_NSIRUNNABLE
523 };
524
525 class ParentImpl::CreateCallbackRunnable MOZ_FINAL : public nsRunnable
526 {
527 nsRefPtr<CreateCallback> mCallback;
528
529 public:
530 CreateCallbackRunnable(CreateCallback* aCallback)
531 : mCallback(aCallback)
532 {
533 AssertIsInMainProcess();
534 AssertIsOnMainThread();
535 MOZ_ASSERT(aCallback);
536 }
537
538 NS_DECL_ISUPPORTS_INHERITED
539
540 private:
541 ~CreateCallbackRunnable()
542 { }
543
544 NS_DECL_NSIRUNNABLE
545 };
546
547 class ParentImpl::ConnectActorRunnable MOZ_FINAL : public nsRunnable
548 {
549 nsRefPtr<ParentImpl> mActor;
550 Transport* mTransport;
551 ProcessHandle mProcessHandle;
552 nsTArray<ParentImpl*>* mLiveActorArray;
553
554 public:
555 ConnectActorRunnable(ParentImpl* aActor,
556 Transport* aTransport,
557 ProcessHandle aProcessHandle,
558 nsTArray<ParentImpl*>* aLiveActorArray)
559 : mActor(aActor), mTransport(aTransport), mProcessHandle(aProcessHandle),
560 mLiveActorArray(aLiveActorArray)
561 {
562 AssertIsInMainProcess();
563 AssertIsOnMainThread();
564 MOZ_ASSERT(aActor);
565 MOZ_ASSERT(aTransport);
566 MOZ_ASSERT(aLiveActorArray);
567 }
568
569 NS_DECL_ISUPPORTS_INHERITED
570
571 private:
572 ~ConnectActorRunnable()
573 {
574 AssertIsInMainProcess();
575 }
576
577 NS_DECL_NSIRUNNABLE
578 };
579
580 class NS_NO_VTABLE ParentImpl::CreateCallback
581 {
582 public:
583 NS_INLINE_DECL_REFCOUNTING(CreateCallback)
584
585 virtual void
586 Success(already_AddRefed<ParentImpl> aActor, MessageLoop* aMessageLoop) = 0;
587
588 virtual void
589 Failure() = 0;
590
591 protected:
592 virtual ~CreateCallback()
593 { }
594 };
595
596 // -----------------------------------------------------------------------------
597 // ChildImpl Helper Declarations
598 // -----------------------------------------------------------------------------
599
600 class ChildImpl::ShutdownObserver MOZ_FINAL : public nsIObserver
601 {
602 public:
603 ShutdownObserver()
604 {
605 AssertIsOnMainThread();
606 }
607
608 NS_DECL_ISUPPORTS
609 NS_DECL_NSIOBSERVER
610
611 private:
612 ~ShutdownObserver()
613 {
614 AssertIsOnMainThread();
615 }
616 };
617
618 class ChildImpl::CreateActorRunnable MOZ_FINAL : public nsRunnable
619 {
620 nsCOMPtr<nsIEventTarget> mEventTarget;
621
622 public:
623 CreateActorRunnable()
624 : mEventTarget(NS_GetCurrentThread())
625 {
626 MOZ_ASSERT(mEventTarget);
627 }
628
629 NS_DECL_ISUPPORTS_INHERITED
630
631 private:
632 ~CreateActorRunnable()
633 { }
634
635 NS_DECL_NSIRUNNABLE
636 };
637
638 class ChildImpl::ParentCreateCallback MOZ_FINAL :
639 public ParentImpl::CreateCallback
640 {
641 nsCOMPtr<nsIEventTarget> mEventTarget;
642
643 public:
644 ParentCreateCallback(nsIEventTarget* aEventTarget)
645 : mEventTarget(aEventTarget)
646 {
647 AssertIsInMainProcess();
648 AssertIsOnMainThread();
649 MOZ_ASSERT(aEventTarget);
650 }
651
652 private:
653 ~ParentCreateCallback()
654 { }
655
656 virtual void
657 Success(already_AddRefed<ParentImpl> aActor, MessageLoop* aMessageLoop)
658 MOZ_OVERRIDE;
659
660 virtual void
661 Failure() MOZ_OVERRIDE;
662 };
663
664 class ChildImpl::CreateCallbackRunnable : public nsRunnable
665 {
666 protected:
667 nsRefPtr<ChildImpl> mActor;
668
669 public:
670 CreateCallbackRunnable(already_AddRefed<ChildImpl>&& aActor)
671 : mActor(aActor)
672 {
673 // May be created on any thread!
674
675 MOZ_ASSERT(mActor);
676 }
677
678 CreateCallbackRunnable()
679 {
680 // May be created on any thread!
681 }
682
683 NS_DECL_ISUPPORTS_INHERITED
684
685 protected:
686 virtual ~CreateCallbackRunnable();
687
688 static already_AddRefed<nsIIPCBackgroundChildCreateCallback>
689 GetNextCallback();
690
691 NS_DECL_NSIRUNNABLE
692 };
693
694 class ChildImpl::OpenChildProcessActorRunnable MOZ_FINAL :
695 public ChildImpl::CreateCallbackRunnable
696 {
697 nsAutoPtr<Transport> mTransport;
698 ProcessHandle mProcessHandle;
699
700 public:
701 OpenChildProcessActorRunnable(already_AddRefed<ChildImpl>&& aActor,
702 Transport* aTransport,
703 ProcessHandle aProcessHandle)
704 : CreateCallbackRunnable(Move(aActor)), mTransport(aTransport),
705 mProcessHandle(aProcessHandle)
706 {
707 AssertIsOnMainThread();
708 MOZ_ASSERT(aTransport);
709 }
710
711 NS_DECL_ISUPPORTS_INHERITED
712
713 private:
714 ~OpenChildProcessActorRunnable()
715 {
716 if (mTransport) {
717 CRASH_IN_CHILD_PROCESS("Leaking transport!");
718 unused << mTransport.forget();
719 }
720 }
721
722 NS_DECL_NSIRUNNABLE
723 };
724
725 class ChildImpl::OpenMainProcessActorRunnable MOZ_FINAL :
726 public ChildImpl::CreateCallbackRunnable
727 {
728 nsRefPtr<ParentImpl> mParentActor;
729 MessageLoop* mParentMessageLoop;
730
731 public:
732 OpenMainProcessActorRunnable(already_AddRefed<ChildImpl>&& aChildActor,
733 already_AddRefed<ParentImpl> aParentActor,
734 MessageLoop* aParentMessageLoop)
735 : CreateCallbackRunnable(Move(aChildActor)), mParentActor(aParentActor),
736 mParentMessageLoop(aParentMessageLoop)
737 {
738 AssertIsOnMainThread();
739 MOZ_ASSERT(mParentActor);
740 MOZ_ASSERT(aParentMessageLoop);
741 }
742
743 NS_DECL_ISUPPORTS_INHERITED
744
745 private:
746 ~OpenMainProcessActorRunnable()
747 { }
748
749 NS_DECL_NSIRUNNABLE
750 };
751
752 } // anonymous namespace
753
754 namespace mozilla {
755 namespace ipc {
756
757 bool
758 IsOnBackgroundThread()
759 {
760 return ParentImpl::IsOnBackgroundThread();
761 }
762
763 #ifdef DEBUG
764
765 void
766 AssertIsOnBackgroundThread()
767 {
768 ParentImpl::AssertIsOnBackgroundThread();
769 }
770
771 #endif // DEBUG
772
773 } // namespace ipc
774 } // namespace mozilla
775
776 // -----------------------------------------------------------------------------
777 // BackgroundParent Public Methods
778 // -----------------------------------------------------------------------------
779
780 // static
781 bool
782 BackgroundParent::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
783 {
784 return ParentImpl::IsOtherProcessActor(aBackgroundActor);
785 }
786
787 // static
788 already_AddRefed<ContentParent>
789 BackgroundParent::GetContentParent(PBackgroundParent* aBackgroundActor)
790 {
791 return ParentImpl::GetContentParent(aBackgroundActor);
792 }
793
794 // static
795 PBackgroundParent*
796 BackgroundParent::Alloc(ContentParent* aContent,
797 Transport* aTransport,
798 ProcessId aOtherProcess)
799 {
800 return ParentImpl::Alloc(aContent, aTransport, aOtherProcess);
801 }
802
803 // -----------------------------------------------------------------------------
804 // BackgroundChild Public Methods
805 // -----------------------------------------------------------------------------
806
807 // static
808 void
809 BackgroundChild::Startup()
810 {
811 ChildImpl::Startup();
812 }
813
814 // static
815 PBackgroundChild*
816 BackgroundChild::Alloc(Transport* aTransport, ProcessId aOtherProcess)
817 {
818 return ChildImpl::Alloc(aTransport, aOtherProcess);
819 }
820
821 // static
822 PBackgroundChild*
823 BackgroundChild::GetForCurrentThread()
824 {
825 return ChildImpl::GetForCurrentThread();
826 }
827
828 // static
829 bool
830 BackgroundChild::GetOrCreateForCurrentThread(
831 nsIIPCBackgroundChildCreateCallback* aCallback)
832 {
833 return ChildImpl::GetOrCreateForCurrentThread(aCallback);
834 }
835
836 // -----------------------------------------------------------------------------
837 // BackgroundChildImpl Public Methods
838 // -----------------------------------------------------------------------------
839
840 // static
841 BackgroundChildImpl::ThreadLocal*
842 BackgroundChildImpl::GetThreadLocalForCurrentThread()
843 {
844 return ChildImpl::GetThreadLocalForCurrentThread();
845 }
846
847 // -----------------------------------------------------------------------------
848 // ParentImpl Static Members
849 // -----------------------------------------------------------------------------
850
851 const ParentImpl::ProcessHandle ParentImpl::kInvalidProcessHandle =
852 #ifdef XP_WIN
853 ProcessHandle(INVALID_HANDLE_VALUE);
854 #else
855 ProcessHandle(-1);
856 #endif
857
858 StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread;
859
860 nsTArray<ParentImpl*>* ParentImpl::sLiveActorsForBackgroundThread;
861
862 StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer;
863
864 Atomic<PRThread*> ParentImpl::sBackgroundPRThread;
865
866 MessageLoop* ParentImpl::sBackgroundThreadMessageLoop = nullptr;
867
868 uint64_t ParentImpl::sLiveActorCount = 0;
869
870 bool ParentImpl::sShutdownObserverRegistered = false;
871
872 bool ParentImpl::sShutdownHasStarted = false;
873
874 StaticAutoPtr<nsTArray<nsRefPtr<ParentImpl::CreateCallback>>>
875 ParentImpl::sPendingCallbacks;
876
877 // -----------------------------------------------------------------------------
878 // ChildImpl Static Members
879 // -----------------------------------------------------------------------------
880
881 unsigned int ChildImpl::sThreadLocalIndex = kBadThreadLocalIndex;
882
883 StaticAutoPtr<nsTArray<nsCOMPtr<nsIEventTarget>>> ChildImpl::sPendingTargets;
884
885 bool ChildImpl::sShutdownHasStarted = false;
886
887 // -----------------------------------------------------------------------------
888 // ParentImpl Implementation
889 // -----------------------------------------------------------------------------
890
891 // static
892 bool
893 ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
894 {
895 AssertIsOnBackgroundThread();
896 MOZ_ASSERT(aBackgroundActor);
897
898 return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
899 }
900
901 // static
902 already_AddRefed<ContentParent>
903 ParentImpl::GetContentParent(PBackgroundParent* aBackgroundActor)
904 {
905 AssertIsOnBackgroundThread();
906 MOZ_ASSERT(aBackgroundActor);
907
908 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
909 if (actor->mActorDestroyed) {
910 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
911 return nullptr;
912 }
913
914 if (actor->mContent) {
915 // We need to hand out a reference to our ContentParent but we also need to
916 // keep the one we have. We can't call AddRef here because ContentParent is
917 // not threadsafe so instead we dispatch a runnable to the main thread to do
918 // it for us. This is safe since we are guaranteed that our AddRef runnable
919 // will run before the reference we hand out can be released, and the
920 // ContentParent can't die as long as the existing reference is maintained.
921 nsCOMPtr<nsIRunnable> runnable =
922 NS_NewNonOwningRunnableMethod(actor->mContent, &ContentParent::AddRef);
923 MOZ_ASSERT(runnable);
924
925 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
926 }
927
928 return actor->mContent.get();
929 }
930
931 // static
932 PBackgroundParent*
933 ParentImpl::Alloc(ContentParent* aContent,
934 Transport* aTransport,
935 ProcessId aOtherProcess)
936 {
937 AssertIsInMainProcess();
938 AssertIsOnMainThread();
939 MOZ_ASSERT(aTransport);
940
941 ProcessHandle processHandle;
942 if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
943 // Process has already died?
944 return nullptr;
945 }
946
947 if (!sBackgroundThread && !CreateBackgroundThread()) {
948 NS_WARNING("Failed to create background thread!");
949 return nullptr;
950 }
951
952 MOZ_ASSERT(sLiveActorsForBackgroundThread);
953
954 sLiveActorCount++;
955
956 nsRefPtr<ParentImpl> actor = new ParentImpl(aContent, aTransport);
957
958 nsCOMPtr<nsIRunnable> connectRunnable =
959 new ConnectActorRunnable(actor, aTransport, processHandle,
960 sLiveActorsForBackgroundThread);
961
962 if (NS_FAILED(sBackgroundThread->Dispatch(connectRunnable,
963 NS_DISPATCH_NORMAL))) {
964 NS_WARNING("Failed to dispatch connect runnable!");
965
966 MOZ_ASSERT(sLiveActorCount);
967 sLiveActorCount--;
968
969 if (!sLiveActorCount) {
970 ShutdownBackgroundThread();
971 }
972
973 return nullptr;
974 }
975
976 return actor;
977 }
978
979 // static
980 bool
981 ParentImpl::CreateActorForSameProcess(CreateCallback* aCallback)
982 {
983 AssertIsInMainProcess();
984 AssertIsOnMainThread();
985 MOZ_ASSERT(aCallback);
986
987 if (!sBackgroundThread && !CreateBackgroundThread()) {
988 NS_WARNING("Failed to create background thread!");
989 return false;
990 }
991
992 MOZ_ASSERT(!sShutdownHasStarted);
993
994 sLiveActorCount++;
995
996 if (sBackgroundThreadMessageLoop) {
997 nsCOMPtr<nsIRunnable> callbackRunnable =
998 new CreateCallbackRunnable(aCallback);
999 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(callbackRunnable)));
1000 return true;
1001 }
1002
1003 if (!sPendingCallbacks) {
1004 sPendingCallbacks = new nsTArray<nsRefPtr<CreateCallback>>();
1005 }
1006
1007 sPendingCallbacks->AppendElement(aCallback);
1008 return true;
1009 }
1010
1011 // static
1012 bool
1013 ParentImpl::CreateBackgroundThread()
1014 {
1015 AssertIsInMainProcess();
1016 AssertIsOnMainThread();
1017 MOZ_ASSERT(!sBackgroundThread);
1018 MOZ_ASSERT(!sLiveActorsForBackgroundThread);
1019
1020 if (sShutdownHasStarted) {
1021 NS_WARNING("Trying to create background thread after shutdown has "
1022 "already begun!");
1023 return false;
1024 }
1025
1026 nsCOMPtr<nsITimer> newShutdownTimer;
1027
1028 if (!sShutdownTimer) {
1029 nsresult rv;
1030 newShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
1031 if (NS_WARN_IF(NS_FAILED(rv))) {
1032 return false;
1033 }
1034 }
1035
1036 if (!sShutdownObserverRegistered) {
1037 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
1038 if (NS_WARN_IF(!obs)) {
1039 return false;
1040 }
1041
1042 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1043
1044 nsresult rv =
1045 obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1046 if (NS_WARN_IF(NS_FAILED(rv))) {
1047 return false;
1048 }
1049
1050 sShutdownObserverRegistered = true;
1051 }
1052
1053 nsCOMPtr<nsIThread> thread;
1054 if (NS_FAILED(NS_NewNamedThread("IPDL Background", getter_AddRefs(thread)))) {
1055 NS_WARNING("NS_NewNamedThread failed!");
1056 return false;
1057 }
1058
1059 nsCOMPtr<nsIRunnable> messageLoopRunnable =
1060 new RequestMessageLoopRunnable(thread);
1061 if (NS_FAILED(thread->Dispatch(messageLoopRunnable, NS_DISPATCH_NORMAL))) {
1062 NS_WARNING("Failed to dispatch RequestMessageLoopRunnable!");
1063 return false;
1064 }
1065
1066 sBackgroundThread = thread;
1067 sLiveActorsForBackgroundThread = new nsTArray<ParentImpl*>(1);
1068
1069 if (!sShutdownTimer) {
1070 MOZ_ASSERT(newShutdownTimer);
1071 sShutdownTimer = newShutdownTimer;
1072 }
1073
1074 return true;
1075 }
1076
1077 // static
1078 void
1079 ParentImpl::ShutdownBackgroundThread()
1080 {
1081 AssertIsInMainProcess();
1082 AssertIsOnMainThread();
1083 MOZ_ASSERT_IF(!sBackgroundThread, !sBackgroundThreadMessageLoop);
1084 MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
1085 MOZ_ASSERT_IF(!sBackgroundThread, !sLiveActorCount);
1086 MOZ_ASSERT_IF(sBackgroundThread, sShutdownTimer);
1087
1088 if (sPendingCallbacks) {
1089 if (!sPendingCallbacks->IsEmpty()) {
1090 nsTArray<nsRefPtr<CreateCallback>> callbacks;
1091 sPendingCallbacks->SwapElements(callbacks);
1092
1093 for (uint32_t index = 0; index < callbacks.Length(); index++) {
1094 nsRefPtr<CreateCallback> callback;
1095 callbacks[index].swap(callback);
1096 MOZ_ASSERT(callback);
1097
1098 callback->Failure();
1099 }
1100 }
1101
1102 if (sShutdownHasStarted) {
1103 sPendingCallbacks = nullptr;
1104 }
1105 }
1106
1107 nsCOMPtr<nsITimer> shutdownTimer;
1108 if (sShutdownHasStarted) {
1109 shutdownTimer = sShutdownTimer.get();
1110 sShutdownTimer = nullptr;
1111 }
1112
1113 if (sBackgroundThread) {
1114 nsCOMPtr<nsIThread> thread = sBackgroundThread.get();
1115 nsAutoPtr<nsTArray<ParentImpl*>> liveActors(sLiveActorsForBackgroundThread);
1116
1117 sBackgroundThread = nullptr;
1118 sLiveActorsForBackgroundThread = nullptr;
1119 sBackgroundThreadMessageLoop = nullptr;
1120
1121 MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
1122
1123 if (sShutdownHasStarted) {
1124 // If this is final shutdown then we need to spin the event loop while we
1125 // wait for all the actors to be cleaned up. We also set a timeout to
1126 // force-kill any hanging actors.
1127
1128 if (sLiveActorCount) {
1129 TimerCallbackClosure closure(thread, liveActors);
1130
1131 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
1132 shutdownTimer->InitWithFuncCallback(&ShutdownTimerCallback, &closure,
1133 kShutdownTimerDelayMS,
1134 nsITimer::TYPE_ONE_SHOT)));
1135
1136 nsIThread* currentThread = NS_GetCurrentThread();
1137 MOZ_ASSERT(currentThread);
1138
1139 while (sLiveActorCount) {
1140 NS_ProcessNextEvent(currentThread);
1141 }
1142
1143 MOZ_ASSERT(liveActors->IsEmpty());
1144
1145 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(shutdownTimer->Cancel()));
1146 }
1147 }
1148
1149 // Dispatch this runnable to unregister the thread from the profiler.
1150 nsCOMPtr<nsIRunnable> shutdownRunnable =
1151 new ShutdownBackgroundThreadRunnable();
1152 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread->Dispatch(shutdownRunnable,
1153 NS_DISPATCH_NORMAL)));
1154
1155 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread->Shutdown()));
1156 }
1157 }
1158
1159 // static
1160 void
1161 ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure)
1162 {
1163 AssertIsInMainProcess();
1164 AssertIsOnMainThread();
1165 MOZ_ASSERT(sShutdownHasStarted);
1166 MOZ_ASSERT(sLiveActorCount);
1167
1168 auto closure = static_cast<TimerCallbackClosure*>(aClosure);
1169 MOZ_ASSERT(closure);
1170
1171 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
1172 // finished.
1173 sLiveActorCount++;
1174
1175 nsCOMPtr<nsIRunnable> forceCloseRunnable =
1176 new ForceCloseBackgroundActorsRunnable(closure->mLiveActors);
1177 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(closure->mThread->Dispatch(forceCloseRunnable,
1178 NS_DISPATCH_NORMAL)));
1179 }
1180
1181 void
1182 ParentImpl::Destroy()
1183 {
1184 // May be called on any thread!
1185
1186 AssertIsInMainProcess();
1187
1188 nsCOMPtr<nsIRunnable> destroyRunnable =
1189 NS_NewNonOwningRunnableMethod(this, &ParentImpl::MainThreadActorDestroy);
1190 MOZ_ASSERT(destroyRunnable);
1191
1192 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(destroyRunnable)));
1193 }
1194
1195 void
1196 ParentImpl::MainThreadActorDestroy()
1197 {
1198 AssertIsInMainProcess();
1199 AssertIsOnMainThread();
1200 MOZ_ASSERT_IF(mIsOtherProcessActor, mContent);
1201 MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
1202 MOZ_ASSERT_IF(mIsOtherProcessActor, mTransport);
1203 MOZ_ASSERT_IF(!mIsOtherProcessActor, !mTransport);
1204
1205 if (mTransport) {
1206 XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
1207 new DeleteTask<Transport>(mTransport));
1208 mTransport = nullptr;
1209 }
1210
1211 ProcessHandle otherProcess = OtherProcess();
1212 if (otherProcess != kInvalidProcessHandle) {
1213 base::CloseProcessHandle(otherProcess);
1214 #ifdef DEBUG
1215 SetOtherProcess(kInvalidProcessHandle);
1216 #endif
1217 }
1218
1219 mContent = nullptr;
1220
1221 MOZ_ASSERT(sLiveActorCount);
1222 sLiveActorCount--;
1223
1224 if (!sLiveActorCount) {
1225 ShutdownBackgroundThread();
1226 }
1227
1228 // This may be the last reference!
1229 Release();
1230 }
1231
1232 IToplevelProtocol*
1233 ParentImpl::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
1234 ProcessHandle aPeerProcess,
1235 ProtocolCloneContext* aCtx)
1236 {
1237 AssertIsInMainProcess();
1238 AssertIsOnMainThread();
1239
1240 const ProtocolId protocolId = GetProtocolId();
1241
1242 for (unsigned int i = 0; i < aFds.Length(); i++) {
1243 if (static_cast<ProtocolId>(aFds[i].protocolId()) != protocolId) {
1244 continue;
1245 }
1246
1247 Transport* transport = OpenDescriptor(aFds[i].fd(),
1248 Transport::MODE_SERVER);
1249 if (!transport) {
1250 NS_WARNING("Failed to open transport!");
1251 break;
1252 }
1253
1254 PBackgroundParent* clonedActor =
1255 Alloc(mContent, transport, base::GetProcId(aPeerProcess));
1256 MOZ_ASSERT(clonedActor);
1257
1258 clonedActor->CloneManagees(this, aCtx);
1259 clonedActor->SetTransport(transport);
1260
1261 return clonedActor;
1262 }
1263
1264 return nullptr;
1265 }
1266
1267 void
1268 ParentImpl::ActorDestroy(ActorDestroyReason aWhy)
1269 {
1270 AssertIsInMainProcess();
1271 AssertIsOnBackgroundThread();
1272 MOZ_ASSERT(!mActorDestroyed);
1273 MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
1274
1275 BackgroundParentImpl::ActorDestroy(aWhy);
1276
1277 mActorDestroyed = true;
1278
1279 if (mLiveActorArray) {
1280 MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1281 mLiveActorArray = nullptr;
1282 }
1283
1284 // This is tricky. We should be able to call Destroy() here directly because
1285 // we're not going to touch 'this' or our MessageChannel any longer on this
1286 // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1287 // it runs it will destroy 'this' and our associated MessageChannel. However,
1288 // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1289 // racing with the main thread we must ensure that the MessageChannel lives
1290 // long enough to be cleared in this call stack.
1291 nsCOMPtr<nsIRunnable> destroyRunnable =
1292 NS_NewNonOwningRunnableMethod(this, &ParentImpl::Destroy);
1293 MOZ_ASSERT(destroyRunnable);
1294
1295 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(destroyRunnable)));
1296 }
1297
1298 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver)
1299
1300 NS_IMETHODIMP
1301 ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject,
1302 const char* aTopic,
1303 const char16_t* aData)
1304 {
1305 AssertIsInMainProcess();
1306 AssertIsOnMainThread();
1307 MOZ_ASSERT(!sShutdownHasStarted);
1308 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1309
1310 sShutdownHasStarted = true;
1311
1312 // Do this first before calling (and spinning the event loop in)
1313 // ShutdownBackgroundThread().
1314 ChildImpl::Shutdown();
1315
1316 ShutdownBackgroundThread();
1317
1318 return NS_OK;
1319 }
1320
1321 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::RequestMessageLoopRunnable,
1322 nsRunnable)
1323
1324 NS_IMETHODIMP
1325 ParentImpl::RequestMessageLoopRunnable::Run()
1326 {
1327 AssertIsInMainProcess();
1328 MOZ_ASSERT(mTargetThread);
1329
1330 if (NS_IsMainThread()) {
1331 MOZ_ASSERT(mMessageLoop);
1332
1333 if (!sBackgroundThread ||
1334 !SameCOMIdentity(mTargetThread.get(), sBackgroundThread.get())) {
1335 return NS_OK;
1336 }
1337
1338 MOZ_ASSERT(!sBackgroundThreadMessageLoop);
1339 sBackgroundThreadMessageLoop = mMessageLoop;
1340
1341 if (sPendingCallbacks && !sPendingCallbacks->IsEmpty()) {
1342 nsTArray<nsRefPtr<CreateCallback>> callbacks;
1343 sPendingCallbacks->SwapElements(callbacks);
1344
1345 for (uint32_t index = 0; index < callbacks.Length(); index++) {
1346 MOZ_ASSERT(callbacks[index]);
1347
1348 nsCOMPtr<nsIRunnable> callbackRunnable =
1349 new CreateCallbackRunnable(callbacks[index]);
1350 if (NS_FAILED(NS_DispatchToCurrentThread(callbackRunnable))) {
1351 NS_WARNING("Failed to dispatch callback runnable!");
1352 }
1353 }
1354 }
1355
1356 return NS_OK;
1357 }
1358
1359 char stackBaseGuess;
1360 profiler_register_thread("IPDL Background", &stackBaseGuess);
1361
1362 #ifdef DEBUG
1363 {
1364 bool correctThread;
1365 MOZ_ASSERT(NS_SUCCEEDED(mTargetThread->IsOnCurrentThread(&correctThread)));
1366 MOZ_ASSERT(correctThread);
1367 }
1368 #endif
1369
1370 DebugOnly<PRThread*> oldBackgroundThread =
1371 sBackgroundPRThread.exchange(PR_GetCurrentThread());
1372
1373 MOZ_ASSERT_IF(oldBackgroundThread,
1374 PR_GetCurrentThread() != oldBackgroundThread);
1375
1376 MOZ_ASSERT(!mMessageLoop);
1377
1378 mMessageLoop = MessageLoop::current();
1379 MOZ_ASSERT(mMessageLoop);
1380
1381 if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
1382 NS_WARNING("Failed to dispatch RequestMessageLoopRunnable to main thread!");
1383 return NS_ERROR_FAILURE;
1384 }
1385
1386 return NS_OK;
1387 }
1388
1389 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ShutdownBackgroundThreadRunnable,
1390 nsRunnable)
1391
1392 NS_IMETHODIMP
1393 ParentImpl::ShutdownBackgroundThreadRunnable::Run()
1394 {
1395 AssertIsInMainProcess();
1396
1397 // It is possible that another background thread was created while this thread
1398 // was shutting down. In that case we can't assert anything about
1399 // sBackgroundPRThread and we should not modify it here.
1400 sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
1401
1402 profiler_unregister_thread();
1403
1404 return NS_OK;
1405 }
1406
1407 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ForceCloseBackgroundActorsRunnable,
1408 nsRunnable)
1409
1410 NS_IMETHODIMP
1411 ParentImpl::ForceCloseBackgroundActorsRunnable::Run()
1412 {
1413 AssertIsInMainProcess();
1414 MOZ_ASSERT(mActorArray);
1415
1416 if (NS_IsMainThread()) {
1417 MOZ_ASSERT(sLiveActorCount);
1418 sLiveActorCount--;
1419 return NS_OK;
1420 }
1421
1422 AssertIsOnBackgroundThread();
1423
1424 if (!mActorArray->IsEmpty()) {
1425 // Copy the array since calling Close() could mutate the actual array.
1426 nsTArray<ParentImpl*> actorsToClose(*mActorArray);
1427
1428 for (uint32_t index = 0; index < actorsToClose.Length(); index++) {
1429 actorsToClose[index]->Close();
1430 }
1431 }
1432
1433 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(this)));
1434
1435 return NS_OK;
1436 }
1437
1438 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::CreateCallbackRunnable, nsRunnable)
1439
1440 NS_IMETHODIMP
1441 ParentImpl::CreateCallbackRunnable::Run()
1442 {
1443 AssertIsInMainProcess();
1444 AssertIsOnMainThread();
1445 MOZ_ASSERT(sBackgroundThreadMessageLoop);
1446 MOZ_ASSERT(mCallback);
1447
1448 nsRefPtr<CreateCallback> callback;
1449 mCallback.swap(callback);
1450
1451 nsRefPtr<ParentImpl> actor = new ParentImpl();
1452
1453 callback->Success(actor.forget(), sBackgroundThreadMessageLoop);
1454
1455 return NS_OK;
1456 }
1457
1458 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ConnectActorRunnable, nsRunnable)
1459
1460 NS_IMETHODIMP
1461 ParentImpl::ConnectActorRunnable::Run()
1462 {
1463 AssertIsInMainProcess();
1464 AssertIsOnBackgroundThread();
1465
1466 // Transfer ownership to this thread. If Open() fails then we will release
1467 // this reference in Destroy.
1468 ParentImpl* actor;
1469 mActor.forget(&actor);
1470
1471 if (!actor->Open(mTransport, mProcessHandle, XRE_GetIOMessageLoop(),
1472 ParentSide)) {
1473 actor->Destroy();
1474 return NS_ERROR_FAILURE;
1475 }
1476
1477 actor->SetLiveActorArray(mLiveActorArray);
1478
1479 return NS_OK;
1480 }
1481
1482 // -----------------------------------------------------------------------------
1483 // ChildImpl Implementation
1484 // -----------------------------------------------------------------------------
1485
1486 // static
1487 void
1488 ChildImpl::Startup()
1489 {
1490 // This happens on the main thread but before XPCOM has started so we can't
1491 // assert that we're being called on the main thread here.
1492
1493 MOZ_ASSERT(sThreadLocalIndex == kBadThreadLocalIndex,
1494 "BackgroundChild::Startup() called more than once!");
1495
1496 PRStatus status =
1497 PR_NewThreadPrivateIndex(&sThreadLocalIndex, ThreadLocalDestructor);
1498 MOZ_RELEASE_ASSERT(status == PR_SUCCESS, "PR_NewThreadPrivateIndex failed!");
1499
1500 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
1501
1502 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1503 MOZ_RELEASE_ASSERT(observerService);
1504
1505 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1506
1507 nsresult rv =
1508 observerService->AddObserver(observer,
1509 NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID,
1510 false);
1511 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
1512 }
1513
1514 // static
1515 void
1516 ChildImpl::Shutdown()
1517 {
1518 AssertIsOnMainThread();
1519
1520 if (sShutdownHasStarted) {
1521 MOZ_ASSERT_IF(sThreadLocalIndex != kBadThreadLocalIndex,
1522 !PR_GetThreadPrivate(sThreadLocalIndex));
1523 return;
1524 }
1525
1526 sShutdownHasStarted = true;
1527
1528 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
1529
1530 DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
1531 MOZ_ASSERT(status == PR_SUCCESS);
1532 }
1533
1534 // static
1535 PBackgroundChild*
1536 ChildImpl::Alloc(Transport* aTransport, ProcessId aOtherProcess)
1537 {
1538 AssertIsInChildProcess();
1539 AssertIsOnMainThread();
1540 MOZ_ASSERT(aTransport);
1541 MOZ_ASSERT(sPendingTargets);
1542 MOZ_ASSERT(!sPendingTargets->IsEmpty());
1543
1544 nsCOMPtr<nsIEventTarget> eventTarget;
1545 sPendingTargets->ElementAt(0).swap(eventTarget);
1546
1547 sPendingTargets->RemoveElementAt(0);
1548
1549 ProcessHandle processHandle;
1550 if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
1551 MOZ_CRASH("Failed to open process handle!");
1552 }
1553
1554 nsRefPtr<ChildImpl> actor = new ChildImpl();
1555
1556 ChildImpl* weakActor = actor;
1557
1558 nsCOMPtr<nsIRunnable> openRunnable =
1559 new OpenChildProcessActorRunnable(actor.forget(), aTransport,
1560 processHandle);
1561 if (NS_FAILED(eventTarget->Dispatch(openRunnable, NS_DISPATCH_NORMAL))) {
1562 MOZ_CRASH("Failed to dispatch OpenActorRunnable!");
1563 }
1564
1565 // This value is only checked against null to determine success/failure, so
1566 // there is no need to worry about the reference count here.
1567 return weakActor;
1568 }
1569
1570 // static
1571 PBackgroundChild*
1572 ChildImpl::GetForCurrentThread()
1573 {
1574 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
1575
1576 auto threadLocalInfo =
1577 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1578
1579 return threadLocalInfo ? threadLocalInfo->mActor : nullptr;
1580 }
1581
1582 // static
1583 bool
1584 ChildImpl::GetOrCreateForCurrentThread(
1585 nsIIPCBackgroundChildCreateCallback* aCallback)
1586 {
1587 MOZ_ASSERT(aCallback);
1588 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
1589 "BackgroundChild::Startup() was never called!");
1590
1591 bool created = false;
1592
1593 auto threadLocalInfo =
1594 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1595
1596 if (threadLocalInfo) {
1597 threadLocalInfo->mCallbacks.AppendElement(aCallback);
1598 } else {
1599 nsAutoPtr<ThreadLocalInfo> newInfo(new ThreadLocalInfo(aCallback));
1600
1601 if (PR_SetThreadPrivate(sThreadLocalIndex, newInfo) != PR_SUCCESS) {
1602 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
1603 return false;
1604 }
1605
1606 created = true;
1607 threadLocalInfo = newInfo.forget();
1608 }
1609
1610 if (threadLocalInfo->mActor) {
1611 nsRefPtr<ChildImpl> actor = threadLocalInfo->mActor;
1612
1613 nsCOMPtr<nsIRunnable> runnable = new CreateCallbackRunnable(actor.forget());
1614 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable)));
1615
1616 return true;
1617 }
1618
1619 if (!created) {
1620 // We have already started the sequence for opening the actor so there's
1621 // nothing else we need to do here. This callback will be called after the
1622 // first callback in CreateCallbackRunnable::Run().
1623 return true;
1624 }
1625
1626 if (NS_IsMainThread()) {
1627 if (NS_WARN_IF(!OpenProtocolOnMainThread(NS_GetCurrentThread()))) {
1628 return false;
1629 }
1630
1631 return true;
1632 }
1633
1634 nsRefPtr<CreateActorRunnable> runnable = new CreateActorRunnable();
1635 if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
1636 CRASH_IN_CHILD_PROCESS("Failed to dispatch to main thread!");
1637 return false;
1638 }
1639
1640 return true;
1641 }
1642
1643 // static
1644 BackgroundChildImpl::ThreadLocal*
1645 ChildImpl::GetThreadLocalForCurrentThread()
1646 {
1647 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
1648 "BackgroundChild::Startup() was never called!");
1649
1650 auto threadLocalInfo =
1651 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1652
1653 if (!threadLocalInfo) {
1654 return nullptr;
1655 }
1656
1657 if (!threadLocalInfo->mConsumerThreadLocal) {
1658 threadLocalInfo->mConsumerThreadLocal =
1659 new BackgroundChildImpl::ThreadLocal();
1660 }
1661
1662 return threadLocalInfo->mConsumerThreadLocal;
1663 }
1664
1665 ChildImpl::CreateCallbackRunnable::~CreateCallbackRunnable()
1666 {
1667 if (mActor) {
1668 CRASH_IN_CHILD_PROCESS("Leaking actor!");
1669 unused << mActor.forget();
1670 }
1671 }
1672
1673 // static
1674 already_AddRefed<nsIIPCBackgroundChildCreateCallback>
1675 ChildImpl::CreateCallbackRunnable::GetNextCallback()
1676 {
1677 // May run on any thread!
1678
1679 auto threadLocalInfo =
1680 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1681 MOZ_ASSERT(threadLocalInfo);
1682
1683 if (threadLocalInfo->mCallbacks.IsEmpty()) {
1684 return nullptr;
1685 }
1686
1687 nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback;
1688 threadLocalInfo->mCallbacks[0].swap(callback);
1689
1690 threadLocalInfo->mCallbacks.RemoveElementAt(0);
1691
1692 return callback.forget();
1693 }
1694
1695 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::CreateCallbackRunnable, nsRunnable)
1696
1697 NS_IMETHODIMP
1698 ChildImpl::CreateCallbackRunnable::Run()
1699 {
1700 // May run on any thread!
1701
1702 nsRefPtr<ChildImpl> actor;
1703 mActor.swap(actor);
1704
1705 nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = GetNextCallback();
1706 while (callback) {
1707 if (actor) {
1708 callback->ActorCreated(actor);
1709 } else {
1710 callback->ActorFailed();
1711 }
1712
1713 callback = GetNextCallback();
1714 }
1715
1716 return NS_OK;
1717 }
1718
1719 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenChildProcessActorRunnable,
1720 ChildImpl::CreateCallbackRunnable)
1721
1722 NS_IMETHODIMP
1723 ChildImpl::OpenChildProcessActorRunnable::Run()
1724 {
1725 // May be run on any thread!
1726
1727 AssertIsInChildProcess();
1728 MOZ_ASSERT(mActor);
1729 MOZ_ASSERT(mTransport);
1730
1731 nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = GetNextCallback();
1732 MOZ_ASSERT(callback,
1733 "There should be at least one callback when first creating the "
1734 "actor!");
1735
1736 nsRefPtr<ChildImpl> strongActor;
1737 mActor.swap(strongActor);
1738
1739 if (!strongActor->Open(mTransport.forget(), mProcessHandle,
1740 XRE_GetIOMessageLoop(), ChildSide)) {
1741 CRASH_IN_CHILD_PROCESS("Failed to open ChildImpl!");
1742
1743 while (callback) {
1744 callback->ActorFailed();
1745 callback = GetNextCallback();
1746 }
1747
1748 return NS_OK;
1749 }
1750
1751 // Now that Open() has succeeded transfer the ownership of the actor to IPDL.
1752 auto threadLocalInfo =
1753 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1754
1755 MOZ_ASSERT(threadLocalInfo);
1756 MOZ_ASSERT(!threadLocalInfo->mActor);
1757
1758 nsRefPtr<ChildImpl>& actor = threadLocalInfo->mActor;
1759 strongActor.swap(actor);
1760
1761 actor->SetBoundThread();
1762
1763 while (callback) {
1764 callback->ActorCreated(actor);
1765 callback = GetNextCallback();
1766 }
1767
1768 return NS_OK;
1769 }
1770
1771 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenMainProcessActorRunnable,
1772 ChildImpl::CreateCallbackRunnable)
1773
1774 NS_IMETHODIMP
1775 ChildImpl::OpenMainProcessActorRunnable::Run()
1776 {
1777 // May run on any thread!
1778
1779 AssertIsInMainProcess();
1780 MOZ_ASSERT(mActor);
1781 MOZ_ASSERT(mParentActor);
1782 MOZ_ASSERT(mParentMessageLoop);
1783
1784 nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = GetNextCallback();
1785 MOZ_ASSERT(callback,
1786 "There should be at least one callback when first creating the "
1787 "actor!");
1788
1789 nsRefPtr<ChildImpl> strongChildActor;
1790 mActor.swap(strongChildActor);
1791
1792 nsRefPtr<ParentImpl> parentActor;
1793 mParentActor.swap(parentActor);
1794
1795 MessageChannel* parentChannel = parentActor->GetIPCChannel();
1796 MOZ_ASSERT(parentChannel);
1797
1798 if (!strongChildActor->Open(parentChannel, mParentMessageLoop, ChildSide)) {
1799 NS_WARNING("Failed to open ChildImpl!");
1800
1801 parentActor->Destroy();
1802
1803 while (callback) {
1804 callback->ActorFailed();
1805 callback = GetNextCallback();
1806 }
1807
1808 return NS_OK;
1809 }
1810
1811 // Now that Open() has succeeded transfer the ownership of the actors to IPDL.
1812 unused << parentActor.forget();
1813
1814 auto threadLocalInfo =
1815 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1816
1817 MOZ_ASSERT(threadLocalInfo);
1818 MOZ_ASSERT(!threadLocalInfo->mActor);
1819
1820 nsRefPtr<ChildImpl>& childActor = threadLocalInfo->mActor;
1821 strongChildActor.swap(childActor);
1822
1823 childActor->SetBoundThread();
1824
1825 while (callback) {
1826 callback->ActorCreated(childActor);
1827 callback = GetNextCallback();
1828 }
1829
1830 return NS_OK;
1831 }
1832
1833 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::CreateActorRunnable, nsRunnable)
1834
1835 NS_IMETHODIMP
1836 ChildImpl::CreateActorRunnable::Run()
1837 {
1838 AssertIsOnMainThread();
1839
1840 if (!OpenProtocolOnMainThread(mEventTarget)) {
1841 NS_WARNING("OpenProtocolOnMainThread failed!");
1842 return NS_ERROR_FAILURE;
1843 }
1844
1845 return NS_OK;
1846 }
1847
1848 void
1849 ChildImpl::ParentCreateCallback::Success(
1850 already_AddRefed<ParentImpl> aParentActor,
1851 MessageLoop* aParentMessageLoop)
1852 {
1853 AssertIsInMainProcess();
1854 AssertIsOnMainThread();
1855
1856 nsRefPtr<ParentImpl> parentActor = aParentActor;
1857 MOZ_ASSERT(parentActor);
1858 MOZ_ASSERT(aParentMessageLoop);
1859 MOZ_ASSERT(mEventTarget);
1860
1861 nsRefPtr<ChildImpl> childActor = new ChildImpl();
1862
1863 nsCOMPtr<nsIEventTarget> target;
1864 mEventTarget.swap(target);
1865
1866 nsCOMPtr<nsIRunnable> openRunnable =
1867 new OpenMainProcessActorRunnable(childActor.forget(), parentActor.forget(),
1868 aParentMessageLoop);
1869 if (NS_FAILED(target->Dispatch(openRunnable, NS_DISPATCH_NORMAL))) {
1870 NS_WARNING("Failed to dispatch open runnable!");
1871 }
1872 }
1873
1874 void
1875 ChildImpl::ParentCreateCallback::Failure()
1876 {
1877 AssertIsInMainProcess();
1878 AssertIsOnMainThread();
1879 MOZ_ASSERT(mEventTarget);
1880
1881 nsCOMPtr<nsIEventTarget> target;
1882 mEventTarget.swap(target);
1883
1884 DispatchFailureCallback(target);
1885 }
1886
1887 // static
1888 bool
1889 ChildImpl::OpenProtocolOnMainThread(nsIEventTarget* aEventTarget)
1890 {
1891 AssertIsOnMainThread();
1892 MOZ_ASSERT(aEventTarget);
1893
1894 if (sShutdownHasStarted) {
1895 MOZ_CRASH("Called BackgroundChild::GetOrCreateForCurrentThread after "
1896 "shutdown has started!");
1897 }
1898
1899 if (IsMainProcess()) {
1900 nsRefPtr<ParentImpl::CreateCallback> parentCallback =
1901 new ParentCreateCallback(aEventTarget);
1902
1903 if (!ParentImpl::CreateActorForSameProcess(parentCallback)) {
1904 NS_WARNING("BackgroundParent::CreateActor() failed!");
1905 DispatchFailureCallback(aEventTarget);
1906 return false;
1907 }
1908
1909 return true;
1910 }
1911
1912 ContentChild* content = ContentChild::GetSingleton();
1913 MOZ_ASSERT(content);
1914
1915 if (!PBackground::Open(content)) {
1916 MOZ_CRASH("Failed to create top level actor!");
1917 return false;
1918 }
1919
1920 if (!sPendingTargets) {
1921 sPendingTargets = new nsTArray<nsCOMPtr<nsIEventTarget>>(1);
1922 ClearOnShutdown(&sPendingTargets);
1923 }
1924
1925 sPendingTargets->AppendElement(aEventTarget);
1926
1927 return true;
1928 }
1929
1930 // static
1931 void
1932 ChildImpl::DispatchFailureCallback(nsIEventTarget* aEventTarget)
1933 {
1934 MOZ_ASSERT(aEventTarget);
1935
1936 nsCOMPtr<nsIRunnable> callbackRunnable = new CreateCallbackRunnable();
1937 if (NS_FAILED(aEventTarget->Dispatch(callbackRunnable, NS_DISPATCH_NORMAL))) {
1938 NS_WARNING("Failed to dispatch CreateCallbackRunnable!");
1939 }
1940 }
1941
1942 void
1943 ChildImpl::ActorDestroy(ActorDestroyReason aWhy)
1944 {
1945 AssertIsOnBoundThread();
1946
1947 BackgroundChildImpl::ActorDestroy(aWhy);
1948 }
1949
1950 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
1951
1952 NS_IMETHODIMP
1953 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject,
1954 const char* aTopic,
1955 const char16_t* aData)
1956 {
1957 AssertIsOnMainThread();
1958 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1959
1960 ChildImpl::Shutdown();
1961
1962 return NS_OK;
1963 }

mercurial