Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/extensions/electron-main/extensionHostStarter.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Promises } from '../../../base/common/async.js';
7
import { canceled } from '../../../base/common/errors.js';
8
import { Event } from '../../../base/common/event.js';
9
import { Disposable, IDisposable } from '../../../base/common/lifecycle.js';
10
import { IExtensionHostProcessOptions, IExtensionHostStarter } from '../common/extensionHostStarter.js';
11
import { ILifecycleMainService } from '../../lifecycle/electron-main/lifecycleMainService.js';
12
import { ILogService } from '../../log/common/log.js';
13
import { ITelemetryService } from '../../telemetry/common/telemetry.js';
14
import { WindowUtilityProcess } from '../../utilityProcess/electron-main/utilityProcess.js';
15
import { IWindowsMainService } from '../../windows/electron-main/windows.js';
16
import { IConfigurationService } from '../../configuration/common/configuration.js';
17
18
export class ExtensionHostStarter extends Disposable implements IDisposable, IExtensionHostStarter {
19
20
readonly _serviceBrand: undefined;
21
22
private static _lastId: number = 0;
23
24
private readonly _extHosts = new Map<string, WindowUtilityProcess>();
25
private _shutdown = false;
26
27
constructor(
28
@ILogService private readonly _logService: ILogService,
29
@ILifecycleMainService private readonly _lifecycleMainService: ILifecycleMainService,
30
@IWindowsMainService private readonly _windowsMainService: IWindowsMainService,
31
@ITelemetryService private readonly _telemetryService: ITelemetryService,
32
@IConfigurationService private readonly _configurationService: IConfigurationService,
33
) {
34
super();
35
36
// On shutdown: gracefully await extension host shutdowns
37
this._register(this._lifecycleMainService.onWillShutdown(e => {
38
this._shutdown = true;
39
e.join('extHostStarter', this._waitForAllExit(6000));
40
}));
41
}
42
43
override dispose(): void {
44
// Intentionally not killing the extension host processes
45
super.dispose();
46
}
47
48
private _getExtHost(id: string): WindowUtilityProcess {
49
const extHostProcess = this._extHosts.get(id);
50
if (!extHostProcess) {
51
throw new Error(`Unknown extension host!`);
52
}
53
return extHostProcess;
54
}
55
56
onDynamicStdout(id: string): Event<string> {
57
return this._getExtHost(id).onStdout;
58
}
59
60
onDynamicStderr(id: string): Event<string> {
61
return this._getExtHost(id).onStderr;
62
}
63
64
onDynamicMessage(id: string): Event<any> {
65
return this._getExtHost(id).onMessage;
66
}
67
68
onDynamicExit(id: string): Event<{ code: number; signal: string }> {
69
return this._getExtHost(id).onExit;
70
}
71
72
async createExtensionHost(): Promise<{ id: string }> {
73
if (this._shutdown) {
74
throw canceled();
75
}
76
const id = String(++ExtensionHostStarter._lastId);
77
const extHost = new WindowUtilityProcess(this._logService, this._windowsMainService, this._telemetryService, this._lifecycleMainService);
78
this._extHosts.set(id, extHost);
79
const disposable = extHost.onExit(({ pid, code, signal }) => {
80
disposable.dispose();
81
this._logService.info(`Extension host with pid ${pid} exited with code: ${code}, signal: ${signal}.`);
82
setTimeout(() => {
83
extHost.dispose();
84
this._extHosts.delete(id);
85
});
86
87
// See https://github.com/microsoft/vscode/issues/194477
88
// We have observed that sometimes the process sends an exit
89
// event, but does not really exit and is stuck in an endless
90
// loop. In these cases we kill the process forcefully after
91
// a certain timeout.
92
setTimeout(() => {
93
try {
94
process.kill(pid, 0); // will throw if the process doesn't exist anymore.
95
this._logService.error(`Extension host with pid ${pid} still exists, forcefully killing it...`);
96
process.kill(pid);
97
} catch (er) {
98
// ignore, as the process is already gone
99
}
100
}, 1000);
101
});
102
return { id };
103
}
104
105
async start(id: string, opts: IExtensionHostProcessOptions): Promise<{ pid: number | undefined }> {
106
if (this._shutdown) {
107
throw canceled();
108
}
109
const extHost = this._getExtHost(id);
110
const args = ['--skipWorkspaceStorageLock'];
111
if (this._configurationService.getValue<boolean>('extensions.supportNodeGlobalNavigator')) {
112
args.push('--supportGlobalNavigator');
113
}
114
extHost.start({
115
...opts,
116
type: 'extensionHost',
117
name: 'extension-host',
118
entryPoint: 'vs/workbench/api/node/extensionHostProcess',
119
args,
120
execArgv: opts.execArgv,
121
allowLoadingUnsignedLibraries: true,
122
respondToAuthRequestsFromMainProcess: true,
123
correlationId: id
124
});
125
const pid = await Event.toPromise(extHost.onSpawn);
126
return { pid };
127
}
128
129
async enableInspectPort(id: string): Promise<boolean> {
130
if (this._shutdown) {
131
throw canceled();
132
}
133
const extHostProcess = this._extHosts.get(id);
134
if (!extHostProcess) {
135
return false;
136
}
137
return extHostProcess.enableInspectPort();
138
}
139
140
async kill(id: string): Promise<void> {
141
if (this._shutdown) {
142
throw canceled();
143
}
144
const extHostProcess = this._extHosts.get(id);
145
if (!extHostProcess) {
146
// already gone!
147
return;
148
}
149
extHostProcess.kill();
150
}
151
152
async _killAllNow(): Promise<void> {
153
for (const [, extHost] of this._extHosts) {
154
extHost.kill();
155
}
156
}
157
158
async _waitForAllExit(maxWaitTimeMs: number): Promise<void> {
159
const exitPromises: Promise<void>[] = [];
160
for (const [, extHost] of this._extHosts) {
161
exitPromises.push(extHost.waitForExit(maxWaitTimeMs));
162
}
163
return Promises.settled(exitPromises).then(() => { });
164
}
165
}
166
167