Path: blob/main/src/vs/platform/diagnostics/electron-main/diagnosticsMainService.ts
3294 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { app, BrowserWindow, Event as IpcEvent } from 'electron';6import { validatedIpcMain } from '../../../base/parts/ipc/electron-main/ipcMain.js';7import { CancellationToken } from '../../../base/common/cancellation.js';8import { URI } from '../../../base/common/uri.js';9import { IDiagnosticInfo, IDiagnosticInfoOptions, IMainProcessDiagnostics, IProcessDiagnostics, IRemoteDiagnosticError, IRemoteDiagnosticInfo, IWindowDiagnostics } from '../common/diagnostics.js';10import { createDecorator } from '../../instantiation/common/instantiation.js';11import { ICodeWindow } from '../../window/electron-main/window.js';12import { getAllWindowsExcludingOffscreen, IWindowsMainService } from '../../windows/electron-main/windows.js';13import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from '../../workspace/common/workspace.js';14import { IWorkspacesManagementMainService } from '../../workspaces/electron-main/workspacesManagementMainService.js';15import { assertReturnsDefined } from '../../../base/common/types.js';16import { ILogService } from '../../log/common/log.js';17import { UtilityProcess } from '../../utilityProcess/electron-main/utilityProcess.js';1819export const ID = 'diagnosticsMainService';20export const IDiagnosticsMainService = createDecorator<IDiagnosticsMainService>(ID);2122export interface IRemoteDiagnosticOptions {23includeProcesses?: boolean;24includeWorkspaceMetadata?: boolean;25}2627export interface IDiagnosticsMainService {28readonly _serviceBrand: undefined;29getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<(IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]>;30getMainDiagnostics(): Promise<IMainProcessDiagnostics>;31}3233export class DiagnosticsMainService implements IDiagnosticsMainService {3435declare readonly _serviceBrand: undefined;3637constructor(38@IWindowsMainService private readonly windowsMainService: IWindowsMainService,39@IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService,40@ILogService private readonly logService: ILogService41) { }4243async getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<(IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]> {44const windows = this.windowsMainService.getWindows();45const diagnostics: Array<IDiagnosticInfo | IRemoteDiagnosticError | undefined> = await Promise.all(windows.map(async window => {46const remoteAuthority = window.remoteAuthority;47if (!remoteAuthority) {48return undefined;49}5051const replyChannel = `vscode:getDiagnosticInfoResponse${window.id}`;52const args: IDiagnosticInfoOptions = {53includeProcesses: options.includeProcesses,54folders: options.includeWorkspaceMetadata ? await this.getFolderURIs(window) : undefined55};5657return new Promise<IDiagnosticInfo | IRemoteDiagnosticError>(resolve => {58window.sendWhenReady('vscode:getDiagnosticInfo', CancellationToken.None, { replyChannel, args });5960validatedIpcMain.once(replyChannel, (_: IpcEvent, data: IRemoteDiagnosticInfo) => {61// No data is returned if getting the connection fails.62if (!data) {63resolve({ hostName: remoteAuthority, errorMessage: `Unable to resolve connection to '${remoteAuthority}'.` });64}6566resolve(data);67});6869setTimeout(() => {70resolve({ hostName: remoteAuthority, errorMessage: `Connection to '${remoteAuthority}' could not be established` });71}, 5000);72});73}));7475return diagnostics.filter((x): x is IRemoteDiagnosticInfo | IRemoteDiagnosticError => !!x);76}7778async getMainDiagnostics(): Promise<IMainProcessDiagnostics> {79this.logService.trace('Received request for main process info from other instance.');8081const windows: IWindowDiagnostics[] = [];82for (const window of getAllWindowsExcludingOffscreen()) {83const codeWindow = this.windowsMainService.getWindowById(window.id);84if (codeWindow) {85windows.push(await this.codeWindowToInfo(codeWindow));86} else {87windows.push(this.browserWindowToInfo(window));88}89}9091const pidToNames: IProcessDiagnostics[] = [];92for (const { pid, name } of UtilityProcess.getAll()) {93pidToNames.push({ pid, name });94}9596return {97mainPID: process.pid,98mainArguments: process.argv.slice(1),99windows,100pidToNames,101screenReader: !!app.accessibilitySupportEnabled,102gpuFeatureStatus: app.getGPUFeatureStatus()103};104}105106private async codeWindowToInfo(window: ICodeWindow): Promise<IWindowDiagnostics> {107const folderURIs = await this.getFolderURIs(window);108const win = assertReturnsDefined(window.win);109110return this.browserWindowToInfo(win, folderURIs, window.remoteAuthority);111}112113private browserWindowToInfo(window: BrowserWindow, folderURIs: URI[] = [], remoteAuthority?: string): IWindowDiagnostics {114return {115id: window.id,116pid: window.webContents.getOSProcessId(),117title: window.getTitle(),118folderURIs,119remoteAuthority120};121}122123private async getFolderURIs(window: ICodeWindow): Promise<URI[]> {124const folderURIs: URI[] = [];125126const workspace = window.openedWorkspace;127if (isSingleFolderWorkspaceIdentifier(workspace)) {128folderURIs.push(workspace.uri);129} else if (isWorkspaceIdentifier(workspace)) {130const resolvedWorkspace = await this.workspacesManagementMainService.resolveLocalWorkspace(workspace.configPath); // workspace folders can only be shown for local (resolved) workspaces131if (resolvedWorkspace) {132const rootFolders = resolvedWorkspace.folders;133rootFolders.forEach(root => {134folderURIs.push(root.uri);135});136}137}138139return folderURIs;140}141}142143144