microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
8df5011e47ada44be3951868ba32e5fae98f48bb

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/extension/android/androidEmulatorManager.ts

122lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import { AdbHelper } from "./adb";
5import { ChildProcess } from "../../common/node/childProcess";
6import { IVirtualDevice, VirtualDeviceManager } from "../VirtualDeviceManager";
7import { OutputChannelLogger } from "../log/OutputChannelLogger";
8import * as nls from "vscode-nls";
9import { ErrorHelper } from "../../common/error/errorHelper";
10import { InternalErrorCode } from "../../common/error/internalErrorCode";
11import { QuickPickOptions, window } from "vscode";
12nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
13const localize = nls.loadMessageBundle();
14export interface IAndroidEmulator extends IVirtualDevice {
15}
16
17export class AndroidEmulatorManager extends VirtualDeviceManager {
18 private static readonly EMULATOR_COMMAND = "emulator";
19 private static readonly EMULATOR_LIST_AVDS_COMMAND = `-list-avds`;
20 private static readonly EMULATOR_AVD_START_COMMAND = `-avd`;
21
22 private static readonly EMULATOR_START_TIMEOUT = 120;
23
24 private logger: OutputChannelLogger = OutputChannelLogger.getChannel(OutputChannelLogger.MAIN_CHANNEL_NAME, true);
25
26 private adbHelper: AdbHelper;
27 private childProcess: ChildProcess;
28
29 constructor(adbHelper: AdbHelper) {
30 super();
31 this.adbHelper = adbHelper;
32 this.childProcess = new ChildProcess();
33 }
34
35 public async startEmulator(target: string): Promise<IAndroidEmulator | null> {
36 const onlineDevices = await this.adbHelper.getOnlineDevices();
37 for (let i = 0; i < onlineDevices.length; i++){
38 if (onlineDevices[i].id === target) {
39 return {id: onlineDevices[i].id};
40 }
41 }
42 if (target && (await this.adbHelper.getOnlineDevices()).length === 0) {
43 if (target === "simulator") {
44 const newEmulator = await this.startSelection();
45 if (newEmulator) {
46 const emulatorId = await this.tryLaunchEmulatorByName(newEmulator);
47 return {name: newEmulator, id: emulatorId};
48 }
49 }
50 else if (!target.includes("device")) {
51 const emulatorId = await this.tryLaunchEmulatorByName(target);
52 return {name: target, id: emulatorId};
53 }
54 }
55 return null;
56 }
57
58 public async tryLaunchEmulatorByName(emulatorName: string): Promise<string> {
59 return new Promise((resolve, reject) => {
60 const emulatorProcess = this.childProcess.spawn(AndroidEmulatorManager.EMULATOR_COMMAND, [AndroidEmulatorManager.EMULATOR_AVD_START_COMMAND, emulatorName], {
61 detached: true,
62 }, true);
63 emulatorProcess.outcome.catch((error) => {
64 if (process.platform == "win32" && process.env.SESSIONNAME && process.env.SESSIONNAME.toLowerCase().includes("rdp-tcp")) {
65 this.logger.warning(localize("RDPEmulatorWarning", "Android emulator was launched from the Windows RDP session, this might lead to failures."));
66 }
67 reject(ErrorHelper.getInternalError(InternalErrorCode.VirtualDeviceSelectionError, error));
68 });
69 emulatorProcess.spawnedProcess.unref();
70
71 const rejectTimeout = setTimeout(() => {
72 cleanup();
73 reject(ErrorHelper.getInternalError(InternalErrorCode.VirtualDeviceSelectionError, localize("EmulatorStartWarning", "Could not start the emulator {0} within {1} seconds.", emulatorName, AndroidEmulatorManager.EMULATOR_START_TIMEOUT)));
74 }, AndroidEmulatorManager.EMULATOR_START_TIMEOUT * 1000);
75
76 const bootCheckInterval = setInterval(async () => {
77 const connectedDevices = await this.adbHelper.getOnlineDevices();
78 if (connectedDevices.length > 0) {
79 this.logger.info(localize("EmulatorLaunched", "Launched emulator {0}", emulatorName));
80 cleanup();
81 resolve(connectedDevices[0].id);
82 }
83 }, 1000);
84
85 const cleanup = () => {
86 clearTimeout(rejectTimeout);
87 clearInterval(bootCheckInterval);
88 };
89 });
90 }
91
92 public startSelection(): Promise<string | undefined> {
93 return this.selectVirtualDevice();
94 }
95
96 public async selectOnlineDevice(): Promise<string | undefined> {
97 const emulatorsList = (await this.adbHelper.getOnlineDevices()).map(device => device.id);
98 const quickPickOptions: QuickPickOptions = {
99 ignoreFocusOut: true,
100 canPickMany: false,
101 placeHolder: localize("SelectOnlineDevice", "Select online Android device"),
102 };
103 let result: string | undefined = emulatorsList[0];
104 if (emulatorsList.length > 1) {
105 result = await window.showQuickPick(emulatorsList, quickPickOptions);
106 }
107 return result?.toString();
108 }
109
110 protected async getVirtualDevicesNamesList(): Promise<string[]> {
111 const res = await this.childProcess.execToString(`${AndroidEmulatorManager.EMULATOR_COMMAND} ${AndroidEmulatorManager.EMULATOR_LIST_AVDS_COMMAND}`);
112 let emulatorsList: string[] = [];
113 if (res) {
114 emulatorsList = res.split(/\r?\n|\r/g);
115 const indexOfBlank = emulatorsList.indexOf("");
116 if (emulatorsList.indexOf("") >= 0) {
117 emulatorsList.splice(indexOfBlank, 1);
118 }
119 }
120 return emulatorsList;
121 }
122}
123