Merge from vscode ec07311dab2556c9d66a4cb3eecdc21c524202e1 (#6739)

This commit is contained in:
Anthony Dresser
2019-08-13 19:14:03 -07:00
committed by GitHub
parent a645a09f42
commit 82c1c57c76
77 changed files with 1319 additions and 741 deletions

View File

@@ -18,6 +18,8 @@ import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/co
import { RemoteExtensionHostClient, IInitDataProvider } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { WebWorkerExtensionHostStarter } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter';
import { URI } from 'vs/base/common/uri';
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
@@ -62,6 +64,11 @@ export class ExtensionService extends AbstractExtensionService implements IExten
const result: ExtensionHostProcessManager[] = [];
const remoteAgentConnection = this._remoteAgentService.getConnection()!;
const webHostProcessWorker = this._instantiationService.createInstance(WebWorkerExtensionHostStarter, true, Promise.resolve([]), URI.parse('empty:value')); //todo@joh
const webHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, webHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents);
result.push(webHostProcessManager);
const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents);
result.push(remoteExtHostProcessManager);

View File

@@ -0,0 +1,150 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory';
import { Emitter, Event } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { VSBuffer } from 'vs/base/common/buffer';
import { createMessageOfType, MessageType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { ILabelService } from 'vs/platform/label/common/label';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as platform from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions';
import { IProductService } from 'vs/platform/product/common/product';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
private _toDispose = new DisposableStore();
private _isTerminating: boolean = false;
private _protocol?: IMessagePassingProtocol;
private readonly _onDidExit = new Emitter<[number, string | null]>();
readonly onExit: Event<[number, string | null]> = this._onDidExit.event;
constructor(
private readonly _autoStart: boolean,
private readonly _extensions: Promise<IExtensionDescription[]>,
private readonly _extensionHostLogsLocation: URI,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@ILabelService private readonly _labelService: ILabelService,
@ILogService private readonly _logService: ILogService,
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
@IProductService private readonly _productService: IProductService,
) {
}
async start(): Promise<IMessagePassingProtocol> {
if (!this._protocol) {
const emitter = new Emitter<VSBuffer>();
const worker = new DefaultWorkerFactory('WorkerExtensionHost').create(
'vs/workbench/services/extensions/worker/extensionHostWorker', data => {
if (data instanceof ArrayBuffer) {
emitter.fire(VSBuffer.wrap(new Uint8Array(data, 0, data.byteLength)));
} else {
console.warn('UNKNOWN data received', data);
this._onDidExit.fire([77, 'UNKNOWN data received']);
}
}, err => {
this._onDidExit.fire([81, err]);
console.error(err);
}
);
// keep for cleanup
this._toDispose.add(emitter);
this._toDispose.add(worker);
const protocol: IMessagePassingProtocol = {
onMessage: emitter.event,
send: vsbuf => {
const data = vsbuf.buffer.buffer.slice(vsbuf.buffer.byteOffset, vsbuf.buffer.byteOffset + vsbuf.buffer.byteLength);
worker.postMessage(data, [data]);
}
};
// extension host handshake happens below
// (1) <== wait for: Ready
// (2) ==> send: init data
// (3) <== wait for: Initialized
await Event.toPromise(Event.filter(protocol.onMessage, msg => isMessageOfType(msg, MessageType.Ready)));
protocol.send(VSBuffer.fromString(JSON.stringify(await this._createExtHostInitData())));
await Event.toPromise(Event.filter(protocol.onMessage, msg => isMessageOfType(msg, MessageType.Initialized)));
this._protocol = protocol;
}
return this._protocol;
}
dispose(): void {
if (!this._protocol) {
this._toDispose.dispose();
return;
}
if (this._isTerminating) {
return;
}
this._isTerminating = true;
this._protocol.send(createMessageOfType(MessageType.Terminate));
setTimeout(() => this._toDispose.dispose(), 10 * 1000);
}
getInspectPort(): number | undefined {
return undefined;
}
private async _createExtHostInitData(): Promise<IInitData> {
const [telemetryInfo, extensionDescriptions] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._extensions]);
const workspace = this._contextService.getWorkspace();
return {
commit: this._productService.commit,
version: this._productService.version,
vscodeVersion: this._productService.vscodeVersion,
parentPid: -1,
environment: {
isExtensionDevelopmentDebug: false,
appRoot: this._environmentService.appRoot ? URI.file(this._environmentService.appRoot) : undefined,
appSettingsHome: this._environmentService.appSettingsHome ? this._environmentService.appSettingsHome : undefined,
appName: this._productService.nameLong,
appUriScheme: this._productService.urlProtocol,
appLanguage: platform.language,
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI,
globalStorageHome: URI.parse('fake:globalStorageHome'), //todo@joh URI.file(this._environmentService.globalStorageHome),
userHome: URI.parse('fake:userHome'), //todo@joh URI.file(this._environmentService.userHome),
webviewResourceRoot: this._environmentService.webviewResourceRoot,
webviewCspSource: this._environmentService.webviewCspSource,
},
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : {
configuration: workspace.configuration || undefined,
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace)
},
resolvedExtensions: [],
hostExtensions: [],
extensions: extensionDescriptions,
telemetryInfo,
logLevel: this._logService.getLevel(),
logsLocation: this._extensionHostLogsLocation,
autoStart: this._autoStart,
remote: {
authority: this._environmentService.configuration.remoteAuthority,
isRemote: false
},
};
}
}

View File

@@ -10,7 +10,6 @@ import { URI, setUriThrowOnMissingScheme } from 'vs/base/common/uri';
import { IURITransformer } from 'vs/base/common/uriIpc';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { IInitData, MainContext, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
import { RPCProtocol } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
@@ -35,10 +34,6 @@ export interface IConsolePatchFn {
(mainThreadConsole: MainThreadConsoleShape): any;
}
export interface ILogServiceFn {
(initData: IInitData): ILogService;
}
export class ExtensionHostMain {
private _isTerminating: boolean;
@@ -50,8 +45,6 @@ export class ExtensionHostMain {
protocol: IMessagePassingProtocol,
initData: IInitData,
hostUtils: IHostUtils,
consolePatchFn: IConsolePatchFn,
logServiceFn: ILogServiceFn,
uriTransformer: IURITransformer | null
) {
this._isTerminating = false;
@@ -61,27 +54,27 @@ export class ExtensionHostMain {
// ensure URIs are transformed and revived
initData = ExtensionHostMain._transform(initData, rpcProtocol);
// allow to patch console
consolePatchFn(rpcProtocol.getProxy(MainContext.MainThreadConsole));
// services
const extHostLogService = new ExtHostLogService(logServiceFn(initData), initData.logsLocation.fsPath);
this._disposables.add(extHostLogService);
// bootstrap services
const services = new ServiceCollection(...getSingletonServiceDescriptors());
services.set(IExtHostInitDataService, { _serviceBrand: undefined, ...initData });
services.set(IExtHostRpcService, new ExtHostRpcService(rpcProtocol));
services.set(ILogService, extHostLogService);
services.set(IURITransformerService, new URITransformerService(uriTransformer));
services.set(IHostUtils, hostUtils);
const instaService: IInstantiationService = new InstantiationService(services, true);
extHostLogService.info('extension host started');
extHostLogService.trace('initData', initData);
// todo@joh
// ugly self - inject
const logService = instaService.invokeFunction(accessor => accessor.get(ILogService));
this._disposables.add(logService);
// todo@joh -> not soo nice...
logService.info('extension host started');
logService.trace('initData', initData);
// todo@joh
// ugly self - inject
// must call initialize *after* creating the extension service
// because `initialize` itself creates instances that depend on it
this._extensionService = instaService.invokeFunction(accessor => accessor.get(IExtHostExtensionService));
this._extensionService.initialize();

View File

@@ -354,6 +354,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
}
const result: ExtensionHostProcessManager[] = [];
const extHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker, autoStart, extensions, this._extensionHostLogsLocation);
const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, true, extHostProcessWorker, null, initialActivationEvents);
result.push(extHostProcessManager);

View File

@@ -12,16 +12,14 @@ import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { PersistentProtocol, ProtocolConstants, createBufferedEvent } from 'vs/base/parts/ipc/common/ipc.net';
import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
import product from 'vs/platform/product/node/product';
import { IInitData, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { ExtensionHostMain, IExitFn, ILogServiceFn } from 'vs/workbench/services/extensions/common/extensionHostMain';
import { ExtensionHostMain, IExitFn } from 'vs/workbench/services/extensions/common/extensionHostMain';
import { VSBuffer } from 'vs/base/common/buffer';
import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
import { IURITransformer, URITransformer, IRawURITransformer } from 'vs/base/common/uriIpc';
import { exists } from 'vs/base/node/pfs';
import { realpath } from 'vs/base/node/extpath';
import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import 'vs/workbench/api/node/extHost.services';
interface ParsedExtHostArgs {
@@ -70,21 +68,6 @@ function patchProcess(allowExit: boolean) {
};
}
// use IPC messages to forward console-calls
function patchPatchedConsole(mainThreadConsole: MainThreadConsoleShape): void {
// The console is already patched to use `process.send()`
const nativeProcessSend = process.send!;
process.send = (...args: any[]) => {
if (args.length === 0 || !args[0] || args[0].type !== '__$console') {
return nativeProcessSend.apply(process, args);
}
mainThreadConsole.$logExtensionHostMessage(args[0]);
};
}
const createLogService: ILogServiceFn = initData => new SpdLogService(ExtensionHostLogFileName, initData.logsLocation.fsPath, initData.logLevel);
interface IRendererConnection {
protocol: IMessagePassingProtocol;
initData: IInitData;
@@ -206,7 +189,7 @@ async function createExtHostProtocol(): Promise<IMessagePassingProtocol> {
}
function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRendererConnection> {
return new Promise<IRendererConnection>((c, e) => {
return new Promise<IRendererConnection>((c) => {
// Listen init data message
const first = protocol.onMessage(raw => {
@@ -335,8 +318,6 @@ export async function startExtensionHostProcess(): Promise<void> {
renderer.protocol,
initData,
hostUtils,
patchPatchedConsole,
createLogService,
uriTransformer
);

View File

@@ -17,11 +17,11 @@ import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorksp
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { ProxyAgent } from 'vscode-proxy-agent';
import { MainThreadTelemetryShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { URI } from 'vs/base/common/uri';
import { promisify } from 'util';
import { ILogService } from 'vs/platform/log/common/log';
interface ConnectionResult {
proxy: string;
@@ -34,7 +34,7 @@ export function connectProxyResolver(
extHostWorkspace: IExtHostWorkspaceProvider,
configProvider: ExtHostConfigProvider,
extensionService: ExtHostExtensionService,
extHostLogService: ExtHostLogService,
extHostLogService: ILogService,
mainThreadTelemetry: MainThreadTelemetryShape
) {
const resolveProxy = setupProxyResolution(extHostWorkspace, configProvider, extHostLogService, mainThreadTelemetry);
@@ -47,7 +47,7 @@ const maxCacheEntries = 5000; // Cache can grow twice that much due to 'oldCache
function setupProxyResolution(
extHostWorkspace: IExtHostWorkspaceProvider,
configProvider: ExtHostConfigProvider,
extHostLogService: ExtHostLogService,
extHostLogService: ILogService,
mainThreadTelemetry: MainThreadTelemetryShape
) {
const env = process.env;
@@ -421,7 +421,7 @@ function configureModuleLoading(extensionService: ExtHostExtensionService, looku
});
}
function useSystemCertificates(extHostLogService: ExtHostLogService, useSystemCertificates: boolean, opts: http.RequestOptions, callback: () => void) {
function useSystemCertificates(extHostLogService: ILogService, useSystemCertificates: boolean, opts: http.RequestOptions, callback: () => void) {
if (useSystemCertificates) {
getCaCertificates(extHostLogService)
.then(caCertificates => {
@@ -443,7 +443,7 @@ function useSystemCertificates(extHostLogService: ExtHostLogService, useSystemCe
}
let _caCertificates: ReturnType<typeof readCaCertificates> | Promise<undefined>;
async function getCaCertificates(extHostLogService: ExtHostLogService) {
async function getCaCertificates(extHostLogService: ILogService) {
if (!_caCertificates) {
_caCertificates = readCaCertificates()
.then(res => res && res.certs.length ? res : undefined)
@@ -469,24 +469,26 @@ async function readCaCertificates() {
}
async function readWindowsCaCertificates() {
const winCA = await import('vscode-windows-ca-certs');
// Not using await to work around minifier bug (https://github.com/microsoft/vscode/issues/79044).
return import('vscode-windows-ca-certs')
.then(winCA => {
let ders: any[] = [];
const store = winCA();
try {
let der: any;
while (der = store.next()) {
ders.push(der);
}
} finally {
store.done();
}
let ders: any[] = [];
const store = winCA();
try {
let der: any;
while (der = store.next()) {
ders.push(der);
}
} finally {
store.done();
}
const certs = new Set(ders.map(derToPem));
return {
certs: Array.from(certs),
append: true
};
const certs = new Set(ders.map(derToPem));
return {
certs: Array.from(certs),
append: true
};
});
}
async function readMacCaCertificates() {

View File

@@ -0,0 +1,57 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtHostOutputService, ExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
import { IExtHostWorkspace, ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { IExtHostDecorations, ExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations';
import { IExtHostConfiguration, ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { IExtHostCommands, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { ExtHostExtensionService } from 'vs/workbench/api/worker/extHostExtensionService';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostLogService } from 'vs/workbench/api/worker/extHostLogService';
// register singleton services
registerSingleton(ILogService, ExtHostLogService);
registerSingleton(IExtHostOutputService, ExtHostOutputService);
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
registerSingleton(IExtHostDecorations, ExtHostDecorations);
registerSingleton(IExtHostConfiguration, ExtHostConfiguration);
registerSingleton(IExtHostCommands, ExtHostCommands);
registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors);
registerSingleton(IExtHostStorage, ExtHostStorage);
registerSingleton(IExtHostExtensionService, ExtHostExtensionService);
// register services that only throw errors
function NotImplementedProxy<T>(name: ServiceIdentifier<T>): { new(): T } {
return <any>class {
constructor() {
return new Proxy({}, {
get(target: any, prop: string | number) {
if (target[prop]) {
return target[prop];
}
throw new Error(`Not Implemented: ${name}->${String(prop)}`);
}
});
}
};
}
registerSingleton(IExtHostTerminalService, class extends NotImplementedProxy(IExtHostTerminalService) { });
registerSingleton(IExtHostTask, class extends NotImplementedProxy(IExtHostTask) { });
registerSingleton(IExtHostDebugService, class extends NotImplementedProxy(IExtHostDebugService) { });
registerSingleton(IExtHostSearch, class extends NotImplementedProxy(IExtHostSearch) { });
registerSingleton(IExtensionStoragePaths, class extends NotImplementedProxy(IExtensionStoragePaths) {
whenReady = Promise.resolve();
});

View File

@@ -0,0 +1,117 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IRequestHandler } from 'vs/base/common/worker/simpleWorker';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { VSBuffer } from 'vs/base/common/buffer';
import { Emitter } from 'vs/base/common/event';
import { isMessageOfType, MessageType, createMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { ExtensionHostMain } from 'vs/workbench/services/extensions/common/extensionHostMain';
import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService';
import 'vs/workbench/services/extensions/worker/extHost.services';
// worker-self
declare namespace self {
function close(): void;
}
// do not allow extensions to call terminate
const nativeClose = self.close.bind(self);
self.close = () => console.trace('An extension called terminate and this was prevented');
let onTerminate = nativeClose;
const hostUtil = new class implements IHostUtils {
_serviceBrand: any;
exit(_code?: number | undefined): void {
nativeClose();
}
async exists(_path: string): Promise<boolean> {
return true;
}
async realpath(path: string): Promise<string> {
return path;
}
};
//todo@joh do not allow extensions to call postMessage and other globals...
class ExtensionWorker implements IRequestHandler {
// worker-contract
readonly _requestHandlerBrand: any;
readonly onmessage: (data: any) => any;
// protocol
readonly protocol: IMessagePassingProtocol;
constructor(postMessage: (message: any, transfer?: Transferable[]) => any) {
let emitter = new Emitter<VSBuffer>();
let terminating = false;
this.onmessage = data => {
if (!(data instanceof ArrayBuffer)) {
console.warn('UNKNOWN data received', data);
return;
}
const msg = VSBuffer.wrap(new Uint8Array(data, 0, data.byteLength));
if (isMessageOfType(msg, MessageType.Terminate)) {
// handle terminate-message right here
terminating = true;
onTerminate();
return;
}
// emit non-terminate messages to the outside
emitter.fire(msg);
};
this.protocol = {
onMessage: emitter.event,
send: vsbuf => {
if (!terminating) {
const data = vsbuf.buffer.buffer.slice(vsbuf.buffer.byteOffset, vsbuf.buffer.byteOffset + vsbuf.buffer.byteLength);
postMessage(data, [data]);
}
}
};
}
}
interface IRendererConnection {
protocol: IMessagePassingProtocol;
initData: IInitData;
}
function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRendererConnection> {
return new Promise<IRendererConnection>(resolve => {
const once = protocol.onMessage(raw => {
once.dispose();
const initData = <IInitData>JSON.parse(raw.toString());
protocol.send(createMessageOfType(MessageType.Initialized));
resolve({ protocol, initData });
});
protocol.send(createMessageOfType(MessageType.Ready));
});
}
export function create(postMessage: (message: any, transfer?: Transferable[]) => any): IRequestHandler {
const res = new ExtensionWorker(postMessage);
connectToRenderer(res.protocol).then(data => {
const extHostMain = new ExtensionHostMain(
data.protocol,
data.initData,
hostUtil,
null,
);
onTerminate = () => extHostMain.terminate();
});
return res;
}