no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / ipc / InProcessImpl.cpp
blobe076a84c44549f6df084e48a2a4c8d5872a110e9
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
16 // facilities.
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 //////////////////////////////////////////
28 /* static */
29 InProcessChild* InProcessChild::Singleton() {
30 MOZ_ASSERT(NS_IsMainThread());
32 if (!sSingleton) {
33 InProcessParent::Startup();
35 return sSingleton;
38 /* static */
39 InProcessParent* InProcessParent::Singleton() {
40 MOZ_ASSERT(NS_IsMainThread());
42 if (!sSingleton) {
43 InProcessParent::Startup();
45 return sSingleton;
48 /* static */
49 void InProcessParent::Startup() {
50 MOZ_ASSERT(NS_IsMainThread());
52 if (sShutdown) {
53 NS_WARNING("Could not get in-process actor while shutting down!");
54 return;
57 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
58 if (!obs) {
59 sShutdown = true;
60 NS_WARNING("Failed to get nsIObserverService for in-process actor");
61 return;
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))) {
70 return;
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);
85 /* static */
86 void InProcessParent::Shutdown() {
87 MOZ_ASSERT(NS_IsMainThread());
89 if (!sSingleton || sShutdown) {
90 return;
93 sShutdown = true;
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.
101 parent->Close();
104 NS_IMETHODIMP
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();
109 return NS_OK;
112 void InProcessParent::ActorDestroy(ActorDestroyReason aWhy) {
113 JSActorDidDestroy();
114 InProcessParent::Shutdown();
117 void InProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
118 JSActorDidDestroy();
119 InProcessParent::Shutdown();
122 /////////////////////////
123 // nsIDOMProcessParent //
124 /////////////////////////
126 NS_IMETHODIMP
127 InProcessParent::GetChildID(uint64_t* aChildID) {
128 *aChildID = 0;
129 return NS_OK;
132 NS_IMETHODIMP
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();
137 return NS_OK;
140 NS_IMETHODIMP InProcessParent::GetRemoteType(nsACString& aRemoteType) {
141 aRemoteType = NOT_REMOTE_TYPE;
142 return NS_OK;
145 NS_IMETHODIMP
146 InProcessParent::GetActor(const nsACString& aName, JSContext* aCx,
147 JSProcessActorParent** aActor) {
148 ErrorResult error;
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);
156 return NS_OK;
159 NS_IMETHODIMP
160 InProcessParent::GetExistingActor(const nsACString& aName,
161 JSProcessActorParent** aActor) {
162 RefPtr<JSProcessActorParent> actor =
163 JSActorManager::GetExistingActor(aName).downcast<JSProcessActorParent>();
164 actor.forget(aActor);
165 return NS_OK;
168 already_AddRefed<JSActor> InProcessParent::InitJSActor(
169 JS::Handle<JSObject*> aMaybeActor, const nsACString& aName,
170 ErrorResult& aRv) {
171 RefPtr<JSProcessActorParent> actor;
172 if (aMaybeActor.get()) {
173 aRv = UNWRAP_OBJECT(JSProcessActorParent, aMaybeActor.get(), actor);
174 if (aRv.Failed()) {
175 return nullptr;
177 } else {
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();
187 NS_IMETHODIMP
188 InProcessParent::GetCanSend(bool* aCanSend) {
189 *aCanSend = CanSend();
190 return NS_OK;
193 ContentParent* InProcessParent::AsContentParent() { return nullptr; }
195 JSActorManager* InProcessParent::AsJSActorManager() { return this; }
197 ////////////////////////
198 // nsIDOMProcessChild //
199 ////////////////////////
201 NS_IMETHODIMP
202 InProcessChild::GetChildID(uint64_t* aChildID) {
203 *aChildID = 0;
204 return NS_OK;
207 NS_IMETHODIMP
208 InProcessChild::GetActor(const nsACString& aName, JSContext* aCx,
209 JSProcessActorChild** aActor) {
210 ErrorResult error;
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);
218 return NS_OK;
221 NS_IMETHODIMP
222 InProcessChild::GetExistingActor(const nsACString& aName,
223 JSProcessActorChild** aActor) {
224 RefPtr<JSProcessActorChild> actor =
225 JSActorManager::GetExistingActor(aName).downcast<JSProcessActorChild>();
226 actor.forget(aActor);
227 return NS_OK;
230 already_AddRefed<JSActor> InProcessChild::InitJSActor(
231 JS::Handle<JSObject*> aMaybeActor, const nsACString& aName,
232 ErrorResult& aRv) {
233 RefPtr<JSProcessActorChild> actor;
234 if (aMaybeActor.get()) {
235 aRv = UNWRAP_OBJECT(JSProcessActorChild, aMaybeActor.get(), actor);
236 if (aRv.Failed()) {
237 return nullptr;
239 } else {
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();
249 NS_IMETHODIMP
250 InProcessChild::GetCanSend(bool* aCanSend) {
251 *aCanSend = CanSend();
252 return NS_OK;
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();
290 } else {
291 otherRoot = InProcessParent::Singleton();
293 if (NS_WARN_IF(!otherRoot)) {
294 return nullptr;
297 // Look up the actor on the other side, and return it.
298 IProtocol* otherActor = otherRoot->Lookup(aActor->Id());
299 if (otherActor) {
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!");
306 return otherActor;
309 /* static */
310 IProtocol* InProcessParent::ChildActorFor(IProtocol* aActor) {
311 MOZ_ASSERT(aActor && aActor->GetSide() == ParentSide);
312 return GetOtherInProcessActor(aActor);
315 /* static */
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