mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-31 20:55:34 +01:00
sandbox - move shared process to node layer (#174581)
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { basename, dirname, join } from 'vs/base/common/path';
|
||||
import { Promises } from 'vs/base/node/pfs';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
|
||||
export class CodeCacheCleaner extends Disposable {
|
||||
|
||||
private readonly _DataMaxAge = this.productService.quality !== 'stable'
|
||||
? 1000 * 60 * 60 * 24 * 7 // roughly 1 week (insiders)
|
||||
: 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months (stable)
|
||||
|
||||
constructor(
|
||||
currentCodeCachePath: string | undefined,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@ILogService private readonly logService: ILogService
|
||||
) {
|
||||
super();
|
||||
|
||||
// Cached data is stored as user data and we run a cleanup task every time
|
||||
// the editor starts. The strategy is to delete all files that are older than
|
||||
// 3 months (1 week respectively)
|
||||
if (currentCodeCachePath) {
|
||||
const scheduler = this._register(new RunOnceScheduler(() => {
|
||||
this.cleanUpCodeCaches(currentCodeCachePath);
|
||||
}, 30 * 1000 /* after 30s */));
|
||||
scheduler.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
private async cleanUpCodeCaches(currentCodeCachePath: string): Promise<void> {
|
||||
this.logService.trace('[code cache cleanup]: Starting to clean up old code cache folders.');
|
||||
|
||||
try {
|
||||
const now = Date.now();
|
||||
|
||||
// The folder which contains folders of cached data.
|
||||
// Each of these folders is partioned per commit
|
||||
const codeCacheRootPath = dirname(currentCodeCachePath);
|
||||
const currentCodeCache = basename(currentCodeCachePath);
|
||||
|
||||
const codeCaches = await Promises.readdir(codeCacheRootPath);
|
||||
await Promise.all(codeCaches.map(async codeCache => {
|
||||
if (codeCache === currentCodeCache) {
|
||||
return; // not the current cache folder
|
||||
}
|
||||
|
||||
// Delete cache folder if old enough
|
||||
const codeCacheEntryPath = join(codeCacheRootPath, codeCache);
|
||||
const codeCacheEntryStat = await Promises.stat(codeCacheEntryPath);
|
||||
if (codeCacheEntryStat.isDirectory() && (now - codeCacheEntryStat.mtime.getTime()) > this._DataMaxAge) {
|
||||
this.logService.trace(`[code cache cleanup]: Removing code cache folder ${codeCache}.`);
|
||||
|
||||
return Promises.rm(codeCacheEntryPath);
|
||||
}
|
||||
}));
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionStorageService, IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage';
|
||||
import { migrateUnsupportedExtensions } from 'vs/platform/extensionManagement/common/unsupportedExtensionsMigration';
|
||||
import { INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
|
||||
export class ExtensionsContributions extends Disposable {
|
||||
constructor(
|
||||
@INativeServerExtensionManagementService extensionManagementService: INativeServerExtensionManagementService,
|
||||
@IExtensionGalleryService extensionGalleryService: IExtensionGalleryService,
|
||||
@IExtensionStorageService extensionStorageService: IExtensionStorageService,
|
||||
@IGlobalExtensionEnablementService extensionEnablementService: IGlobalExtensionEnablementService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@ILogService logService: ILogService,
|
||||
) {
|
||||
super();
|
||||
|
||||
extensionManagementService.cleanUp();
|
||||
migrateUnsupportedExtensions(extensionManagementService, extensionGalleryService, extensionStorageService, extensionEnablementService, logService);
|
||||
ExtensionStorageService.removeOutdatedExtensionVersions(extensionManagementService, storageService);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { Promises } from 'vs/base/node/pfs';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
|
||||
interface IExtensionEntry {
|
||||
version: string;
|
||||
extensionIdentifier: {
|
||||
id: string;
|
||||
uuid: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface ILanguagePackEntry {
|
||||
hash: string;
|
||||
extensions: IExtensionEntry[];
|
||||
}
|
||||
|
||||
interface ILanguagePackFile {
|
||||
[locale: string]: ILanguagePackEntry;
|
||||
}
|
||||
|
||||
export class LanguagePackCachedDataCleaner extends Disposable {
|
||||
|
||||
private readonly _DataMaxAge = this.productService.quality !== 'stable'
|
||||
? 1000 * 60 * 60 * 24 * 7 // roughly 1 week (insiders)
|
||||
: 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months (stable)
|
||||
|
||||
constructor(
|
||||
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IProductService private readonly productService: IProductService
|
||||
) {
|
||||
super();
|
||||
|
||||
// We have no Language pack support for dev version (run from source)
|
||||
// So only cleanup when we have a build version.
|
||||
if (this.environmentService.isBuilt) {
|
||||
const scheduler = this._register(new RunOnceScheduler(() => {
|
||||
this.cleanUpLanguagePackCache();
|
||||
}, 40 * 1000 /* after 40s */));
|
||||
scheduler.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
private async cleanUpLanguagePackCache(): Promise<void> {
|
||||
this.logService.trace('[language pack cache cleanup]: Starting to clean up unused language packs.');
|
||||
|
||||
try {
|
||||
const installed: IStringDictionary<boolean> = Object.create(null);
|
||||
const metaData: ILanguagePackFile = JSON.parse(await Promises.readFile(join(this.environmentService.userDataPath, 'languagepacks.json'), 'utf8'));
|
||||
for (const locale of Object.keys(metaData)) {
|
||||
const entry = metaData[locale];
|
||||
installed[`${entry.hash}.${locale}`] = true;
|
||||
}
|
||||
|
||||
// Cleanup entries for language packs that aren't installed anymore
|
||||
const cacheDir = join(this.environmentService.userDataPath, 'clp');
|
||||
const cacheDirExists = await Promises.exists(cacheDir);
|
||||
if (!cacheDirExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entries = await Promises.readdir(cacheDir);
|
||||
for (const entry of entries) {
|
||||
if (installed[entry]) {
|
||||
this.logService.trace(`[language pack cache cleanup]: Skipping folder ${entry}. Language pack still in use.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
this.logService.trace(`[language pack cache cleanup]: Removing unused language pack: ${entry}`);
|
||||
|
||||
await Promises.rm(join(cacheDir, entry));
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
for (const packEntry of Object.keys(installed)) {
|
||||
const folder = join(cacheDir, packEntry);
|
||||
const entries = await Promises.readdir(folder);
|
||||
for (const entry of entries) {
|
||||
if (entry === 'tcf.json') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const candidate = join(folder, entry);
|
||||
const stat = await Promises.stat(candidate);
|
||||
if (stat.isDirectory() && (now - stat.mtime.getTime()) > this._DataMaxAge) {
|
||||
this.logService.trace(`[language pack cache cleanup]: Removing language pack cache folder: ${join(packEntry, entry)}`);
|
||||
|
||||
await Promises.rm(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks';
|
||||
import { NativeLanguagePackService } from 'vs/platform/languagePacks/node/languagePacks';
|
||||
|
||||
export class LocalizationsUpdater extends Disposable {
|
||||
|
||||
constructor(
|
||||
@ILanguagePackService private readonly localizationsService: NativeLanguagePackService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.updateLocalizations();
|
||||
}
|
||||
|
||||
private updateLocalizations(): void {
|
||||
this.localizationsService.update();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { basename, dirname, join } from 'vs/base/common/path';
|
||||
import { Promises } from 'vs/base/node/pfs';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
export class LogsDataCleaner extends Disposable {
|
||||
|
||||
constructor(
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@ILogService private readonly logService: ILogService
|
||||
) {
|
||||
super();
|
||||
|
||||
const scheduler = this._register(new RunOnceScheduler(() => {
|
||||
this.cleanUpOldLogs();
|
||||
}, 10 * 1000 /* after 10s */));
|
||||
scheduler.schedule();
|
||||
}
|
||||
|
||||
private async cleanUpOldLogs(): Promise<void> {
|
||||
this.logService.trace('[logs cleanup]: Starting to clean up old logs.');
|
||||
|
||||
try {
|
||||
const currentLog = basename(this.environmentService.logsPath);
|
||||
const logsRoot = dirname(this.environmentService.logsPath);
|
||||
|
||||
const logFiles = await Promises.readdir(logsRoot);
|
||||
|
||||
const allSessions = logFiles.filter(logFile => /^\d{8}T\d{6}$/.test(logFile));
|
||||
const oldSessions = allSessions.sort().filter(session => session !== currentLog);
|
||||
const sessionsToDelete = oldSessions.slice(0, Math.max(0, oldSessions.length - 9));
|
||||
|
||||
if (sessionsToDelete.length > 0) {
|
||||
this.logService.trace(`[logs cleanup]: Removing log folders '${sessionsToDelete.join(', ')}'`);
|
||||
|
||||
await Promise.all(sessionsToDelete.map(sessionToDelete => Promises.rm(join(logsRoot, sessionToDelete))));
|
||||
}
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { Promises } from 'vs/base/node/pfs';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { StorageClient } from 'vs/platform/storage/common/storageIpc';
|
||||
import { EXTENSION_DEVELOPMENT_EMPTY_WINDOW_WORKSPACE } from 'vs/platform/workspace/common/workspace';
|
||||
import { NON_EMPTY_WORKSPACE_ID_LENGTH } from 'vs/platform/workspaces/node/workspaces';
|
||||
|
||||
/* eslint-disable local/code-layering, local/code-import-patterns */
|
||||
// TODO@bpasero layer is not allowed in utility process
|
||||
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services';
|
||||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
|
||||
export class UnusedWorkspaceStorageDataCleaner extends Disposable {
|
||||
|
||||
constructor(
|
||||
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@INativeHostService private readonly nativeHostService: INativeHostService,
|
||||
@IMainProcessService private readonly mainProcessService: IMainProcessService
|
||||
) {
|
||||
super();
|
||||
|
||||
const scheduler = this._register(new RunOnceScheduler(() => {
|
||||
this.cleanUpStorage();
|
||||
}, 30 * 1000 /* after 30s */));
|
||||
scheduler.schedule();
|
||||
}
|
||||
|
||||
private async cleanUpStorage(): Promise<void> {
|
||||
this.logService.trace('[storage cleanup]: Starting to clean up workspace storage folders for unused empty workspaces.');
|
||||
|
||||
try {
|
||||
const workspaceStorageFolders = await Promises.readdir(this.environmentService.workspaceStorageHome.fsPath);
|
||||
const storageClient = new StorageClient(this.mainProcessService.getChannel('storage'));
|
||||
|
||||
await Promise.all(workspaceStorageFolders.map(async workspaceStorageFolder => {
|
||||
const workspaceStoragePath = join(this.environmentService.workspaceStorageHome.fsPath, workspaceStorageFolder);
|
||||
|
||||
if (workspaceStorageFolder.length === NON_EMPTY_WORKSPACE_ID_LENGTH) {
|
||||
return; // keep workspace storage for folders/workspaces that can be accessed still
|
||||
}
|
||||
|
||||
if (workspaceStorageFolder === EXTENSION_DEVELOPMENT_EMPTY_WINDOW_WORKSPACE.id) {
|
||||
return; // keep workspace storage for empty extension development workspaces
|
||||
}
|
||||
|
||||
const windows = await this.nativeHostService.getWindows();
|
||||
if (windows.some(window => window.workspace?.id === workspaceStorageFolder)) {
|
||||
return; // keep workspace storage for empty workspaces opened as window
|
||||
}
|
||||
|
||||
const isStorageUsed = await storageClient.isUsed(workspaceStoragePath);
|
||||
if (isStorageUsed) {
|
||||
return; // keep workspace storage for empty workspaces that are in use
|
||||
}
|
||||
|
||||
this.logService.trace(`[storage cleanup]: Deleting workspace storage folder ${workspaceStorageFolder} as it seems to be an unused empty workspace.`);
|
||||
|
||||
await Promises.rm(workspaceStoragePath);
|
||||
}));
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
|
||||
export class UserDataProfilesCleaner extends Disposable {
|
||||
|
||||
constructor(
|
||||
@IUserDataProfilesService userDataProfilesService: IUserDataProfilesService
|
||||
) {
|
||||
super();
|
||||
|
||||
const scheduler = this._register(new RunOnceScheduler(() => {
|
||||
userDataProfilesService.cleanUp();
|
||||
}, 10 * 1000 /* after 10s */));
|
||||
scheduler.schedule();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; connect-src 'self' https:;">
|
||||
</head>
|
||||
|
||||
<body aria-label="">
|
||||
Shared Process
|
||||
</body>
|
||||
|
||||
<!-- Startup (do not modify order of script tags!) -->
|
||||
<script src="../../../../bootstrap.js"></script>
|
||||
<script src="../../../../vs/loader.js"></script>
|
||||
<script src="../../../../bootstrap-window.js"></script>
|
||||
<script src="sharedProcess.js"></script>
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; connect-src 'self' https:;">
|
||||
</head>
|
||||
|
||||
<body aria-label="">
|
||||
Shared Process
|
||||
</body>
|
||||
|
||||
<!-- Startup (do not modify order of script tags!) -->
|
||||
<script src="sharedProcess.js"></script>
|
||||
</html>
|
||||
@@ -0,0 +1,46 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
//@ts-check
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const bootstrapWindow = bootstrapWindowLib();
|
||||
|
||||
// Load shared process into window
|
||||
bootstrapWindow.load(['vs/code/node/sharedProcess/sharedProcessMain'], function (sharedProcess, configuration) {
|
||||
return sharedProcess.main(configuration);
|
||||
},
|
||||
{
|
||||
configureDeveloperSettings: function () {
|
||||
return {
|
||||
disallowReloadKeybinding: true
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @typedef {import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration} ISandboxConfiguration
|
||||
*
|
||||
* @returns {{
|
||||
* load: (
|
||||
* modules: string[],
|
||||
* resultCallback: (result, configuration: ISandboxConfiguration) => unknown,
|
||||
* options?: {
|
||||
* configureDeveloperSettings?: (config: ISandboxConfiguration) => {
|
||||
* forceEnableDeveloperKeybindings?: boolean,
|
||||
* disallowReloadKeybinding?: boolean,
|
||||
* removeDeveloperKeybindingsAfterLoad?: boolean
|
||||
* }
|
||||
* }
|
||||
* ) => Promise<unknown>
|
||||
* }}
|
||||
*/
|
||||
function bootstrapWindowLib() {
|
||||
// @ts-ignore (defined in bootstrap-window.js)
|
||||
return window.MonacoBootstrapWindow;
|
||||
}
|
||||
}());
|
||||
@@ -0,0 +1,535 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { hostname, release } from 'os';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors';
|
||||
import { combinedDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IPCServer, ProxyChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Server as UtilityProcessMessagePortServer, once } from 'vs/base/parts/ipc/node/ipc.mp';
|
||||
import { CodeCacheCleaner } from 'vs/code/node/sharedProcess/contrib/codeCacheCleaner';
|
||||
import { LanguagePackCachedDataCleaner } from 'vs/code/node/sharedProcess/contrib/languagePackCachedDataCleaner';
|
||||
import { LocalizationsUpdater } from 'vs/code/node/sharedProcess/contrib/localizationsUpdater';
|
||||
import { LogsDataCleaner } from 'vs/code/node/sharedProcess/contrib/logsDataCleaner';
|
||||
import { UnusedWorkspaceStorageDataCleaner } from 'vs/code/node/sharedProcess/contrib/storageDataCleaner';
|
||||
import { IChecksumService } from 'vs/platform/checksum/common/checksumService';
|
||||
import { ChecksumService } from 'vs/platform/checksum/node/checksumService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
|
||||
import { IDiagnosticsService } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService';
|
||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||
import { DownloadService } from 'vs/platform/download/common/downloadService';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { SharedProcessEnvironmentService } from 'vs/platform/sharedProcess/node/sharedProcessEnvironmentService';
|
||||
import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
|
||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
||||
import { IExtensionGalleryService, IExtensionManagementService, IExtensionTipsService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionSignatureVerificationService, IExtensionSignatureVerificationService } from 'vs/platform/extensionManagement/node/extensionSignatureVerificationService';
|
||||
import { ExtensionManagementChannel, ExtensionTipsChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
|
||||
import { ExtensionManagementService, INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { FileService } from 'vs/platform/files/common/fileService';
|
||||
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks';
|
||||
import { NativeLanguagePackService } from 'vs/platform/languagePacks/node/languagePacks';
|
||||
import { ConsoleLogger, ILoggerService, ILogService } from 'vs/platform/log/common/log';
|
||||
import { LoggerChannelClient } from 'vs/platform/log/common/logIpc';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { ISharedProcessConfiguration } from 'vs/platform/sharedProcess/node/sharedProcess';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties';
|
||||
import { ICustomEndpointTelemetryService, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetryIpc';
|
||||
import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender';
|
||||
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
|
||||
import { supportsTelemetry, ITelemetryAppender, NullAppender, NullTelemetryService, getPiiPathsFromEnvironment, isInternalTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { CustomEndpointTelemetryService } from 'vs/platform/telemetry/node/customEndpointTelemetryService';
|
||||
import { LocalReconnectConstants, TerminalIpcChannels, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
|
||||
import { PtyHostService } from 'vs/platform/terminal/node/ptyHostService';
|
||||
import { ExtensionStorageService, IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage';
|
||||
import { IgnoredExtensionsManagementService, IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions';
|
||||
import { IUserDataSyncBackupStoreService, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncService, IUserDataSyncStoreManagementService, IUserDataSyncStoreService, IUserDataSyncUtilService, registerConfiguration as registerUserDataSyncConfiguration, IUserDataSyncResourceProviderService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncAccountService, UserDataSyncAccountService } from 'vs/platform/userDataSync/common/userDataSyncAccount';
|
||||
import { UserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSyncBackupStoreService';
|
||||
import { UserDataAutoSyncChannel, UserDataSyncAccountServiceChannel, UserDataSyncMachinesServiceChannel, UserDataSyncStoreManagementServiceChannel, UserDataSyncUtilServiceClient } from 'vs/platform/userDataSync/common/userDataSyncIpc';
|
||||
import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog';
|
||||
import { IUserDataSyncMachinesService, UserDataSyncMachinesService } from 'vs/platform/userDataSync/common/userDataSyncMachines';
|
||||
import { UserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSyncEnablementService';
|
||||
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
|
||||
import { UserDataSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncServiceIpc';
|
||||
import { UserDataSyncStoreManagementService, UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
|
||||
import { IUserDataProfileStorageService } from 'vs/platform/userDataProfile/common/userDataProfileStorageService';
|
||||
import { ActiveWindowManager } from 'vs/platform/windows/node/windowTracker';
|
||||
import { ISignService } from 'vs/platform/sign/common/sign';
|
||||
import { SignService } from 'vs/platform/sign/node/signService';
|
||||
import { ISharedTunnelsService } from 'vs/platform/tunnel/common/tunnel';
|
||||
import { SharedTunnelsService } from 'vs/platform/tunnel/node/tunnelService';
|
||||
import { ipcSharedProcessTunnelChannelName, ISharedProcessTunnelService } from 'vs/platform/remote/common/sharedProcessTunnelService';
|
||||
import { SharedProcessTunnelService } from 'vs/platform/tunnel/node/sharedProcessTunnelService';
|
||||
import { ISharedProcessWorkerService } from 'vs/platform/sharedProcess/common/sharedProcessWorkerService';
|
||||
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
||||
import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { FileUserDataProvider } from 'vs/platform/userData/common/fileUserDataProvider';
|
||||
import { DiskFileSystemProviderClient, LOCAL_FILE_SYSTEM_CHANNEL_NAME } from 'vs/platform/files/common/diskFileSystemProviderClient';
|
||||
import { InspectProfilingService as V8InspectProfilingService } from 'vs/platform/profiling/node/profilingService';
|
||||
import { IV8InspectProfilingService } from 'vs/platform/profiling/common/profiling';
|
||||
import { IExtensionsScannerService } from 'vs/platform/extensionManagement/common/extensionsScannerService';
|
||||
import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/extensionsScannerService';
|
||||
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
|
||||
import { PolicyChannelClient } from 'vs/platform/policy/common/policyIpc';
|
||||
import { IPolicyService, NullPolicyService } from 'vs/platform/policy/common/policy';
|
||||
import { UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfileIpc';
|
||||
import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender';
|
||||
import { UserDataProfilesCleaner } from 'vs/code/node/sharedProcess/contrib/userDataProfilesCleaner';
|
||||
import { IRemoteTunnelService } from 'vs/platform/remoteTunnel/common/remoteTunnel';
|
||||
import { UserDataSyncResourceProviderService } from 'vs/platform/userDataSync/common/userDataSyncResourceProvider';
|
||||
import { ExtensionsContributions } from 'vs/code/node/sharedProcess/contrib/extensions';
|
||||
import { localize } from 'vs/nls';
|
||||
import { LogService } from 'vs/platform/log/common/logService';
|
||||
import { ipcUtilityProcessWorkerChannelName, IUtilityProcessWorkerConfiguration } from 'vs/platform/utilityProcess/common/utilityProcessWorkerService';
|
||||
import { isUtilityProcess } from 'vs/base/parts/sandbox/node/electronTypes';
|
||||
|
||||
/* eslint-disable local/code-layering, local/code-import-patterns */
|
||||
// TODO@bpasero layer is not allowed in utility process
|
||||
import { Server as BrowserWindowMessagePortServer } from 'vs/base/parts/ipc/electron-browser/ipc.mp';
|
||||
import { ExtensionTipsService } from 'vs/platform/extensionManagement/electron-sandbox/extensionTipsService';
|
||||
import { ExtensionRecommendationNotificationServiceChannelClient } from 'vs/platform/extensionRecommendations/electron-sandbox/extensionRecommendationsIpc';
|
||||
import { MessagePortMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
|
||||
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services';
|
||||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
import { NativeStorageService } from 'vs/platform/storage/electron-sandbox/storageService';
|
||||
import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal';
|
||||
import { UserDataAutoSyncService } from 'vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService';
|
||||
import { UserDataProfileStorageService } from 'vs/platform/userDataProfile/electron-sandbox/userDataProfileStorageService';
|
||||
import { SharedProcessWorkerService } from 'vs/platform/sharedProcess/electron-browser/sharedProcessWorkerService';
|
||||
import { SharedProcessRequestService } from 'vs/platform/request/electron-browser/sharedProcessRequestService';
|
||||
import { RemoteTunnelService } from 'vs/platform/remoteTunnel/electron-browser/remoteTunnelService';
|
||||
import { ISharedProcessLifecycleService, SharedProcessLifecycleService } from 'vs/platform/lifecycle/electron-browser/sharedProcessLifecycleService';
|
||||
import { ExtensionsProfileScannerService } from 'vs/platform/extensionManagement/electron-sandbox/extensionsProfileScannerService';
|
||||
|
||||
class SharedProcessMain extends Disposable {
|
||||
|
||||
private readonly server: IPCServer;
|
||||
|
||||
private sharedProcessWorkerService: ISharedProcessWorkerService | undefined = undefined;
|
||||
|
||||
private lifecycleService: SharedProcessLifecycleService | undefined = undefined;
|
||||
|
||||
constructor(private configuration: ISharedProcessConfiguration, private ipcRenderer?: typeof import('electron').ipcRenderer) {
|
||||
super();
|
||||
|
||||
if (isUtilityProcess(process)) {
|
||||
this.server = this._register(new UtilityProcessMessagePortServer());
|
||||
} else {
|
||||
this.server = this._register(new BrowserWindowMessagePortServer());
|
||||
}
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
|
||||
// Shared process lifecycle
|
||||
const onExit = async () => {
|
||||
this.lifecycleService?.fireOnWillShutdown();
|
||||
this.dispose();
|
||||
};
|
||||
process.once('exit', onExit);
|
||||
if (isUtilityProcess(process)) {
|
||||
once(process.parentPort, 'vscode:electron-main->shared-process=exit', onExit);
|
||||
} else {
|
||||
this.ipcRenderer!.once('vscode:electron-main->shared-process=exit', onExit);
|
||||
}
|
||||
|
||||
if (!isUtilityProcess(process)) {
|
||||
|
||||
// Shared process worker lifecycle
|
||||
//
|
||||
// We dispose the listener when the shared process is
|
||||
// disposed to avoid disposing workers when the entire
|
||||
// application is shutting down anyways.
|
||||
|
||||
const eventName = 'vscode:electron-main->shared-process=disposeWorker';
|
||||
const onDisposeWorker = (event: unknown, configuration: IUtilityProcessWorkerConfiguration) => { this.onDisposeWorker(configuration); };
|
||||
this.ipcRenderer!.on(eventName, onDisposeWorker);
|
||||
this._register(toDisposable(() => this.ipcRenderer!.removeListener(eventName, onDisposeWorker)));
|
||||
}
|
||||
}
|
||||
|
||||
private onDisposeWorker(configuration: IUtilityProcessWorkerConfiguration): void {
|
||||
this.sharedProcessWorkerService?.disposeWorker(configuration);
|
||||
}
|
||||
|
||||
async init(): Promise<void> {
|
||||
|
||||
// Services
|
||||
const instantiationService = await this.initServices();
|
||||
|
||||
// Config
|
||||
registerUserDataSyncConfiguration();
|
||||
|
||||
instantiationService.invokeFunction(accessor => {
|
||||
const logService = accessor.get(ILogService);
|
||||
|
||||
// Log info
|
||||
logService.trace('sharedProcess configuration', JSON.stringify(this.configuration));
|
||||
|
||||
// Channels
|
||||
this.initChannels(accessor);
|
||||
|
||||
// Error handler
|
||||
this.registerErrorHandler(logService);
|
||||
});
|
||||
|
||||
// Instantiate Contributions
|
||||
this._register(combinedDisposable(
|
||||
instantiationService.createInstance(CodeCacheCleaner, this.configuration.codeCachePath),
|
||||
instantiationService.createInstance(LanguagePackCachedDataCleaner),
|
||||
instantiationService.createInstance(UnusedWorkspaceStorageDataCleaner),
|
||||
instantiationService.createInstance(LogsDataCleaner),
|
||||
instantiationService.createInstance(LocalizationsUpdater),
|
||||
instantiationService.createInstance(ExtensionsContributions),
|
||||
instantiationService.createInstance(UserDataProfilesCleaner)
|
||||
));
|
||||
}
|
||||
|
||||
private async initServices(): Promise<IInstantiationService> {
|
||||
const services = new ServiceCollection();
|
||||
|
||||
// Product
|
||||
const productService = { _serviceBrand: undefined, ...product };
|
||||
services.set(IProductService, productService);
|
||||
|
||||
// Main Process
|
||||
const mainRouter = new StaticRouter(ctx => ctx === 'main');
|
||||
const mainProcessService = new MessagePortMainProcessService(this.server, mainRouter);
|
||||
services.set(IMainProcessService, mainProcessService);
|
||||
|
||||
// Policies
|
||||
const policyService = this.configuration.policiesData ? new PolicyChannelClient(this.configuration.policiesData, mainProcessService.getChannel('policy')) : new NullPolicyService();
|
||||
services.set(IPolicyService, policyService);
|
||||
|
||||
// Environment
|
||||
const environmentService = new SharedProcessEnvironmentService(this.configuration.args, productService);
|
||||
services.set(INativeEnvironmentService, environmentService);
|
||||
|
||||
// Logger
|
||||
const loggerService = new LoggerChannelClient(undefined, this.configuration.logLevel, this.configuration.loggers.map(loggerResource => ({ ...loggerResource, resource: URI.revive(loggerResource.resource) })), mainProcessService.getChannel('logger'));
|
||||
services.set(ILoggerService, loggerService);
|
||||
|
||||
// Log
|
||||
const logger = this._register(loggerService.createLogger(joinPath(URI.file(environmentService.logsPath), 'sharedprocess.log'), { id: 'sharedLog', name: localize('sharedLog', "Shared") }));
|
||||
const consoleLogger = this._register(new ConsoleLogger(logger.getLevel()));
|
||||
const logService = this._register(new LogService(logger, [consoleLogger]));
|
||||
services.set(ILogService, logService);
|
||||
|
||||
// Lifecycle
|
||||
this.lifecycleService = this._register(new SharedProcessLifecycleService(logService));
|
||||
services.set(ISharedProcessLifecycleService, this.lifecycleService);
|
||||
|
||||
// Worker
|
||||
this.sharedProcessWorkerService = new SharedProcessWorkerService(logService);
|
||||
services.set(ISharedProcessWorkerService, this.sharedProcessWorkerService);
|
||||
|
||||
// Files
|
||||
const fileService = this._register(new FileService(logService));
|
||||
services.set(IFileService, fileService);
|
||||
|
||||
const diskFileSystemProvider = this._register(new DiskFileSystemProvider(logService));
|
||||
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
||||
|
||||
const userDataFileSystemProvider = this._register(new FileUserDataProvider(
|
||||
Schemas.file,
|
||||
// Specifically for user data, use the disk file system provider
|
||||
// from the main process to enable atomic read/write operations.
|
||||
// Since user data can change very frequently across multiple
|
||||
// processes, we want a single process handling these operations.
|
||||
this._register(new DiskFileSystemProviderClient(mainProcessService.getChannel(LOCAL_FILE_SYSTEM_CHANNEL_NAME), { pathCaseSensitive: isLinux })),
|
||||
Schemas.vscodeUserData,
|
||||
logService
|
||||
));
|
||||
fileService.registerProvider(Schemas.vscodeUserData, userDataFileSystemProvider);
|
||||
|
||||
// User Data Profiles
|
||||
const userDataProfilesService = this._register(new UserDataProfilesService(this.configuration.profiles.all, URI.revive(this.configuration.profiles.home), mainProcessService.getChannel('userDataProfiles')));
|
||||
services.set(IUserDataProfilesService, userDataProfilesService);
|
||||
|
||||
// Configuration
|
||||
const configurationService = this._register(new ConfigurationService(userDataProfilesService.defaultProfile.settingsResource, fileService, policyService, logService));
|
||||
services.set(IConfigurationService, configurationService);
|
||||
|
||||
// Storage (global access only)
|
||||
const storageService = new NativeStorageService(undefined, { defaultProfile: userDataProfilesService.defaultProfile, currentProfile: userDataProfilesService.defaultProfile }, mainProcessService, environmentService);
|
||||
services.set(IStorageService, storageService);
|
||||
this._register(toDisposable(() => storageService.flush()));
|
||||
|
||||
// Initialize config & storage in parallel
|
||||
await Promise.all([
|
||||
configurationService.initialize(),
|
||||
storageService.initialize()
|
||||
]);
|
||||
|
||||
// URI Identity
|
||||
const uriIdentityService = new UriIdentityService(fileService);
|
||||
services.set(IUriIdentityService, uriIdentityService);
|
||||
|
||||
// Request
|
||||
services.set(IRequestService, new SharedProcessRequestService(mainProcessService, configurationService, logService));
|
||||
|
||||
// Checksum
|
||||
services.set(IChecksumService, new SyncDescriptor(ChecksumService, undefined, false /* proxied to other processes */));
|
||||
|
||||
// V8 Inspect profiler
|
||||
services.set(IV8InspectProfilingService, new SyncDescriptor(V8InspectProfilingService, undefined, false /* proxied to other processes */));
|
||||
|
||||
// Native Host
|
||||
const nativeHostService = ProxyChannel.toService<INativeHostService>(mainProcessService.getChannel('nativeHost'), { context: this.configuration.windowId });
|
||||
services.set(INativeHostService, nativeHostService);
|
||||
|
||||
// Download
|
||||
services.set(IDownloadService, new SyncDescriptor(DownloadService, undefined, true));
|
||||
|
||||
// Extension recommendations
|
||||
const activeWindowManager = this._register(new ActiveWindowManager(nativeHostService));
|
||||
const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id));
|
||||
services.set(IExtensionRecommendationNotificationService, new ExtensionRecommendationNotificationServiceChannelClient(this.server.getChannel('extensionRecommendationNotification', activeWindowRouter)));
|
||||
|
||||
// Telemetry
|
||||
let telemetryService: ITelemetryService;
|
||||
const appenders: ITelemetryAppender[] = [];
|
||||
const internalTelemetry = isInternalTelemetry(productService, configurationService);
|
||||
if (supportsTelemetry(productService, environmentService)) {
|
||||
const logAppender = new TelemetryLogAppender(logService, loggerService, environmentService, productService);
|
||||
appenders.push(logAppender);
|
||||
const { installSourcePath } = environmentService;
|
||||
if (productService.aiConfig?.ariaKey) {
|
||||
const collectorAppender = new OneDataSystemAppender(internalTelemetry, 'monacoworkbench', null, productService.aiConfig.ariaKey);
|
||||
this._register(toDisposable(() => collectorAppender.flush())); // Ensure the 1DS appender is disposed so that it flushes remaining data
|
||||
appenders.push(collectorAppender);
|
||||
}
|
||||
|
||||
telemetryService = new TelemetryService({
|
||||
appenders,
|
||||
commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, internalTelemetry, installSourcePath),
|
||||
sendErrorTelemetry: true,
|
||||
piiPaths: getPiiPathsFromEnvironment(environmentService),
|
||||
}, configurationService, productService);
|
||||
} else {
|
||||
telemetryService = NullTelemetryService;
|
||||
const nullAppender = NullAppender;
|
||||
appenders.push(nullAppender);
|
||||
}
|
||||
|
||||
this.server.registerChannel('telemetryAppender', new TelemetryAppenderChannel(appenders));
|
||||
services.set(ITelemetryService, telemetryService);
|
||||
|
||||
// Custom Endpoint Telemetry
|
||||
const customEndpointTelemetryService = new CustomEndpointTelemetryService(configurationService, telemetryService, logService, loggerService, environmentService, productService);
|
||||
services.set(ICustomEndpointTelemetryService, customEndpointTelemetryService);
|
||||
|
||||
// Extension Management
|
||||
services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService, undefined, true));
|
||||
services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService, undefined, true));
|
||||
services.set(IExtensionSignatureVerificationService, new SyncDescriptor(ExtensionSignatureVerificationService, undefined, true));
|
||||
services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService, undefined, true));
|
||||
|
||||
// Extension Gallery
|
||||
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService, undefined, true));
|
||||
|
||||
// Extension Tips
|
||||
services.set(IExtensionTipsService, new SyncDescriptor(ExtensionTipsService, undefined, false /* Eagerly scans and computes exe based recommendations */));
|
||||
|
||||
// Localizations
|
||||
services.set(ILanguagePackService, new SyncDescriptor(NativeLanguagePackService, undefined, false /* proxied to other processes */));
|
||||
|
||||
// Diagnostics
|
||||
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService, undefined, false /* proxied to other processes */));
|
||||
|
||||
// Settings Sync
|
||||
services.set(IUserDataSyncAccountService, new SyncDescriptor(UserDataSyncAccountService, undefined, true));
|
||||
services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService, undefined, true));
|
||||
services.set(IUserDataSyncUtilService, new UserDataSyncUtilServiceClient(this.server.getChannel('userDataSyncUtil', client => client.ctx !== 'main')));
|
||||
services.set(IGlobalExtensionEnablementService, new SyncDescriptor(GlobalExtensionEnablementService, undefined, false /* Eagerly resets installed extensions */));
|
||||
services.set(IIgnoredExtensionsManagementService, new SyncDescriptor(IgnoredExtensionsManagementService, undefined, true));
|
||||
services.set(IExtensionStorageService, new SyncDescriptor(ExtensionStorageService));
|
||||
services.set(IUserDataSyncStoreManagementService, new SyncDescriptor(UserDataSyncStoreManagementService, undefined, true));
|
||||
services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService, undefined, true));
|
||||
services.set(IUserDataSyncMachinesService, new SyncDescriptor(UserDataSyncMachinesService, undefined, true));
|
||||
services.set(IUserDataSyncBackupStoreService, new SyncDescriptor(UserDataSyncBackupStoreService, undefined, false /* Eagerly cleans up old backups */));
|
||||
services.set(IUserDataSyncEnablementService, new SyncDescriptor(UserDataSyncEnablementService, undefined, true));
|
||||
services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService, undefined, false /* Initializes the Sync State */));
|
||||
services.set(IUserDataProfileStorageService, new SyncDescriptor(UserDataProfileStorageService, undefined, true));
|
||||
services.set(IUserDataSyncResourceProviderService, new SyncDescriptor(UserDataSyncResourceProviderService, undefined, true));
|
||||
|
||||
// Terminal
|
||||
|
||||
const ptyHostService = new PtyHostService({
|
||||
graceTime: LocalReconnectConstants.GraceTime,
|
||||
shortGraceTime: LocalReconnectConstants.ShortGraceTime,
|
||||
scrollback: configurationService.getValue<number>(TerminalSettingId.PersistentSessionScrollback) ?? 100
|
||||
},
|
||||
localize('ptyHost', "Pty Host"),
|
||||
configurationService,
|
||||
environmentService,
|
||||
logService,
|
||||
loggerService
|
||||
);
|
||||
ptyHostService.initialize();
|
||||
|
||||
services.set(ILocalPtyService, this._register(ptyHostService));
|
||||
|
||||
// Signing
|
||||
services.set(ISignService, new SyncDescriptor(SignService, undefined, false /* proxied to other processes */));
|
||||
|
||||
// Tunnel
|
||||
services.set(ISharedTunnelsService, new SyncDescriptor(SharedTunnelsService));
|
||||
services.set(ISharedProcessTunnelService, new SyncDescriptor(SharedProcessTunnelService));
|
||||
|
||||
// Remote Tunnel
|
||||
services.set(IRemoteTunnelService, new SyncDescriptor(RemoteTunnelService));
|
||||
|
||||
return new InstantiationService(services);
|
||||
}
|
||||
|
||||
private initChannels(accessor: ServicesAccessor): void {
|
||||
|
||||
// Extensions Management
|
||||
const channel = new ExtensionManagementChannel(accessor.get(IExtensionManagementService), () => null);
|
||||
this.server.registerChannel('extensions', channel);
|
||||
|
||||
// Language Packs
|
||||
const languagePacksChannel = ProxyChannel.fromService(accessor.get(ILanguagePackService));
|
||||
this.server.registerChannel('languagePacks', languagePacksChannel);
|
||||
|
||||
// Diagnostics
|
||||
const diagnosticsChannel = ProxyChannel.fromService(accessor.get(IDiagnosticsService));
|
||||
this.server.registerChannel('diagnostics', diagnosticsChannel);
|
||||
|
||||
// Extension Tips
|
||||
const extensionTipsChannel = new ExtensionTipsChannel(accessor.get(IExtensionTipsService));
|
||||
this.server.registerChannel('extensionTipsService', extensionTipsChannel);
|
||||
|
||||
// Checksum
|
||||
const checksumChannel = ProxyChannel.fromService(accessor.get(IChecksumService));
|
||||
this.server.registerChannel('checksum', checksumChannel);
|
||||
|
||||
// Profiling
|
||||
const profilingChannel = ProxyChannel.fromService(accessor.get(IV8InspectProfilingService));
|
||||
this.server.registerChannel('v8InspectProfiling', profilingChannel);
|
||||
|
||||
// Settings Sync
|
||||
const userDataSyncMachineChannel = new UserDataSyncMachinesServiceChannel(accessor.get(IUserDataSyncMachinesService));
|
||||
this.server.registerChannel('userDataSyncMachines', userDataSyncMachineChannel);
|
||||
|
||||
// Custom Endpoint Telemetry
|
||||
const customEndpointTelemetryChannel = ProxyChannel.fromService(accessor.get(ICustomEndpointTelemetryService));
|
||||
this.server.registerChannel('customEndpointTelemetry', customEndpointTelemetryChannel);
|
||||
|
||||
const userDataSyncAccountChannel = new UserDataSyncAccountServiceChannel(accessor.get(IUserDataSyncAccountService));
|
||||
this.server.registerChannel('userDataSyncAccount', userDataSyncAccountChannel);
|
||||
|
||||
const userDataSyncStoreManagementChannel = new UserDataSyncStoreManagementServiceChannel(accessor.get(IUserDataSyncStoreManagementService));
|
||||
this.server.registerChannel('userDataSyncStoreManagement', userDataSyncStoreManagementChannel);
|
||||
|
||||
const userDataSyncChannel = new UserDataSyncChannel(accessor.get(IUserDataSyncService), accessor.get(IUserDataProfilesService), accessor.get(ILogService));
|
||||
this.server.registerChannel('userDataSync', userDataSyncChannel);
|
||||
|
||||
const userDataAutoSync = this._register(accessor.get(IInstantiationService).createInstance(UserDataAutoSyncService));
|
||||
const userDataAutoSyncChannel = new UserDataAutoSyncChannel(userDataAutoSync);
|
||||
this.server.registerChannel('userDataAutoSync', userDataAutoSyncChannel);
|
||||
|
||||
// Terminal
|
||||
const localPtyService = accessor.get(ILocalPtyService);
|
||||
const localPtyChannel = ProxyChannel.fromService(localPtyService);
|
||||
this.server.registerChannel(TerminalIpcChannels.LocalPty, localPtyChannel);
|
||||
|
||||
// Tunnel
|
||||
const sharedProcessTunnelChannel = ProxyChannel.fromService(accessor.get(ISharedProcessTunnelService));
|
||||
this.server.registerChannel(ipcSharedProcessTunnelChannelName, sharedProcessTunnelChannel);
|
||||
|
||||
// Worker
|
||||
const sharedProcessWorkerChannel = ProxyChannel.fromService(accessor.get(ISharedProcessWorkerService));
|
||||
this.server.registerChannel(ipcUtilityProcessWorkerChannelName, sharedProcessWorkerChannel);
|
||||
|
||||
// Remote Tunnel
|
||||
const remoteTunnelChannel = ProxyChannel.fromService(accessor.get(IRemoteTunnelService));
|
||||
this.server.registerChannel('remoteTunnel', remoteTunnelChannel);
|
||||
}
|
||||
|
||||
private registerErrorHandler(logService: ILogService): void {
|
||||
|
||||
// Listen on global error events
|
||||
if (isUtilityProcess(process)) {
|
||||
process.on('uncaughtException', error => onUnexpectedError(error));
|
||||
process.on('unhandledRejection', (reason: unknown) => onUnexpectedError(reason));
|
||||
} else {
|
||||
(globalThis as any).addEventListener('unhandledrejection', (event: any) => {
|
||||
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent
|
||||
onUnexpectedError(event.reason);
|
||||
|
||||
// Prevent the printing of this event to the console
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
// Install handler for unexpected errors
|
||||
setUnexpectedErrorHandler(error => {
|
||||
const message = toErrorMessage(error, true);
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
logService.error(`[uncaught exception in sharedProcess]: ${message}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function main(configuration: ISharedProcessConfiguration): Promise<void> {
|
||||
|
||||
// create shared process and signal back to main that we are
|
||||
// ready to accept message ports as client connections
|
||||
|
||||
let ipcRenderer: typeof import('electron').ipcRenderer | undefined = undefined;
|
||||
if (!isUtilityProcess(process)) {
|
||||
ipcRenderer = (await import('electron')).ipcRenderer;
|
||||
}
|
||||
|
||||
const sharedProcess = new SharedProcessMain(configuration, ipcRenderer);
|
||||
|
||||
if (isUtilityProcess(process)) {
|
||||
process.parentPort.postMessage('vscode:shared-process->electron-main=ipc-ready');
|
||||
} else {
|
||||
ipcRenderer!.send('vscode:shared-process->electron-main=ipc-ready');
|
||||
}
|
||||
|
||||
// await initialization and signal this back to electron-main
|
||||
await sharedProcess.init();
|
||||
|
||||
if (isUtilityProcess(process)) {
|
||||
process.parentPort.postMessage('vscode:shared-process->electron-main=init-done');
|
||||
} else {
|
||||
ipcRenderer!.send('vscode:shared-process->electron-main=init-done');
|
||||
}
|
||||
}
|
||||
|
||||
if (isUtilityProcess(process)) {
|
||||
process.parentPort.once('message', (e: Electron.MessageEvent) => {
|
||||
main(e.data as ISharedProcessConfiguration);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user