Merge from vscode 2cd495805cf99b31b6926f08ff4348124b2cf73d

This commit is contained in:
ADS Merger
2020-06-30 04:40:21 +00:00
committed by AzureDataStudio
parent a8a7559229
commit 1388493cc1
602 changed files with 16375 additions and 12940 deletions

View File

@@ -5,35 +5,31 @@
import * as nls from 'vs/nls';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IWorkbenchExtensionEnablementService, IWebExtensionsScannerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionService, IExtensionHost } from 'vs/workbench/services/extensions/common/extensions';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { IProductService } from 'vs/platform/product/common/productService';
import { AbstractExtensionService } from 'vs/workbench/services/extensions/common/abstractExtensionService';
import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager';
import { RemoteExtensionHostClient, IInitDataProvider } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { AbstractExtensionService, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
import { RemoteExtensionHost, IRemoteExtensionHostDataProvider, IRemoteExtensionHostInitData } from 'vs/workbench/services/extensions/common/remoteExtensionHost';
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';
import { WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
import { canExecuteOnWeb } from 'vs/workbench/services/extensions/common/extensionsUtil';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { FetchFileSystemProvider } from 'vs/workbench/services/extensions/browser/webWorkerFileSystemProvider';
import { Schemas } from 'vs/base/common/network';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions';
import { DeltaExtensionsResult } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
private _disposables = new DisposableStore();
private _remoteExtensionsEnvironmentData: IRemoteAgentEnvironment | null = null;
private _remoteInitData: IRemoteExtensionHostInitData | null = null;
constructor(
@IInstantiationService instantiationService: IInstantiationService,
@@ -46,7 +42,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
@IConfigurationService private readonly _configService: IConfigurationService,
@IStaticExtensionsService private readonly _staticExtensions: IStaticExtensionsService,
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
) {
super(
instantiationService,
@@ -73,32 +69,39 @@ export class ExtensionService extends AbstractExtensionService implements IExten
this._disposables.add(this._fileService.registerProvider(Schemas.https, provider));
}
private _createProvider(remoteAuthority: string): IInitDataProvider {
private _createLocalExtensionHostDataProvider() {
return {
remoteAuthority: remoteAuthority,
getInitData: async () => {
await this.whenInstalledExtensionsRegistered();
const connectionData = this._remoteAuthorityResolverService.getConnectionData(remoteAuthority);
const remoteEnvironment = this._remoteExtensionsEnvironmentData!;
return { connectionData, remoteEnvironment };
const allExtensions = await this.getExtensions();
const webExtensions = allExtensions.filter(ext => canExecuteOnWeb(ext, this._productService, this._configService));
return {
autoStart: true,
extensions: webExtensions
};
}
};
}
protected _createExtensionHosts(_isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[] {
const result: ExtensionHostProcessManager[] = [];
private _createRemoteExtensionHostDataProvider(remoteAuthority: string): IRemoteExtensionHostDataProvider {
return {
remoteAuthority: remoteAuthority,
getInitData: async () => {
await this.whenInstalledExtensionsRegistered();
return this._remoteInitData!;
}
};
}
const webExtensions = this.getExtensions().then(extensions => extensions.filter(ext => canExecuteOnWeb(ext, this._productService, this._configService)));
const webHostProcessWorker = this._instantiationService.createInstance(WebWorkerExtensionHostStarter, true, webExtensions, URI.file(this._environmentService.logsPath).with({ scheme: this._environmentService.logFile.scheme }));
const webHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, webHostProcessWorker, null, initialActivationEvents);
result.push(webHostProcessManager);
protected _createExtensionHosts(_isInitialStart: boolean): IExtensionHost[] {
const result: IExtensionHost[] = [];
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, this._createLocalExtensionHostDataProvider());
result.push(webWorkerExtHost);
const remoteAgentConnection = this._remoteAgentService.getConnection();
if (remoteAgentConnection) {
const remoteExtensions = this.getExtensions().then(extensions => extensions.filter(ext => !canExecuteOnWeb(ext, this._productService, this._configService)));
const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, remoteExtensions, this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents);
result.push(remoteExtHostProcessManager);
const remoteExtHost = this._instantiationService.createInstance(RemoteExtensionHost, this._createRemoteExtensionHostDataProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
result.push(remoteExtHost);
}
return result;
@@ -108,16 +111,18 @@ export class ExtensionService extends AbstractExtensionService implements IExten
// fetch the remote environment
let [remoteEnv, localExtensions] = await Promise.all([
this._remoteAgentService.getEnvironment(),
this._staticExtensions.getExtensions()
this._webExtensionsScannerService.scanExtensions().then(extensions => extensions.map(parseScannedExtension))
]);
const remoteAgentConnection = this._remoteAgentService.getConnection();
let result: DeltaExtensionsResult;
// local: only enabled and web'ish extension
localExtensions = localExtensions!.filter(ext => this._isEnabled(ext) && canExecuteOnWeb(ext, this._productService, this._configService));
this._checkEnableProposedApi(localExtensions);
if (!remoteEnv) {
if (!remoteEnv || !remoteAgentConnection) {
result = this._registry.deltaExtensions(localExtensions, []);
} else {
@@ -131,7 +136,17 @@ export class ExtensionService extends AbstractExtensionService implements IExten
localExtensions = localExtensions.filter(extension => !isRemoteExtension.has(ExtensionIdentifier.toKey(extension.identifier)));
// save for remote extension's init data
this._remoteExtensionsEnvironmentData = remoteEnv;
this._remoteInitData = {
connectionData: this._remoteAuthorityResolverService.getConnectionData(remoteAgentConnection.remoteAuthority),
pid: remoteEnv.pid,
appRoot: remoteEnv.appRoot,
appSettingsHome: remoteEnv.appSettingsHome,
extensionHostLogsPath: remoteEnv.extensionHostLogsPath,
globalStorageHome: remoteEnv.globalStorageHome,
userHome: remoteEnv.userHome,
extensions: remoteEnv.extensions,
allExtensions: remoteEnv.extensions.concat(localExtensions)
};
result = this._registry.deltaExtensions(remoteEnv.extensions.concat(localExtensions), []);
}

View File

@@ -17,7 +17,7 @@ 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, ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionHost, ExtensionHostLogFileName, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
import { IProductService } from 'vs/platform/product/common/productService';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { joinPath } from 'vs/base/common/resources';
@@ -25,7 +25,19 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output';
import { localize } from 'vs/nls';
export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
export interface IWebWorkerExtensionHostInitData {
readonly autoStart: boolean;
readonly extensions: IExtensionDescription[];
}
export interface IWebWorkerExtensionHostDataProvider {
getInitData(): Promise<IWebWorkerExtensionHostInitData>;
}
export class WebWorkerExtensionHost implements IExtensionHost {
public readonly kind = ExtensionHostKind.LocalWebWorker;
public readonly remoteAuthority = null;
private _toDispose = new DisposableStore();
private _isTerminating: boolean = false;
@@ -34,12 +46,11 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
private readonly _onDidExit = new Emitter<[number, string | null]>();
readonly onExit: Event<[number, string | null]> = this._onDidExit.event;
private readonly _extensionHostLogsLocation: URI;
private readonly _extensionHostLogFile: URI;
constructor(
private readonly _autoStart: boolean,
private readonly _extensions: Promise<IExtensionDescription[]>,
private readonly _extensionHostLogsLocation: URI,
private readonly _initDataProvider: IWebWorkerExtensionHostDataProvider,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@ILabelService private readonly _labelService: ILabelService,
@@ -47,6 +58,7 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
@IProductService private readonly _productService: IProductService,
) {
this._extensionHostLogsLocation = URI.file(this._environmentService.logsPath).with({ scheme: this._environmentService.logFile.scheme });
this._extensionHostLogFile = joinPath(this._extensionHostLogsLocation, `${ExtensionHostLogFileName}.log`);
}
@@ -127,7 +139,7 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
}
private async _createExtHostInitData(): Promise<IInitData> {
const [telemetryInfo, extensionDescriptions] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._extensions]);
const [telemetryInfo, initData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]);
const workspace = this._contextService.getWorkspace();
return {
commit: this._productService.commit,
@@ -153,12 +165,12 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
},
resolvedExtensions: [],
hostExtensions: [],
extensions: extensionDescriptions,
extensions: initData.extensions,
telemetryInfo,
logLevel: this._logService.getLevel(),
logsLocation: this._extensionHostLogsLocation,
logFile: this._extensionHostLogFile,
autoStart: this._autoStart,
autoStart: initData.autoStart,
remote: {
authority: this._environmentService.configuration.remoteAuthority,
connectionData: null,

View File

@@ -15,12 +15,12 @@ import { BetterMergeId } from 'vs/platform/extensionManagement/common/extensionM
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension } from 'vs/workbench/services/extensions/common/extensions';
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension, IExtensionHost } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
import { ExtensionIdentifier, IExtensionDescription, IScannedExtension, ExtensionType } from 'vs/platform/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
import { IProductService } from 'vs/platform/product/common/productService';
@@ -29,6 +29,16 @@ import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtens
const hasOwnProperty = Object.hasOwnProperty;
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
export function parseScannedExtension(extension: IScannedExtension): IExtensionDescription {
return {
identifier: new ExtensionIdentifier(`${extension.packageJSON.publisher}.${extension.packageJSON.name}`),
isBuiltin: extension.type === ExtensionType.System,
isUnderDevelopment: false,
extensionLocation: extension.location,
...extension.packageJSON,
};
}
export abstract class AbstractExtensionService extends Disposable implements IExtensionService {
public _serviceBrand: undefined;
@@ -58,9 +68,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
protected readonly _isExtensionDevTestFromCli: boolean;
// --- Members used per extension host process
protected _extensionHostProcessManagers: ExtensionHostProcessManager[];
protected _extensionHostManagers: ExtensionHostManager[];
protected _extensionHostActiveExtensions: Map<string, ExtensionIdentifier>;
private _extensionHostProcessActivationTimes: Map<string, ActivationTimes>;
private _extensionHostActivationTimes: Map<string, ActivationTimes>;
private _extensionHostExtensionRuntimeErrors: Map<string, Error[]>;
constructor(
@@ -85,9 +95,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
this._extensionsMessages = new Map<string, IMessage[]>();
this._proposedApiController = new ProposedApiController(this._environmentService, this._productService);
this._extensionHostProcessManagers = [];
this._extensionHostManagers = [];
this._extensionHostActiveExtensions = new Map<string, ExtensionIdentifier>();
this._extensionHostProcessActivationTimes = new Map<string, ActivationTimes>();
this._extensionHostActivationTimes = new Map<string, ActivationTimes>();
this._extensionHostExtensionRuntimeErrors = new Map<string, Error[]>();
const devOpts = parseExtensionDevOptions(this._environmentService);
@@ -97,7 +107,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
protected async _initialize(): Promise<void> {
perf.mark('willLoadExtensions');
this._startExtensionHostProcess(true, []);
this._startExtensionHosts(true, []);
this.whenInstalledExtensionsRegistered().then(() => perf.mark('didLoadExtensions'));
await this._scanAndHandleExtensions();
this._releaseBarrier();
@@ -110,18 +120,18 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
this._onDidChangeExtensionsStatus.fire(this._registry.getAllExtensionDescriptions().map(e => e.identifier));
}
private _stopExtensionHostProcess(): void {
private _stopExtensionHosts(): void {
let previouslyActivatedExtensionIds: ExtensionIdentifier[] = [];
this._extensionHostActiveExtensions.forEach((value) => {
previouslyActivatedExtensionIds.push(value);
});
for (const manager of this._extensionHostProcessManagers) {
for (const manager of this._extensionHostManagers) {
manager.dispose();
}
this._extensionHostProcessManagers = [];
this._extensionHostManagers = [];
this._extensionHostActiveExtensions = new Map<string, ExtensionIdentifier>();
this._extensionHostProcessActivationTimes = new Map<string, ActivationTimes>();
this._extensionHostActivationTimes = new Map<string, ActivationTimes>();
this._extensionHostExtensionRuntimeErrors = new Map<string, Error[]>();
if (previouslyActivatedExtensionIds.length > 0) {
@@ -129,18 +139,19 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
}
}
private _startExtensionHostProcess(isInitialStart: boolean, initialActivationEvents: string[]): void {
this._stopExtensionHostProcess();
private _startExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): void {
this._stopExtensionHosts();
const processManagers = this._createExtensionHosts(isInitialStart, initialActivationEvents);
processManagers.forEach((processManager) => {
const extensionHosts = this._createExtensionHosts(isInitialStart);
extensionHosts.forEach((extensionHost) => {
const processManager = this._instantiationService.createInstance(ExtensionHostManager, extensionHost, initialActivationEvents);
processManager.onDidExit(([code, signal]) => this._onExtensionHostCrashOrExit(processManager, code, signal));
processManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ isResponsive: responsiveState === ResponsiveState.Responsive }); });
this._extensionHostProcessManagers.push(processManager);
this._extensionHostManagers.push(processManager);
});
}
private _onExtensionHostCrashOrExit(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void {
private _onExtensionHostCrashOrExit(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
// Unexpected termination
if (!this._isExtensionDevHost) {
@@ -151,9 +162,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
this._onExtensionHostExit(code);
}
protected _onExtensionHostCrashed(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void {
protected _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
console.error('Extension host terminated unexpectedly. Code: ', code, ' Signal: ', signal);
this._stopExtensionHostProcess();
this._stopExtensionHosts();
}
//#region IExtensionService
@@ -167,12 +178,12 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
}
public restartExtensionHost(): void {
this._stopExtensionHostProcess();
this._startExtensionHostProcess(false, Array.from(this._allRequestedActivateEvents.keys()));
this._stopExtensionHosts();
this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys()));
}
protected startExtensionHost(): void {
this._startExtensionHostProcess(false, Array.from(this._allRequestedActivateEvents.keys()));
this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys()));
}
public activateByEvent(activationEvent: string): Promise<void> {
@@ -200,7 +211,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
private _activateByEvent(activationEvent: string): Promise<void> {
const result = Promise.all(
this._extensionHostProcessManagers.map(extHostManager => extHostManager.activateByEvent(activationEvent))
this._extensionHostManagers.map(extHostManager => extHostManager.activateByEvent(activationEvent))
).then(() => { });
this._onWillActivateByEvent.fire({
event: activationEvent,
@@ -248,7 +259,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
const extensionKey = ExtensionIdentifier.toKey(extension.identifier);
result[extension.identifier.value] = {
messages: this._extensionsMessages.get(extensionKey) || [],
activationTimes: this._extensionHostProcessActivationTimes.get(extensionKey),
activationTimes: this._extensionHostActivationTimes.get(extensionKey),
runtimeErrors: this._extensionHostExtensionRuntimeErrors.get(extensionKey) || [],
};
}
@@ -261,7 +272,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
}
public async setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
await this._extensionHostProcessManagers
await this._extensionHostManagers
.map(manager => manager.setRemoteEnvironment(env));
}
@@ -275,6 +286,14 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
}
}
protected _checkEnabledAndProposedAPI(extensions: IExtensionDescription[]): IExtensionDescription[] {
// enable or disable proposed API per extension
this._checkEnableProposedApi(extensions);
// keep only enabled extensions
return extensions.filter(extension => this._isEnabled(extension));
}
private _isExtensionUnderDevelopment(extension: IExtensionDescription): boolean {
if (this._environmentService.isExtensionDevelopment) {
const extDevLocs = this._environmentService.extensionDevelopmentLocationURI;
@@ -291,21 +310,17 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
}
protected _isEnabled(extension: IExtensionDescription): boolean {
return !this._isDisabled(extension);
}
protected _isDisabled(extension: IExtensionDescription): boolean {
if (this._isExtensionUnderDevelopment(extension)) {
// Never disable extensions under development
return false;
return true;
}
if (ExtensionIdentifier.equals(extension.identifier, BetterMergeId)) {
// Check if this is the better merge extension which was migrated to a built-in extension
return true;
return false;
}
return !this._extensionEnablementService.isEnabled(toExtension(extension));
return this._extensionEnablementService.isEnabled(toExtension(extension));
}
protected _doHandleExtensionPoints(affectedExtensions: IExtensionDescription[]): void {
@@ -413,7 +428,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
public async _activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> {
const results = await Promise.all(
this._extensionHostProcessManagers.map(manager => manager.activate(extensionId, reason))
this._extensionHostManagers.map(manager => manager.activate(extensionId, reason))
);
const activated = results.some(e => e);
if (!activated) {
@@ -426,7 +441,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
}
public _onDidActivateExtension(extensionId: ExtensionIdentifier, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationReason: ExtensionActivationReason): void {
this._extensionHostProcessActivationTimes.set(ExtensionIdentifier.toKey(extensionId), new ActivationTimes(codeLoadingTime, activateCallTime, activateResolvedTime, activationReason));
this._extensionHostActivationTimes.set(ExtensionIdentifier.toKey(extensionId), new ActivationTimes(codeLoadingTime, activateCallTime, activateResolvedTime, activationReason));
this._onDidChangeExtensionsStatus.fire([extensionId]);
}
@@ -441,7 +456,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
//#endregion
protected abstract _createExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[];
protected abstract _createExtensionHosts(isInitialStart: boolean): IExtensionHost[];
protected abstract _scanAndHandleExtensions(): Promise<void>;
public abstract _onExtensionHostExit(code: number): void;
}

View File

@@ -21,17 +21,17 @@ import { registerAction2, Action2 } from 'vs/platform/actions/common/actions';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { StopWatch } from 'vs/base/common/stopwatch';
import { VSBuffer } from 'vs/base/common/buffer';
import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionHost, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
// Enable to see detailed message communication between window and extension host
const LOG_EXTENSION_HOST_COMMUNICATION = false;
const LOG_USE_COLORS = true;
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
export class ExtensionHostProcessManager extends Disposable {
export class ExtensionHostManager extends Disposable {
public readonly kind: ExtensionHostKind;
public readonly onDidExit: Event<[number, string | null]>;
private readonly _onDidChangeResponsiveState: Emitter<ResponsiveState> = this._register(new Emitter<ResponsiveState>());
@@ -40,32 +40,31 @@ export class ExtensionHostProcessManager extends Disposable {
/**
* A map of already activated events to speed things up if the same activation event is triggered multiple times.
*/
private readonly _extensionHostProcessFinishedActivateEvents: { [activationEvent: string]: boolean; };
private _extensionHostProcessRPCProtocol: RPCProtocol | null;
private readonly _extensionHostProcessCustomers: IDisposable[];
private readonly _extensionHostProcessWorker: IExtensionHostStarter;
private readonly _finishedActivateEvents: { [activationEvent: string]: boolean; };
private _rpcProtocol: RPCProtocol | null;
private readonly _customers: IDisposable[];
private readonly _extensionHost: IExtensionHost;
/**
* winjs believes a proxy is a promise because it has a `then` method, so wrap the result in an object.
*/
private _extensionHostProcessProxy: Promise<{ value: ExtHostExtensionServiceShape; } | null> | null;
private _proxy: Promise<{ value: ExtHostExtensionServiceShape; } | null> | null;
private _resolveAuthorityAttempt: number;
constructor(
public readonly isLocal: boolean,
extensionHostProcessWorker: IExtensionHostStarter,
private readonly _remoteAuthority: string | null,
extensionHost: IExtensionHost,
initialActivationEvents: string[],
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
) {
super();
this._extensionHostProcessFinishedActivateEvents = Object.create(null);
this._extensionHostProcessRPCProtocol = null;
this._extensionHostProcessCustomers = [];
this._finishedActivateEvents = Object.create(null);
this._rpcProtocol = null;
this._customers = [];
this._extensionHostProcessWorker = extensionHostProcessWorker;
this.onDidExit = this._extensionHostProcessWorker.onExit;
this._extensionHostProcessProxy = this._extensionHostProcessWorker.start()!.then(
this._extensionHost = extensionHost;
this.kind = this._extensionHost.kind;
this.onDidExit = this._extensionHost.onExit;
this._proxy = this._extensionHost.start()!.then(
(protocol) => {
return { value: this._createExtensionHostCustomers(protocol) };
},
@@ -75,7 +74,7 @@ export class ExtensionHostProcessManager extends Disposable {
return null;
}
);
this._extensionHostProcessProxy.then(() => {
this._proxy.then(() => {
initialActivationEvents.forEach((activationEvent) => this.activateByEvent(activationEvent));
this._register(registerLatencyTestProvider({
measure: () => this.measure()
@@ -85,27 +84,27 @@ export class ExtensionHostProcessManager extends Disposable {
}
public dispose(): void {
if (this._extensionHostProcessWorker) {
this._extensionHostProcessWorker.dispose();
if (this._extensionHost) {
this._extensionHost.dispose();
}
if (this._extensionHostProcessRPCProtocol) {
this._extensionHostProcessRPCProtocol.dispose();
if (this._rpcProtocol) {
this._rpcProtocol.dispose();
}
for (let i = 0, len = this._extensionHostProcessCustomers.length; i < len; i++) {
const customer = this._extensionHostProcessCustomers[i];
for (let i = 0, len = this._customers.length; i < len; i++) {
const customer = this._customers[i];
try {
customer.dispose();
} catch (err) {
errors.onUnexpectedError(err);
}
}
this._extensionHostProcessProxy = null;
this._proxy = null;
super.dispose();
}
private async measure(): Promise<ExtHostLatencyResult | null> {
const proxy = await this._getExtensionHostProcessProxy();
const proxy = await this._getProxy();
if (!proxy) {
return null;
}
@@ -113,18 +112,18 @@ export class ExtensionHostProcessManager extends Disposable {
const down = await this._measureDown(proxy);
const up = await this._measureUp(proxy);
return {
remoteAuthority: this._remoteAuthority,
remoteAuthority: this._extensionHost.remoteAuthority,
latency,
down,
up
};
}
private async _getExtensionHostProcessProxy(): Promise<ExtHostExtensionServiceShape | null> {
if (!this._extensionHostProcessProxy) {
private async _getProxy(): Promise<ExtHostExtensionServiceShape | null> {
if (!this._proxy) {
return null;
}
const p = await this._extensionHostProcessProxy;
const p = await this._proxy;
if (!p) {
return null;
}
@@ -159,7 +158,7 @@ export class ExtensionHostProcessManager extends Disposable {
const sw = StopWatch.create(true);
await proxy.$test_up(buff);
sw.stop();
return ExtensionHostProcessManager._convert(SIZE, sw.elapsed());
return ExtensionHostManager._convert(SIZE, sw.elapsed());
}
private async _measureDown(proxy: ExtHostExtensionServiceShape): Promise<number> {
@@ -168,7 +167,7 @@ export class ExtensionHostProcessManager extends Disposable {
const sw = StopWatch.create(true);
await proxy.$test_down(SIZE);
sw.stop();
return ExtensionHostProcessManager._convert(SIZE, sw.elapsed());
return ExtensionHostManager._convert(SIZE, sw.elapsed());
}
private _createExtensionHostCustomers(protocol: IMessagePassingProtocol): ExtHostExtensionServiceShape {
@@ -178,13 +177,13 @@ export class ExtensionHostProcessManager extends Disposable {
logger = new RPCLogger();
}
this._extensionHostProcessRPCProtocol = new RPCProtocol(protocol, logger);
this._register(this._extensionHostProcessRPCProtocol.onDidChangeResponsiveState((responsiveState: ResponsiveState) => this._onDidChangeResponsiveState.fire(responsiveState)));
this._rpcProtocol = new RPCProtocol(protocol, logger);
this._register(this._rpcProtocol.onDidChangeResponsiveState((responsiveState: ResponsiveState) => this._onDidChangeResponsiveState.fire(responsiveState)));
const extHostContext: IExtHostContext = {
remoteAuthority: this._remoteAuthority! /* TODO: alexdima, remove not-null assertion */,
getProxy: <T>(identifier: ProxyIdentifier<T>): T => this._extensionHostProcessRPCProtocol!.getProxy(identifier),
set: <T, R extends T>(identifier: ProxyIdentifier<T>, instance: R): R => this._extensionHostProcessRPCProtocol!.set(identifier, instance),
assertRegistered: (identifiers: ProxyIdentifier<any>[]): void => this._extensionHostProcessRPCProtocol!.assertRegistered(identifiers),
remoteAuthority: this._extensionHost.remoteAuthority,
getProxy: <T>(identifier: ProxyIdentifier<T>): T => this._rpcProtocol!.getProxy(identifier),
set: <T, R extends T>(identifier: ProxyIdentifier<T>, instance: R): R => this._rpcProtocol!.set(identifier, instance),
assertRegistered: (identifiers: ProxyIdentifier<any>[]): void => this._rpcProtocol!.assertRegistered(identifiers),
};
// Named customers
@@ -192,28 +191,28 @@ export class ExtensionHostProcessManager extends Disposable {
for (let i = 0, len = namedCustomers.length; i < len; i++) {
const [id, ctor] = namedCustomers[i];
const instance = this._instantiationService.createInstance(ctor, extHostContext);
this._extensionHostProcessCustomers.push(instance);
this._extensionHostProcessRPCProtocol.set(id, instance);
this._customers.push(instance);
this._rpcProtocol.set(id, instance);
}
// Customers
const customers = ExtHostCustomersRegistry.getCustomers();
for (const ctor of customers) {
const instance = this._instantiationService.createInstance(ctor, extHostContext);
this._extensionHostProcessCustomers.push(instance);
this._customers.push(instance);
}
// Check that no named customers are missing
// {{SQL CARBON EDIT}} filter out services we don't expose
const filtered: ProxyIdentifier<any>[] = [MainContext.MainThreadDebugService, MainContext.MainThreadTask];
const expected: ProxyIdentifier<any>[] = Object.keys(MainContext).map((key) => (<any>MainContext)[key]).filter(v => !filtered.some(x => x === v));
this._extensionHostProcessRPCProtocol.assertRegistered(expected);
this._rpcProtocol.assertRegistered(expected);
return this._extensionHostProcessRPCProtocol.getProxy(ExtHostContext.ExtHostExtensionService);
return this._rpcProtocol.getProxy(ExtHostContext.ExtHostExtensionService);
}
public async activate(extension: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean> {
const proxy = await this._getExtensionHostProcessProxy();
const proxy = await this._getProxy();
if (!proxy) {
return false;
}
@@ -221,10 +220,10 @@ export class ExtensionHostProcessManager extends Disposable {
}
public activateByEvent(activationEvent: string): Promise<void> {
if (this._extensionHostProcessFinishedActivateEvents[activationEvent] || !this._extensionHostProcessProxy) {
if (this._finishedActivateEvents[activationEvent] || !this._proxy) {
return NO_OP_VOID_PROMISE;
}
return this._extensionHostProcessProxy.then((proxy) => {
return this._proxy.then((proxy) => {
if (!proxy) {
// this case is already covered above and logged.
// i.e. the extension host could not be started
@@ -232,16 +231,16 @@ export class ExtensionHostProcessManager extends Disposable {
}
return proxy.value.$activateByEvent(activationEvent);
}).then(() => {
this._extensionHostProcessFinishedActivateEvents[activationEvent] = true;
this._finishedActivateEvents[activationEvent] = true;
});
}
public async getInspectPort(tryEnableInspector: boolean): Promise<number> {
if (this._extensionHostProcessWorker) {
if (this._extensionHost) {
if (tryEnableInspector) {
await this._extensionHostProcessWorker.enableInspectPort();
await this._extensionHost.enableInspectPort();
}
let port = this._extensionHostProcessWorker.getInspectPort();
let port = this._extensionHost.getInspectPort();
if (port) {
return port;
}
@@ -262,7 +261,7 @@ export class ExtensionHostProcessManager extends Disposable {
}
});
}
const proxy = await this._getExtensionHostProcessProxy();
const proxy = await this._getProxy();
if (!proxy) {
throw new Error(`Cannot resolve authority`);
}
@@ -276,7 +275,7 @@ export class ExtensionHostProcessManager extends Disposable {
}
public async start(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
const proxy = await this._getExtensionHostProcessProxy();
const proxy = await this._getProxy();
if (!proxy) {
return;
}
@@ -284,7 +283,7 @@ export class ExtensionHostProcessManager extends Disposable {
}
public async deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
const proxy = await this._getExtensionHostProcessProxy();
const proxy = await this._getProxy();
if (!proxy) {
return;
}
@@ -292,7 +291,7 @@ export class ExtensionHostProcessManager extends Disposable {
}
public async setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
const proxy = await this._getExtensionHostProcessProxy();
const proxy = await this._getProxy();
if (!proxy) {
return;
}
@@ -396,7 +395,7 @@ registerAction2(class MeasureExtHostLatencyAction extends Action2 {
value: nls.localize('measureExtHostLatency', "Measure Extension Host Latency"),
original: 'Measure Extension Host Latency'
},
category: nls.localize('developer', "Developer"),
category: nls.localize({ key: 'developer', comment: ['A developer on Code itself or someone diagnosing issues in Code'] }, "Developer"),
f1: true
});
}

View File

@@ -24,6 +24,8 @@ export const nullExtensionDescription = Object.freeze(<IExtensionDescription>{
isBuiltin: false,
});
export const webWorkerExtHostConfig = 'extensions.webWorker';
export const IExtensionService = createDecorator<IExtensionService>('extensionService');
export interface IMessage {
@@ -84,7 +86,15 @@ export interface IExtensionHostProfile {
getAggregatedTimes(): Map<ProfileSegmentId, number>;
}
export interface IExtensionHostStarter {
export const enum ExtensionHostKind {
LocalProcess,
LocalWebWorker,
Remote
}
export interface IExtensionHost {
readonly kind: ExtensionHostKind;
readonly remoteAuthority: string | null;
readonly onExit: Event<[number, string | null]>;
start(): Promise<IMessagePassingProtocol> | null;
@@ -257,6 +267,17 @@ export function toExtension(extensionDescription: IExtensionDescription): IExten
};
}
export function toExtensionDescription(extension: IExtension): IExtensionDescription {
return {
identifier: new ExtensionIdentifier(extension.identifier.id),
isBuiltin: extension.type === ExtensionType.System,
isUnderDevelopment: false,
extensionLocation: extension.location,
...extension.manifest,
uuid: extension.identifier.uuid
};
}
export class NullExtensionService implements IExtensionService {
declare readonly _serviceBrand: undefined;

View File

@@ -11,7 +11,7 @@ import { EXTENSION_IDENTIFIER_PATTERN } from 'vs/platform/extensionManagement/co
import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { IMessage } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtensionIdentifier, IExtensionDescription, EXTENSION_CATEGORIES } from 'vs/platform/extensions/common/extensions';
import { values } from 'vs/base/common/map';
const schemaRegistry = Registry.as<IJSONContributionRegistry>(Extensions.JSONContribution);
@@ -187,7 +187,7 @@ export const schema: IJSONSchema = {
items: {
oneOf: [{
type: 'string',
enum: ['Programming Languages', 'Snippets', 'Linters', 'Themes', 'Debuggers', 'Other', 'Keymaps', 'Formatters', 'Extension Packs', 'SCM Providers', 'Azure', 'Language Packs'],
enum: EXTENSION_CATEGORIES,
},
{
type: 'string',
@@ -271,7 +271,7 @@ export const schema: IJSONSchema = {
},
{
label: 'onStartupFinished',
description: nls.localize('vscode.extension.activationEvents.onStartupFinished', 'An activation event emitted after the start-up finished (after all eager activated extensions have finished activating).'),
description: nls.localize('vscode.extension.activationEvents.onStartupFinished', 'An activation event emitted after the start-up finished (after all `*` activated extensions have finished activating).'),
body: 'onStartupFinished'
},
{

View File

@@ -20,6 +20,11 @@ export function prefersExecuteOnWorkspace(manifest: IExtensionManifest, productS
return (extensionKind.length > 0 && extensionKind[0] === 'workspace');
}
export function prefersExecuteOnWeb(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean {
const extensionKind = getExtensionKind(manifest, productService, configurationService);
return (extensionKind.length > 0 && extensionKind[0] === 'web');
}
export function canExecuteOnUI(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean {
const extensionKind = getExtensionKind(manifest, productService, configurationService);
return extensionKind.some(kind => kind === 'ui');

View File

@@ -13,9 +13,8 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IInitData, UIKind } from 'vs/workbench/api/common/extHost.protocol';
import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { IExtensionHostStarter, ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionHost, ExtensionHostLogFileName, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { IRemoteAuthorityResolverService, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
import * as platform from 'vs/base/common/platform';
import { Schemas } from 'vs/base/common/network';
@@ -33,30 +32,37 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output';
import { localize } from 'vs/nls';
export interface IRemoteInitData {
export interface IRemoteExtensionHostInitData {
readonly connectionData: IRemoteConnectionData | null;
readonly remoteEnvironment: IRemoteAgentEnvironment;
readonly pid: number;
readonly appRoot: URI;
readonly appSettingsHome: URI;
readonly extensionHostLogsPath: URI;
readonly globalStorageHome: URI;
readonly userHome: URI;
readonly extensions: IExtensionDescription[];
readonly allExtensions: IExtensionDescription[];
}
export interface IInitDataProvider {
export interface IRemoteExtensionHostDataProvider {
readonly remoteAuthority: string;
getInitData(): Promise<IRemoteInitData>;
getInitData(): Promise<IRemoteExtensionHostInitData>;
}
export class RemoteExtensionHostClient extends Disposable implements IExtensionHostStarter {
export class RemoteExtensionHost extends Disposable implements IExtensionHost {
public readonly kind = ExtensionHostKind.Remote;
public readonly remoteAuthority: string;
private _onExit: Emitter<[number, string | null]> = this._register(new Emitter<[number, string | null]>());
public readonly onExit: Event<[number, string | null]> = this._onExit.event;
private _protocol: PersistentProtocol | null;
private _terminating: boolean;
private readonly _isExtensionDevHost: boolean;
private _terminating: boolean;
constructor(
private readonly _allExtensions: Promise<IExtensionDescription[]>,
private readonly _initDataProvider: IInitDataProvider,
private readonly _initDataProvider: IRemoteExtensionHostDataProvider,
private readonly _socketFactory: ISocketFactory,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
@@ -70,6 +76,7 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH
@ISignService private readonly _signService: ISignService
) {
super();
this.remoteAuthority = this._initDataProvider.remoteAuthority;
this._protocol = null;
this._terminating = false;
@@ -194,54 +201,52 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH
this._onExit.fire([0, null]);
}
private _createExtHostInitData(isExtensionDevelopmentDebug: boolean): Promise<IInitData> {
return Promise.all([this._allExtensions, this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]).then(([allExtensions, telemetryInfo, remoteInitData]) => {
// Collect all identifiers for extension ids which can be considered "resolved"
const resolvedExtensions = allExtensions.filter(extension => !extension.main).map(extension => extension.identifier);
const hostExtensions = allExtensions.filter(extension => extension.main && extension.api === 'none').map(extension => extension.identifier);
const workspace = this._contextService.getWorkspace();
const remoteEnv = remoteInitData.remoteEnvironment;
const r: IInitData = {
commit: this._productService.commit,
version: this._productService.version,
vscodeVersion: this._productService.vscodeVersion, // {{SQL CARBON EDIT}} add vscode version
parentPid: remoteEnv.pid,
environment: {
isExtensionDevelopmentDebug,
appRoot: remoteEnv.appRoot,
appSettingsHome: remoteEnv.appSettingsHome,
appName: this._productService.nameLong,
appUriScheme: this._productService.urlProtocol,
appLanguage: platform.language,
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI,
globalStorageHome: remoteEnv.globalStorageHome,
userHome: remoteEnv.userHome,
webviewResourceRoot: this._environmentService.webviewResourceRoot,
webviewCspSource: this._environmentService.webviewCspSource,
},
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : {
configuration: workspace.configuration,
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace)
},
remote: {
isRemote: true,
authority: this._initDataProvider.remoteAuthority,
connectionData: remoteInitData.connectionData
},
resolvedExtensions: resolvedExtensions,
hostExtensions: hostExtensions,
extensions: remoteEnv.extensions,
telemetryInfo,
logLevel: this._logService.getLevel(),
logsLocation: remoteEnv.extensionHostLogsPath,
logFile: joinPath(remoteEnv.extensionHostLogsPath, `${ExtensionHostLogFileName}.log`),
autoStart: true,
uiKind: platform.isWeb ? UIKind.Web : UIKind.Desktop
};
return r;
});
private async _createExtHostInitData(isExtensionDevelopmentDebug: boolean): Promise<IInitData> {
const [telemetryInfo, remoteInitData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]);
// Collect all identifiers for extension ids which can be considered "resolved"
const resolvedExtensions = remoteInitData.allExtensions.filter(extension => !extension.main).map(extension => extension.identifier);
const hostExtensions = remoteInitData.allExtensions.filter(extension => extension.main && extension.api === 'none').map(extension => extension.identifier);
const workspace = this._contextService.getWorkspace();
return {
commit: this._productService.commit,
version: this._productService.version,
vscodeVersion: this._productService.vscodeVersion, // {{SQL CARBON EDIT}} add vscode version
parentPid: remoteInitData.pid,
environment: {
isExtensionDevelopmentDebug,
appRoot: remoteInitData.appRoot,
appSettingsHome: remoteInitData.appSettingsHome,
appName: this._productService.nameLong,
appUriScheme: this._productService.urlProtocol,
appLanguage: platform.language,
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI,
globalStorageHome: remoteInitData.globalStorageHome,
userHome: remoteInitData.userHome,
webviewResourceRoot: this._environmentService.webviewResourceRoot,
webviewCspSource: this._environmentService.webviewCspSource,
},
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : {
configuration: workspace.configuration,
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace)
},
remote: {
isRemote: true,
authority: this._initDataProvider.remoteAuthority,
connectionData: remoteInitData.connectionData
},
resolvedExtensions: resolvedExtensions,
hostExtensions: hostExtensions,
extensions: remoteInitData.extensions,
telemetryInfo,
logLevel: this._logService.getLevel(),
logsLocation: remoteInitData.extensionHostLogsPath,
logFile: joinPath(remoteInitData.extensionHostLogsPath, `${ExtensionHostLogFileName}.log`),
autoStart: true,
uiKind: platform.isWeb ? UIKind.Web : UIKind.Desktop
};
}
getInspectPort(): number | undefined {

View File

@@ -1,40 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export const IStaticExtensionsService = createDecorator<IStaticExtensionsService>('IStaticExtensionsService');
export interface IStaticExtensionsService {
readonly _serviceBrand: undefined;
getExtensions(): Promise<IExtensionDescription[]>;
}
export class StaticExtensionsService implements IStaticExtensionsService {
declare readonly _serviceBrand: undefined;
private readonly _descriptions: IExtensionDescription[] = [];
constructor(@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService) {
const staticExtensions = environmentService.options && Array.isArray(environmentService.options.staticExtensions) ? environmentService.options.staticExtensions : [];
this._descriptions = staticExtensions.map(data => <IExtensionDescription>{
identifier: new ExtensionIdentifier(`${data.packageJSON.publisher}.${data.packageJSON.name}`),
extensionLocation: data.extensionLocation,
isBuiltin: !!data.isBuiltin,
...data.packageJSON,
});
}
async getExtensions(): Promise<IExtensionDescription[]> {
return this._descriptions;
}
}
registerSingleton(IStaticExtensionsService, StaticExtensionsService, true);

View File

@@ -3,28 +3,27 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ExtensionHostProcessWorker } from 'vs/workbench/services/extensions/electron-browser/extensionHost';
import { LocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-browser/localProcessExtensionHost';
import { CachedExtensionScanner } from 'vs/workbench/services/extensions/electron-browser/cachedExtensionScanner';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { AbstractExtensionService } from 'vs/workbench/services/extensions/common/abstractExtensionService';
import { AbstractExtensionService, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
import * as nls from 'vs/nls';
import { runWhenIdle } from 'vs/base/common/async';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IWorkbenchExtensionEnablementService, EnablementState } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IWorkbenchExtensionEnablementService, EnablementState, IWebExtensionsScannerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInitDataProvider, RemoteExtensionHostClient } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient';
import { IRemoteExtensionHostDataProvider, RemoteExtensionHost, IRemoteExtensionHostInitData } from 'vs/workbench/services/extensions/common/remoteExtensionHost';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { getExtensionKind } from 'vs/workbench/services/extensions/common/extensionsUtil';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager';
import { IExtensionService, toExtension, ExtensionHostKind, IExtensionHost, webWorkerExtHostConfig } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { Schemas } from 'vs/base/common/network';
import { IFileService } from 'vs/platform/files/common/files';
@@ -32,7 +31,6 @@ import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteA
import { IProductService } from 'vs/platform/product/common/productService';
import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints';
import { flatten } from 'vs/base/common/arrays';
import { IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions';
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService';
import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService';
@@ -41,6 +39,8 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
class DeltaExtensionsQueueItem {
constructor(
@@ -51,8 +51,9 @@ class DeltaExtensionsQueueItem {
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
private readonly _remoteEnvironment: Map<string, IRemoteAgentEnvironment>;
private readonly _enableLocalWebWorker: boolean;
private readonly _remoteInitData: Map<string, IRemoteExtensionHostInitData>;
private _runningLocation: Map<string, ExtensionRunningLocation>;
private readonly _extensionScanner: CachedExtensionScanner;
private _deltaExtensionsQueue: DeltaExtensionsQueueItem[];
@@ -69,7 +70,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
@IStaticExtensionsService private readonly _staticExtensions: IStaticExtensionsService,
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
@IElectronService private readonly _electronService: IElectronService,
@IHostService private readonly _hostService: IHostService,
@IRemoteExplorerService private readonly _remoteExplorerService: IRemoteExplorerService,
@@ -85,16 +86,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
productService
);
if (this._extensionEnablementService.allUserExtensionsDisabled) {
this._notificationService.prompt(Severity.Info, nls.localize('extensionsDisabled', "All installed extensions are temporarily disabled. Reload the window to return to the previous state."), [{
label: nls.localize('Reload', "Reload"),
run: () => {
this._hostService.reload();
}
}]);
}
this._enableLocalWebWorker = this._configurationService.getValue<boolean>(webWorkerExtHostConfig);
this._remoteEnvironment = new Map<string, IRemoteAgentEnvironment>();
this._remoteInitData = new Map<string, IRemoteExtensionHostInitData>();
this._runningLocation = new Map<string, ExtensionRunningLocation>();
this._extensionScanner = instantiationService.createInstance(CachedExtensionScanner);
this._deltaExtensionsQueue = [];
@@ -142,8 +137,28 @@ export class ExtensionService extends AbstractExtensionService implements IExten
this._initialize();
}, 50 /*max delay*/);
});
// delay notification for extensions disabled until workbench restored
if (this._extensionEnablementService.allUserExtensionsDisabled) {
this._lifecycleService.when(LifecyclePhase.Restored).then(() => {
this._notificationService.prompt(Severity.Info, nls.localize('extensionsDisabled', "All installed extensions are temporarily disabled. Reload the window to return to the previous state."), [{
label: nls.localize('Reload', "Reload"),
run: () => {
this._hostService.reload();
}
}]);
});
}
}
private _getExtensionHostManager(kind: ExtensionHostKind): ExtensionHostManager | null {
for (const extensionHostManager of this._extensionHostManagers) {
if (extensionHostManager.kind === kind) {
return extensionHostManager;
}
}
return null;
}
//#region deltaExtensions
@@ -222,11 +237,12 @@ export class ExtensionService extends AbstractExtensionService implements IExten
this._checkEnableProposedApi(toAdd);
// Update extension points
this._rehandleExtensionPoints((<IExtensionDescription[]>[]).concat(toAdd).concat(toRemove));
this._doHandleExtensionPoints((<IExtensionDescription[]>[]).concat(toAdd).concat(toRemove));
// Update the extension host
if (this._extensionHostProcessManagers.length > 0) {
await this._extensionHostProcessManagers[0].deltaExtensions(toAdd, toRemove.map(e => e.identifier));
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess);
if (localProcessExtensionHost) {
await localProcessExtensionHost.deltaExtensions(toAdd, toRemove.map(e => e.identifier));
}
for (let i = 0; i < toAdd.length; i++) {
@@ -234,15 +250,11 @@ export class ExtensionService extends AbstractExtensionService implements IExten
}
}
private _rehandleExtensionPoints(extensionDescriptions: IExtensionDescription[]): void {
this._doHandleExtensionPoints(extensionDescriptions);
}
public canAddExtension(extensionDescription: IExtensionDescription): boolean {
return this._canAddExtension(toExtension(extensionDescription));
}
public _canAddExtension(extension: IExtension): boolean {
private _canAddExtension(extension: IExtension): boolean {
if (this._environmentService.configuration.remoteAuthority) {
return false;
}
@@ -338,57 +350,78 @@ export class ExtensionService extends AbstractExtensionService implements IExten
if (shouldActivate) {
await Promise.all(
this._extensionHostProcessManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: shouldActivateReason! }))
this._extensionHostManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: shouldActivateReason! }))
).then(() => { });
}
}
//#endregion
private _createProvider(remoteAuthority: string): IInitDataProvider {
private async _scanAllLocalExtensions(): Promise<IExtensionDescription[]> {
return flatten(await Promise.all([
this._extensionScanner.scannedExtensions,
this._webExtensionsScannerService.scanExtensions().then(extensions => extensions.map(parseScannedExtension))
]));
}
private _createLocalExtensionHostDataProvider(isInitialStart: boolean, desiredRunningLocation: ExtensionRunningLocation) {
return {
remoteAuthority: remoteAuthority,
getInitData: async () => {
await this.whenInstalledExtensionsRegistered();
const connectionData = this._remoteAuthorityResolverService.getConnectionData(remoteAuthority);
const remoteEnvironment = this._remoteEnvironment.get(remoteAuthority)!;
return { connectionData, remoteEnvironment };
if (isInitialStart) {
const localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions());
const runningLocation = determineRunningLocation(this._productService, this._configurationService, localExtensions, [], false, this._enableLocalWebWorker);
const localProcessExtensions = filterByRunningLocation(localExtensions, runningLocation, desiredRunningLocation);
return {
autoStart: false,
extensions: localProcessExtensions
};
} else {
// restart case
const allExtensions = await this.getExtensions();
const localProcessExtensions = filterByRunningLocation(allExtensions, this._runningLocation, desiredRunningLocation);
return {
autoStart: true,
extensions: localProcessExtensions
};
}
}
};
}
protected _createExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[] {
let autoStart: boolean;
let extensions: Promise<IExtensionDescription[]>;
if (isInitialStart) {
autoStart = false;
extensions = this._extensionScanner.scannedExtensions.then(extensions => extensions.filter(extension => this._isEnabled(extension))); // remove disabled extensions
} else {
// restart case
autoStart = true;
extensions = this.getExtensions().then((extensions) => extensions.filter(ext => ext.extensionLocation.scheme === Schemas.file));
private _createRemoteExtensionHostDataProvider(remoteAuthority: string): IRemoteExtensionHostDataProvider {
return {
remoteAuthority: remoteAuthority,
getInitData: async () => {
await this.whenInstalledExtensionsRegistered();
return this._remoteInitData.get(remoteAuthority)!;
}
};
}
protected _createExtensionHosts(isInitialStart: boolean): IExtensionHost[] {
const result: IExtensionHost[] = [];
const localProcessExtHost = this._instantiationService.createInstance(LocalProcessExtensionHost, this._createLocalExtensionHostDataProvider(isInitialStart, ExtensionRunningLocation.LocalProcess));
result.push(localProcessExtHost);
if (this._enableLocalWebWorker) {
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, this._createLocalExtensionHostDataProvider(isInitialStart, ExtensionRunningLocation.LocalWebWorker));
result.push(webWorkerExtHost);
}
const result: ExtensionHostProcessManager[] = [];
const extHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker, autoStart, extensions, this._environmentService.extHostLogsPath);
const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, true, extHostProcessWorker, null, initialActivationEvents);
result.push(extHostProcessManager);
const remoteAgentConnection = this._remoteAgentService.getConnection();
if (remoteAgentConnection) {
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);
const remoteExtHost = this._instantiationService.createInstance(RemoteExtensionHost, this._createRemoteExtensionHostDataProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
result.push(remoteExtHost);
}
return result;
}
protected _onExtensionHostCrashed(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void {
protected _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
super._onExtensionHostCrashed(extensionHost, code, signal);
if (extensionHost.isLocal) {
if (extensionHost.kind === ExtensionHostKind.LocalProcess) {
if (code === 55) {
this._notificationService.prompt(
Severity.Error,
@@ -437,10 +470,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
return;
}
const extensionHost = this._extensionHostProcessManagers[0];
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!;
this._remoteAuthorityResolverService._clearResolvedAuthority(remoteAuthority);
try {
const result = await extensionHost.resolveAuthority(remoteAuthority);
const result = await localProcessExtensionHost.resolveAuthority(remoteAuthority);
this._remoteAuthorityResolverService._setResolvedAuthority(result.authority, result.options);
} catch (err) {
this._remoteAuthorityResolverService._setResolvedAuthorityError(remoteAuthority, err);
@@ -451,25 +484,19 @@ export class ExtensionService extends AbstractExtensionService implements IExten
this._extensionScanner.startScanningExtensions(this.createLogger());
const remoteAuthority = this._environmentService.configuration.remoteAuthority;
const extensionHost = this._extensionHostProcessManagers[0];
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!;
const allExtensions = flatten(await Promise.all([this._extensionScanner.scannedExtensions, this._staticExtensions.getExtensions()]));
// enable or disable proposed API per extension
this._checkEnableProposedApi(allExtensions);
// remove disabled extensions
let localExtensions = remove(allExtensions, extension => this._isDisabled(extension));
let localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions());
let remoteEnv: IRemoteAgentEnvironment | null = null;
if (remoteAuthority) {
let resolvedAuthority: ResolverResult;
let resolverResult: ResolverResult;
try {
resolvedAuthority = await extensionHost.resolveAuthority(remoteAuthority);
resolverResult = await localProcessExtensionHost.resolveAuthority(remoteAuthority);
} catch (err) {
const remoteName = getRemoteName(remoteAuthority);
if (RemoteAuthorityResolverError.isNoResolverFound(err)) {
err.isHandled = await this._handleNoResolverFound(remoteName, allExtensions);
err.isHandled = await this._handleNoResolverFound(remoteAuthority);
} else {
console.log(err);
if (RemoteAuthorityResolverError.isHandled(err)) {
@@ -479,22 +506,18 @@ export class ExtensionService extends AbstractExtensionService implements IExten
this._remoteAuthorityResolverService._setResolvedAuthorityError(remoteAuthority, err);
// Proceed with the local extension host
await this._startLocalExtensionHost(extensionHost, localExtensions, localExtensions.map(extension => extension.identifier));
await this._startLocalExtensionHost(localExtensions);
return;
}
// set the resolved authority
this._remoteAuthorityResolverService._setResolvedAuthority(resolvedAuthority.authority, resolvedAuthority.options);
this._remoteExplorerService.setTunnelInformation(resolvedAuthority.tunnelInformation);
this._remoteAuthorityResolverService._setResolvedAuthority(resolverResult.authority, resolverResult.options);
this._remoteExplorerService.setTunnelInformation(resolverResult.tunnelInformation);
// monitor for breakage
const connection = this._remoteAgentService.getConnection();
if (connection) {
connection.onDidStateChange(async (e) => {
const remoteAuthority = this._environmentService.configuration.remoteAuthority;
if (!remoteAuthority) {
return;
}
if (e.type === PersistentConnectionEventType.ConnectionLost) {
this._remoteAuthorityResolverService._clearResolvedAuthority(remoteAuthority);
}
@@ -503,80 +526,64 @@ export class ExtensionService extends AbstractExtensionService implements IExten
}
// fetch the remote environment
const remoteEnv = (await this._remoteAgentService.getEnvironment());
remoteEnv = await this._remoteAgentService.getEnvironment();
if (!remoteEnv) {
this._notificationService.notify({ severity: Severity.Error, message: nls.localize('getEnvironmentFailure', "Could not fetch remote environment") });
// Proceed with the local extension host
await this._startLocalExtensionHost(extensionHost, localExtensions, localExtensions.map(extension => extension.identifier));
await this._startLocalExtensionHost(localExtensions);
return;
}
// enable or disable proposed API per extension
this._checkEnableProposedApi(remoteEnv.extensions);
// remove disabled extensions
remoteEnv.extensions = remove(remoteEnv.extensions, extension => this._isDisabled(extension));
// Determine where each extension will execute, based on extensionKind
const isInstalledLocally = new Set<string>();
localExtensions.forEach(ext => isInstalledLocally.add(ExtensionIdentifier.toKey(ext.identifier)));
const isInstalledRemotely = new Set<string>();
remoteEnv.extensions.forEach(ext => isInstalledRemotely.add(ExtensionIdentifier.toKey(ext.identifier)));
const enum RunningLocation { None, Local, Remote }
const pickRunningLocation = (extension: IExtensionDescription): RunningLocation => {
for (const extensionKind of getExtensionKind(extension, this._productService, this._configurationService)) {
if (extensionKind === 'ui') {
if (isInstalledLocally.has(ExtensionIdentifier.toKey(extension.identifier))) {
return RunningLocation.Local;
}
} else if (extensionKind === 'workspace') {
if (isInstalledRemotely.has(ExtensionIdentifier.toKey(extension.identifier))) {
return RunningLocation.Remote;
}
}
}
return RunningLocation.None;
};
const runningLocation = new Map<string, RunningLocation>();
localExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
remoteEnv.extensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
// remove non-UI extensions from the local extensions
localExtensions = localExtensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(ext.identifier)) === RunningLocation.Local);
// in case of UI extensions overlap, the local extension wins
remoteEnv.extensions = remoteEnv.extensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(ext.identifier)) === RunningLocation.Remote);
// save for remote extension's init data
this._remoteEnvironment.set(remoteAuthority, remoteEnv);
await this._startLocalExtensionHost(extensionHost, remoteEnv.extensions.concat(localExtensions), localExtensions.map(extension => extension.identifier));
} else {
await this._startLocalExtensionHost(extensionHost, localExtensions, localExtensions.map(extension => extension.identifier));
}
await this._startLocalExtensionHost(localExtensions, remoteAuthority, remoteEnv);
}
private async _startLocalExtensionHost(extensionHost: ExtensionHostProcessManager, allExtensions: IExtensionDescription[], localExtensions: ExtensionIdentifier[]): Promise<void> {
this._registerAndHandleExtensions(allExtensions);
extensionHost.start(localExtensions.filter(id => this._registry.containsExtension(id)));
}
private async _startLocalExtensionHost(localExtensions: IExtensionDescription[], remoteAuthority: string | undefined = undefined, remoteEnv: IRemoteAgentEnvironment | null = null): Promise<void> {
private _registerAndHandleExtensions(allExtensions: IExtensionDescription[]): void {
const result = this._registry.deltaExtensions(allExtensions, []);
let remoteExtensions = remoteEnv ? this._checkEnabledAndProposedAPI(remoteEnv.extensions) : [];
this._runningLocation = determineRunningLocation(this._productService, this._configurationService, localExtensions, remoteExtensions, Boolean(remoteAuthority), this._enableLocalWebWorker);
// remove non-UI extensions from the local extensions
const localProcessExtensions = filterByRunningLocation(localExtensions, this._runningLocation, ExtensionRunningLocation.LocalProcess);
const localWebWorkerExtensions = filterByRunningLocation(localExtensions, this._runningLocation, ExtensionRunningLocation.LocalWebWorker);
remoteExtensions = filterByRunningLocation(remoteExtensions, this._runningLocation, ExtensionRunningLocation.Remote);
const result = this._registry.deltaExtensions(remoteExtensions.concat(localProcessExtensions).concat(localWebWorkerExtensions), []);
if (result.removedDueToLooping.length > 0) {
this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', ')));
}
if (remoteAuthority && remoteEnv) {
this._remoteInitData.set(remoteAuthority, {
connectionData: this._remoteAuthorityResolverService.getConnectionData(remoteAuthority),
pid: remoteEnv.pid,
appRoot: remoteEnv.appRoot,
appSettingsHome: remoteEnv.appSettingsHome,
extensionHostLogsPath: remoteEnv.extensionHostLogsPath,
globalStorageHome: remoteEnv.globalStorageHome,
userHome: remoteEnv.userHome,
extensions: remoteExtensions,
allExtensions: this._registry.getAllExtensionDescriptions(),
});
}
this._doHandleExtensionPoints(this._registry.getAllExtensionDescriptions());
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!;
localProcessExtensionHost.start(localProcessExtensions.map(extension => extension.identifier).filter(id => this._registry.containsExtension(id)));
const localWebWorkerExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalWebWorker);
if (localWebWorkerExtensionHost) {
localWebWorkerExtensionHost.start(localWebWorkerExtensions.map(extension => extension.identifier).filter(id => this._registry.containsExtension(id)));
}
}
public async getInspectPort(tryEnableInspector: boolean): Promise<number> {
if (this._extensionHostProcessManagers.length > 0) {
return this._extensionHostProcessManagers[0].getInspectPort(tryEnableInspector);
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess);
if (localProcessExtensionHost) {
return localProcessExtensionHost.getInspectPort(tryEnableInspector);
}
return 0;
}
@@ -591,7 +598,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten
}
}
private async _handleNoResolverFound(remoteName: string, allExtensions: IExtensionDescription[]): Promise<boolean> {
private async _handleNoResolverFound(remoteAuthority: string): Promise<boolean> {
const remoteName = getRemoteName(remoteAuthority);
const recommendation = this._productService.remoteExtensionTips?.[remoteName];
if (!recommendation) {
return false;
@@ -607,9 +615,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
};
const resolverExtensionId = recommendation.extensionId;
const allExtensions = await this._scanAllLocalExtensions();
const extension = allExtensions.filter(e => e.identifier.value === resolverExtensionId)[0];
if (extension) {
if (this._isDisabled(extension)) {
if (!this._isEnabled(extension)) {
const message = nls.localize('enableResolver', "Extension '{0}' is required to open the remote window.\nOK to enable?", recommendation.friendlyName);
this._notificationService.prompt(Severity.Info, message,
[{
@@ -649,27 +658,59 @@ export class ExtensionService extends AbstractExtensionService implements IExten
}
return true;
}
}
function remove(arr: IExtensionDescription[], predicate: (item: IExtensionDescription) => boolean): IExtensionDescription[];
function remove(arr: IExtensionDescription[], toRemove: IExtensionDescription[]): IExtensionDescription[];
function remove(arr: IExtensionDescription[], arg2: ((item: IExtensionDescription) => boolean) | IExtensionDescription[]): IExtensionDescription[] {
if (typeof arg2 === 'function') {
return _removePredicate(arr, arg2);
}
return _removeSet(arr, arg2);
const enum ExtensionRunningLocation {
None,
LocalProcess,
LocalWebWorker,
Remote
}
function _removePredicate(arr: IExtensionDescription[], predicate: (item: IExtensionDescription) => boolean): IExtensionDescription[] {
return arr.filter(extension => !predicate(extension));
function determineRunningLocation(productService: IProductService, configurationService: IConfigurationService, localExtensions: IExtensionDescription[], remoteExtensions: IExtensionDescription[], hasRemote: boolean, hasLocalWebWorker: boolean): Map<string, ExtensionRunningLocation> {
const localExtensionsSet = new Set<string>();
localExtensions.forEach(ext => localExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
const remoteExtensionsSet = new Set<string>();
remoteExtensions.forEach(ext => remoteExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
const pickRunningLocation = (extension: IExtensionDescription): ExtensionRunningLocation => {
const isInstalledLocally = localExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
const isInstalledRemotely = remoteExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
for (const extensionKind of getExtensionKind(extension, productService, configurationService)) {
if (extensionKind === 'ui' && isInstalledLocally) {
// ui extensions run locally if possible
return ExtensionRunningLocation.LocalProcess;
}
if (extensionKind === 'workspace' && isInstalledRemotely) {
// workspace extensions run remotely if possible
return ExtensionRunningLocation.Remote;
}
if (extensionKind === 'workspace' && !hasRemote) {
// workspace extensions also run locally if there is no remote
return ExtensionRunningLocation.LocalProcess;
}
if (extensionKind === 'web' && isInstalledLocally && hasLocalWebWorker) {
// web worker extensions run in the local web worker if possible
if (typeof extension.browser !== 'undefined') {
// The "browser" field determines the entry point
(<any>extension).main = extension.browser;
}
return ExtensionRunningLocation.LocalWebWorker;
}
}
return ExtensionRunningLocation.None;
};
const runningLocation = new Map<string, ExtensionRunningLocation>();
localExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
remoteExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
return runningLocation;
}
function _removeSet(arr: IExtensionDescription[], toRemove: IExtensionDescription[]): IExtensionDescription[] {
const toRemoveSet = new Set<string>();
toRemove.forEach(extension => toRemoveSet.add(ExtensionIdentifier.toKey(extension.identifier)));
return arr.filter(extension => !toRemoveSet.has(ExtensionIdentifier.toKey(extension.identifier)));
function filterByRunningLocation(extensions: IExtensionDescription[], runningLocation: Map<string, ExtensionRunningLocation>, desiredRunningLocation: ExtensionRunningLocation): IExtensionDescription[] {
return extensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(ext.identifier)) === desiredRunningLocation);
}
registerSingleton(IExtensionService, ExtensionService);
@@ -693,4 +734,4 @@ class RestartExtensionHostAction extends Action {
}
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
registry.registerWorkbenchAction(SyncActionDescriptor.from(RestartExtensionHostAction), 'Developer: Restart Extension Host', nls.localize('developer', "Developer"));
registry.registerWorkbenchAction(SyncActionDescriptor.from(RestartExtensionHostAction), 'Developer: Restart Extension Host', nls.localize({ key: 'developer', comment: ['A developer on Code itself or someone diagnosing issues in Code'] }, "Developer"));

View File

@@ -37,7 +37,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
import { parseExtensionDevOptions } from '../common/extensionDevOptions';
import { VSBuffer } from 'vs/base/common/buffer';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
import { IExtensionHostStarter, ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionHost, ExtensionHostLogFileName, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
import { isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { joinPath } from 'vs/base/common/resources';
@@ -45,7 +45,19 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output';
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService';
export class ExtensionHostProcessWorker implements IExtensionHostStarter {
export interface ILocalProcessExtensionHostInitData {
readonly autoStart: boolean;
readonly extensions: IExtensionDescription[];
}
export interface ILocalProcessExtensionHostDataProvider {
getInitData(): Promise<ILocalProcessExtensionHostInitData>;
}
export class LocalProcessExtensionHost implements IExtensionHost {
public readonly kind = ExtensionHostKind.LocalProcess;
public readonly remoteAuthority = null;
private readonly _onExit: Emitter<[number, string]> = new Emitter<[number, string]>();
public readonly onExit: Event<[number, string]> = this._onExit.event;
@@ -73,9 +85,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
private readonly _extensionHostLogFile: URI;
constructor(
private readonly _autoStart: boolean,
private readonly _extensions: Promise<IExtensionDescription[]>,
private readonly _extensionHostLogsLocation: URI,
private readonly _initDataProvider: ILocalProcessExtensionHostDataProvider,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@INotificationService private readonly _notificationService: INotificationService,
@IElectronService private readonly _electronService: IElectronService,
@@ -103,7 +113,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
this._extensionHostConnection = null;
this._messageProtocol = null;
this._extensionHostLogFile = joinPath(this._extensionHostLogsLocation, `${ExtensionHostLogFileName}.log`);
this._extensionHostLogFile = joinPath(this._environmentService.extHostLogsPath, `${ExtensionHostLogFileName}.log`);
this._toDispose.add(this._onExit);
this._toDispose.add(this._lifecycleService.onWillShutdown(e => this._onWillShutdown(e)));
@@ -410,52 +420,49 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
});
}
private _createExtHostInitData(): Promise<IInitData> {
return Promise.all([this._telemetryService.getTelemetryInfo(), this._extensions])
.then(([telemetryInfo, extensionDescriptions]) => {
const workspace = this._contextService.getWorkspace();
const r: IInitData = {
commit: this._productService.commit,
version: this._productService.version,
vscodeVersion: this._productService.vscodeVersion, // {{SQL CARBON EDIT}} add vscode version
parentPid: process.pid,
environment: {
isExtensionDevelopmentDebug: this._isExtensionDevDebug,
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.file(this._environmentService.globalStorageHome),
userHome: this._environmentService.userHome,
webviewResourceRoot: this._environmentService.webviewResourceRoot,
webviewCspSource: this._environmentService.webviewCspSource,
},
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : {
configuration: withNullAsUndefined(workspace.configuration),
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace),
isUntitled: workspace.configuration ? isUntitledWorkspace(workspace.configuration, this._environmentService) : false
},
remote: {
authority: this._environmentService.configuration.remoteAuthority,
connectionData: null,
isRemote: false
},
resolvedExtensions: [],
hostExtensions: [],
extensions: extensionDescriptions,
telemetryInfo,
logLevel: this._logService.getLevel(),
logsLocation: this._extensionHostLogsLocation,
logFile: this._extensionHostLogFile,
autoStart: this._autoStart,
uiKind: UIKind.Desktop
};
return r;
});
private async _createExtHostInitData(): Promise<IInitData> {
const [telemetryInfo, initData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]);
const workspace = this._contextService.getWorkspace();
return {
commit: this._productService.commit,
version: this._productService.version,
vscodeVersion: this._productService.vscodeVersion, // {{SQL CARBON EDIT}} add vscode version
parentPid: process.pid,
environment: {
isExtensionDevelopmentDebug: this._isExtensionDevDebug,
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.file(this._environmentService.globalStorageHome),
userHome: this._environmentService.userHome,
webviewResourceRoot: this._environmentService.webviewResourceRoot,
webviewCspSource: this._environmentService.webviewCspSource,
},
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : {
configuration: withNullAsUndefined(workspace.configuration),
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace),
isUntitled: workspace.configuration ? isUntitledWorkspace(workspace.configuration, this._environmentService) : false
},
remote: {
authority: this._environmentService.configuration.remoteAuthority,
connectionData: null,
isRemote: false
},
resolvedExtensions: [],
hostExtensions: [],
extensions: initData.extensions,
telemetryInfo,
logLevel: this._logService.getLevel(),
logsLocation: this._environmentService.extHostLogsPath,
logFile: this._extensionHostLogFile,
autoStart: initData.autoStart,
uiKind: UIKind.Desktop
};
}
private _logExtensionHostMessage(entry: IRemoteConsoleLog) {

View File

@@ -22,6 +22,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostLogService } from 'vs/workbench/api/worker/extHostLogService';
import { IExtHostTunnelService, ExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
import { IExtHostApiDeprecationService, ExtHostApiDeprecationService, } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { IExtHostWindow, ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
import { NotImplementedProxy } from 'vs/base/common/types';
// register singleton services
@@ -29,6 +30,7 @@ registerSingleton(ILogService, ExtHostLogService);
registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService);
registerSingleton(IExtHostOutputService, ExtHostOutputService);
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
registerSingleton(IExtHostWindow, ExtHostWindow);
registerSingleton(IExtHostDecorations, ExtHostDecorations);
registerSingleton(IExtHostConfiguration, ExtHostConfiguration);
registerSingleton(IExtHostCommands, ExtHostCommands);