fix: update process.parentPort API

This commit is contained in:
deepak1556 committed 2022-09-23 17:51:03 +09:00
1 parent 9bed7868ab
commit 489d3ac164
18 files changed
+195 -32

No files matched your search

+22
View File
@@ -135,6 +135,28 @@ Each frame has its own JavaScript context. When contextIsolation is enabled, the
world also has a separate JavaScript context.
This property is only available in the renderer process.
### `process.parentPort`
A `MessagePort` if this is a [`UtilityProcess`](utility-process.md) allowing communication
with the parent process. Messages sent using `process.parentPort.postMessage` are available in
the parent process using [`utilityProcess.on('message')`](utility-process.md#event-message) and messages sent
from the parent process using [`utilityProcess.postMessage()`](utility-process.md#childpostmessagemessage-transfer) are available
in this process using `process.parentPort.on('message')`.
```js
// Main process
const child = new UtilityProcess(path.join(__dirname, 'test.js'))
child.postMessage({ message: 'hello' })
child.on('message', (ev, data) => {
console.log(data) // hello world!
})
// Child process
process.parentPort.on('message', (e) => {
process.parentPort.postMessage(`${e.data} world!`)
})
```
## Methods
The `process` object has the following methods:
+9
View File
@@ -114,6 +114,15 @@ Returns:
Emitted when the child process has a normal termination.
For other abnormal exit cases listen to the [`child-process-gone` event of `app`](app.md#event-child-process-gone).
#### Event: 'message'
Returns:
* `event` Event
* `message` any
Emitted when the child process sends a message using [`process.parentPort.postMessage()`](process.md#processparentport).
[`child_process.fork`]: https://nodejs.org/dist/latest-v16.x/docs/api/child_process.html#child_processforkmodulepath-args-options
[Services API]: https://chromium.googlesource.com/chromium/src/+/master/docs/mojo_and_services.md
[stdio]: https://nodejs.org/dist/latest/docs/api/child_process.html#optionsstdio
+2
View File
@@ -456,6 +456,8 @@ filenames = {
"shell/browser/net/web_request_api_interface.h",
"shell/browser/network_hints_handler_impl.cc",
"shell/browser/network_hints_handler_impl.h",
"shell/browser/node_service_host_impl.cc",
"shell/browser/node_service_host_impl.h",
"shell/browser/notifications/notification.cc",
"shell/browser/notifications/notification.h",
"shell/browser/notifications/notification_delegate.h",
+1
View File
@@ -15,6 +15,7 @@ require('../common/reset-search-paths');
require('@electron/internal/common/init');
const parentPort: NodeJS.ParentPort = new EventEmitter() as any;
parentPort.postMessage = v8Util.getHiddenValue(process, '_postMessage');
v8Util.setHiddenValue(global, 'messagechannel', {
didReceiveMessage (event: any, ports: any[]) {
+1
View File
@@ -124,3 +124,4 @@ fix_return_v8_value_from_localframe_requestexecutescript.patch
create_browser_v8_snapshot_file_name_fuse.patch
chore_posix_support_remapping_fds_when_launching_service_process.patch
feat_remap_fds_or_inherit_handles_for_child_process.patch
feat_support_remapping_inheriting_fds_handles_for_service_process.patch
@@ -112,7 +112,7 @@ index 5f89cc089f8cca58c4d5f5168d0cf893ab461005..99b53cd36484c7c30b273e62c2fb4193
host->GetChildProcess()->BindServiceInterface(std::move(receiver));
}
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index b96072fd917fce5cd8abb16a4ef705aea4dfe132..e85c2de6726453409d3144d3a07f48b9aacb7670 100644
index cde30840e19c6838233a26f11549a85411f3e99a..e7092d2520396946b24f8c8f9f250590e650666b 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -153,6 +153,19 @@ void UtilityProcessHost::SetExtraCommandLineSwitches(
@@ -135,7 +135,7 @@ index b96072fd917fce5cd8abb16a4ef705aea4dfe132..e85c2de6726453409d3144d3a07f48b9
mojom::ChildProcess* UtilityProcessHost::GetChildProcess() {
return static_cast<ChildProcessHostImpl*>(process_->GetHost())
->child_process();
@@ -357,6 +370,18 @@ bool UtilityProcessHost::StartProcess() {
@@ -356,6 +369,18 @@ bool UtilityProcessHost::StartProcess() {
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
@@ -320,10 +320,10 @@ index ba4da80ea34b038d22f048d17c267c92040667c4..f31413cd670d8075419f6e74f1cefb96
} // namespace content
diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc
index 73627a4c488b1658469184efe57731ca3fefdc71..054f53ab02b4eeb052b21786e8d6bf267b40a6bf 100644
index 2d1a89a0bf50df40177e41010adb5b05fae10ce2..2ceadaa38ad52451b04a0f3b70eae479b9af95c4 100644
--- a/sandbox/policy/win/sandbox_win.cc
+++ b/sandbox/policy/win/sandbox_win.cc
@@ -740,11 +740,9 @@ ResultCode SetupAppContainerProfile(AppContainer* container,
@@ -864,11 +864,9 @@ ResultCode GenerateConfigForSandboxedProcess(const base::CommandLine& cmd_line,
// command line flag.
ResultCode LaunchWithoutSandbox(
const base::CommandLine& cmd_line,
@@ -336,7 +336,7 @@ index 73627a4c488b1658469184efe57731ca3fefdc71..054f53ab02b4eeb052b21786e8d6bf26
// Network process runs in a job even when unsandboxed. This is to ensure it
// does not outlive the browser, which could happen if there is a lot of I/O
// on process shutdown, in which case TerminateProcess can fail. See
@@ -975,7 +973,7 @@ bool SandboxWin::InitTargetServices(TargetServices* target_services) {
@@ -1103,7 +1101,7 @@ bool SandboxWin::InitTargetServices(TargetServices* target_services) {
ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
const base::CommandLine& cmd_line,
const std::string& process_type,
@@ -345,7 +345,7 @@ index 73627a4c488b1658469184efe57731ca3fefdc71..054f53ab02b4eeb052b21786e8d6bf26
SandboxDelegate* delegate,
TargetPolicy* policy) {
const base::CommandLine& launcher_process_command_line =
@@ -995,7 +993,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
@@ -1117,7 +1115,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
}
// Add any handles to be inherited to the policy.
@@ -353,8 +353,8 @@ index 73627a4c488b1658469184efe57731ca3fefdc71..054f53ab02b4eeb052b21786e8d6bf26
+ for (HANDLE handle : options.handles_to_inherit)
policy->AddHandleToShare(handle);
// Pre-startup mitigations.
@@ -1125,6 +1123,13 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
if (!policy->GetConfig()->IsConfigured()) {
@@ -1138,6 +1136,13 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
// have no effect. These calls can fail with SBOX_ERROR_BAD_PARAMS.
policy->SetStdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE));
policy->SetStderrHandle(GetStdHandle(STD_ERROR_HANDLE));
@@ -368,7 +368,7 @@ index 73627a4c488b1658469184efe57731ca3fefdc71..054f53ab02b4eeb052b21786e8d6bf26
#endif
if (!delegate->PreSpawnTarget(policy))
@@ -1137,7 +1142,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
@@ -1150,7 +1155,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
ResultCode SandboxWin::StartSandboxedProcess(
const base::CommandLine& cmd_line,
const std::string& process_type,
@@ -377,7 +377,7 @@ index 73627a4c488b1658469184efe57731ca3fefdc71..054f53ab02b4eeb052b21786e8d6bf26
SandboxDelegate* delegate,
base::Process* process) {
const base::ElapsedTimer timer;
@@ -1145,7 +1150,7 @@ ResultCode SandboxWin::StartSandboxedProcess(
@@ -1158,7 +1163,7 @@ ResultCode SandboxWin::StartSandboxedProcess(
// Avoid making a policy if we won't use it.
if (IsUnsandboxedProcess(delegate->GetSandboxType(), cmd_line,
*base::CommandLine::ForCurrentProcess())) {
@@ -386,7 +386,7 @@ index 73627a4c488b1658469184efe57731ca3fefdc71..054f53ab02b4eeb052b21786e8d6bf26
process);
}
@@ -1156,7 +1161,7 @@ ResultCode SandboxWin::StartSandboxedProcess(
@@ -1169,7 +1174,7 @@ ResultCode SandboxWin::StartSandboxedProcess(
auto policy = g_broker_services->CreatePolicy(tag);
auto time_policy_created = timer.Elapsed();
ResultCode result = GeneratePolicyForSandboxedProcess(
@@ -396,10 +396,10 @@ index 73627a4c488b1658469184efe57731ca3fefdc71..054f53ab02b4eeb052b21786e8d6bf26
return result;
auto time_policy_generated = timer.Elapsed();
diff --git a/sandbox/policy/win/sandbox_win.h b/sandbox/policy/win/sandbox_win.h
index ec9cb8b12e1d7cf9bada846b99e578199e34b711..76077b4bd05068e7d3330dae5554641e09628518 100644
index cd8b2dcd6f8eeab0bdd1fd09dcb118012ef64e60..2325e4831958564e2ae36b982bd7523621a7b763 100644
--- a/sandbox/policy/win/sandbox_win.h
+++ b/sandbox/policy/win/sandbox_win.h
@@ -49,7 +49,7 @@ class SANDBOX_POLICY_EXPORT SandboxWin {
@@ -50,7 +50,7 @@ class SANDBOX_POLICY_EXPORT SandboxWin {
static ResultCode StartSandboxedProcess(
const base::CommandLine& cmd_line,
const std::string& process_type,
@@ -408,7 +408,7 @@ index ec9cb8b12e1d7cf9bada846b99e578199e34b711..76077b4bd05068e7d3330dae5554641e
SandboxDelegate* delegate,
base::Process* process);
@@ -63,7 +63,7 @@ class SANDBOX_POLICY_EXPORT SandboxWin {
@@ -64,7 +64,7 @@ class SANDBOX_POLICY_EXPORT SandboxWin {
static ResultCode GeneratePolicyForSandboxedProcess(
const base::CommandLine& cmd_line,
const std::string& process_type,
@@ -22,6 +22,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/service_process_host.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/result_codes.h"
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "gin/wrappable.h"
@@ -476,10 +477,14 @@ void UtilityProcessWrapper::PostMessage(gin::Arguments* args) {
node_service_remote_->ReceivePostMessage(std::move(transferable_message));
}
int UtilityProcessWrapper::Kill(int signal) const {
bool UtilityProcessWrapper::Kill() const {
if (pid_ == base::kNullProcessId)
return 0;
return uv_kill(pid_, signal);
base::Process process = base::Process::Open(pid_);
bool result = process.Terminate(content::RESULT_CODE_NORMAL_EXIT, false);
// Refs https://bugs.chromium.org/p/chromium/issues/detail?id=818244
base::EnsureProcessTerminated(process.Duplicate());
return result;
}
v8::Local<v8::Value> UtilityProcessWrapper::GetOSProcessId(
@@ -489,6 +494,15 @@ v8::Local<v8::Value> UtilityProcessWrapper::GetOSProcessId(
return gin::ConvertToV8(isolate, pid_);
}
void UtilityProcessWrapper::ReceivePostMessage(
blink::TransferableMessage message) {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Value> message_value =
electron::DeserializeV8Value(isolate, message);
Emit("message", message_value);
}
void UtilityProcessWrapper::HandleMessage(ReaderType type,
std::vector<uint8_t> message) {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
@@ -53,6 +53,7 @@ class UtilityProcessWrapper
v8::Isolate* isolate) override;
const char* GetTypeName() override;
void ReceivePostMessage(blink::TransferableMessage message);
void HandleMessage(ReaderType type, std::vector<uint8_t> message);
void ResumeReading(PipeReaderBase* pipe_io);
void ShutdownReader(ReaderType type);
@@ -65,7 +66,7 @@ class UtilityProcessWrapper
void OnServiceProcessLaunched(const base::Process& process);
void PostMessage(gin::Arguments* args);
int Kill(int signal) const;
bool Kill() const;
v8::Local<v8::Value> GetOSProcessId(v8::Isolate* isolate) const;
base::ProcessId pid_ = base::kNullProcessId;
+11
View File
@@ -96,6 +96,7 @@
#include "shell/browser/net/proxying_websocket.h"
#include "shell/browser/net/system_network_context_manager.h"
#include "shell/browser/network_hints_handler_impl.h"
#include "shell/browser/node_service_host_impl.h"
#include "shell/browser/notifications/notification_presenter.h"
#include "shell/browser/notifications/platform_notification_service.h"
#include "shell/browser/protocol_registry.h"
@@ -112,6 +113,7 @@
#include "shell/common/logging.h"
#include "shell/common/options_switches.h"
#include "shell/common/platform_util.h"
#include "shell/services/node/public/mojom/node_service.mojom.h"
#include "third_party/blink/public/common/loader/url_loader_throttle.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
@@ -1655,6 +1657,15 @@ bool ElectronBrowserClient::ShouldEnableStrictSiteIsolation() {
return true;
}
void ElectronBrowserClient::BindUtilityHostReceiver(
mojo::GenericPendingReceiver receiver) {
if (auto r = receiver.As<node::mojom::NodeServiceHost>()) {
static base::NoDestructor<NodeServiceHostImpl> node_service_host;
node_service_host->BindReceiver(std::move(r));
return;
}
}
void ElectronBrowserClient::BindHostReceiverForRenderer(
content::RenderProcessHost* render_process_host,
mojo::GenericPendingReceiver receiver) {
+1
View File
@@ -72,6 +72,7 @@ class ElectronBrowserClient : public content::ContentBrowserClient,
std::string GetApplicationLocale() override;
base::FilePath GetFontLookupTableCacheDir() override;
bool ShouldEnableStrictSiteIsolation() override;
void BindUtilityHostReceiver(mojo::GenericPendingReceiver receiver) override;
void BindHostReceiverForRenderer(
content::RenderProcessHost* render_process_host,
mojo::GenericPendingReceiver receiver) override;
+32
View File
@@ -0,0 +1,32 @@
// Copyright (c) 2022 Microsoft, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/node_service_host_impl.h"
#include <utility>
#include "shell/browser/api/electron_api_utility_process.h"
namespace electron {
NodeServiceHostImpl::NodeServiceHostImpl() = default;
NodeServiceHostImpl::~NodeServiceHostImpl() = default;
void NodeServiceHostImpl::BindReceiver(
mojo::PendingReceiver<node::mojom::NodeServiceHost> receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
receivers_.Add(this, std::move(receiver));
}
void NodeServiceHostImpl::ReceivePostMessage(
base::ProcessId pid,
blink::TransferableMessage message) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto* utility_process_wrapper = GetAllUtilityProcessWrappers().Lookup(pid);
if (utility_process_wrapper)
utility_process_wrapper->ReceivePostMessage(std::move(message));
}
} // namespace electron
+38
View File
@@ -0,0 +1,38 @@
// Copyright (c) 2022 Microsoft, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ELECTRON_SHELL_BROWSER_NODE_SERVICE_HOST_IMPL_H_
#define ELECTRON_SHELL_BROWSER_NODE_SERVICE_HOST_IMPL_H_
#include "base/sequence_checker.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "shell/services/node/public/mojom/node_service.mojom.h"
namespace electron {
class NodeServiceHostImpl : public node::mojom::NodeServiceHost {
public:
NodeServiceHostImpl();
NodeServiceHostImpl(const NodeServiceHostImpl&) = delete;
NodeServiceHostImpl& operator=(const NodeServiceHostImpl&) = delete;
~NodeServiceHostImpl() override;
void BindReceiver(
mojo::PendingReceiver<node::mojom::NodeServiceHost> receiver);
// node::mojom::NodeServiceHost:
void ReceivePostMessage(base::ProcessId pid,
blink::TransferableMessage message) override;
private:
mojo::ReceiverSet<node::mojom::NodeServiceHost> receivers_;
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace electron
#endif // ELECTRON_SHELL_BROWSER_NODE_SERVICE_HOST_IMPL_H_
+21
View File
@@ -9,12 +9,15 @@
#include "base/command_line.h"
#include "base/environment.h"
#include "base/process/process.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/utility/utility_thread.h"
#include "gin/data_object_builder.h"
#include "gin/handle.h"
#include "shell/browser/api/message_port.h"
#include "shell/browser/javascript_environment.h"
#include "shell/common/api/electron_bindings.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/event_emitter_caller.h"
@@ -33,6 +36,10 @@ NodeService::NodeService(
std::make_unique<ElectronBindings>(node_bindings_->uv_loop())) {
if (receiver.is_valid())
receiver_.Bind(std::move(receiver));
if (auto* thread = content::UtilityThread::Get()) {
thread->BindHostReceiver(
node_service_host_remote_.BindNewPipeAndPassReceiver());
}
}
NodeService::~NodeService() {
@@ -82,6 +89,9 @@ void NodeService::Initialize(node::mojom::NodeServiceParamsPtr params) {
// Add entry script to process object.
gin_helper::Dictionary process(env->isolate(), env->process_object());
process.SetReadOnly("_serviceStartupScript", params->script);
process.SetHidden("_postMessage",
base::BindRepeating(&NodeService::PostMessage,
weak_factory_.GetWeakPtr()));
// Load everything.
node_bindings_->LoadEnvironment(env);
@@ -97,6 +107,17 @@ void NodeService::Initialize(node::mojom::NodeServiceParamsPtr params) {
node_bindings_->StartPolling();
}
void NodeService::PostMessage(v8::Local<v8::Value> message_value) {
if (!node_service_host_remote_)
return;
v8::Isolate* isolate = js_env_->isolate();
blink::TransferableMessage transferable_message;
electron::SerializeV8Value(isolate, message_value, &transferable_message);
node_service_host_remote_->ReceivePostMessage(
base::Process::Current().Pid(), std::move(transferable_message));
}
void NodeService::ReceivePostMessage(blink::TransferableMessage message) {
v8::Isolate* isolate = js_env_->isolate();
v8::HandleScope handle_scope(isolate);
+11 -1
View File
@@ -10,8 +10,15 @@
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "shell/services/node/public/mojom/node_service.mojom.h"
namespace v8 {
template <class T>
class Local;
class Value;
} // namespace v8
namespace electron {
class ElectronBindings;
@@ -29,6 +36,8 @@ class NodeService : public node::mojom::NodeService {
~NodeService() override;
void PostMessage(v8::Local<v8::Value> message_value);
// mojom::NodeService implementation:
void Initialize(node::mojom::NodeServiceParamsPtr params) override;
void ReceivePostMessage(blink::TransferableMessage message) override;
@@ -40,8 +49,9 @@ class NodeService : public node::mojom::NodeService {
std::unique_ptr<NodeBindings> node_bindings_;
std::unique_ptr<ElectronBindings> electron_bindings_;
std::unique_ptr<NodeEnvironment> node_env_;
mojo::Remote<node::mojom::NodeServiceHost> node_service_host_remote_;
mojo::Receiver<node::mojom::NodeService> receiver_{this};
base::WeakPtrFactory<NodeService> weak_factory_{this};
};
} // namespace electron
@@ -5,6 +5,7 @@
module node.mojom;
import "mojo/public/mojom/base/file_path.mojom";
import "mojo/public/mojom/base/process_id.mojom";
import "sandbox/policy/mojom/sandbox.mojom";
import "third_party/blink/public/mojom/messaging/transferable_message.mojom";
@@ -26,3 +27,8 @@ interface NodeService {
ReceivePostMessage(blink.mojom.TransferableMessage message);
};
interface NodeServiceHost {
ReceivePostMessage(mojo_base.mojom.ProcessId pid,
blink.mojom.TransferableMessage message);
};
+6 -12
View File
@@ -161,11 +161,9 @@ describe('UtilityProcess module', () => {
const result = 'I will be echoed.';
const child = new UtilityProcess(path.join(fixturesPath, 'post-message.js'));
await emittedOnce(child, 'spawn');
const { port1, port2 } = new MessageChannelMain();
child.postMessage(result, [port2]);
port1.start();
const [e] = await emittedOnce(port1, 'message');
expect(e.data).to.equal(result);
child.postMessage(result);
const [, data] = await emittedOnce(child, 'message');
expect(data).to.equal(result);
const exit = emittedOnce(child, 'exit');
expect(child.kill()).to.be.true();
await exit;
@@ -263,17 +261,13 @@ describe('UtilityProcess module', () => {
await w.loadFile(path.join(__dirname, 'fixtures', 'blank.html'));
// Create Message port pair for Renderer <-> Utility Process.
const { port1: rendererPort, port2: childPort1 } = new MessageChannelMain();
// Create Message port pair for Utility Process <-> Main.
const { port1: mainPort, port2: childPort2 } = new MessageChannelMain();
w.webContents.postMessage('port', result, [rendererPort]);
// Send renderer and main channel port to utility process.
const child = new UtilityProcess(path.join(fixturesPath, 'receive-message.js'));
await emittedOnce(child, 'spawn');
child.postMessage('', [childPort1, childPort2]);
// Receive result from utility process.
mainPort.start();
const [e] = await emittedOnce(mainPort, 'message');
expect(e.data).to.equal(result);
child.postMessage('', [childPort1]);
const [, data] = await emittedOnce(child, 'message');
expect(data).to.equal(result);
// Cleanup.
const exit = emittedOnce(child, 'exit');
expect(child.kill()).to.be.true();
+1 -1
View File
@@ -1,3 +1,3 @@
process.parentPort.on('message', (e) => {
e.ports[0].postMessage(e.data);
process.parentPort.postMessage(e.data);
});
+1 -1
View File
@@ -1,6 +1,6 @@
process.parentPort.on('message', (e) => {
e.ports[0].on('message', (ev) => {
e.ports[1].postMessage(ev.data);
process.parentPort.postMessage(ev.data);
});
e.ports[0].start();
});