diff --git a/shell/browser/api/electron_api_utility_process.cc b/shell/browser/api/electron_api_utility_process.cc index 1a88b8ce3953..c1bdfdda8ca6 100644 --- a/shell/browser/api/electron_api_utility_process.cc +++ b/shell/browser/api/electron_api_utility_process.cc @@ -246,12 +246,16 @@ void UtilityProcessWrapper::OnServiceProcessLaunch( } void UtilityProcessWrapper::HandleTermination(uint64_t exit_code) { + // HandleTermination is called from multiple callsites, + // we need to ensure we only process it for the first callsite. + if (terminated_) + return; + terminated_ = true; + if (pid_ != base::kNullProcessId) GetAllUtilityProcessWrappers().Remove(pid_); CloseConnectorPort(); - EmitWithoutEvent("exit", exit_code); - Unpin(); } @@ -290,13 +294,8 @@ void UtilityProcessWrapper::CloseConnectorPort() { } void UtilityProcessWrapper::Shutdown(uint64_t exit_code) { - if (pid_ != base::kNullProcessId) - GetAllUtilityProcessWrappers().Remove(pid_); node_service_remote_.reset(); - CloseConnectorPort(); - // Emit 'exit' event - EmitWithoutEvent("exit", exit_code); - Unpin(); + HandleTermination(exit_code); } void UtilityProcessWrapper::PostMessage(gin::Arguments* args) { diff --git a/shell/browser/api/electron_api_utility_process.h b/shell/browser/api/electron_api_utility_process.h index 29b6d26a2fd7..d4bcfc791dd5 100644 --- a/shell/browser/api/electron_api_utility_process.h +++ b/shell/browser/api/electron_api_utility_process.h @@ -98,6 +98,7 @@ class UtilityProcessWrapper final int stdout_read_fd_ = -1; int stderr_read_fd_ = -1; bool connector_closed_ = false; + bool terminated_ = false; std::unique_ptr connector_; blink::MessagePortDescriptor host_port_; mojo::Remote node_service_remote_; diff --git a/spec/api-utility-process-spec.ts b/spec/api-utility-process-spec.ts index 33c3640d80ad..2765fdc059fb 100644 --- a/spec/api-utility-process-spec.ts +++ b/spec/api-utility-process-spec.ts @@ -58,10 +58,20 @@ describe('utilityProcess module', () => { await once(child, 'spawn'); }); - it('emits \'exit\' when child process exits gracefully', async () => { + it('emits \'exit\' when child process exits gracefully', (done) => { const child = utilityProcess.fork(path.join(fixturesPath, 'empty.js')); - const [code] = await once(child, 'exit'); - expect(code).to.equal(0); + child.on('exit', (code) => { + expect(code).to.equal(0); + done(); + }); + }); + + it('emits \'exit\' when the child process file does not exist', (done) => { + const child = utilityProcess.fork('nonexistent'); + child.on('exit', (code) => { + expect(code).to.equal(1); + done(); + }); }); ifit(!isWindows32Bit)('emits the correct error code when child process exits nonzero', async () => {