Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/diagnostics/electron-main/diagnosticsMainService.ts
5241 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { app, BrowserWindow, Event as IpcEvent } from 'electron';
7
import { validatedIpcMain } from '../../../base/parts/ipc/electron-main/ipcMain.js';
8
import { CancellationToken } from '../../../base/common/cancellation.js';
9
import { URI } from '../../../base/common/uri.js';
10
import { IDiagnosticInfo, IDiagnosticInfoOptions, IGPULogMessage, IMainProcessDiagnostics, IProcessDiagnostics, IRemoteDiagnosticError, IRemoteDiagnosticInfo, IWindowDiagnostics } from '../common/diagnostics.js';
11
import { createDecorator } from '../../instantiation/common/instantiation.js';
12
import { ICodeWindow } from '../../window/electron-main/window.js';
13
import { getAllWindowsExcludingOffscreen, IWindowsMainService } from '../../windows/electron-main/windows.js';
14
import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from '../../workspace/common/workspace.js';
15
import { IWorkspacesManagementMainService } from '../../workspaces/electron-main/workspacesManagementMainService.js';
16
import { assertReturnsDefined } from '../../../base/common/types.js';
17
import { ILogService } from '../../log/common/log.js';
18
import { UtilityProcess } from '../../utilityProcess/electron-main/utilityProcess.js';
19
20
export const ID = 'diagnosticsMainService';
21
export const IDiagnosticsMainService = createDecorator<IDiagnosticsMainService>(ID);
22
23
export interface IRemoteDiagnosticOptions {
24
includeProcesses?: boolean;
25
includeWorkspaceMetadata?: boolean;
26
}
27
28
export interface IDiagnosticsMainService {
29
readonly _serviceBrand: undefined;
30
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<(IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]>;
31
getMainDiagnostics(): Promise<IMainProcessDiagnostics>;
32
}
33
34
export class DiagnosticsMainService implements IDiagnosticsMainService {
35
36
declare readonly _serviceBrand: undefined;
37
38
constructor(
39
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
40
@IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService,
41
@ILogService private readonly logService: ILogService
42
) { }
43
44
async getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<(IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]> {
45
const windows = this.windowsMainService.getWindows();
46
const diagnostics: Array<IDiagnosticInfo | IRemoteDiagnosticError | undefined> = await Promise.all(windows.map(async window => {
47
const remoteAuthority = window.remoteAuthority;
48
if (!remoteAuthority) {
49
return undefined;
50
}
51
52
const replyChannel = `vscode:getDiagnosticInfoResponse${window.id}`;
53
const args: IDiagnosticInfoOptions = {
54
includeProcesses: options.includeProcesses,
55
folders: options.includeWorkspaceMetadata ? await this.getFolderURIs(window) : undefined
56
};
57
58
return new Promise<IDiagnosticInfo | IRemoteDiagnosticError>(resolve => {
59
window.sendWhenReady('vscode:getDiagnosticInfo', CancellationToken.None, { replyChannel, args });
60
61
validatedIpcMain.once(replyChannel, (_: IpcEvent, data: IRemoteDiagnosticInfo) => {
62
// No data is returned if getting the connection fails.
63
if (!data) {
64
resolve({ hostName: remoteAuthority, errorMessage: `Unable to resolve connection to '${remoteAuthority}'.` });
65
}
66
67
resolve(data);
68
});
69
70
setTimeout(() => {
71
resolve({ hostName: remoteAuthority, errorMessage: `Connection to '${remoteAuthority}' could not be established` });
72
}, 5000);
73
});
74
}));
75
76
return diagnostics.filter((x): x is IRemoteDiagnosticInfo | IRemoteDiagnosticError => !!x);
77
}
78
79
async getMainDiagnostics(): Promise<IMainProcessDiagnostics> {
80
this.logService.trace('Received request for main process info from other instance.');
81
82
const windows: IWindowDiagnostics[] = [];
83
for (const window of getAllWindowsExcludingOffscreen()) {
84
const codeWindow = this.windowsMainService.getWindowById(window.id);
85
if (codeWindow) {
86
windows.push(await this.codeWindowToInfo(codeWindow));
87
} else {
88
windows.push(this.browserWindowToInfo(window));
89
}
90
}
91
92
const pidToNames: IProcessDiagnostics[] = [];
93
for (const { pid, name } of UtilityProcess.getAll()) {
94
pidToNames.push({ pid, name });
95
}
96
97
type AppWithGPULogMethod = typeof app & {
98
getGPULogMessages(): IGPULogMessage[];
99
};
100
101
let gpuLogMessages: IGPULogMessage[] = [];
102
const customApp = app as AppWithGPULogMethod;
103
if (typeof customApp.getGPULogMessages === 'function') {
104
gpuLogMessages = customApp.getGPULogMessages();
105
}
106
107
return {
108
mainPID: process.pid,
109
mainArguments: process.argv.slice(1),
110
windows,
111
pidToNames,
112
screenReader: !!app.accessibilitySupportEnabled,
113
gpuFeatureStatus: app.getGPUFeatureStatus(),
114
gpuLogMessages
115
};
116
}
117
118
private async codeWindowToInfo(window: ICodeWindow): Promise<IWindowDiagnostics> {
119
const folderURIs = await this.getFolderURIs(window);
120
const win = assertReturnsDefined(window.win);
121
122
return this.browserWindowToInfo(win, folderURIs, window.remoteAuthority);
123
}
124
125
private browserWindowToInfo(window: BrowserWindow, folderURIs: URI[] = [], remoteAuthority?: string): IWindowDiagnostics {
126
return {
127
id: window.id,
128
pid: window.webContents.getOSProcessId(),
129
title: window.getTitle(),
130
folderURIs,
131
remoteAuthority
132
};
133
}
134
135
private async getFolderURIs(window: ICodeWindow): Promise<URI[]> {
136
const folderURIs: URI[] = [];
137
138
const workspace = window.openedWorkspace;
139
if (isSingleFolderWorkspaceIdentifier(workspace)) {
140
folderURIs.push(workspace.uri);
141
} else if (isWorkspaceIdentifier(workspace)) {
142
const resolvedWorkspace = await this.workspacesManagementMainService.resolveLocalWorkspace(workspace.configPath); // workspace folders can only be shown for local (resolved) workspaces
143
if (resolvedWorkspace) {
144
const rootFolders = resolvedWorkspace.folders;
145
rootFolders.forEach(root => {
146
folderURIs.push(root.uri);
147
});
148
}
149
}
150
151
return folderURIs;
152
}
153
}
154
155