mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-25 10:58:42 +00:00
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:
@@ -73,10 +73,13 @@ class ADBSocket extends AndroidSocket {
|
||||
/**
|
||||
* Sends an ADB command, checks the returned status and then reads raw data from the socket
|
||||
* @param {string} command
|
||||
* @param {number} timeout_ms
|
||||
* @param {boolean} [until_closed]
|
||||
*/
|
||||
async cmd_and_read_stdout(command) {
|
||||
async cmd_and_read_stdout(command, timeout_ms, until_closed) {
|
||||
await this.cmd_and_status(command);
|
||||
return this.read_stdout();
|
||||
const buf = await this.read_stdout(timeout_ms, until_closed);
|
||||
return buf.toString('latin1');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,8 +64,9 @@ class AndroidSocket extends EventEmitter {
|
||||
*
|
||||
* @param {number|'length+data'|undefined} length
|
||||
* @param {string} [format]
|
||||
* @param {number} [timeout_ms]
|
||||
*/
|
||||
async read_bytes(length, format) {
|
||||
async read_bytes(length, format, timeout_ms) {
|
||||
//D(`reading ${length} bytes`);
|
||||
let actual_length = length;
|
||||
if (typeof actual_length === 'undefined') {
|
||||
@@ -95,25 +96,40 @@ class AndroidSocket extends EventEmitter {
|
||||
return Promise.resolve(data);
|
||||
}
|
||||
// wait for the socket to update and then retry the read
|
||||
await this.wait_for_socket_data();
|
||||
await this.wait_for_socket_data(timeout_ms);
|
||||
return this.read_bytes(length, format);
|
||||
}
|
||||
|
||||
wait_for_socket_data() {
|
||||
/**
|
||||
*
|
||||
* @param {number} [timeout_ms]
|
||||
*/
|
||||
wait_for_socket_data(timeout_ms) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let done = 0;
|
||||
let done = 0, timer = null;
|
||||
let onDataChanged = () => {
|
||||
if ((done += 1) !== 1) return;
|
||||
this.off('socket-ended', onSocketEnded);
|
||||
clearTimeout(timer);
|
||||
resolve();
|
||||
}
|
||||
let onSocketEnded = () => {
|
||||
if ((done += 1) !== 1) return;
|
||||
this.off('data-changed', onDataChanged);
|
||||
clearTimeout(timer);
|
||||
reject(new Error(`${this.which} socket read failed. Socket closed.`));
|
||||
}
|
||||
let onTimerExpired = () => {
|
||||
if ((done += 1) !== 1) return;
|
||||
this.off('socket-ended', onSocketEnded);
|
||||
this.off('data-changed', onDataChanged);
|
||||
reject(new Error(`${this.which} socket read failed. Read timeout.`));
|
||||
}
|
||||
this.once('data-changed', onDataChanged);
|
||||
this.once('socket-ended', onSocketEnded);
|
||||
if (typeof timeout_ms === 'number' && timeout_ms >= 0) {
|
||||
timer = setTimeout(onTimerExpired, timeout_ms);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -122,8 +138,26 @@ class AndroidSocket extends EventEmitter {
|
||||
return this.read_bytes(len.readUInt32LE(0), format);
|
||||
}
|
||||
|
||||
read_stdout(format = 'latin1') {
|
||||
return this.read_bytes(undefined, format);
|
||||
/**
|
||||
*
|
||||
* @param {number} [timeout_ms]
|
||||
* @param {boolean} [until_closed]
|
||||
* @returns {Promise<Buffer>}
|
||||
*/
|
||||
async read_stdout(timeout_ms, until_closed) {
|
||||
let buf = await this.read_bytes(undefined, null, timeout_ms);
|
||||
if (!until_closed) {
|
||||
return buf;
|
||||
}
|
||||
const parts = [buf];
|
||||
try {
|
||||
for (;;) {
|
||||
buf = await this.read_bytes(undefined, null);
|
||||
parts.push(buf);
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
return Buffer.concat(parts);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,6 +168,7 @@ class AndroidSocket extends EventEmitter {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.check_socket_active('write');
|
||||
try {
|
||||
// @ts-ignore
|
||||
const flushed = this.socket.write(bytes, () => {
|
||||
flushed ? resolve() : this.socket.once('drain', resolve);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user