Skip to content

Commit 3da6e17

Browse files
author
David Teller
committed
Bug 1580448 - JSProcessActor API;r=nika
This patch introduces the bulk of JSProcessActor{Child, Parent}. Differential Revision: https://phabricator.services.mozilla.com/D64595
1 parent cd067d3 commit 3da6e17

24 files changed

+1494
-36
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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/. */
6+
7+
/**
8+
* An actor architecture designed to allow compositional parent/content
9+
* communications. The lifetime of a JSProcessActor{Child, Parent} is the `ContentParent`
10+
* (for the parent-side) / `ContentChild` (for the child-side).
11+
*/
12+
13+
interface nsISupports;
14+
15+
/**
16+
* Base class for parent-side actor.
17+
*/
18+
[ChromeOnly, Exposed=Window]
19+
interface JSProcessActorParent {
20+
[ChromeOnly]
21+
constructor();
22+
23+
readonly attribute nsIContentParent manager;
24+
};
25+
JSProcessActorParent includes JSActor;
26+
27+
[ChromeOnly, Exposed=Window]
28+
interface JSProcessActorChild {
29+
[ChromeOnly]
30+
constructor();
31+
32+
readonly attribute nsIContentChild manager;
33+
};
34+
JSProcessActorChild includes JSActor;
35+
36+
37+
/**
38+
* Used by `ChromeUtils.registerProcessActor()` to register actors.
39+
*/
40+
dictionary ProcessActorOptions {
41+
/**
42+
* An array of remote type which restricts the actor is allowed to instantiate
43+
* in specific process type. If this is defined, the prefix of process type
44+
* matches the remote type by prefix match is allowed to instantiate, ex: if
45+
* Fission is enabled, the prefix of process type will be `webIsolated`, it
46+
* can prefix match remote type either `web` or `webIsolated`. If not passed,
47+
* all content processes are allowed to instantiate the actor.
48+
*/
49+
sequence<DOMString> remoteTypes;
50+
51+
/** This fields are used for configuring individual sides of the actor. */
52+
ProcessActorSidedOptions parent;
53+
ProcessActorChildOptions child;
54+
};
55+
56+
dictionary ProcessActorSidedOptions {
57+
/**
58+
* The JSM path which should be loaded for the actor on this side.
59+
* If not passed, the specified side cannot receive messages, but may send
60+
* them using `sendAsyncMessage` or `sendQuery`.
61+
*/
62+
required ByteString moduleURI;
63+
};
64+
65+
dictionary ProcessActorChildOptions : ProcessActorSidedOptions {
66+
/**
67+
* An array of observer topics to listen to. An observer will be added for each
68+
* topic in the list.
69+
*
70+
* Observer notifications in the list use nsGlobalContentInner or
71+
* nsGlobalContentOuter object as their subject, and the events will only be
72+
* dispatched to the corresponding content actor. If additional observer
73+
* notification's subjects are needed, please file a bug for that.
74+
**/
75+
sequence<ByteString> observers;
76+
};

dom/chrome-webidl/JSWindowActor.webidl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44
* License, v. 2.0. If a copy of the MPL was not distributed with this
55
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
66

7+
/**
8+
* An actor architecture designed to allow compositional parent/content
9+
* communications. The lifetime of a JSWindowActor{Child, Parent} is the `WindowGlobalParent`
10+
* (for the parent-side) / `WindowGlobalChild` (for the child-side).
11+
*
12+
* See https://firefox-source-docs.mozilla.org/dom/Fission.html#jswindowactor for
13+
* more details on how to use this architecture.
14+
*/
15+
716
interface nsISupports;
817

918
[ChromeOnly, Exposed=Window]

dom/chrome-webidl/moz.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ WEBIDL_FILES = [
5050
'InspectorUtils.webidl',
5151
'IteratorResult.webidl',
5252
'JSActor.webidl',
53+
'JSProcessActor.webidl',
5354
'JSWindowActor.webidl',
5455
'L10nOverlays.webidl',
5556
'Localization.webidl',

dom/ipc/ContentChild.cpp

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
#include "mozilla/dom/IPCBlobInputStreamChild.h"
5050
#include "mozilla/dom/IPCBlobUtils.h"
5151
#include "mozilla/dom/JSActorService.h"
52+
#include "mozilla/dom/JSProcessActorBinding.h"
53+
#include "mozilla/dom/JSProcessActorChild.h"
5254
#include "mozilla/dom/LSObject.h"
5355
#include "mozilla/dom/MemoryReportRequest.h"
5456
#include "mozilla/dom/PLoginReputationChild.h"
@@ -74,6 +76,7 @@
7476
#include "mozilla/ipc/FileDescriptorSetChild.h"
7577
#include "mozilla/ipc/FileDescriptorUtils.h"
7678
#include "mozilla/ipc/GeckoChildProcessHost.h"
79+
#include "mozilla/ipc/InProcessChild.h"
7780
#include "mozilla/ipc/LibrarySandboxPreload.h"
7881
#include "mozilla/ipc/ProcessChild.h"
7982
#include "mozilla/ipc/PChildToParentStreamChild.h"
@@ -2622,10 +2625,11 @@ mozilla::ipc::IPCResult ContentChild::RecvInitBlobURLs(
26222625
return IPC_OK();
26232626
}
26242627

2625-
mozilla::ipc::IPCResult ContentChild::RecvInitJSWindowActorInfos(
2626-
nsTArray<JSWindowActorInfo>&& aInfos) {
2628+
mozilla::ipc::IPCResult ContentChild::RecvInitJSActorInfos(
2629+
nsTArray<JSProcessActorInfo>&& aContentInfos,
2630+
nsTArray<JSWindowActorInfo>&& aWindowInfos) {
26272631
RefPtr<JSActorService> actSvc = JSActorService::GetSingleton();
2628-
actSvc->LoadJSWindowActorInfos(aInfos);
2632+
actSvc->LoadJSActorInfos(aContentInfos, aWindowInfos);
26292633
return IPC_OK();
26302634
}
26312635

@@ -2636,6 +2640,13 @@ mozilla::ipc::IPCResult ContentChild::RecvUnregisterJSWindowActor(
26362640
return IPC_OK();
26372641
}
26382642

2643+
mozilla::ipc::IPCResult ContentChild::RecvUnregisterJSProcessActor(
2644+
const nsCString& aName) {
2645+
RefPtr<JSActorService> actSvc = JSActorService::GetSingleton();
2646+
actSvc->UnregisterProcessActor(aName);
2647+
return IPC_OK();
2648+
}
2649+
26392650
mozilla::ipc::IPCResult ContentChild::RecvLastPrivateDocShellDestroyed() {
26402651
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
26412652
obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
@@ -4191,6 +4202,62 @@ NS_IMETHODIMP ContentChild::GetChildID(uint64_t* aOut) {
41914202
return NS_OK;
41924203
}
41934204

4205+
IPCResult ContentChild::RecvRawMessage(const JSActorMessageMeta& aMeta,
4206+
const ClonedMessageData& aData,
4207+
const ClonedMessageData& aStack) {
4208+
StructuredCloneData data;
4209+
data.BorrowFromClonedMessageDataForChild(aData);
4210+
StructuredCloneData stack;
4211+
stack.BorrowFromClonedMessageDataForChild(aStack);
4212+
ReceiveRawMessage(aMeta, std::move(data), std::move(stack));
4213+
return IPC_OK();
4214+
}
4215+
4216+
void ContentChild::ReceiveRawMessage(const JSActorMessageMeta& aMeta,
4217+
StructuredCloneData&& aData,
4218+
StructuredCloneData&& aStack) {
4219+
RefPtr<JSProcessActorChild> actor =
4220+
GetActor(aMeta.actorName(), IgnoreErrors());
4221+
if (actor) {
4222+
actor->ReceiveRawMessage(aMeta, std::move(aData), std::move(aStack));
4223+
}
4224+
}
4225+
4226+
already_AddRefed<mozilla::dom::JSProcessActorChild> ContentChild::GetActor(
4227+
const nsACString& aName, ErrorResult& aRv) {
4228+
if (!CanSend()) {
4229+
aRv.ThrowInvalidStateError(
4230+
"Cannot get JSProcessActor, process is shutting down");
4231+
return nullptr;
4232+
}
4233+
4234+
// Check if this actor has already been created, and return it if it has.
4235+
if (mProcessActors.Contains(aName)) {
4236+
return mProcessActors.Get(aName);
4237+
}
4238+
4239+
// Otherwise, we want to create a new instance of this actor.
4240+
JS::RootedObject obj(RootingCx());
4241+
ConstructActor(aName, &obj, aRv);
4242+
if (aRv.Failed()) {
4243+
return nullptr;
4244+
}
4245+
4246+
// Unwrap our actor to a JSProcessActorChild object.
4247+
RefPtr<JSProcessActorChild> actor;
4248+
if (NS_FAILED(UNWRAP_OBJECT(JSProcessActorChild, &obj, actor))) {
4249+
aRv.ThrowTypeMismatchError(
4250+
"Constructed actor does not inherit from JSProcessActorChild");
4251+
return nullptr;
4252+
}
4253+
4254+
MOZ_RELEASE_ASSERT(!actor->Manager(),
4255+
"mManager was already initialized once!");
4256+
actor->Init(aName, this);
4257+
mProcessActors.Put(aName, RefPtr{actor});
4258+
return actor.forget();
4259+
}
4260+
41944261
} // namespace dom
41954262

41964263
#if defined(__OpenBSD__) && defined(MOZ_SANDBOX)

dom/ipc/ContentChild.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include "mozilla/Attributes.h"
1313
#include "mozilla/UniquePtr.h"
1414
#include "mozilla/dom/BrowserBridgeChild.h"
15+
#include "mozilla/dom/ProcessActor.h"
16+
#include "mozilla/dom/JSProcessActorChild.h"
1517
#include "mozilla/dom/PBrowserOrId.h"
1618
#include "mozilla/dom/PContentChild.h"
1719
#include "mozilla/dom/RemoteBrowser.h"
@@ -42,6 +44,7 @@ struct LookAndFeelInt;
4244
class nsDocShellLoadState;
4345
class nsFrameLoader;
4446
class nsIOpenWindowInfo;
47+
class JSProcessActorChild;
4548

4649
namespace mozilla {
4750
class RemoteSpellcheckEngineChild;
@@ -78,7 +81,8 @@ class ContentChild final
7881
public nsIContentChild,
7982
public nsIWindowProvider,
8083
public mozilla::ipc::IShmemAllocator,
81-
public mozilla::ipc::ChildToParentStreamActorManager {
84+
public mozilla::ipc::ChildToParentStreamActorManager,
85+
public ProcessActor {
8286
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
8387
typedef mozilla::ipc::FileDescriptor FileDescriptor;
8488
typedef mozilla::ipc::PFileDescriptorSetChild PFileDescriptorSetChild;
@@ -390,19 +394,22 @@ class ContentChild final
390394

391395
// Call RemoteTypePrefix() on the result to remove URIs if you want to use
392396
// this for telemetry.
393-
const nsAString& GetRemoteType() const;
397+
const nsAString& GetRemoteType() const override;
394398

395399
mozilla::ipc::IPCResult RecvInitServiceWorkers(
396400
const ServiceWorkerConfiguration& aConfig);
397401

398402
mozilla::ipc::IPCResult RecvInitBlobURLs(
399403
nsTArray<BlobURLRegistrationData>&& aRegistations);
400404

401-
mozilla::ipc::IPCResult RecvInitJSWindowActorInfos(
402-
nsTArray<JSWindowActorInfo>&& aInfos);
405+
mozilla::ipc::IPCResult RecvInitJSActorInfos(
406+
nsTArray<JSProcessActorInfo>&& aContentInfos,
407+
nsTArray<JSWindowActorInfo>&& aWindowInfos);
403408

404409
mozilla::ipc::IPCResult RecvUnregisterJSWindowActor(const nsCString& aName);
405410

411+
mozilla::ipc::IPCResult RecvUnregisterJSProcessActor(const nsCString& aName);
412+
406413
mozilla::ipc::IPCResult RecvLastPrivateDocShellDestroyed();
407414

408415
mozilla::ipc::IPCResult RecvNotifyProcessPriorityChanged(
@@ -701,6 +708,10 @@ class ContentChild final
701708
PFileDescriptorSetChild* SendPFileDescriptorSetConstructor(
702709
const FileDescriptor& aFD) override;
703710

711+
// Get a JS actor object by name.
712+
already_AddRefed<mozilla::dom::JSProcessActorChild> GetActor(
713+
const nsACString& aName, ErrorResult& aRv);
714+
704715
private:
705716
static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
706717
void StartForceKillTimer();
@@ -793,6 +804,17 @@ class ContentChild final
793804
mozilla::ipc::IPCResult RecvDisplayLoadError(
794805
const MaybeDiscarded<BrowsingContext>& aContext, const nsAString& aURI);
795806

807+
mozilla::ipc::IPCResult RecvRawMessage(const JSActorMessageMeta& aMeta,
808+
const ClonedMessageData& aData,
809+
const ClonedMessageData& aStack);
810+
811+
void ReceiveRawMessage(const JSActorMessageMeta& aMeta,
812+
ipc::StructuredCloneData&& aData,
813+
ipc::StructuredCloneData&& aStack);
814+
815+
JSActor::Type GetSide() override { return JSActor::Type::Child; }
816+
817+
private:
796818
#ifdef NIGHTLY_BUILD
797819
virtual PContentChild::Result OnMessageReceived(const Message& aMsg) override;
798820
#else
@@ -884,6 +906,8 @@ class ContentChild final
884906
// See `BrowsingContext::mEpochs` for an explanation of this field.
885907
uint64_t mBrowsingContextFieldEpoch = 0;
886908

909+
nsRefPtrHashtable<nsCStringHashKey, JSProcessActorChild> mProcessActors;
910+
887911
DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
888912
};
889913

dom/ipc/ContentParent.cpp

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
#include "mozilla/dom/IPCBlobInputStreamParent.h"
9494
#include "mozilla/dom/IPCBlobUtils.h"
9595
#include "mozilla/dom/JSActorService.h"
96+
#include "mozilla/dom/JSProcessActorBinding.h"
9697
#include "mozilla/dom/LocalStorageCommon.h"
9798
#include "mozilla/dom/MediaController.h"
9899
#include "mozilla/dom/MemoryReportRequest.h"
@@ -2613,12 +2614,16 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
26132614
}
26142615
}
26152616

2616-
// Send down WindowActorOptions at startup to content process.
2617+
// Send down { Parent, Window }ActorOptions at startup to content process.
26172618
RefPtr<JSActorService> actorSvc = JSActorService::GetSingleton();
26182619
if (actorSvc) {
2619-
nsTArray<JSWindowActorInfo> infos;
2620-
actorSvc->GetJSWindowActorInfos(infos);
2621-
Unused << SendInitJSWindowActorInfos(infos);
2620+
nsTArray<JSProcessActorInfo> contentInfos;
2621+
actorSvc->GetJSProcessActorInfos(contentInfos);
2622+
2623+
nsTArray<JSWindowActorInfo> windowInfos;
2624+
actorSvc->GetJSWindowActorInfos(windowInfos);
2625+
2626+
Unused << SendInitJSActorInfos(contentInfos, windowInfos);
26222627
}
26232628

26242629
// Start up nsPluginHost and run FindPlugins to cache the plugin list.
@@ -6421,6 +6426,63 @@ NS_IMETHODIMP ContentParent::GetChildID(uint64_t* aOut) {
64216426
return NS_OK;
64226427
}
64236428

6429+
IPCResult ContentParent::RecvRawMessage(const JSActorMessageMeta& aMeta,
6430+
const ClonedMessageData& aData,
6431+
const ClonedMessageData& aStack) {
6432+
StructuredCloneData data;
6433+
data.BorrowFromClonedMessageDataForParent(aData);
6434+
StructuredCloneData stack;
6435+
stack.BorrowFromClonedMessageDataForParent(aStack);
6436+
ReceiveRawMessage(aMeta, std::move(data), std::move(stack));
6437+
return IPC_OK();
6438+
}
6439+
6440+
void ContentParent::ReceiveRawMessage(const JSActorMessageMeta& aMeta,
6441+
StructuredCloneData&& aData,
6442+
StructuredCloneData&& aStack) {
6443+
RefPtr<JSProcessActorParent> actor =
6444+
GetActor(aMeta.actorName(), IgnoreErrors());
6445+
if (actor) {
6446+
actor->ReceiveRawMessage(aMeta, std::move(aData), std::move(aStack));
6447+
}
6448+
}
6449+
6450+
already_AddRefed<JSProcessActorParent> ContentParent::GetActor(
6451+
const nsACString& aName, ErrorResult& aRv) {
6452+
if (!CanSend()) {
6453+
aRv.ThrowInvalidStateError(nsPrintfCString("Cannot get actor '%s': content parent is ready to communicate.",
6454+
PromiseFlatCString(aName).get()
6455+
));
6456+
return nullptr;
6457+
}
6458+
6459+
// Check if this actor has already been created, and return it if it has.
6460+
if (mProcessActors.Contains(aName)) {
6461+
return do_AddRef(mProcessActors.GetWeak(aName));
6462+
}
6463+
6464+
// Otherwise, we want to create a new instance of this actor.
6465+
JS::RootedObject obj(RootingCx());
6466+
ConstructActor(aName, &obj, aRv);
6467+
if (aRv.Failed()) {
6468+
return nullptr;
6469+
}
6470+
6471+
// Unwrap our actor to a JSProcessActorParent object.
6472+
RefPtr<JSProcessActorParent> actor;
6473+
if (NS_FAILED(UNWRAP_OBJECT(JSProcessActorParent, &obj, actor))) {
6474+
aRv.ThrowTypeMismatchError(
6475+
"Constructed actor does not inherit from JSProcessActorParent");
6476+
return nullptr;
6477+
}
6478+
6479+
MOZ_RELEASE_ASSERT(!actor->Manager(),
6480+
"mManager was already initialized once!");
6481+
actor->Init(aName, this);
6482+
mProcessActors.Put(aName, RefPtr{actor});
6483+
return actor.forget();
6484+
}
6485+
64246486
} // namespace dom
64256487
} // namespace mozilla
64266488

0 commit comments

Comments
 (0)