src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts/CachedExtensionScanner/_scanInstalledExtensions
class CachedExtensionScanner:	private static _scanInstalledExtensions(
		hostService: IHostService,
		notificationService: INotificationService,
		environmentService: INativeWorkbenchEnvironmentService,
		extensionEnablementService: IWorkbenchExtensionEnablementService,
		productService: IProductService,
		log: ILog,
		translations: Translations
	): Promise<{ system: IExtensionDescription[], user: IExtensionDescription[], development: IExtensionDescription[] }> {

		const version = productService.version;
		const commit = productService.commit;
		const date = productService.date;
		const devMode = !!process.env['VSCODE_DEV'];
		const locale = platform.language;

		const builtinExtensions = this._scanExtensionsWithCache(
			hostService,
			notificationService,
			environmentService,
			BUILTIN_MANIFEST_CACHE_FILE,
			new ExtensionScannerInput(version, date, commit, locale, devMode, getSystemExtensionsRoot(), true, false, translations),
			log
		);

		let finalBuiltinExtensions: Promise<IExtensionDescription[]> = builtinExtensions;

		if (devMode) {
			const builtInExtensions = Promise.resolve<IBuiltInExtension[]>(productService.builtInExtensions || []);

			const controlFilePath = joinPath(environmentService.userHome, '.vscode-oss-dev', 'extensions', 'control.json').fsPath;
			const controlFile = pfs.Promises.readFile(controlFilePath, 'utf8')
				.then<IBuiltInExtensionControl>(raw => JSON.parse(raw), () => ({} as any));

			const input = new ExtensionScannerInput(version, date, commit, locale, devMode, getExtraDevSystemExtensionsRoot(), true, false, translations);
			const extraBuiltinExtensions = Promise.all([builtInExtensions, controlFile])
				.then(([builtInExtensions, control]) => new ExtraBuiltInExtensionResolver(builtInExtensions, control))
				.then(resolver => ExtensionScanner.scanExtensions(input, log, resolver));

			finalBuiltinExtensions = ExtensionScanner.mergeBuiltinExtensions(builtinExtensions, extraBuiltinExtensions);
		}

		const userExtensions = (this._scanExtensionsWithCache(
			hostService,
			notificationService,
			environmentService,
			USER_MANIFEST_CACHE_FILE,
			new ExtensionScannerInput(version, date, commit, locale, devMode, environmentService.extensionsPath, false, false, translations),
			log
		));

		// Always load developed extensions while extensions development
		let developedExtensions: Promise<IExtensionDescription[]> = Promise.resolve([]);
		if (environmentService.isExtensionDevelopment && environmentService.extensionDevelopmentLocationURI) {
			const extDescsP = environmentService.extensionDevelopmentLocationURI.filter(extLoc => extLoc.scheme === Schemas.file).map(extLoc => {
				return ExtensionScanner.scanOneOrMultipleExtensions(
					new ExtensionScannerInput(version, date, commit, locale, devMode, originalFSPath(extLoc), false, true, translations), log
				);
			});
			developedExtensions = Promise.all(extDescsP).then((extDescArrays: IExtensionDescription[][]) => {
				let extDesc: IExtensionDescription[] = [];
				for (let eds of extDescArrays) {
					extDesc = extDesc.concat(eds);
				}
				return extDesc;
			});
		}

		return Promise.all([finalBuiltinExtensions, userExtensions, developedExtensions]).then((extensionDescriptions: IExtensionDescription[][]) => {
			const system = extensionDescriptions[0];
			const user = extensionDescriptions[1];
			const development = extensionDescriptions[2];
			return { system, user, development };
		}).then(undefined, err => {
			log.error('', err);
			return { system: [], user: [], development: [] };
		});
	}