Skip to content

Commit 4bbebd8

Browse files
authored
splits up process explorer and issue reporter services (#216766)
* split up process explorer and issue reporter services * more cleanup * fix comment * remove comments
1 parent ee173b0 commit 4bbebd8

17 files changed

+629
-391
lines changed

src/vs/code/electron-main/app.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro
5252
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
5353
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
5454
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
55-
import { IIssueMainService } from 'vs/platform/issue/common/issue';
55+
import { IIssueMainService, IProcessMainService } from 'vs/platform/issue/common/issue';
5656
import { IssueMainService } from 'vs/platform/issue/electron-main/issueMainService';
57+
import { ProcessMainService } from 'vs/platform/issue/electron-main/processMainService';
5758
import { IKeyboardLayoutMainService, KeyboardLayoutMainService } from 'vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService';
5859
import { ILaunchMainService, LaunchMainService } from 'vs/platform/launch/electron-main/launchMainService';
5960
import { ILifecycleMainService, LifecycleMainPhase, ShutdownReason } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
@@ -121,7 +122,6 @@ import { Lazy } from 'vs/base/common/lazy';
121122
import { IAuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows';
122123
import { AuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService';
123124
import { normalizeNFC } from 'vs/base/common/normalization';
124-
125125
/**
126126
* The main VS Code application. There will only ever be one instance,
127127
* even if the user starts many instances (e.g. from the command line).
@@ -1051,6 +1051,9 @@ export class CodeApplication extends Disposable {
10511051
// Issues
10521052
services.set(IIssueMainService, new SyncDescriptor(IssueMainService, [this.userEnv]));
10531053

1054+
// Process
1055+
services.set(IProcessMainService, new SyncDescriptor(ProcessMainService, [this.userEnv]));
1056+
10541057
// Encryption
10551058
services.set(IEncryptionMainService, new SyncDescriptor(EncryptionMainService));
10561059

@@ -1183,6 +1186,10 @@ export class CodeApplication extends Disposable {
11831186
const issueChannel = ProxyChannel.fromService(accessor.get(IIssueMainService), disposables);
11841187
mainProcessElectronServer.registerChannel('issue', issueChannel);
11851188

1189+
// Process
1190+
const processChannel = ProxyChannel.fromService(accessor.get(IProcessMainService), disposables);
1191+
mainProcessElectronServer.registerChannel('process', processChannel);
1192+
11861193
// Encryption
11871194
const encryptionChannel = ProxyChannel.fromService(accessor.get(IEncryptionMainService), disposables);
11881195
mainProcessElectronServer.registerChannel('encryption', encryptionChannel);

src/vs/platform/issue/common/issue.ts

+14-7
Original file line numberDiff line numberDiff line change
@@ -127,18 +127,25 @@ export const IIssueMainService = createDecorator<IIssueMainService>('issueServic
127127

128128
export interface IIssueMainService {
129129
readonly _serviceBrand: undefined;
130-
stopTracing(): Promise<void>;
131-
openReporter(data: IssueReporterData): Promise<void>;
132-
openProcessExplorer(data: ProcessExplorerData): Promise<void>;
133-
getSystemStatus(): Promise<string>;
134130

135131
// Used by the issue reporter
136-
137-
$getSystemInfo(): Promise<SystemInfo>;
138-
$getPerformanceInfo(): Promise<PerformanceInfo>;
132+
openReporter(data: IssueReporterData): Promise<void>;
139133
$reloadWithExtensionsDisabled(): Promise<void>;
140134
$showConfirmCloseDialog(): Promise<void>;
141135
$showClipboardDialog(): Promise<boolean>;
142136
$sendReporterMenu(extensionId: string, extensionName: string): Promise<IssueReporterData | undefined>;
143137
$closeReporter(): Promise<void>;
144138
}
139+
140+
export const IProcessMainService = createDecorator<IProcessMainService>('processService');
141+
142+
export interface IProcessMainService {
143+
readonly _serviceBrand: undefined;
144+
getSystemStatus(): Promise<string>;
145+
stopTracing(): Promise<void>;
146+
openProcessExplorer(data: ProcessExplorerData): Promise<void>;
147+
148+
// Used by the process explorer
149+
$getSystemInfo(): Promise<SystemInfo>;
150+
$getPerformanceInfo(): Promise<PerformanceInfo>;
151+
}

src/vs/platform/issue/electron-main/issueMainService.ts

+3-229
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,26 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { BrowserWindow, BrowserWindowConstructorOptions, contentTracing, Display, IpcMainEvent, screen } from 'electron';
6+
import { BrowserWindow, BrowserWindowConstructorOptions, Display, screen } from 'electron';
77
import { arch, release, type } from 'os';
88
import { raceTimeout } from 'vs/base/common/async';
99
import { CancellationTokenSource } from 'vs/base/common/cancellation';
10-
import { randomPath } from 'vs/base/common/extpath';
1110
import { DisposableStore } from 'vs/base/common/lifecycle';
1211
import { FileAccess } from 'vs/base/common/network';
1312
import { IProcessEnvironment, isMacintosh } from 'vs/base/common/platform';
14-
import { listProcesses } from 'vs/base/node/ps';
1513
import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain';
1614
import { localize } from 'vs/nls';
17-
import { IDiagnosticsService, isRemoteDiagnosticError, PerformanceInfo, SystemInfo } from 'vs/platform/diagnostics/common/diagnostics';
18-
import { IDiagnosticsMainService } from 'vs/platform/diagnostics/electron-main/diagnosticsMainService';
1915
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
2016
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
21-
import { IIssueMainService, IssueReporterData, IssueReporterWindowConfiguration, ProcessExplorerData, ProcessExplorerWindowConfiguration } from 'vs/platform/issue/common/issue';
17+
import { IIssueMainService, IssueReporterData, IssueReporterWindowConfiguration } from 'vs/platform/issue/common/issue';
2218
import { ILogService } from 'vs/platform/log/common/log';
2319
import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService';
2420
import product from 'vs/platform/product/common/product';
25-
import { IProductService } from 'vs/platform/product/common/productService';
2621
import { IIPCObjectUrl, IProtocolMainService } from 'vs/platform/protocol/electron-main/protocol';
27-
import { IStateService } from 'vs/platform/state/node/state';
28-
import { UtilityProcess } from 'vs/platform/utilityProcess/electron-main/utilityProcess';
2922
import { zoomLevelToZoomFactor } from 'vs/platform/window/common/window';
3023
import { ICodeWindow, IWindowState } from 'vs/platform/window/electron-main/window';
3124
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
3225

33-
const processExplorerWindowState = 'issue.processExplorerWindowState';
34-
3526
interface IBrowserWindowOptions {
3627
backgroundColor: string | undefined;
3728
title: string;
@@ -50,94 +41,15 @@ export class IssueMainService implements IIssueMainService {
5041
private issueReporterWindow: BrowserWindow | null = null;
5142
private issueReporterParentWindow: BrowserWindow | null = null;
5243

53-
private processExplorerWindow: BrowserWindow | null = null;
54-
private processExplorerParentWindow: BrowserWindow | null = null;
55-
5644
constructor(
5745
private userEnv: IProcessEnvironment,
5846
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService,
5947
@ILogService private readonly logService: ILogService,
60-
@IDiagnosticsService private readonly diagnosticsService: IDiagnosticsService,
61-
@IDiagnosticsMainService private readonly diagnosticsMainService: IDiagnosticsMainService,
6248
@IDialogMainService private readonly dialogMainService: IDialogMainService,
6349
@INativeHostMainService private readonly nativeHostMainService: INativeHostMainService,
6450
@IProtocolMainService private readonly protocolMainService: IProtocolMainService,
65-
@IProductService private readonly productService: IProductService,
66-
@IStateService private readonly stateService: IStateService,
6751
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
68-
) {
69-
this.registerListeners();
70-
}
71-
72-
//#region Register Listeners
73-
74-
private registerListeners(): void {
75-
validatedIpcMain.on('vscode:listProcesses', async event => {
76-
const processes = [];
77-
78-
try {
79-
processes.push({ name: localize('local', "Local"), rootProcess: await listProcesses(process.pid) });
80-
81-
const remoteDiagnostics = await this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: true });
82-
remoteDiagnostics.forEach(data => {
83-
if (isRemoteDiagnosticError(data)) {
84-
processes.push({
85-
name: data.hostName,
86-
rootProcess: data
87-
});
88-
} else {
89-
if (data.processes) {
90-
processes.push({
91-
name: data.hostName,
92-
rootProcess: data.processes
93-
});
94-
}
95-
}
96-
});
97-
} catch (e) {
98-
this.logService.error(`Listing processes failed: ${e}`);
99-
}
100-
101-
this.safeSend(event, 'vscode:listProcessesResponse', processes);
102-
});
103-
104-
validatedIpcMain.on('vscode:workbenchCommand', (_: unknown, commandInfo: { id: any; from: any; args: any }) => {
105-
const { id, from, args } = commandInfo;
106-
107-
let parentWindow: BrowserWindow | null;
108-
switch (from) {
109-
case 'processExplorer':
110-
parentWindow = this.processExplorerParentWindow;
111-
break;
112-
default:
113-
// The issue reporter does not use this anymore.
114-
throw new Error(`Unexpected command source: ${from}`);
115-
}
116-
117-
parentWindow?.webContents.send('vscode:runAction', { id, from, args });
118-
});
119-
120-
validatedIpcMain.on('vscode:closeProcessExplorer', event => {
121-
this.processExplorerWindow?.close();
122-
});
123-
124-
validatedIpcMain.on('vscode:pidToNameRequest', async event => {
125-
const mainProcessInfo = await this.diagnosticsMainService.getMainDiagnostics();
126-
127-
const pidToNames: [number, string][] = [];
128-
for (const window of mainProcessInfo.windows) {
129-
pidToNames.push([window.pid, `window [${window.id}] (${window.title})`]);
130-
}
131-
132-
for (const { pid, name } of UtilityProcess.getAll()) {
133-
pidToNames.push([pid, name]);
134-
}
135-
136-
this.safeSend(event, 'vscode:pidToNameResponse', pidToNames);
137-
});
138-
}
139-
140-
//#endregion
52+
) { }
14153

14254
//#region Used by renderer
14355

@@ -196,125 +108,9 @@ export class IssueMainService implements IIssueMainService {
196108
}
197109
}
198110

199-
async openProcessExplorer(data: ProcessExplorerData): Promise<void> {
200-
if (!this.processExplorerWindow) {
201-
this.processExplorerParentWindow = BrowserWindow.getFocusedWindow();
202-
if (this.processExplorerParentWindow) {
203-
const processExplorerDisposables = new DisposableStore();
204-
205-
const processExplorerWindowConfigUrl = processExplorerDisposables.add(this.protocolMainService.createIPCObjectUrl<ProcessExplorerWindowConfiguration>());
206-
207-
const savedPosition = this.stateService.getItem<IWindowState>(processExplorerWindowState, undefined);
208-
const position = isStrictWindowState(savedPosition) ? savedPosition : this.getWindowPosition(this.processExplorerParentWindow, 800, 500);
209-
210-
this.processExplorerWindow = this.createBrowserWindow(position, processExplorerWindowConfigUrl, {
211-
backgroundColor: data.styles.backgroundColor,
212-
title: localize('processExplorer', "Process Explorer"),
213-
zoomLevel: data.zoomLevel,
214-
alwaysOnTop: true
215-
}, 'process-explorer');
216-
217-
// Store into config object URL
218-
processExplorerWindowConfigUrl.update({
219-
appRoot: this.environmentMainService.appRoot,
220-
windowId: this.processExplorerWindow.id,
221-
userEnv: this.userEnv,
222-
data,
223-
product
224-
});
225-
226-
this.processExplorerWindow.loadURL(
227-
FileAccess.asBrowserUri(`vs/code/electron-sandbox/processExplorer/processExplorer${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true)
228-
);
229-
230-
this.processExplorerWindow.on('close', () => {
231-
this.processExplorerWindow = null;
232-
processExplorerDisposables.dispose();
233-
});
234-
235-
this.processExplorerParentWindow.on('close', () => {
236-
if (this.processExplorerWindow) {
237-
this.processExplorerWindow.close();
238-
this.processExplorerWindow = null;
239-
240-
processExplorerDisposables.dispose();
241-
}
242-
});
243-
244-
const storeState = () => {
245-
if (!this.processExplorerWindow) {
246-
return;
247-
}
248-
const size = this.processExplorerWindow.getSize();
249-
const position = this.processExplorerWindow.getPosition();
250-
if (!size || !position) {
251-
return;
252-
}
253-
const state: IWindowState = {
254-
width: size[0],
255-
height: size[1],
256-
x: position[0],
257-
y: position[1]
258-
};
259-
this.stateService.setItem(processExplorerWindowState, state);
260-
};
261-
262-
this.processExplorerWindow.on('moved', storeState);
263-
this.processExplorerWindow.on('resized', storeState);
264-
}
265-
}
266-
267-
if (this.processExplorerWindow) {
268-
this.focusWindow(this.processExplorerWindow);
269-
}
270-
}
271-
272-
async stopTracing(): Promise<void> {
273-
if (!this.environmentMainService.args.trace) {
274-
return; // requires tracing to be on
275-
}
276-
277-
const path = await contentTracing.stopRecording(`${randomPath(this.environmentMainService.userHome.fsPath, this.productService.applicationName)}.trace.txt`);
278-
279-
// Inform user to report an issue
280-
await this.dialogMainService.showMessageBox({
281-
type: 'info',
282-
message: localize('trace.message', "Successfully created the trace file"),
283-
detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path),
284-
buttons: [localize({ key: 'trace.ok', comment: ['&& denotes a mnemonic'] }, "&&OK")],
285-
}, BrowserWindow.getFocusedWindow() ?? undefined);
286-
287-
// Show item in explorer
288-
this.nativeHostMainService.showItemInFolder(undefined, path);
289-
}
290-
291-
async getSystemStatus(): Promise<string> {
292-
const [info, remoteData] = await Promise.all([this.diagnosticsMainService.getMainDiagnostics(), this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })]);
293-
294-
return this.diagnosticsService.getDiagnostics(info, remoteData);
295-
}
296-
297111
//#endregion
298112

299113
//#region used by issue reporter window
300-
301-
async $getSystemInfo(): Promise<SystemInfo> {
302-
const [info, remoteData] = await Promise.all([this.diagnosticsMainService.getMainDiagnostics(), this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })]);
303-
const msg = await this.diagnosticsService.getSystemInfo(info, remoteData);
304-
return msg;
305-
}
306-
307-
async $getPerformanceInfo(): Promise<PerformanceInfo> {
308-
try {
309-
const [info, remoteData] = await Promise.all([this.diagnosticsMainService.getMainDiagnostics(), this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true })]);
310-
return await this.diagnosticsService.getPerformanceInfo(info, remoteData);
311-
} catch (error) {
312-
this.logService.warn('issueService#getPerformanceInfo ', error.message);
313-
314-
throw error;
315-
}
316-
}
317-
318114
async $reloadWithExtensionsDisabled(): Promise<void> {
319115
if (this.issueReporterParentWindow) {
320116
try {
@@ -389,10 +185,6 @@ export class IssueMainService implements IIssueMainService {
389185
this.issueReporterWindow?.close();
390186
}
391187

392-
async closeProcessExplorer(): Promise<void> {
393-
this.processExplorerWindow?.close();
394-
}
395-
396188
//#endregion
397189

398190
private focusWindow(window: BrowserWindow): void {
@@ -403,12 +195,6 @@ export class IssueMainService implements IIssueMainService {
403195
window.focus();
404196
}
405197

406-
private safeSend(event: IpcMainEvent, channel: string, ...args: unknown[]): void {
407-
if (!event.sender.isDestroyed()) {
408-
event.sender.send(channel, ...args);
409-
}
410-
}
411-
412198
private createBrowserWindow<T>(position: IWindowState, ipcObjectUrl: IIPCObjectUrl<T>, options: IBrowserWindowOptions, windowKind: string): BrowserWindow {
413199
const window = new BrowserWindow({
414200
fullscreen: false,
@@ -509,15 +295,3 @@ export class IssueMainService implements IIssueMainService {
509295
return state;
510296
}
511297
}
512-
513-
function isStrictWindowState(obj: unknown): obj is IStrictWindowState {
514-
if (typeof obj !== 'object' || obj === null) {
515-
return false;
516-
}
517-
return (
518-
'x' in obj &&
519-
'y' in obj &&
520-
'width' in obj &&
521-
'height' in obj
522-
);
523-
}

0 commit comments

Comments
 (0)