Skip to content

Commit

Permalink
fix: update process.parentPort API
Browse files Browse the repository at this point in the history
  • Loading branch information
deepak1556 committed Sep 13, 2022
1 parent 277facc commit 5f8e796
Show file tree
Hide file tree
Showing 18 changed files with 195 additions and 34 deletions.
22 changes: 22 additions & 0 deletions docs/api/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
9 changes: 9 additions & 0 deletions docs/api/utility-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 2 additions & 0 deletions filenames.gni
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions lib/utility_process/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[]) {
Expand Down
3 changes: 1 addition & 2 deletions patches/chromium/.patches
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,4 @@ fix_revert_emulationhandler_update_functions_to_early_return.patch
fix_crash_loading_non-standard_schemes_in_iframes.patch
disable_optimization_guide_for_preconnect_feature.patch
fix_return_v8_value_from_localframe_requestexecutescript.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
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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)

Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -345,16 +345,16 @@ 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.
- for (HANDLE handle : handles_to_inherit)
+ 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));
Expand All @@ -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,
Expand All @@ -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())) {
Expand All @@ -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(
Expand All @@ -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,
Expand All @@ -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,
Expand Down
18 changes: 16 additions & 2 deletions shell/browser/api/electron_api_utility_process.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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(
Expand All @@ -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();
Expand Down
3 changes: 2 additions & 1 deletion shell/browser/api/electron_api_utility_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions shell/browser/electron_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -111,6 +112,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"
Expand Down Expand Up @@ -1654,6 +1656,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) {
Expand Down
1 change: 1 addition & 0 deletions shell/browser/electron_browser_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,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;
Expand Down
32 changes: 32 additions & 0 deletions shell/browser/node_service_host_impl.cc
Original file line number Diff line number Diff line change
@@ -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 changes: 38 additions & 0 deletions shell/browser/node_service_host_impl.h
Original file line number Diff line number Diff line change
@@ -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_

0 comments on commit 5f8e796

Please sign in to comment.