microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1.5.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/android/adb.ts

296lines · 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";
4bb0956eRedMickey5 years ago6import { IDevice } from "../../common/device";
db6fd42aRuslan Bikkinin7 years ago7import * as path from "path";
8import * as fs from "fs";
9import { ILogger } from "../log/LogHelper";
8b383051Ruslan Bikkinin7 years ago10import * as os from "os";
d7d405aeYuri Skorokhodov7 years ago11import * as nls from "vscode-nls";
34472878RedMickey5 years ago12nls.config({
13messageFormat: nls.MessageFormat.bundle,
14bundleFormat: nls.BundleFormat.standalone,
15})();
d7d405aeYuri Skorokhodov7 years ago16const localize = nls.loadMessageBundle();
52f3873ddigeff10 years ago17
ce7fd946digeff10 years ago18// See android versions usage at: http://developer.android.com/about/dashboards/index.html
52f3873ddigeff10 years ago19export enum AndroidAPILevel {
ce7fd946digeff10 years ago20Marshmallow = 23,
52f3873ddigeff10 years ago21LOLLIPOP_MR1 = 22,
34472878RedMickey5 years ago22LOLLIPOP = 21 /* Supports adb reverse */,
52f3873ddigeff10 years ago23KITKAT = 19,
24JELLY_BEAN_MR2 = 18,
25JELLY_BEAN_MR1 = 17,
26JELLY_BEAN = 16,
27ICE_CREAM_SANDWICH_MR1 = 15,
28GINGERBREAD_MR1 = 10,
29}
30
7daed3fcArtem Egorov8 years ago31enum KeyEvents {
32KEYCODE_BACK = 4,
33KEYCODE_DPAD_UP = 19,
34KEYCODE_DPAD_DOWN = 20,
35KEYCODE_DPAD_CENTER = 23,
36KEYCODE_MENU = 82,
37}
38
4bb0956eRedMickey5 years ago39export enum AdbDeviceType {
52f3873ddigeff10 years ago40AndroidSdkEmulator, // These seem to have emulator-<port> ids
27710197Vladimir Kotikov8 years ago41Other,
52f3873ddigeff10 years ago42}
43
4bb0956eRedMickey5 years ago44export interface IAdbDevice extends IDevice {
52f3873ddigeff10 years ago45isOnline: boolean;
4bb0956eRedMickey5 years ago46type: AdbDeviceType;
52f3873ddigeff10 years ago47}
48
7daed3fcArtem Egorov8 years ago49const AndroidSDKEmulatorPattern = /^emulator-\d{1,5}$/;
52f3873ddigeff10 years ago50
7daed3fcArtem Egorov8 years ago51export class AdbHelper {
4dfb1c4cetatanova5 years ago52private nodeModulesRoot: string;
53private launchActivity: string;
db6fd42aRuslan Bikkinin7 years ago54private childProcess: ChildProcess = new ChildProcess();
4dfb1c4cetatanova5 years ago55private commandExecutor: CommandExecutor;
db6fd42aRuslan Bikkinin7 years ago56private adbExecutable: string = "";
57
4dfb1c4cetatanova5 years ago58constructor(
59projectRoot: string,
60nodeModulesRoot: string,
61logger?: ILogger,
62launchActivity: string = "MainActivity",
63) {
64this.nodeModulesRoot = nodeModulesRoot;
8152571aYuri Skorokhodov5 years ago65this.adbExecutable = this.getAdbPath(projectRoot, logger);
4dfb1c4cetatanova5 years ago66this.commandExecutor = new CommandExecutor(this.nodeModulesRoot);
78c2b4deRedMickey6 years ago67this.launchActivity = launchActivity;
db6fd42aRuslan Bikkinin7 years ago68}
52f3873ddigeff10 years ago69
70/**
71* Gets the list of Android connected devices and emulators.
72*/
4bb0956eRedMickey5 years ago73public getConnectedDevices(): Promise<IAdbDevice[]> {
34472878RedMickey5 years ago74return this.childProcess.execToString(`${this.adbExecutable} devices`).then(output => {
75return this.parseConnectedDevices(output);
76});
52f3873ddigeff10 years ago77}
78
78c2b4deRedMickey6 years ago79public setLaunchActivity(launchActivity: string): void {
80this.launchActivity = launchActivity;
81}
82
52f3873ddigeff10 years ago83/**
84* Broadcasts an intent to reload the application in debug mode.
85*/
34472878RedMickey5 years ago86public switchDebugMode(
87projectRoot: string,
88packageName: string,
89enable: boolean,
90debugTarget?: string,
69ad2ab3RedMickey5 years ago91appIdSuffix?: string,
34472878RedMickey5 years ago92): Promise<void> {
93let enableDebugCommand = `${this.adbExecutable} ${
94debugTarget ? "-s " + debugTarget : ""
95} shell am broadcast -a "${packageName}.RELOAD_APP_ACTION" --ez jsproxy ${enable}`;
4dfb1c4cetatanova5 years ago96return new CommandExecutor(this.nodeModulesRoot, projectRoot)
34472878RedMickey5 years ago97.execute(enableDebugCommand)
98.then(() => {
99// We should stop and start application again after RELOAD_APP_ACTION, otherwise app going to hangs up
100return new Promise(resolve => {
ce5e88eeYuri Skorokhodov5 years ago101setTimeout(() => {
69ad2ab3RedMickey5 years ago102this.stopApp(projectRoot, packageName, debugTarget, appIdSuffix).then(
103() => {
4dfb1c4cetatanova5 years ago104return resolve(void 0);
69ad2ab3RedMickey5 years ago105},
106);
ce5e88eeYuri Skorokhodov5 years ago107}, 200); // We need a little delay after broadcast command
108});
b57ea017Artem Egorov8 years ago109})
110.then(() => {
69ad2ab3RedMickey5 years ago111return this.launchApp(projectRoot, packageName, debugTarget, appIdSuffix);
b57ea017Artem Egorov8 years ago112});
52f3873ddigeff10 years ago113}
114
115/**
116* Sends an intent which launches the main activity of the application.
117*/
34472878RedMickey5 years ago118public launchApp(
119projectRoot: string,
120packageName: string,
121debugTarget?: string,
69ad2ab3RedMickey5 years ago122appIdSuffix?: string,
34472878RedMickey5 years ago123): Promise<void> {
124let launchAppCommand = `${this.adbExecutable} ${
125debugTarget ? "-s " + debugTarget : ""
69ad2ab3RedMickey5 years ago126} shell am start -n ${packageName}${appIdSuffix ? "." + appIdSuffix : ""}/${packageName}.${
127this.launchActivity
128}`;
52f3873ddigeff10 years ago129return new CommandExecutor(projectRoot).execute(launchAppCommand);
130}
131
69ad2ab3RedMickey5 years ago132public stopApp(
133projectRoot: string,
134packageName: string,
135debugTarget?: string,
136appIdSuffix?: string,
137): Promise<void> {
34472878RedMickey5 years ago138let stopAppCommand = `${this.adbExecutable} ${
139debugTarget ? "-s " + debugTarget : ""
69ad2ab3RedMickey5 years ago140} shell am force-stop ${packageName}${appIdSuffix ? "." + appIdSuffix : ""}`;
b57ea017Artem Egorov8 years ago141return new CommandExecutor(projectRoot).execute(stopAppCommand);
142}
143
ce5e88eeYuri Skorokhodov5 years ago144public apiVersion(deviceId: string): Promise<AndroidAPILevel> {
52f3873ddigeff10 years ago145return this.executeQuery(deviceId, "shell getprop ro.build.version.sdk").then(output =>
34472878RedMickey5 years ago146parseInt(output, 10),
147);
52f3873ddigeff10 years ago148}
149
4bb0956eRedMickey5 years ago150public reverseAdb(deviceId: string, port: number): Promise<void> {
151return this.execute(deviceId, `reverse tcp:${port} tcp:${port}`);
52f3873ddigeff10 years ago152}
153
ce5e88eeYuri Skorokhodov5 years ago154public showDevMenu(deviceId?: string): Promise<void> {
34472878RedMickey5 years ago155let command = `${this.adbExecutable} ${
156deviceId ? "-s " + deviceId : ""
157} shell input keyevent ${KeyEvents.KEYCODE_MENU}`;
7daed3fcArtem Egorov8 years ago158return this.commandExecutor.execute(command);
159}
160
ce5e88eeYuri Skorokhodov5 years ago161public reloadApp(deviceId?: string): Promise<void> {
34472878RedMickey5 years ago162let command = `${this.adbExecutable} ${
163deviceId ? "-s " + deviceId : ""
164} shell input text "RR"`;
e23ea82cAlter Code7 years ago165return this.commandExecutor.execute(command);
7daed3fcArtem Egorov8 years ago166}
167
4bb0956eRedMickey5 years ago168public getOnlineDevices(): Promise<IAdbDevice[]> {
7daed3fcArtem Egorov8 years ago169return this.getConnectedDevices().then(devices => {
34472878RedMickey5 years ago170return devices.filter(device => device.isOnline);
7daed3fcArtem Egorov8 years ago171});
172}
173
db6fd42aRuslan Bikkinin7 years ago174public startLogCat(adbParameters: string[]): ISpawnResult {
b78a1aaeYuri Skorokhodov5 years ago175return this.childProcess.spawn(this.adbExecutable.replace(/\"/g, ""), adbParameters);
db6fd42aRuslan Bikkinin7 years ago176}
177
8df5011eYuri Skorokhodov5 years ago178public parseSdkLocation(fileContent: string, logger?: ILogger): string | null {
8b383051Ruslan Bikkinin7 years ago179const matches = fileContent.match(/^sdk\.dir=(.+)$/m);
180if (!matches || !matches[1]) {
181if (logger) {
34472878RedMickey5 years ago182logger.info(
183localize(
184"NoSdkDirFoundInLocalPropertiesFile",
185"No sdk.dir value found in local.properties file. Using Android SDK location from PATH.",
186),
187);
8b383051Ruslan Bikkinin7 years ago188}
189return null;
190}
191
192let sdkLocation = matches[1].trim();
193if (os.platform() === "win32") {
194// For Windows we need to unescape files separators and drive letter separators
195sdkLocation = sdkLocation.replace(/\\\\/g, "\\").replace("\\:", ":");
196}
197if (logger) {
34472878RedMickey5 years ago198logger.info(
199localize(
200"UsindAndroidSDKLocationDefinedInLocalPropertiesFile",
201"Using Android SDK location defined in android/local.properties file: {0}.",
202sdkLocation,
203),
204);
8b383051Ruslan Bikkinin7 years ago205}
206
207return sdkLocation;
208}
209
8152571aYuri Skorokhodov5 years ago210public getAdbPath(projectRoot: string, logger?: ILogger): string {
211// Trying to read sdk location from local.properties file and if we succueded then
212// we would run adb from inside it, otherwise we would rely to PATH
213const sdkLocation = this.getSdkLocationFromLocalPropertiesFile(projectRoot, logger);
214return sdkLocation ? `"${path.join(sdkLocation, "platform-tools", "adb")}"` : "adb";
215}
216
4bb0956eRedMickey5 years ago217public executeShellCommand(deviceId: string, command: string): Promise<string> {
218return this.executeQuery(deviceId, `shell "${command}"`);
219}
220
221public executeQuery(deviceId: string, command: string): Promise<string> {
222return this.childProcess.execToString(this.generateCommandForDevice(deviceId, command));
223}
224
225private parseConnectedDevices(input: string): IAdbDevice[] {
226let result: IAdbDevice[] = [];
52f3873ddigeff10 years ago227let regex = new RegExp("^(\\S+)\\t(\\S+)$", "mg");
228let match = regex.exec(input);
229while (match != null) {
34472878RedMickey5 years ago230result.push({
231id: match[1],
232isOnline: match[2] === "device",
233type: this.extractDeviceType(match[1]),
234});
52f3873ddigeff10 years ago235match = regex.exec(input);
236}
237return result;
238}
239
4bb0956eRedMickey5 years ago240private extractDeviceType(id: string): AdbDeviceType {
52f3873ddigeff10 years ago241return id.match(AndroidSDKEmulatorPattern)
4bb0956eRedMickey5 years ago242? AdbDeviceType.AndroidSdkEmulator
243: AdbDeviceType.Other;
52f3873ddigeff10 years ago244}
245
ce5e88eeYuri Skorokhodov5 years ago246private execute(deviceId: string, command: string): Promise<void> {
52f3873ddigeff10 years ago247return this.commandExecutor.execute(this.generateCommandForDevice(deviceId, command));
248}
249
db6fd42aRuslan Bikkinin7 years ago250private generateCommandForDevice(deviceId: string, adbCommand: string): string {
251return `${this.adbExecutable} -s "${deviceId}" ${adbCommand}`;
252}
253
34472878RedMickey5 years ago254private getSdkLocationFromLocalPropertiesFile(
255projectRoot: string,
256logger?: ILogger,
257): string | null {
db6fd42aRuslan Bikkinin7 years ago258const localPropertiesFilePath = path.join(projectRoot, "android", "local.properties");
259if (!fs.existsSync(localPropertiesFilePath)) {
260if (logger) {
34472878RedMickey5 years ago261logger.info(
262localize(
263"LocalPropertiesFileDoesNotExist",
264"local.properties file doesn't exist. Using Android SDK location from PATH.",
265),
266);
db6fd42aRuslan Bikkinin7 years ago267}
268return null;
269}
270
8b383051Ruslan Bikkinin7 years ago271let fileContent: string;
db6fd42aRuslan Bikkinin7 years ago272try {
273fileContent = fs.readFileSync(localPropertiesFilePath).toString();
274} catch (e) {
275if (logger) {
34472878RedMickey5 years ago276logger.error(
277localize(
278"CouldNotReadFrom",
279"Couldn't read from {0}.",
280localPropertiesFilePath,
281),
282e,
283e.stack,
284);
285logger.info(
286localize(
287"UsingAndroidSDKLocationFromPATH",
288"Using Android SDK location from PATH.",
289),
290);
db6fd42aRuslan Bikkinin7 years ago291}
292return null;
293}
8b383051Ruslan Bikkinin7 years ago294return this.parseSdkLocation(fileContent, logger);
52f3873ddigeff10 years ago295}
296}