microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
improve-configuration

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/android/adb.ts

336lines · modeblame

52f3873ddigeff10 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
db6fd42aRuslan Bikkinin7 years ago4import * as path from "path";
5import * as fs from "fs";
8b383051Ruslan Bikkinin7 years ago6import * as os from "os";
d7d405aeYuri Skorokhodov7 years ago7import * as nls from "vscode-nls";
09f6024fHeniker4 years ago8import { ILogger } from "../log/LogHelper";
9import { CommandExecutor } from "../../common/commandExecutor";
10import { ChildProcess, ISpawnResult } from "../../common/node/childProcess";
0d77292aJiglioNero4 years ago11import { PromiseUtil } from "../../common/node/promise";
4cd25962JiglioNero4 years ago12import { IDebuggableMobileTarget } from "../mobileTarget";
09f6024fHeniker4 years ago13
34472878RedMickey5 years ago14nls.config({
15messageFormat: nls.MessageFormat.bundle,
16bundleFormat: nls.BundleFormat.standalone,
17})();
d7d405aeYuri Skorokhodov7 years ago18const localize = nls.loadMessageBundle();
52f3873ddigeff10 years ago19
ce7fd946digeff10 years ago20// See android versions usage at: http://developer.android.com/about/dashboards/index.html
52f3873ddigeff10 years ago21export enum AndroidAPILevel {
ce7fd946digeff10 years ago22Marshmallow = 23,
52f3873ddigeff10 years ago23LOLLIPOP_MR1 = 22,
34472878RedMickey5 years ago24LOLLIPOP = 21 /* Supports adb reverse */,
52f3873ddigeff10 years ago25KITKAT = 19,
26JELLY_BEAN_MR2 = 18,
27JELLY_BEAN_MR1 = 17,
28JELLY_BEAN = 16,
29ICE_CREAM_SANDWICH_MR1 = 15,
30GINGERBREAD_MR1 = 10,
31}
32
7daed3fcArtem Egorov8 years ago33enum KeyEvents {
34KEYCODE_BACK = 4,
35KEYCODE_DPAD_UP = 19,
36KEYCODE_DPAD_DOWN = 20,
37KEYCODE_DPAD_CENTER = 23,
38KEYCODE_MENU = 82,
39}
40
41export class AdbHelper {
4dfb1c4cetatanova5 years ago42private nodeModulesRoot: string;
43private launchActivity: string;
db6fd42aRuslan Bikkinin7 years ago44private childProcess: ChildProcess = new ChildProcess();
4dfb1c4cetatanova5 years ago45private commandExecutor: CommandExecutor;
db6fd42aRuslan Bikkinin7 years ago46private adbExecutable: string = "";
47
09f6024fHeniker4 years ago48private static readonly AndroidRemoteTargetPattern =
49/^((?:\d{1,3}\.){3}\d{1,3}:\d{1,5}|.*_adb-tls-con{2}ect\._tcp.*)$/gm;
4cd25962JiglioNero4 years ago50public static readonly AndroidSDKEmulatorPattern = /^emulator-\d{1,5}$/;
247f6e8cRedMickey5 years ago51
4dfb1c4cetatanova5 years ago52constructor(
53projectRoot: string,
54nodeModulesRoot: string,
55logger?: ILogger,
56launchActivity: string = "MainActivity",
57) {
58this.nodeModulesRoot = nodeModulesRoot;
8152571aYuri Skorokhodov5 years ago59this.adbExecutable = this.getAdbPath(projectRoot, logger);
4dfb1c4cetatanova5 years ago60this.commandExecutor = new CommandExecutor(this.nodeModulesRoot);
78c2b4deRedMickey6 years ago61this.launchActivity = launchActivity;
db6fd42aRuslan Bikkinin7 years ago62}
52f3873ddigeff10 years ago63
64/**
65* Gets the list of Android connected devices and emulators.
66*/
4cd25962JiglioNero4 years ago67public async getConnectedTargets(): Promise<IDebuggableMobileTarget[]> {
0d77292aJiglioNero4 years ago68const output = await this.childProcess.execToString(`${this.adbExecutable} devices`);
4cd25962JiglioNero4 years ago69return this.parseConnectedTargets(output);
70}
71
72public async findOnlineTargetById(
73targetId: string,
74): Promise<IDebuggableMobileTarget | undefined> {
75return (await this.getOnlineTargets()).find(target => target.id === targetId);
76}
77
78public async getAvdsNames(): Promise<string[]> {
79const res = await this.childProcess.execToString("emulator -list-avds");
80let emulatorsNames: string[] = [];
81if (res) {
82emulatorsNames = res.split(/\r?\n|\r/g);
83const indexOfBlank = emulatorsNames.indexOf("");
84if (indexOfBlank >= 0) {
85emulatorsNames.splice(indexOfBlank, 1);
86}
87}
88return emulatorsNames;
89}
90
91public isRemoteTarget(id: string): boolean {
92return !!id.match(AdbHelper.AndroidRemoteTargetPattern);
93}
94
95public async getAvdNameById(emulatorId: string): Promise<string | null> {
96try {
97const output = await this.childProcess.execToString(
98`${this.adbExecutable} -s ${emulatorId} emu avd name`,
99);
100// The command returns the name of avd by id of this running emulator.
101// Return value example:
102// "
103// emuName
104// OK
105// "
09f6024fHeniker4 years ago106return output ? output.split(/\r?\n|\r/g)[0] : null;
4cd25962JiglioNero4 years ago107} catch {
108// If the command returned an error, it means that we could not find the emulator with the passed id
109return null;
110}
52f3873ddigeff10 years ago111}
112
78c2b4deRedMickey6 years ago113public setLaunchActivity(launchActivity: string): void {
114this.launchActivity = launchActivity;
115}
116
52f3873ddigeff10 years ago117/**
118* Broadcasts an intent to reload the application in debug mode.
119*/
0d77292aJiglioNero4 years ago120public async switchDebugMode(
34472878RedMickey5 years ago121projectRoot: string,
122packageName: string,
123enable: boolean,
124debugTarget?: string,
69ad2ab3RedMickey5 years ago125appIdSuffix?: string,
34472878RedMickey5 years ago126): Promise<void> {
09f6024fHeniker4 years ago127const enableDebugCommand = `${this.adbExecutable} ${
128debugTarget ? `-s ${debugTarget}` : ""
129} shell am broadcast -a "${packageName}.RELOAD_APP_ACTION" --ez jsproxy ${String(enable)}`;
0d77292aJiglioNero4 years ago130await new CommandExecutor(this.nodeModulesRoot, projectRoot).execute(enableDebugCommand);
131// We should stop and start application again after RELOAD_APP_ACTION, otherwise app going to hangs up
132await PromiseUtil.delay(200); // We need a little delay after broadcast command
133await this.stopApp(projectRoot, packageName, debugTarget, appIdSuffix);
134return this.launchApp(projectRoot, packageName, debugTarget, appIdSuffix);
52f3873ddigeff10 years ago135}
136
137/**
138* Sends an intent which launches the main activity of the application.
139*/
34472878RedMickey5 years ago140public launchApp(
141projectRoot: string,
142packageName: string,
143debugTarget?: string,
69ad2ab3RedMickey5 years ago144appIdSuffix?: string,
34472878RedMickey5 years ago145): Promise<void> {
09f6024fHeniker4 years ago146const launchAppCommand = `${this.adbExecutable} ${
147debugTarget ? `-s ${debugTarget}` : ""
148} shell am start -n ${packageName}${appIdSuffix ? `.${appIdSuffix}` : ""}/${packageName}.${
69ad2ab3RedMickey5 years ago149this.launchActivity
150}`;
52f3873ddigeff10 years ago151return new CommandExecutor(projectRoot).execute(launchAppCommand);
152}
153
69ad2ab3RedMickey5 years ago154public stopApp(
155projectRoot: string,
156packageName: string,
157debugTarget?: string,
158appIdSuffix?: string,
159): Promise<void> {
09f6024fHeniker4 years ago160const stopAppCommand = `${this.adbExecutable} ${
161debugTarget ? `-s ${debugTarget}` : ""
162} shell am force-stop ${packageName}${appIdSuffix ? `.${appIdSuffix}` : ""}`;
b57ea017Artem Egorov8 years ago163return new CommandExecutor(projectRoot).execute(stopAppCommand);
164}
165
0d77292aJiglioNero4 years ago166public async apiVersion(deviceId: string): Promise<AndroidAPILevel> {
167const output = await this.executeQuery(deviceId, "shell getprop ro.build.version.sdk");
168return parseInt(output, 10);
52f3873ddigeff10 years ago169}
170
4bb0956eRedMickey5 years ago171public reverseAdb(deviceId: string, port: number): Promise<void> {
172return this.execute(deviceId, `reverse tcp:${port} tcp:${port}`);
52f3873ddigeff10 years ago173}
174
ce5e88eeYuri Skorokhodov5 years ago175public showDevMenu(deviceId?: string): Promise<void> {
09f6024fHeniker4 years ago176const command = `${this.adbExecutable} ${
177deviceId ? `-s ${deviceId}` : ""
34472878RedMickey5 years ago178} shell input keyevent ${KeyEvents.KEYCODE_MENU}`;
7daed3fcArtem Egorov8 years ago179return this.commandExecutor.execute(command);
180}
181
ce5e88eeYuri Skorokhodov5 years ago182public reloadApp(deviceId?: string): Promise<void> {
09f6024fHeniker4 years ago183const command = `${this.adbExecutable} ${
184deviceId ? `-s ${deviceId}` : ""
34472878RedMickey5 years ago185} shell input text "RR"`;
e23ea82cAlter Code7 years ago186return this.commandExecutor.execute(command);
7daed3fcArtem Egorov8 years ago187}
188
4cd25962JiglioNero4 years ago189public async getOnlineTargets(): Promise<IDebuggableMobileTarget[]> {
190const devices = await this.getConnectedTargets();
0d77292aJiglioNero4 years ago191return devices.filter(device => device.isOnline);
7daed3fcArtem Egorov8 years ago192}
193
db6fd42aRuslan Bikkinin7 years ago194public startLogCat(adbParameters: string[]): ISpawnResult {
09f6024fHeniker4 years ago195return this.childProcess.spawn(this.adbExecutable.replace(/"/g, ""), adbParameters);
db6fd42aRuslan Bikkinin7 years ago196}
197
8df5011eYuri Skorokhodov5 years ago198public parseSdkLocation(fileContent: string, logger?: ILogger): string | null {
1864d974RedMickey4 years ago199const matches = fileContent.match(/^sdk\.dir\s*=(.+)$/m);
8b383051Ruslan Bikkinin7 years ago200if (!matches || !matches[1]) {
201if (logger) {
34472878RedMickey5 years ago202logger.info(
203localize(
204"NoSdkDirFoundInLocalPropertiesFile",
205"No sdk.dir value found in local.properties file. Using Android SDK location from PATH.",
206),
207);
8b383051Ruslan Bikkinin7 years ago208}
209return null;
210}
211
212let sdkLocation = matches[1].trim();
213if (os.platform() === "win32") {
214// For Windows we need to unescape files separators and drive letter separators
215sdkLocation = sdkLocation.replace(/\\\\/g, "\\").replace("\\:", ":");
216}
217if (logger) {
34472878RedMickey5 years ago218logger.info(
219localize(
220"UsindAndroidSDKLocationDefinedInLocalPropertiesFile",
221"Using Android SDK location defined in android/local.properties file: {0}.",
222sdkLocation,
223),
224);
8b383051Ruslan Bikkinin7 years ago225}
226
227return sdkLocation;
228}
229
8152571aYuri Skorokhodov5 years ago230public getAdbPath(projectRoot: string, logger?: ILogger): string {
231const sdkLocation = this.getSdkLocationFromLocalPropertiesFile(projectRoot, logger);
e4e4820aEzio Li3 years ago232if (sdkLocation) {
233const localPropertiesSdkPath = path.join(
234sdkLocation as string,
235"platform-tools",
236os.platform() === "win32" ? "adb.exe" : "adb",
237);
238const isExist = fs.existsSync(localPropertiesSdkPath);
239if (isExist) {
79e49c88Gradyn Wursten2 years ago240return `"${localPropertiesSdkPath}"`;
e4e4820aEzio Li3 years ago241}
242if (logger) {
243logger.warning(
244localize(
245"LocalPropertiesAndroidSDKPathNotExistingInLocal",
246"Local.properties file has Andriod SDK path but cannot find it in your local, will switch to SDK PATH in environment variable. Please check Android SDK path in android/local.properties file.",
247),
248);
249}
250return "adb";
251}
252return "adb";
8152571aYuri Skorokhodov5 years ago253}
254
4bb0956eRedMickey5 years ago255public executeShellCommand(deviceId: string, command: string): Promise<string> {
256return this.executeQuery(deviceId, `shell "${command}"`);
257}
258
2a485fd5Ezio Li2 years ago259public installApplicationToEmulator(appPath: string): Promise<string> {
260return this.childProcess.execToString(`adb install ${appPath}`);
261}
262
4bb0956eRedMickey5 years ago263public executeQuery(deviceId: string, command: string): Promise<string> {
4cd25962JiglioNero4 years ago264return this.childProcess.execToString(this.generateCommandForTarget(deviceId, command));
4bb0956eRedMickey5 years ago265}
266
4cd25962JiglioNero4 years ago267private parseConnectedTargets(input: string): IDebuggableMobileTarget[] {
09f6024fHeniker4 years ago268const result: IDebuggableMobileTarget[] = [];
269const regex = new RegExp("^(\\S+)\\t(\\S+)$", "mg");
52f3873ddigeff10 years ago270let match = regex.exec(input);
271while (match != null) {
34472878RedMickey5 years ago272result.push({
273id: match[1],
274isOnline: match[2] === "device",
4cd25962JiglioNero4 years ago275isVirtualTarget: this.isVirtualTarget(match[1]),
34472878RedMickey5 years ago276});
52f3873ddigeff10 years ago277match = regex.exec(input);
278}
279return result;
280}
281
4cd25962JiglioNero4 years ago282public isVirtualTarget(id: string): boolean {
283return !!id.match(AdbHelper.AndroidSDKEmulatorPattern);
52f3873ddigeff10 years ago284}
285
ce5e88eeYuri Skorokhodov5 years ago286private execute(deviceId: string, command: string): Promise<void> {
4cd25962JiglioNero4 years ago287return this.commandExecutor.execute(this.generateCommandForTarget(deviceId, command));
52f3873ddigeff10 years ago288}
289
4cd25962JiglioNero4 years ago290private generateCommandForTarget(deviceId: string, adbCommand: string): string {
db6fd42aRuslan Bikkinin7 years ago291return `${this.adbExecutable} -s "${deviceId}" ${adbCommand}`;
292}
293
34472878RedMickey5 years ago294private getSdkLocationFromLocalPropertiesFile(
295projectRoot: string,
296logger?: ILogger,
297): string | null {
db6fd42aRuslan Bikkinin7 years ago298const localPropertiesFilePath = path.join(projectRoot, "android", "local.properties");
299if (!fs.existsSync(localPropertiesFilePath)) {
300if (logger) {
34472878RedMickey5 years ago301logger.info(
302localize(
303"LocalPropertiesFileDoesNotExist",
304"local.properties file doesn't exist. Using Android SDK location from PATH.",
305),
306);
db6fd42aRuslan Bikkinin7 years ago307}
308return null;
309}
310
8b383051Ruslan Bikkinin7 years ago311let fileContent: string;
db6fd42aRuslan Bikkinin7 years ago312try {
313fileContent = fs.readFileSync(localPropertiesFilePath).toString();
314} catch (e) {
315if (logger) {
34472878RedMickey5 years ago316logger.error(
317localize(
318"CouldNotReadFrom",
319"Couldn't read from {0}.",
320localPropertiesFilePath,
321),
322e,
323e.stack,
324);
325logger.info(
326localize(
327"UsingAndroidSDKLocationFromPATH",
328"Using Android SDK location from PATH.",
329),
330);
db6fd42aRuslan Bikkinin7 years ago331}
332return null;
333}
8b383051Ruslan Bikkinin7 years ago334return this.parseSdkLocation(fileContent, logger);
52f3873ddigeff10 years ago335}
336}