src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts/LocalProcessExtensionHost/start
class LocalProcessExtensionHost:	public start(): Promise<IMessagePassingProtocol> | null {
		if (this._terminating) {
			// .terminate() was called
			return null;
		}

		if (!this._messageProtocol) {
			this._messageProtocol = Promise.all([
				this._tryListenOnPipe(),
				this._tryFindDebugPort(),
				this._shellEnvironmentService.getShellEnv()
			]).then(([pipeName, portNumber, processEnv]) => {
				const env = objects.mixin(processEnv, {
					VSCODE_AMD_ENTRYPOINT: 'vs/workbench/services/extensions/node/extensionHostProcess',
					VSCODE_PIPE_LOGGING: 'true',
					VSCODE_VERBOSE_LOGGING: true,
					VSCODE_LOG_NATIVE: this._isExtensionDevHost,
					VSCODE_IPC_HOOK_EXTHOST: pipeName,
					VSCODE_HANDLES_UNCAUGHT_ERRORS: true,
					VSCODE_LOG_STACK: !this._isExtensionDevTestFromCli && (this._isExtensionDevHost || !this._environmentService.isBuilt || this._productService.quality !== 'stable' || this._environmentService.verbose),
					VSCODE_LOG_LEVEL: this._environmentService.verbose ? 'trace' : this._environmentService.log
				});

				if (platform.isMacintosh) {
					// Unset `DYLD_LIBRARY_PATH`, as it leads to extension host crashes
					// See https://github.com/microsoft/vscode/issues/104525
					delete env['DYLD_LIBRARY_PATH'];
				}

				if (this._isExtensionDevHost) {
					// Unset `VSCODE_CODE_CACHE_PATH` when developing extensions because it might
					// be that dependencies, that otherwise would be cached, get modified.
					delete env['VSCODE_CODE_CACHE_PATH'];
				}

				const opts = {
					env,
					// We only detach the extension host on windows. Linux and Mac orphan by default
					// and detach under Linux and Mac create another process group.
					// We detach because we have noticed that when the renderer exits, its child processes
					// (i.e. extension host) are taken down in a brutal fashion by the OS
					detached: !!platform.isWindows,
					execArgv: undefined as string[] | undefined,
					silent: true
				};

				if (portNumber !== 0) {
					opts.execArgv = [
						'--nolazy',
						(this._isExtensionDevDebugBrk ? '--inspect-brk=' : '--inspect=') + portNumber
					];
				} else {
					opts.execArgv = ['--inspect-port=0'];
				}

				if (this._environmentService.args['prof-v8-extensions']) {
					opts.execArgv.unshift('--prof');
				}

				if (this._environmentService.args['max-memory']) {
					opts.execArgv.unshift(`--max-old-space-size=${this._environmentService.args['max-memory']}`);
				}

				// On linux crash reporter needs to be started on child node processes explicitly
				if (platform.isLinux) {
					const crashReporterStartOptions: CrashReporterStartOptions = {
						companyName: this._productService.crashReporter?.companyName || 'Microsoft',
						productName: this._productService.crashReporter?.productName || this._productService.nameShort,
						submitURL: '',
						uploadToServer: false
					};
					const crashReporterId = this._environmentService.crashReporterId; // crashReporterId is set by the main process only when crash reporting is enabled by the user.
					const appcenter = this._productService.appCenter;
					const uploadCrashesToServer = !this._environmentService.crashReporterDirectory; // only upload unless --crash-reporter-directory is provided
					if (uploadCrashesToServer && appcenter && crashReporterId && isUUID(crashReporterId)) {
						const submitURL = appcenter[`linux-x64`];
						crashReporterStartOptions.submitURL = submitURL.concat('&uid=', crashReporterId, '&iid=', crashReporterId, '&sid=', crashReporterId);
						crashReporterStartOptions.uploadToServer = true;
					}
					// In the upload to server case, there is a bug in electron that creates client_id file in the current
					// working directory. Setting the env BREAKPAD_DUMP_LOCATION will force electron to create the file in that location,
					// For https://github.com/microsoft/vscode/issues/105743
					const extHostCrashDirectory = this._environmentService.crashReporterDirectory || this._environmentService.userDataPath;
					opts.env.BREAKPAD_DUMP_LOCATION = join(extHostCrashDirectory, `${ExtensionHostLogFileName} Crash Reports`);
					opts.env.VSCODE_CRASH_REPORTER_START_OPTIONS = JSON.stringify(crashReporterStartOptions);
				}

				// Run Extension Host as fork of current process
				this._extensionHostProcess = fork(FileAccess.asFileUri('bootstrap-fork', require).fsPath, ['--type=extensionHost'], opts);

				// Catch all output coming from the extension host process
				type Output = { data: string, format: string[] };
				const onStdout = this._handleProcessOutputStream(this._extensionHostProcess.stdout!);
				const onStderr = this._handleProcessOutputStream(this._extensionHostProcess.stderr!);
				const onOutput = Event.any(
					Event.map(onStdout.event, o => ({ data: `%c${o}`, format: [''] })),
					Event.map(onStderr.event, o => ({ data: `%c${o}`, format: ['color: red'] }))
				);

				// Debounce all output, so we can render it in the Chrome console as a group
				const onDebouncedOutput = Event.debounce<Output>(onOutput, (r, o) => {
					return r
						? { data: r.data + o.data, format: [...r.format, ...o.format] }
						: { data: o.data, format: o.format };
				}, 100);

				// Print out extension host output
				onDebouncedOutput(output => {
					const inspectorUrlMatch = output.data && output.data.match(/ws:\/\/([^\s]+:(\d+)\/[^\s]+)/);
					if (inspectorUrlMatch) {
						if (!this._environmentService.isBuilt && !this._isExtensionDevTestFromCli) {
							console.log(`%c[Extension Host] %cdebugger inspector at chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${inspectorUrlMatch[1]}`, 'color: blue', 'color:');
						}
						if (!this._inspectPort) {
							this._inspectPort = Number(inspectorUrlMatch[2]);
							this._onDidSetInspectPort.fire();
						}
					} else {
						if (!this._isExtensionDevTestFromCli) {
							console.group('Extension Host');
							console.log(output.data, ...output.format);
							console.groupEnd();
						}
					}
				});

				// Support logging from extension host
				this._extensionHostProcess.on('message', msg => {
					if (msg && (<IRemoteConsoleLog>msg).type === '__$console') {
						this._logExtensionHostMessage(<IRemoteConsoleLog>msg);
					}
				});

				// Lifecycle
				this._extensionHostProcess.on('error', (err) => this._onExtHostProcessError(err));
				this._extensionHostProcess.on('exit', (code: number, signal: string) => this._onExtHostProcessExit(code, signal));

				// Notify debugger that we are ready to attach to the process if we run a development extension
				if (portNumber) {
					if (this._isExtensionDevHost && portNumber && this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) {
						this._extensionHostDebugService.attachSession(this._environmentService.debugExtensionHost.debugId, portNumber);
					}
					this._inspectPort = portNumber;
					this._onDidSetInspectPort.fire();
				}

				// Help in case we fail to start it
				let startupTimeoutHandle: any;
				if (!this._environmentService.isBuilt && !this._environmentService.remoteAuthority || this._isExtensionDevHost) {
					startupTimeoutHandle = setTimeout(() => {
						const msg = this._isExtensionDevDebugBrk
							? nls.localize('extensionHost.startupFailDebug', "Extension host did not start in 10 seconds, it might be stopped on the first line and needs a debugger to continue.")
							: nls.localize('extensionHost.startupFail', "Extension host did not start in 10 seconds, that might be a problem.");

						this._notificationService.prompt(Severity.Warning, msg,
							[{
								label: nls.localize('reloadWindow', "Reload Window"),
								run: () => this._hostService.reload()
							}],
							{ sticky: true }
						);
					}, 10000);
				}

				// Initialize extension host process with hand shakes
				return this._tryExtHostHandshake().then((protocol) => {
					clearTimeout(startupTimeoutHandle);
					return protocol;
				});
			});
		}

		return this._messageProtocol;
	}