Skip to content

Commit

Permalink
Merge pull request #197440 from microsoft/alexd/future-goose
Browse files Browse the repository at this point in the history
Skip going to an extension host if no extensions are interested in a certain activation event
  • Loading branch information
alexdima authored Nov 4, 2023
2 parents 3e452bf + 2481749 commit b41d864
Show file tree
Hide file tree
Showing 21 changed files with 415 additions and 322 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ export class ImplicitActivationEventsImpl {
}

const activationEvents: string[] = (Array.isArray(desc.activationEvents) ? desc.activationEvents.slice(0) : []);

for (let i = 0; i < activationEvents.length; i++) {
// TODO@joao: there's no easy way to contribute this
if (activationEvents[i] === 'onUri') {
activationEvents[i] = `onUri:${ExtensionIdentifier.toKey(desc.identifier)}`;
}
}

if (!desc.contributes) {
// no implicit activation events
return activationEvents;
Expand Down
2 changes: 1 addition & 1 deletion src/vs/platform/extensions/common/extensionHostStarter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface IExtensionHostStarter {
onDynamicExit(id: string): Event<{ code: number; signal: string }>;

createExtensionHost(): Promise<{ id: string }>;
start(id: string, opts: IExtensionHostProcessOptions): Promise<void>;
start(id: string, opts: IExtensionHostProcessOptions): Promise<{ pid: number | undefined }>;
enableInspectPort(id: string): Promise<boolean>;
kill(id: string): Promise<void>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,12 @@ export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter
return { id };
}

async start(id: string, opts: IExtensionHostProcessOptions): Promise<void> {
async start(id: string, opts: IExtensionHostProcessOptions): Promise<{ pid: number | undefined }> {
if (this._shutdown) {
throw canceled();
}
this._getExtHost(id).start({
const extHost = this._getExtHost(id);
extHost.start({
...opts,
type: 'extensionHost',
entryPoint: 'vs/workbench/api/node/extensionHostProcess',
Expand All @@ -111,6 +112,8 @@ export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter
forceAllocationsToV8Sandbox: true,
correlationId: id
});
const pid = await Event.toPromise(extHost.onSpawn);
return { pid };
}

async enableInspectPort(id: string): Promise<boolean> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ export class UtilityProcess extends Disposable {
private readonly _onMessage = this._register(new Emitter<unknown>());
readonly onMessage = this._onMessage.event;

private readonly _onSpawn = this._register(new Emitter<number | undefined>());
readonly onSpawn = this._onSpawn.event;

private readonly _onExit = this._register(new Emitter<IUtilityProcessExitEvent>());
readonly onExit = this._onExit.event;

Expand Down Expand Up @@ -303,6 +306,7 @@ export class UtilityProcess extends Disposable {
}

this.log('successfully created', Severity.Info);
this._onSpawn.fire(process.pid);
}));

// Exit
Expand Down
4 changes: 3 additions & 1 deletion src/vs/server/node/webClientServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,11 +362,13 @@ export class WebClientServer {
return void res.end('Not found');
}

const webWorkerExtensionHostIframeScriptSHA = 'sha256-75NYUUvf+5++1WbfCZOV3PSWxBhONpaxwx+mkOFRv/Y=';

const cspDirectives = [
'default-src \'self\';',
'img-src \'self\' https: data: blob:;',
'media-src \'self\';',
`script-src 'self' 'unsafe-eval' ${this._getScriptCspHashes(data).join(' ')} 'sha256-fh3TwPMflhsEIpR8g1OYTIMVWhXTLcjQ9kh2tIpmv54=' ${useTestResolver ? '' : `http://${remoteAuthority}`};`, // the sha is the same as in src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html
`script-src 'self' 'unsafe-eval' ${this._getScriptCspHashes(data).join(' ')} '${webWorkerExtensionHostIframeScriptSHA}' ${useTestResolver ? '' : `http://${remoteAuthority}`};`, // the sha is the same as in src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html
'child-src \'self\';',
`frame-src 'self' https://*.vscode-cdn.net data:;`,
'worker-src \'self\' data: blob:;',
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/api/common/extHostExtensionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1213,8 +1213,8 @@ class SyncedActivationEventsReader implements IActivationEventsReader {
this.addActivationEvents(activationEvents);
}

public readActivationEvents(extensionDescription: Readonly<IRelaxedExtensionDescription>): string[] | undefined {
return this._map.get(extensionDescription.identifier);
public readActivationEvents(extensionDescription: Readonly<IRelaxedExtensionDescription>): string[] {
return this._map.get(extensionDescription.identifier) ?? [];
}

public addActivationEvents(activationEvents: { [extensionId: string]: string[] }): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri';
import { ExtensionIdentifier, IExtensionDescription, IRelaxedExtensionDescription, TargetPlatform } from 'vs/platform/extensions/common/extensions';
import { NullLogService } from 'vs/platform/log/common/log';
import { ActivatedExtension, EmptyExtension, ExtensionActivationTimes, ExtensionsActivator, IExtensionsActivatorHost } from 'vs/workbench/api/common/extHostExtensionActivator';
import { ExtensionDescriptionRegistry, basicActivationEventsReader } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import { ExtensionDescriptionRegistry, IActivationEventsReader } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import { ExtensionActivationReason, MissingExtensionDependency } from 'vs/workbench/services/extensions/common/extensions';

suite('ExtensionsActivator', () => {
Expand Down Expand Up @@ -248,6 +248,12 @@ suite('ExtensionsActivator', () => {
}
}

const basicActivationEventsReader: IActivationEventsReader = {
readActivationEvents: (extensionDescription: IExtensionDescription): string[] => {
return extensionDescription.activationEvents ?? [];
}
};

function createActivator(host: IExtensionsActivatorHost, extensionDescriptions: IExtensionDescription[], otherHostExtensionDescriptions: IExtensionDescription[] = []): ExtensionsActivator {
const registry = new ExtensionDescriptionRegistry(basicActivationEventsReader, extensionDescriptions);
const globalRegistry = new ExtensionDescriptionRegistry(basicActivationEventsReader, extensionDescriptions.concat(otherHostExtensionDescriptions));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface IWebWorkerExtensionHostDataProvider {

export class WebWorkerExtensionHost extends Disposable implements IExtensionHost {

public readonly pid = null;
public readonly remoteAuthority = null;
public extensions: ExtensionHostExtensions | null = null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,17 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { IWorkbenchExtensionEnablementService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { ExtensionDescriptionRegistryLock, ExtensionDescriptionRegistrySnapshot, IActivationEventsReader, LockableExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
import { ExtensionHostKind, ExtensionRunningPreference, IExtensionHostKindPicker, extensionHostKindToString } from 'vs/workbench/services/extensions/common/extensionHostKind';
import { IExtensionHostManager, createExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
import { ExtensionHostKind, ExtensionRunningPreference, IExtensionHostKindPicker } from 'vs/workbench/services/extensions/common/extensionHostKind';
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
import { IExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManagers';
import { IResolveAuthorityErrorResult } from 'vs/workbench/services/extensions/common/extensionHostProxy';
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
import { ExtensionRunningLocation, LocalProcessRunningLocation, LocalWebWorkerRunningLocation, RemoteRunningLocation } from 'vs/workbench/services/extensions/common/extensionRunningLocation';
import { ExtensionRunningLocationTracker, filterExtensionIdentifiers } from 'vs/workbench/services/extensions/common/extensionRunningLocationTracker';
import { ActivationKind, ActivationTimes, ExtensionActivationReason, ExtensionHostStartup, ExtensionPointContribution, IExtensionHost, IExtensionService, IExtensionsStatus, IInternalExtensionService, IMessage, IResponsiveStateChangeEvent, IWillActivateEvent, WillStopExtensionHostsEvent, toExtension } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionsProposedApi } from 'vs/workbench/services/extensions/common/extensionsProposedApi';
import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { LazyCreateExtensionHostManager } from 'vs/workbench/services/extensions/common/lazyCreateExtensionHostManager';
import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { IExtensionActivationHost as IWorkspaceContainsActivationHost, checkActivateWorkspaceContainsExtension, checkGlobFileExists } from 'vs/workbench/services/extensions/common/workspaceContains';
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
Expand Down Expand Up @@ -371,12 +373,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
let shouldActivateReason: string | null = null;
let hasWorkspaceContains = false;
const activationEvents = this._activationEventReader.readActivationEvents(extensionDescription);
for (let activationEvent of activationEvents) {
// TODO@joao: there's no easy way to contribute this
if (activationEvent === 'onUri') {
activationEvent = `onUri:${ExtensionIdentifier.toKey(extensionDescription.identifier)}`;
}

for (const activationEvent of activationEvents) {
if (this._allRequestedActivateEvents.has(activationEvent)) {
// This activation event was fired before the extension was added
shouldActivate = true;
Expand Down Expand Up @@ -753,6 +750,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
const processManager: IExtensionHostManager = this._doCreateExtensionHostManager(extensionHost, initialActivationEvents);
processManager.onDidExit(([code, signal]) => this._onExtensionHostCrashOrExit(processManager, code, signal));
processManager.onDidChangeResponsiveState((responsiveState) => {
this._logService.info(`Extension host (${processManager.friendyName}) is ${responsiveState === ResponsiveState.Responsive ? 'responsive' : 'unresponsive'}.`);
this._onDidChangeResponsiveChange.fire({
extensionHostKind: processManager.kind,
isResponsive: responsiveState === ResponsiveState.Responsive,
Expand All @@ -765,7 +763,11 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
}

protected _doCreateExtensionHostManager(extensionHost: IExtensionHost, initialActivationEvents: string[]): IExtensionHostManager {
return createExtensionHostManager(this._instantiationService, extensionHost, initialActivationEvents, this._acquireInternalAPI(extensionHost));
const internalExtensionService = this._acquireInternalAPI(extensionHost);
if (extensionHost.startup === ExtensionHostStartup.Lazy && initialActivationEvents.length === 0) {
return this._instantiationService.createInstance(LazyCreateExtensionHostManager, extensionHost, internalExtensionService);
}
return this._instantiationService.createInstance(ExtensionHostManager, extensionHost, initialActivationEvents, internalExtensionService);
}

private _onExtensionHostCrashOrExit(extensionHost: IExtensionHostManager, code: number, signal: string | null): void {
Expand All @@ -781,7 +783,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
}

protected _onExtensionHostCrashed(extensionHost: IExtensionHostManager, code: number, signal: string | null): void {
console.error(`Extension host (${extensionHostKindToString(extensionHost.kind)}) terminated unexpectedly. Code: ${code}, Signal: ${signal}`);
console.error(`Extension host (${extensionHost.friendyName}) terminated unexpectedly. Code: ${code}, Signal: ${signal}`);
if (extensionHost.kind === ExtensionHostKind.LocalProcess) {
this._doStopExtensionHosts();
} else if (extensionHost.kind === ExtensionHostKind.Remote) {
Expand Down Expand Up @@ -817,7 +819,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
try {
const info = await this._getExtensionHostExitInfoWithTimeout(reconnectionToken);
if (info) {
this._logService.error(`Extension host (${extensionHostKindToString(extensionHost.kind)}) terminated unexpectedly with code ${info.code}.`);
this._logService.error(`Extension host (${extensionHost.friendyName}) terminated unexpectedly with code ${info.code}.`);
}

this._logExtensionHostCrash(extensionHost);
Expand Down Expand Up @@ -852,9 +854,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
}

if (activatedExtensions.length > 0) {
this._logService.error(`Extension host (${extensionHostKindToString(extensionHost.kind)}) terminated unexpectedly. The following extensions were running: ${activatedExtensions.map(id => id.value).join(', ')}`);
this._logService.error(`Extension host (${extensionHost.friendyName}) terminated unexpectedly. The following extensions were running: ${activatedExtensions.map(id => id.value).join(', ')}`);
} else {
this._logService.error(`Extension host (${extensionHostKindToString(extensionHost.kind)}) terminated unexpectedly. No extensions were activated.`);
this._logService.error(`Extension host (${extensionHost.friendyName}) terminated unexpectedly. No extensions were activated.`);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,11 @@ export class ExtensionDescriptionRegistry implements IReadOnlyExtensionDescripti
this._extensionsArr.push(extensionDescription);

const activationEvents = this._activationEventsReader.readActivationEvents(extensionDescription);
if (Array.isArray(activationEvents)) {
for (let activationEvent of activationEvents) {
// TODO@joao: there's no easy way to contribute this
if (activationEvent === 'onUri') {
activationEvent = `onUri:${ExtensionIdentifier.toKey(extensionDescription.identifier)}`;
}

if (!this._activationMap.has(activationEvent)) {
this._activationMap.set(activationEvent, []);
}
this._activationMap.get(activationEvent)!.push(extensionDescription);
for (const activationEvent of activationEvents) {
if (!this._activationMap.has(activationEvent)) {
this._activationMap.set(activationEvent, []);
}
this._activationMap.get(activationEvent)!.push(extensionDescription);
}
}
}
Expand Down Expand Up @@ -261,15 +254,9 @@ export class ExtensionDescriptionRegistrySnapshot {
}

export interface IActivationEventsReader {
readActivationEvents(extensionDescription: IExtensionDescription): string[] | undefined;
readActivationEvents(extensionDescription: IExtensionDescription): string[];
}

export const basicActivationEventsReader: IActivationEventsReader = {
readActivationEvents: (extensionDescription: IExtensionDescription): string[] | undefined => {
return extensionDescription.activationEvents;
}
};

export class LockableExtensionDescriptionRegistry implements IReadOnlyExtensionDescriptionRegistry {

private readonly _actual: ExtensionDescriptionRegistry;
Expand Down
Loading

0 comments on commit b41d864

Please sign in to comment.