microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1.8.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/android/adb.ts

317lines · 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 { ChildProcess, ISpawnResult } from "../../common/node/childProcess";
5import { CommandExecutor } from "../../common/commandExecutor";
6import * as path from "path";
7import * as fs from "fs";
8import { ILogger } from "../log/LogHelper";
8b383051Ruslan Bikkinin7 years ago9import * as os from "os";
d7d405aeYuri Skorokhodov7 years ago10import * as nls from "vscode-nls";
0d77292aJiglioNero4 years ago11import { PromiseUtil } from "../../common/node/promise";
4cd25962JiglioNero4 years ago12import { IDebuggableMobileTarget } from "../mobileTarget";
34472878RedMickey5 years ago13nls.config({
14messageFormat: nls.MessageFormat.bundle,
15bundleFormat: nls.BundleFormat.standalone,
16})();
d7d405aeYuri Skorokhodov7 years ago17const localize = nls.loadMessageBundle();
52f3873ddigeff10 years ago18
ce7fd946digeff10 years ago19// See android versions usage at: http://developer.android.com/about/dashboards/index.html
52f3873ddigeff10 years ago20export enum AndroidAPILevel {
ce7fd946digeff10 years ago21Marshmallow = 23,
52f3873ddigeff10 years ago22LOLLIPOP_MR1 = 22,
34472878RedMickey5 years ago23LOLLIPOP = 21 /* Supports adb reverse */,
52f3873ddigeff10 years ago24KITKAT = 19,
25JELLY_BEAN_MR2 = 18,
26JELLY_BEAN_MR1 = 17,
27JELLY_BEAN = 16,
28ICE_CREAM_SANDWICH_MR1 = 15,
29GINGERBREAD_MR1 = 10,
30}
31
7daed3fcArtem Egorov8 years ago32enum KeyEvents {
33KEYCODE_BACK = 4,
34KEYCODE_DPAD_UP = 19,
35KEYCODE_DPAD_DOWN = 20,
36KEYCODE_DPAD_CENTER = 23,
37KEYCODE_MENU = 82,
38}
39
40export class AdbHelper {
4dfb1c4cetatanova5 years ago41private nodeModulesRoot: string;
42private launchActivity: string;
db6fd42aRuslan Bikkinin7 years ago43private childProcess: ChildProcess = new ChildProcess();
4dfb1c4cetatanova5 years ago44private commandExecutor: CommandExecutor;
db6fd42aRuslan Bikkinin7 years ago45private adbExecutable: string = "";
46
4cd25962JiglioNero4 years ago47private static readonly AndroidRemoteTargetPattern = /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}|.*_adb-tls-connect\._tcp.*)$/gm;
48public static readonly AndroidSDKEmulatorPattern = /^emulator-\d{1,5}$/;
247f6e8cRedMickey5 years ago49
4dfb1c4cetatanova5 years ago50constructor(
51projectRoot: string,
52nodeModulesRoot: string,
53logger?: ILogger,
54launchActivity: string = "MainActivity",
55) {
56this.nodeModulesRoot = nodeModulesRoot;
8152571aYuri Skorokhodov5 years ago57this.adbExecutable = this.getAdbPath(projectRoot, logger);
4dfb1c4cetatanova5 years ago58this.commandExecutor = new CommandExecutor(this.nodeModulesRoot);
78c2b4deRedMickey6 years ago59this.launchActivity = launchActivity;
db6fd42aRuslan Bikkinin7 years ago60}
52f3873ddigeff10 years ago61
62/**
63* Gets the list of Android connected devices and emulators.
64*/
4cd25962JiglioNero4 years ago65public async getConnectedTargets(): Promise<IDebuggableMobileTarget[]> {
0d77292aJiglioNero4 years ago66const output = await this.childProcess.execToString(`${this.adbExecutable} devices`);
4cd25962JiglioNero4 years ago67return this.parseConnectedTargets(output);
68}
69
70public async findOnlineTargetById(
71targetId: string,
72): Promise<IDebuggableMobileTarget | undefined> {
73return (await this.getOnlineTargets()).find(target => target.id === targetId);
74}
75
76public async getAvdsNames(): Promise<string[]> {
77const res = await this.childProcess.execToString("emulator -list-avds");
78let emulatorsNames: string[] = [];
79if (res) {
80emulatorsNames = res.split(/\r?\n|\r/g);
81const indexOfBlank = emulatorsNames.indexOf("");
82if (indexOfBlank >= 0) {
83emulatorsNames.splice(indexOfBlank, 1);
84}
85}
86return emulatorsNames;
87}
88
89public isRemoteTarget(id: string): boolean {
90return !!id.match(AdbHelper.AndroidRemoteTargetPattern);
91}
92
93public async getAvdNameById(emulatorId: string): Promise<string | null> {
94try {
95const output = await this.childProcess.execToString(
96`${this.adbExecutable} -s ${emulatorId} emu avd name`,
97);
98// The command returns the name of avd by id of this running emulator.
99// Return value example:
100// "
101// emuName
102// OK
103// "
104if (output) {
105// Return the name of avd: emuName
106return output.split(/\r?\n|\r/g)[0];
107} else {
108return null;
109}
110} catch {
111// If the command returned an error, it means that we could not find the emulator with the passed id
112return null;
113}
52f3873ddigeff10 years ago114}
115
78c2b4deRedMickey6 years ago116public setLaunchActivity(launchActivity: string): void {
117this.launchActivity = launchActivity;
118}
119
52f3873ddigeff10 years ago120/**
121* Broadcasts an intent to reload the application in debug mode.
122*/
0d77292aJiglioNero4 years ago123public async switchDebugMode(
34472878RedMickey5 years ago124projectRoot: string,
125packageName: string,
126enable: boolean,
127debugTarget?: string,
69ad2ab3RedMickey5 years ago128appIdSuffix?: string,
34472878RedMickey5 years ago129): Promise<void> {
130let enableDebugCommand = `${this.adbExecutable} ${
131debugTarget ? "-s " + debugTarget : ""
132} shell am broadcast -a "${packageName}.RELOAD_APP_ACTION" --ez jsproxy ${enable}`;
0d77292aJiglioNero4 years ago133await new CommandExecutor(this.nodeModulesRoot, projectRoot).execute(enableDebugCommand);
134// We should stop and start application again after RELOAD_APP_ACTION, otherwise app going to hangs up
135await PromiseUtil.delay(200); // We need a little delay after broadcast command
136await this.stopApp(projectRoot, packageName, debugTarget, appIdSuffix);
137return this.launchApp(projectRoot, packageName, debugTarget, appIdSuffix);
52f3873ddigeff10 years ago138}
139
140/**
141* Sends an intent which launches the main activity of the application.
142*/
34472878RedMickey5 years ago143public launchApp(
144projectRoot: string,
145packageName: string,
146debugTarget?: string,
69ad2ab3RedMickey5 years ago147appIdSuffix?: string,
34472878RedMickey5 years ago148): Promise<void> {
149let launchAppCommand = `${this.adbExecutable} ${
150debugTarget ? "-s " + debugTarget : ""
69ad2ab3RedMickey5 years ago151} shell am start -n ${packageName}${appIdSuffix ? "." + appIdSuffix : ""}/${packageName}.${
152this.launchActivity
153}`;
52f3873ddigeff10 years ago154return new CommandExecutor(projectRoot).execute(launchAppCommand);
155}
156
69ad2ab3RedMickey5 years ago157public stopApp(
158projectRoot: string,
159packageName: string,
160debugTarget?: string,
161appIdSuffix?: string,
162): Promise<void> {
34472878RedMickey5 years ago163let stopAppCommand = `${this.adbExecutable} ${
164debugTarget ? "-s " + debugTarget : ""
69ad2ab3RedMickey5 years ago165} shell am force-stop ${packageName}${appIdSuffix ? "." + appIdSuffix : ""}`;
b57ea017Artem Egorov8 years ago166return new CommandExecutor(projectRoot).execute(stopAppCommand);
167}
168
0d77292aJiglioNero4 years ago169public async apiVersion(deviceId: string): Promise<AndroidAPILevel> {
170const output = await this.executeQuery(deviceId, "shell getprop ro.build.version.sdk");
171return parseInt(output, 10);
52f3873ddigeff10 years ago172}
173
4bb0956eRedMickey5 years ago174public reverseAdb(deviceId: string, port: number): Promise<void> {
175return this.execute(deviceId, `reverse tcp:${port} tcp:${port}`);
52f3873ddigeff10 years ago176}
177
ce5e88eeYuri Skorokhodov5 years ago178public showDevMenu(deviceId?: string): Promise<void> {
34472878RedMickey5 years ago179let command = `${this.adbExecutable} ${
180deviceId ? "-s " + deviceId : ""
181} shell input keyevent ${KeyEvents.KEYCODE_MENU}`;
7daed3fcArtem Egorov8 years ago182return this.commandExecutor.execute(command);
183}
184
ce5e88eeYuri Skorokhodov5 years ago185public reloadApp(deviceId?: string): Promise<void> {
34472878RedMickey5 years ago186let command = `${this.adbExecutable} ${
187deviceId ? "-s " + deviceId : ""
188} shell input text "RR"`;
e23ea82cAlter Code7 years ago189return this.commandExecutor.execute(command);
7daed3fcArtem Egorov8 years ago190}
191
4cd25962JiglioNero4 years ago192public async getOnlineTargets(): Promise<IDebuggableMobileTarget[]> {
193const devices = await this.getConnectedTargets();
0d77292aJiglioNero4 years ago194return devices.filter(device => device.isOnline);
7daed3fcArtem Egorov8 years ago195}
196
db6fd42aRuslan Bikkinin7 years ago197public startLogCat(adbParameters: string[]): ISpawnResult {
b78a1aaeYuri Skorokhodov5 years ago198return this.childProcess.spawn(this.adbExecutable.replace(/\"/g, ""), adbParameters);
db6fd42aRuslan Bikkinin7 years ago199}
200
8df5011eYuri Skorokhodov5 years ago201public parseSdkLocation(fileContent: string, logger?: ILogger): string | null {
1864d974RedMickey4 years ago202const matches = fileContent.match(/^sdk\.dir\s*=(.+)$/m);
8b383051Ruslan Bikkinin7 years ago203if (!matches || !matches[1]) {
204if (logger) {
34472878RedMickey5 years ago205logger.info(
206localize(
207"NoSdkDirFoundInLocalPropertiesFile",
208"No sdk.dir value found in local.properties file. Using Android SDK location from PATH.",
209),
210);
8b383051Ruslan Bikkinin7 years ago211}
212return null;
213}
214
215let sdkLocation = matches[1].trim();
216if (os.platform() === "win32") {
217// For Windows we need to unescape files separators and drive letter separators
218sdkLocation = sdkLocation.replace(/\\\\/g, "\\").replace("\\:", ":");
219}
220if (logger) {
34472878RedMickey5 years ago221logger.info(
222localize(
223"UsindAndroidSDKLocationDefinedInLocalPropertiesFile",
224"Using Android SDK location defined in android/local.properties file: {0}.",
225sdkLocation,
226),
227);
8b383051Ruslan Bikkinin7 years ago228}
229
230return sdkLocation;
231}
232
8152571aYuri Skorokhodov5 years ago233public getAdbPath(projectRoot: string, logger?: ILogger): string {
234// Trying to read sdk location from local.properties file and if we succueded then
235// we would run adb from inside it, otherwise we would rely to PATH
236const sdkLocation = this.getSdkLocationFromLocalPropertiesFile(projectRoot, logger);
237return sdkLocation ? `"${path.join(sdkLocation, "platform-tools", "adb")}"` : "adb";
238}
239
4bb0956eRedMickey5 years ago240public executeShellCommand(deviceId: string, command: string): Promise<string> {
241return this.executeQuery(deviceId, `shell "${command}"`);
242}
243
244public executeQuery(deviceId: string, command: string): Promise<string> {
4cd25962JiglioNero4 years ago245return this.childProcess.execToString(this.generateCommandForTarget(deviceId, command));
4bb0956eRedMickey5 years ago246}
247
4cd25962JiglioNero4 years ago248private parseConnectedTargets(input: string): IDebuggableMobileTarget[] {
249let result: IDebuggableMobileTarget[] = [];
52f3873ddigeff10 years ago250let regex = new RegExp("^(\\S+)\\t(\\S+)$", "mg");
251let match = regex.exec(input);
252while (match != null) {
34472878RedMickey5 years ago253result.push({
254id: match[1],
255isOnline: match[2] === "device",
4cd25962JiglioNero4 years ago256isVirtualTarget: this.isVirtualTarget(match[1]),
34472878RedMickey5 years ago257});
52f3873ddigeff10 years ago258match = regex.exec(input);
259}
260return result;
261}
262
4cd25962JiglioNero4 years ago263public isVirtualTarget(id: string): boolean {
264return !!id.match(AdbHelper.AndroidSDKEmulatorPattern);
52f3873ddigeff10 years ago265}
266
ce5e88eeYuri Skorokhodov5 years ago267private execute(deviceId: string, command: string): Promise<void> {
4cd25962JiglioNero4 years ago268return this.commandExecutor.execute(this.generateCommandForTarget(deviceId, command));
52f3873ddigeff10 years ago269}
270
4cd25962JiglioNero4 years ago271private generateCommandForTarget(deviceId: string, adbCommand: string): string {
db6fd42aRuslan Bikkinin7 years ago272return `${this.adbExecutable} -s "${deviceId}" ${adbCommand}`;
273}
274
34472878RedMickey5 years ago275private getSdkLocationFromLocalPropertiesFile(
276projectRoot: string,
277logger?: ILogger,
278): string | null {
db6fd42aRuslan Bikkinin7 years ago279const localPropertiesFilePath = path.join(projectRoot, "android", "local.properties");
280if (!fs.existsSync(localPropertiesFilePath)) {
281if (logger) {
34472878RedMickey5 years ago282logger.info(
283localize(
284"LocalPropertiesFileDoesNotExist",
285"local.properties file doesn't exist. Using Android SDK location from PATH.",
286),
287);
db6fd42aRuslan Bikkinin7 years ago288}
289return null;
290}
291
8b383051Ruslan Bikkinin7 years ago292let fileContent: string;
db6fd42aRuslan Bikkinin7 years ago293try {
294fileContent = fs.readFileSync(localPropertiesFilePath).toString();
295} catch (e) {
296if (logger) {
34472878RedMickey5 years ago297logger.error(
298localize(
299"CouldNotReadFrom",
300"Couldn't read from {0}.",
301localPropertiesFilePath,
302),
303e,
304e.stack,
305);
306logger.info(
307localize(
308"UsingAndroidSDKLocationFromPATH",
309"Using Android SDK location from PATH.",
310),
311);
db6fd42aRuslan Bikkinin7 years ago312}
313return null;
314}
8b383051Ruslan Bikkinin7 years ago315return this.parseSdkLocation(fileContent, logger);
52f3873ddigeff10 years ago316}
317}