1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/InProcessParent.h"
8 #include "mozilla/dom/InProcessChild.h"
9 #include "mozilla/dom/JSProcessActorBinding.h"
10 #include "nsIObserverService.h"
11 #include "mozilla/Services.h"
13 using namespace mozilla::ipc
;
15 // This file contains the implementation of core InProcess lifecycle management
18 namespace mozilla::dom
{
20 StaticRefPtr
<InProcessParent
> InProcessParent::sSingleton
;
21 StaticRefPtr
<InProcessChild
> InProcessChild::sSingleton
;
22 bool InProcessParent::sShutdown
= false;
24 //////////////////////////////////////////
25 // InProcess actor lifecycle management //
26 //////////////////////////////////////////
29 InProcessChild
* InProcessChild::Singleton() {
30 MOZ_ASSERT(NS_IsMainThread());
33 InProcessParent::Startup();
39 InProcessParent
* InProcessParent::Singleton() {
40 MOZ_ASSERT(NS_IsMainThread());
43 InProcessParent::Startup();
49 void InProcessParent::Startup() {
50 MOZ_ASSERT(NS_IsMainThread());
53 NS_WARNING("Could not get in-process actor while shutting down!");
57 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
60 NS_WARNING("Failed to get nsIObserverService for in-process actor");
64 RefPtr
<InProcessParent
> parent
= new InProcessParent();
65 RefPtr
<InProcessChild
> child
= new InProcessChild();
67 // Observe the shutdown event to close & clean up after ourselves.
68 nsresult rv
= obs
->AddObserver(parent
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, false);
69 if (NS_WARN_IF(NS_FAILED(rv
))) {
73 // Link the two actors
74 if (!child
->OpenOnSameThread(parent
, ChildSide
)) {
75 MOZ_CRASH("Failed to open InProcessChild!");
78 parent
->SetOtherProcessId(base::GetCurrentProcId());
80 // Stash global references to fetch the other side of the reference.
81 InProcessParent::sSingleton
= std::move(parent
);
82 InProcessChild::sSingleton
= std::move(child
);
86 void InProcessParent::Shutdown() {
87 MOZ_ASSERT(NS_IsMainThread());
89 if (!sSingleton
|| sShutdown
) {
95 RefPtr
<InProcessParent
> parent
= sSingleton
;
96 InProcessParent::sSingleton
= nullptr;
97 InProcessChild::sSingleton
= nullptr;
99 // Calling `Close` on the actor will cause the `Dealloc` methods to be called,
100 // freeing the remaining references.
105 InProcessParent::Observe(nsISupports
* aSubject
, const char* aTopic
,
106 const char16_t
* aData
) {
107 MOZ_ASSERT(!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
));
108 InProcessParent::Shutdown();
112 void InProcessParent::ActorDestroy(ActorDestroyReason aWhy
) {
114 InProcessParent::Shutdown();
117 void InProcessChild::ActorDestroy(ActorDestroyReason aWhy
) {
119 InProcessParent::Shutdown();
122 /////////////////////////
123 // nsIDOMProcessParent //
124 /////////////////////////
127 InProcessParent::GetChildID(uint64_t* aChildID
) {
133 InProcessParent::GetOsPid(int32_t* aOsPid
) {
134 // InProcessParent always run in the parent process,
135 // so we can return the current process id.
136 *aOsPid
= base::GetCurrentProcId();
140 NS_IMETHODIMP
InProcessParent::GetRemoteType(nsACString
& aRemoteType
) {
141 aRemoteType
= NOT_REMOTE_TYPE
;
146 InProcessParent::GetActor(const nsACString
& aName
, JSContext
* aCx
,
147 JSProcessActorParent
** aActor
) {
149 RefPtr
<JSProcessActorParent
> actor
=
150 JSActorManager::GetActor(aCx
, aName
, error
)
151 .downcast
<JSProcessActorParent
>();
152 if (error
.MaybeSetPendingException(aCx
)) {
153 return NS_ERROR_FAILURE
;
155 actor
.forget(aActor
);
160 InProcessParent::GetExistingActor(const nsACString
& aName
,
161 JSProcessActorParent
** aActor
) {
162 RefPtr
<JSProcessActorParent
> actor
=
163 JSActorManager::GetExistingActor(aName
).downcast
<JSProcessActorParent
>();
164 actor
.forget(aActor
);
168 already_AddRefed
<JSActor
> InProcessParent::InitJSActor(
169 JS::Handle
<JSObject
*> aMaybeActor
, const nsACString
& aName
,
171 RefPtr
<JSProcessActorParent
> actor
;
172 if (aMaybeActor
.get()) {
173 aRv
= UNWRAP_OBJECT(JSProcessActorParent
, aMaybeActor
.get(), actor
);
178 actor
= new JSProcessActorParent();
181 MOZ_RELEASE_ASSERT(!actor
->Manager(),
182 "mManager was already initialized once!");
183 actor
->Init(aName
, this);
184 return actor
.forget();
188 InProcessParent::GetCanSend(bool* aCanSend
) {
189 *aCanSend
= CanSend();
193 ContentParent
* InProcessParent::AsContentParent() { return nullptr; }
195 JSActorManager
* InProcessParent::AsJSActorManager() { return this; }
197 ////////////////////////
198 // nsIDOMProcessChild //
199 ////////////////////////
202 InProcessChild::GetChildID(uint64_t* aChildID
) {
208 InProcessChild::GetActor(const nsACString
& aName
, JSContext
* aCx
,
209 JSProcessActorChild
** aActor
) {
211 RefPtr
<JSProcessActorChild
> actor
=
212 JSActorManager::GetActor(aCx
, aName
, error
)
213 .downcast
<JSProcessActorChild
>();
214 if (error
.MaybeSetPendingException(aCx
)) {
215 return NS_ERROR_FAILURE
;
217 actor
.forget(aActor
);
222 InProcessChild::GetExistingActor(const nsACString
& aName
,
223 JSProcessActorChild
** aActor
) {
224 RefPtr
<JSProcessActorChild
> actor
=
225 JSActorManager::GetExistingActor(aName
).downcast
<JSProcessActorChild
>();
226 actor
.forget(aActor
);
230 already_AddRefed
<JSActor
> InProcessChild::InitJSActor(
231 JS::Handle
<JSObject
*> aMaybeActor
, const nsACString
& aName
,
233 RefPtr
<JSProcessActorChild
> actor
;
234 if (aMaybeActor
.get()) {
235 aRv
= UNWRAP_OBJECT(JSProcessActorChild
, aMaybeActor
.get(), actor
);
240 actor
= new JSProcessActorChild();
243 MOZ_RELEASE_ASSERT(!actor
->Manager(),
244 "mManager was already initialized once!");
245 actor
->Init(aName
, this);
246 return actor
.forget();
250 InProcessChild::GetCanSend(bool* aCanSend
) {
251 *aCanSend
= CanSend();
255 ContentChild
* InProcessChild::AsContentChild() { return nullptr; }
257 JSActorManager
* InProcessChild::AsJSActorManager() { return this; }
259 ////////////////////////////////
260 // In-Process Actor Utilities //
261 ////////////////////////////////
263 // Helper method for implementing ParentActorFor and ChildActorFor.
264 static IProtocol
* GetOtherInProcessActor(IProtocol
* aActor
) {
265 MOZ_ASSERT(aActor
->GetSide() != UnknownSide
, "bad unknown side");
267 // Discover the manager of aActor which is PInProcess.
268 IProtocol
* current
= aActor
;
269 while (current
&& current
->CanRecv()) {
270 if (current
->GetProtocolId() == PInProcessMsgStart
) {
271 break; // Found the correct actor.
273 current
= current
->Manager();
275 if (!current
|| !current
->CanRecv()) {
276 return nullptr; // Not a live PInProcess actor, return |nullptr|
279 MOZ_ASSERT(current
->GetSide() == aActor
->GetSide(), "side changed?");
280 MOZ_ASSERT_IF(aActor
->GetSide() == ParentSide
,
281 current
== InProcessParent::Singleton());
282 MOZ_ASSERT_IF(aActor
->GetSide() == ChildSide
,
283 current
== InProcessChild::Singleton());
285 // Check whether this is InProcessParent or InProcessChild, and get the other
286 // side's toplevel actor.
287 IProtocol
* otherRoot
= nullptr;
288 if (aActor
->GetSide() == ParentSide
) {
289 otherRoot
= InProcessChild::Singleton();
291 otherRoot
= InProcessParent::Singleton();
293 if (NS_WARN_IF(!otherRoot
)) {
297 // Look up the actor on the other side, and return it.
298 IProtocol
* otherActor
= otherRoot
->Lookup(aActor
->Id());
300 MOZ_ASSERT(otherActor
->GetSide() != UnknownSide
, "bad unknown side");
301 MOZ_ASSERT(otherActor
->GetSide() != aActor
->GetSide(), "Wrong side!");
302 MOZ_ASSERT(otherActor
->GetProtocolId() == aActor
->GetProtocolId(),
303 "Wrong type of protocol!");
310 IProtocol
* InProcessParent::ChildActorFor(IProtocol
* aActor
) {
311 MOZ_ASSERT(aActor
&& aActor
->GetSide() == ParentSide
);
312 return GetOtherInProcessActor(aActor
);
316 IProtocol
* InProcessChild::ParentActorFor(IProtocol
* aActor
) {
317 MOZ_ASSERT(aActor
&& aActor
->GetSide() == ChildSide
);
318 return GetOtherInProcessActor(aActor
);
321 NS_IMPL_ISUPPORTS(InProcessParent
, nsIDOMProcessParent
, nsIObserver
)
322 NS_IMPL_ISUPPORTS(InProcessChild
, nsIDOMProcessChild
)
324 } // namespace mozilla::dom