1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/dom/JSActorService.h"
9 #include "mozilla/dom/ChromeUtilsBinding.h"
10 #include "mozilla/dom/BrowserChild.h"
11 #include "mozilla/dom/BrowserParent.h"
12 #include "mozilla/dom/EventListenerBinding.h"
13 #include "mozilla/dom/Event.h"
14 #include "mozilla/dom/EventTargetBinding.h"
15 #include "mozilla/dom/EventTarget.h"
16 #include "mozilla/dom/InProcessChild.h"
17 #include "mozilla/dom/InProcessParent.h"
18 #include "mozilla/dom/JSActorManager.h"
19 #include "mozilla/dom/JSProcessActorBinding.h"
20 #include "mozilla/dom/JSProcessActorChild.h"
21 #include "mozilla/dom/JSProcessActorProtocol.h"
22 #include "mozilla/dom/JSWindowActorBinding.h"
23 #include "mozilla/dom/JSWindowActorChild.h"
24 #include "mozilla/dom/JSWindowActorProtocol.h"
25 #include "mozilla/dom/MessageManagerBinding.h"
26 #include "mozilla/dom/PContent.h"
27 #include "mozilla/dom/ContentChild.h"
28 #include "mozilla/dom/ContentParent.h"
29 #include "mozilla/dom/WindowGlobalChild.h"
30 #include "mozilla/dom/WindowGlobalParent.h"
31 #include "mozilla/ArrayAlgorithm.h"
32 #include "mozilla/Services.h"
33 #include "mozilla/StaticPtr.h"
34 #include "mozilla/Logging.h"
35 #include "nsIObserverService.h"
37 namespace mozilla::dom
{
39 StaticRefPtr
<JSActorService
> gJSActorService
;
42 JSActorService::JSActorService() { MOZ_ASSERT(NS_IsMainThread()); }
44 JSActorService::~JSActorService() { MOZ_ASSERT(NS_IsMainThread()); }
47 already_AddRefed
<JSActorService
> JSActorService::GetSingleton() {
48 MOZ_ASSERT(NS_IsMainThread());
49 if (!gJSActorService
) {
50 gJSActorService
= new JSActorService();
51 ClearOnShutdown(&gJSActorService
);
54 RefPtr
<JSActorService
> service
= gJSActorService
.get();
55 return service
.forget();
58 void JSActorService::RegisterWindowActor(const nsACString
& aName
,
59 const WindowActorOptions
& aOptions
,
61 MOZ_ASSERT(NS_IsMainThread());
62 MOZ_ASSERT(XRE_IsParentProcess());
64 const auto proto
= mWindowActorDescriptors
.WithEntryHandle(
65 aName
, [&](auto&& entry
) -> RefPtr
<JSWindowActorProtocol
> {
67 aRv
.ThrowNotSupportedError(
68 nsPrintfCString("'%s' actor is already registered.",
69 PromiseFlatCString(aName
).get()));
73 // Insert a new entry for the protocol.
74 RefPtr
<JSWindowActorProtocol
> protocol
=
75 JSWindowActorProtocol::FromWebIDLOptions(aName
, aOptions
, aRv
);
76 if (NS_WARN_IF(aRv
.Failed())) {
80 entry
.Insert(protocol
);
86 MOZ_ASSERT(aRv
.Failed());
90 // Send information about the newly added entry to every existing content
92 AutoTArray
<JSWindowActorInfo
, 1> windowInfos
{proto
->ToIPC()};
93 nsTArray
<JSProcessActorInfo
> contentInfos
{};
94 for (auto* cp
: ContentParent::AllProcesses(ContentParent::eLive
)) {
95 Unused
<< cp
->SendInitJSActorInfos(contentInfos
, windowInfos
);
98 // Register event listeners for any existing chrome targets.
99 for (EventTarget
* target
: mChromeEventTargets
) {
100 proto
->RegisterListenersFor(target
);
103 // Add observers to the protocol.
104 proto
->AddObservers();
107 void JSActorService::UnregisterWindowActor(const nsACString
& aName
) {
108 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
109 CrashReporter::AutoRecordAnnotation
autoActorName(
110 CrashReporter::Annotation::JSActorName
, aName
);
111 CrashReporter::AutoRecordAnnotation
autoMessageName(
112 CrashReporter::Annotation::JSActorMessage
, "<Unregister>"_ns
);
114 nsAutoCString
name(aName
);
115 RefPtr
<JSWindowActorProtocol
> proto
;
116 if (mWindowActorDescriptors
.Remove(name
, getter_AddRefs(proto
))) {
117 // Remove listeners for this actor from each of our chrome targets.
118 for (EventTarget
* target
: mChromeEventTargets
) {
119 proto
->UnregisterListenersFor(target
);
122 // Remove observers for this actor from observer serivce.
123 proto
->RemoveObservers();
125 // Tell every content process to also unregister, and accumulate the set of
126 // potential managers, to have the actor disabled.
127 nsTArray
<RefPtr
<JSActorManager
>> managers
;
128 if (XRE_IsParentProcess()) {
129 for (auto* cp
: ContentParent::AllProcesses(ContentParent::eLive
)) {
130 Unused
<< cp
->SendUnregisterJSWindowActor(name
);
131 for (const auto& bp
: cp
->ManagedPBrowserParent()) {
132 for (const auto& wgp
: bp
->ManagedPWindowGlobalParent()) {
133 managers
.AppendElement(static_cast<WindowGlobalParent
*>(wgp
));
138 for (const auto& wgp
:
139 InProcessParent::Singleton()->ManagedPWindowGlobalParent()) {
140 managers
.AppendElement(static_cast<WindowGlobalParent
*>(wgp
));
142 for (const auto& wgc
:
143 InProcessChild::Singleton()->ManagedPWindowGlobalChild()) {
144 managers
.AppendElement(static_cast<WindowGlobalChild
*>(wgc
));
147 for (const auto& bc
:
148 ContentChild::GetSingleton()->ManagedPBrowserChild()) {
149 for (const auto& wgc
: bc
->ManagedPWindowGlobalChild()) {
150 managers
.AppendElement(static_cast<WindowGlobalChild
*>(wgc
));
155 for (auto& mgr
: managers
) {
156 mgr
->JSActorUnregister(name
);
161 void JSActorService::LoadJSActorInfos(nsTArray
<JSProcessActorInfo
>& aProcess
,
162 nsTArray
<JSWindowActorInfo
>& aWindow
) {
163 MOZ_ASSERT(NS_IsMainThread());
164 MOZ_ASSERT(XRE_IsContentProcess());
166 for (auto& info
: aProcess
) {
167 // Create our JSProcessActorProtocol, register it in
168 // mProcessActorDescriptors.
169 auto name
= info
.name();
170 RefPtr
<JSProcessActorProtocol
> proto
=
171 JSProcessActorProtocol::FromIPC(std::move(info
));
172 mProcessActorDescriptors
.InsertOrUpdate(std::move(name
), RefPtr
{proto
});
174 // Add observers for each actor.
175 proto
->AddObservers();
178 for (auto& info
: aWindow
) {
179 auto name
= info
.name();
180 RefPtr
<JSWindowActorProtocol
> proto
=
181 JSWindowActorProtocol::FromIPC(std::move(info
));
182 mWindowActorDescriptors
.InsertOrUpdate(std::move(name
), RefPtr
{proto
});
184 // Register listeners for each chrome target.
185 for (EventTarget
* target
: mChromeEventTargets
) {
186 proto
->RegisterListenersFor(target
);
189 // Add observers for each actor.
190 proto
->AddObservers();
194 void JSActorService::GetJSWindowActorInfos(
195 nsTArray
<JSWindowActorInfo
>& aInfos
) {
196 MOZ_ASSERT(NS_IsMainThread());
197 MOZ_ASSERT(XRE_IsParentProcess());
199 for (const auto& data
: mWindowActorDescriptors
.Values()) {
200 aInfos
.AppendElement(data
->ToIPC());
204 void JSActorService::RegisterChromeEventTarget(EventTarget
* aTarget
) {
205 MOZ_ASSERT(!mChromeEventTargets
.Contains(aTarget
));
206 mChromeEventTargets
.AppendElement(aTarget
);
208 // Register event listeners on the newly added Window Root.
209 for (const auto& data
: mWindowActorDescriptors
.Values()) {
210 data
->RegisterListenersFor(aTarget
);
213 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
214 obs
->NotifyObservers(aTarget
, "chrome-event-target-created", nullptr);
218 void JSActorService::UnregisterChromeEventTarget(EventTarget
* aTarget
) {
219 if (gJSActorService
) {
220 // NOTE: No need to unregister listeners here, as the target is going away.
221 gJSActorService
->mChromeEventTargets
.RemoveElement(aTarget
);
225 void JSActorService::RegisterProcessActor(const nsACString
& aName
,
226 const ProcessActorOptions
& aOptions
,
228 MOZ_ASSERT(NS_IsMainThread());
229 MOZ_ASSERT(XRE_IsParentProcess());
231 const auto proto
= mProcessActorDescriptors
.WithEntryHandle(
232 aName
, [&](auto&& entry
) -> RefPtr
<JSProcessActorProtocol
> {
234 aRv
.ThrowNotSupportedError(
235 nsPrintfCString("'%s' actor is already registered.",
236 PromiseFlatCString(aName
).get()));
240 // Insert a new entry for the protocol.
241 RefPtr
<JSProcessActorProtocol
> protocol
=
242 JSProcessActorProtocol::FromWebIDLOptions(aName
, aOptions
, aRv
);
243 if (NS_WARN_IF(aRv
.Failed())) {
247 entry
.Insert(protocol
);
253 MOZ_ASSERT(aRv
.Failed());
257 // Send information about the newly added entry to every existing content
259 AutoTArray
<JSProcessActorInfo
, 1> contentInfos
{proto
->ToIPC()};
260 nsTArray
<JSWindowActorInfo
> windowInfos
{};
261 for (auto* cp
: ContentParent::AllProcesses(ContentParent::eLive
)) {
262 Unused
<< cp
->SendInitJSActorInfos(contentInfos
, windowInfos
);
265 // Add observers to the protocol.
266 proto
->AddObservers();
269 void JSActorService::UnregisterProcessActor(const nsACString
& aName
) {
270 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
271 CrashReporter::AutoRecordAnnotation
autoActorName(
272 CrashReporter::Annotation::JSActorName
, aName
);
273 CrashReporter::AutoRecordAnnotation
autoMessageName(
274 CrashReporter::Annotation::JSActorMessage
, "<Unregister>"_ns
);
276 nsAutoCString
name(aName
);
277 RefPtr
<JSProcessActorProtocol
> proto
;
278 if (mProcessActorDescriptors
.Remove(name
, getter_AddRefs(proto
))) {
279 // Remove observers for this actor from observer serivce.
280 proto
->RemoveObservers();
282 // Tell every content process to also unregister, and accumulate the set of
283 // potential managers, to have the actor disabled.
284 nsTArray
<RefPtr
<JSActorManager
>> managers
;
285 if (XRE_IsParentProcess()) {
286 for (auto* cp
: ContentParent::AllProcesses(ContentParent::eLive
)) {
287 Unused
<< cp
->SendUnregisterJSProcessActor(name
);
288 managers
.AppendElement(cp
);
290 managers
.AppendElement(InProcessChild::Singleton());
291 managers
.AppendElement(InProcessParent::Singleton());
293 managers
.AppendElement(ContentChild::GetSingleton());
296 for (auto& mgr
: managers
) {
297 mgr
->JSActorUnregister(name
);
302 void JSActorService::GetJSProcessActorInfos(
303 nsTArray
<JSProcessActorInfo
>& aInfos
) {
304 MOZ_ASSERT(NS_IsMainThread());
305 MOZ_ASSERT(XRE_IsParentProcess());
307 for (const auto& data
: mProcessActorDescriptors
.Values()) {
308 aInfos
.AppendElement(data
->ToIPC());
312 already_AddRefed
<JSProcessActorProtocol
>
313 JSActorService::GetJSProcessActorProtocol(const nsACString
& aName
) {
314 return mProcessActorDescriptors
.Get(aName
);
317 already_AddRefed
<JSWindowActorProtocol
>
318 JSActorService::GetJSWindowActorProtocol(const nsACString
& aName
) {
319 return mWindowActorDescriptors
.Get(aName
);
322 } // namespace mozilla::dom