Support attaching to running app (#85)

* add support for timeout on adb socket reads

* add debugger support for attaching to a process

* add new launch configuration and support for picking an Android process ID

* initial support for attaching to android process

* display enhanced quick pick list with pids and names

* add flag to prevent disconnect messages when not connected

* Retrieve all loaded classes during startup.
This allows us to identify breakpoints in anonymous classes that are already loaded.

* correct name of process picker command

* make PickAndroidProcess command private

* selectAndroidProcessID always returns an object

* make breakpoint setup a loop instead of recursive

* tidy some labels and error messages

* use a more consistent command for retrieving process names

* show pid list sorted by pid instead of name

* refactor some Android and ADB-specific functions
Check ANDROID_SDK as replacement for ANDROID_HOME

* tidy up logcat launch and refactor target device selection

* fix logcat not displaying

* filter duplicates and blanks from logcat output
This commit is contained in:
Dave Holoway
2020-04-23 13:28:03 +01:00
committed by GitHub
parent 9aeca6b96b
commit 44d887dd6c
15 changed files with 781 additions and 278 deletions

83
src/process-attach.js Normal file
View File

@@ -0,0 +1,83 @@
const os = require('os');
const { ADBClient } = require('./adbclient');
const { selectTargetDevice } = require('./utils/device');
/**
* @param {import('vscode')} vscode
* @param {{pid:number,name:string}[]} pids
*/
async function showPIDPicker(vscode, pids) {
// sort by PID (the user can type the package name to search)
const sorted_pids = pids.slice().sort((a,b) => a.pid - b.pid);
/** @type {import('vscode').QuickPickItem[]} */
const device_pick_items = sorted_pids
.map(x => ({
label: `${x.pid}`,
description: x.name,
}));
/** @type {import('vscode').QuickPickOptions} */
const device_pick_options = {
matchOnDescription: true,
canPickMany: false,
placeHolder: 'Choose the Android process to attach to',
};
const chosen_option = await vscode.window.showQuickPick(device_pick_items, device_pick_options);
return sorted_pids[device_pick_items.indexOf(chosen_option)] || null;
}
/**
* @param {import('vscode')} vscode
*/
async function selectAndroidProcessID(vscode) {
const res = {
/** @type {string|'ok'|'cancelled'|'failed'} */
status: 'failed',
pid: 0,
serial: '',
}
const err = await new ADBClient().test_adb_connection()
if (err) {
vscode.window.showWarningMessage('Attach failed. ADB is not running.');
return res;
}
const device = await selectTargetDevice(vscode, 'Attach');
if (!device) {
// user cancelled picker
res.status = 'cancelled';
return res;
}
let named_pids = await new ADBClient(device.serial).named_jdwp_list(5000);
if (named_pids.length === 0) {
vscode.window.showWarningMessage(
'Attach failed. No debuggable processes are running on the device.'
+ `${os.EOL}${os.EOL}`
+ `To allow a debugger to attach, the app must have the "android:debuggable=true" attribute present in AndroidManifest.xml and be running on the device.`
+ `${os.EOL}`
+ `See https://developer.android.com/guide/topics/manifest/application-element#debug`
);
return res;
}
// always show the pid picker - even if there's only one
const named_pid = await showPIDPicker(vscode, named_pids);
if (named_pid === null) {
// user cancelled picker
res.status = 'cancelled';
return res;
}
res.pid = named_pid.pid;
res.serial = device.serial;
res.status = 'ok';
return res;
}
module.exports = {
selectAndroidProcessID,
}