提交 29a7a86c 编写于 作者: R Ramya Rao 提交者: Dirk Baeumer

Start crash reporter inside child processes (#27180)

* Use service to get crash reporter start options

* some refactorings and fixes

* Move crashesDirectory to the main payload from extra bag
上级 f962f52c
......@@ -126,4 +126,16 @@ if (process.env['VSCODE_PARENT_PID']) {
}
}
const crashReporterOptionsRaw = process.env['CRASH_REPORTER_START_OPTIONS'];
if (typeof crashReporterOptionsRaw === 'string') {
try {
const crashReporterOptions = JSON.parse(crashReporterOptionsRaw);
if (crashReporterOptions) {
process.crashReporter.start(crashReporterOptions);
}
} catch (error) {
console.error(error);
}
}
require('./bootstrap-amd').bootstrap(process.env['AMD_ENTRYPOINT']);
\ No newline at end of file
......@@ -2066,6 +2066,13 @@ declare namespace Electron {
* Only string properties are sent correctly, nested objects are not supported.
*/
extra?: { [prop: string]: string };
/**
* Path to a folder where the crashes will be temporarily stored by the electron crash reporter
* Applies only to child processes that need crash reporting.
* Electron figures out the crashesDirectory on its own for Main and Renderer process
*/
crashesDirectory?: string;
}
interface CrashReport {
......
......@@ -32,6 +32,7 @@ import Event, { Emitter } from 'vs/base/common/event';
import { IInitData } from 'vs/workbench/api/node/extHost.protocol';
import { MainProcessExtensionService } from 'vs/workbench/api/electron-browser/mainThreadExtensionService';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { ICrashReporterService } from 'vs/workbench/services/crashReporter/common/crashReporterService';
export const EXTENSION_LOG_BROADCAST_CHANNEL = 'vscode:extensionLog';
export const EXTENSION_ATTACH_BROADCAST_CHANNEL = 'vscode:extensionAttach';
......@@ -92,7 +93,9 @@ export class ExtensionHostProcessWorker {
@IInstantiationService private instantiationService: IInstantiationService,
@IEnvironmentService private environmentService: IEnvironmentService,
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
@ITelemetryService private telemetryService: ITelemetryService
@ITelemetryService private telemetryService: ITelemetryService,
@ICrashReporterService private crashReporterService: ICrashReporterService
) {
// handle extension host lifecycle a bit special when we know we are developing an extension that runs inside
this.isExtensionDevelopmentHost = environmentService.isExtensionDevelopment;
......@@ -111,7 +114,7 @@ export class ExtensionHostProcessWorker {
const [server, hook] = <[Server, string]>data[0];
const port = <number>data[1];
let opts = {
const opts = {
env: objects.mixin(objects.clone(process.env), {
AMD_ENTRYPOINT: 'vs/workbench/node/extensionHostProcess',
PIPE_LOGGING: 'true',
......@@ -130,6 +133,11 @@ export class ExtensionHostProcessWorker {
: undefined
};
const crashReporterOptions = this.crashReporterService.getChildProcessStartOptions('extensionHost');
if (crashReporterOptions) {
opts.env.CRASH_REPORTER_START_OPTIONS = JSON.stringify(crashReporterOptions);
}
// Run Extension Host as fork of current process
this.extensionHostProcess = fork(URI.parse(require.toUrl('bootstrap')).fsPath, ['--type=extensionHost'], opts);
......
......@@ -73,7 +73,8 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { WorkbenchModeServiceImpl } from 'vs/workbench/services/mode/common/workbenchModeService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { CrashReporter } from 'vs/workbench/electron-browser/crashReporter';
import { ICrashReporterService, NullCrashReporterService } from 'vs/workbench/services/crashReporter/common/crashReporterService';
import { CrashReporterService } from 'vs/workbench/services/crashReporter/electron-browser/crashReporterService';
import { NodeCachedDataManager } from 'vs/workbench/electron-browser/nodeCachedDataManager';
import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net';
......@@ -168,29 +169,6 @@ export class WorkbenchShell {
// Instantiation service with services
const [instantiationService, serviceCollection] = this.initServiceCollection(parent.getHTMLElement());
//crash reporting
if (product.crashReporter && product.hockeyApp) {
let submitURL: string;
if (platform.isWindows) {
submitURL = product.hockeyApp[`win32-${process.arch}`];
} else if (platform.isMacintosh) {
submitURL = product.hockeyApp.darwin;
} else if (platform.isLinux) {
submitURL = product.hockeyApp[`linux-${process.arch}`];
}
if (submitURL) {
const opts: Electron.CrashReporterStartOptions = {
companyName: product.crashReporter.companyName,
productName: product.crashReporter.productName,
submitURL
};
instantiationService.createInstance(CrashReporter, opts);
}
}
// Workbench
this.workbench = instantiationService.createInstance(Workbench, parent.getHTMLElement(), workbenchContainer.getHTMLElement(), this.options, serviceCollection);
this.workbench.startup({
......@@ -333,6 +311,12 @@ export class WorkbenchShell {
serviceCollection.set(ITelemetryService, this.telemetryService);
disposables.add(configurationTelemetry(this.telemetryService, this.configurationService));
let crashReporterService = NullCrashReporterService;
if (product.crashReporter && product.hockeyApp) {
crashReporterService = instantiationService.createInstance(CrashReporterService);
}
serviceCollection.set(ICrashReporterService, crashReporterService);
this.messageService = instantiationService.createInstance(MessageService, container);
serviceCollection.set(IMessageService, this.messageService);
serviceCollection.set(IChoiceService, this.messageService);
......
......@@ -5,20 +5,15 @@
'use strict';
import nls = require('vs/nls');
import { onUnexpectedError } from 'vs/base/common/errors';
import { assign, clone } from 'vs/base/common/objects';
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { Registry } from 'vs/platform/platform';
import { crashReporter } from 'electron';
import product from 'vs/platform/node/product';
import pkg from 'vs/platform/node/package';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
const TELEMETRY_SECTION_ID = 'telemetry';
export const ICrashReporterService = createDecorator<ICrashReporterService>('crashReporterService');
interface ICrashReporterConfig {
export const TELEMETRY_SECTION_ID = 'telemetry';
export interface ICrashReporterConfig {
enableCrashReporter: boolean;
}
......@@ -37,35 +32,12 @@ configurationRegistry.registerConfiguration({
}
});
export class CrashReporter {
constructor(
configuration: Electron.CrashReporterStartOptions,
@ITelemetryService telemetryService: ITelemetryService,
@IWindowsService windowsService: IWindowsService,
@IConfigurationService configurationService: IConfigurationService
) {
const config = configurationService.getConfiguration<ICrashReporterConfig>(TELEMETRY_SECTION_ID);
if (!config.enableCrashReporter) {
return;
}
telemetryService.getTelemetryInfo()
.then(info => ({
vscode_sessionId: info.sessionId,
vscode_version: pkg.version,
vscode_commit: product.commit,
vscode_machineId: info.machineId
}))
.then(extra => assign(configuration, { extra }))
.then(configuration => {
// start crash reporter right here
crashReporter.start(clone(configuration));
export interface ICrashReporterService {
_serviceBrand: any;
getChildProcessStartOptions(processName: string): Electron.CrashReporterStartOptions;
}
// TODO: start crash reporter in the main process
return windowsService.startCrashReporter(configuration);
})
.done(null, onUnexpectedError);
}
}
\ No newline at end of file
export const NullCrashReporterService: ICrashReporterService = {
_serviceBrand: undefined,
getChildProcessStartOptions(processName: string) { return undefined; }
};
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { onUnexpectedError } from 'vs/base/common/errors';
import { assign, clone } from 'vs/base/common/objects';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { crashReporter } from 'electron';
import product from 'vs/platform/node/product';
import pkg from 'vs/platform/node/package';
import * as os from 'os';
import { ICrashReporterService, TELEMETRY_SECTION_ID, ICrashReporterConfig } from "vs/workbench/services/crashReporter/common/crashReporterService";
import { isWindows, isMacintosh, isLinux } from "vs/base/common/platform";
export class CrashReporterService implements ICrashReporterService {
public _serviceBrand: any;
private options: Electron.CrashReporterStartOptions;
constructor(
@ITelemetryService private telemetryService: ITelemetryService,
@IWindowsService private windowsService: IWindowsService,
@IConfigurationService configurationService: IConfigurationService
) {
const config = configurationService.getConfiguration<ICrashReporterConfig>(TELEMETRY_SECTION_ID);
if (config.enableCrashReporter) {
this.startCrashReporter();
}
}
private startCrashReporter(): void {
// base options
this.options = {
companyName: product.crashReporter.companyName,
productName: product.crashReporter.productName,
submitURL: this.getSubmitURL()
};
// mixin telemetry info and product info
this.telemetryService.getTelemetryInfo()
.then(info => {
assign(this.options, {
extra: {
vscode_sessionId: info.sessionId,
vscode_version: pkg.version,
vscode_commit: product.commit,
vscode_machineId: info.machineId
}
});
// start crash reporter right here
crashReporter.start(clone(this.options));
// start crash reporter in the main process
return this.windowsService.startCrashReporter(this.options);
})
.done(null, onUnexpectedError);
}
private getSubmitURL(): string {
let submitURL: string;
if (isWindows) {
submitURL = product.hockeyApp[`win32-${process.arch}`];
} else if (isMacintosh) {
submitURL = product.hockeyApp.darwin;
} else if (isLinux) {
submitURL = product.hockeyApp[`linux-${process.arch}`];
}
return submitURL;
}
public getChildProcessStartOptions(name: string): Electron.CrashReporterStartOptions {
// Experimental attempt on Mac only for now
if (isMacintosh) {
const childProcessOptions = clone(this.options);
childProcessOptions.extra.processName = name;
childProcessOptions.crashesDirectory = os.tmpdir();
return childProcessOptions;
}
return void 0;
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册