Version 1 (#83)

* replace jq-promises with native Promises

* updates to use native promises and async await

* Fix variable errors, remove extra parameters and correct export declaratons

* refactor launch request to use async/await

* fix running debugger on custom ADB port

* remove unused files

* move socket_ended check to ensure we don't loop reading 0 bytes

* refactor logcat code and ensure disconnect status is passed on to webview

* Fix warnings

* Clean up util and remove unused functions

* convert Debugger into a class

* update jsconfig target to es2018 and enable checkJS

* more updates to use async/await and more readable refactoring.

- added type definitions and debugger classes
- improved expression evaluation
- refactored expressions into parsing, evaluation and variable assignment
- fixed invoking methods with parameters
- added support for static method invokes
- improved exception display reliability
- refactored launch into smaller functions
- refactored utils into smaller modules
- removed redundant code
- converted JDWP functions to classes

* set version 1.0.0 and update dependencies

* add changelog notes
This commit is contained in:
Dave Holoway
2020-04-20 12:53:08 +01:00
committed by GitHub
parent f92f247ef6
commit 0672e54401
45 changed files with 8050 additions and 9829 deletions

143
src/sockets/adbsocket.js Normal file
View File

@@ -0,0 +1,143 @@
const AndroidSocket = require('./androidsocket');
/**
* Manages a socket connection to Android Debug Bridge
*/
class ADBSocket extends AndroidSocket {
/**
* The port number to run ADB on.
* The value can be overriden by the adbPort value in each configuration.
*/
static ADBPort = 5037;
constructor() {
super('ADBSocket');
}
/**
* Reads and checks the reply from an ADB command
* @param {boolean} [throw_on_fail] true if the function should throw on non-OKAY status
*/
async read_adb_status(throw_on_fail = true) {
// read back the status
const status = await this.read_bytes(4, 'latin1')
if (status !== 'OKAY' && throw_on_fail) {
throw new Error(`ADB command failed. Status: '${status}'`);
}
return status;
}
/**
* Reads and decodes an ADB reply. The reply is always in the form XXXXnnnn where XXXX is a 4 digit ascii hex length
*/
async read_adb_reply() {
const hexlen = await this.read_bytes(4, 'latin1');
if (/[^\da-fA-F]/.test(hexlen)) {
throw new Error('Bad ADB reply - invalid length data');
}
return this.read_bytes(parseInt(hexlen, 16), 'latin1');
}
/**
* Writes a command to the ADB socket
* @param {string} command
*/
write_adb_command(command) {
const command_bytes = Buffer.from(command);
const command_length = Buffer.from(('000' + command_bytes.byteLength.toString(16)).slice(-4));
return this.write_bytes(Buffer.concat([command_length, command_bytes]));
}
/**
* Sends an ADB command and checks the returned status
* @param {String} command ADB command to send
* @returns {Promise<string>} OKAY status or rejected
*/
async cmd_and_status(command) {
await this.write_adb_command(command);
return this.read_adb_status();
}
/**
* Sends an ADB command, checks the returned status and then reads the return reply
* @param {String} command ADB command to send
* @returns {Promise<string>} reply string or rejected if the status is not OKAY
*/
async cmd_and_reply(command) {
await this.cmd_and_status(command);
return this.read_adb_reply();
}
/**
* Sends an ADB command, checks the returned status and then reads raw data from the socket
* @param {string} command
*/
async cmd_and_read_stdout(command) {
await this.cmd_and_status(command);
return this.read_stdout();
}
/**
* Copies a file to the device, setting the file time and permissions
* @param {ADBFileTransferParams} file file parameters
*/
async transfer_file(file) {
await this.cmd_and_status('sync:');
// initiate the file send
const filename_and_perms = `${file.pathname},${file.perms}`;
const send_and_fileinfo = Buffer.from(`SEND\0\0\0\0${filename_and_perms}`);
send_and_fileinfo.writeUInt32LE(filename_and_perms.length, 4);
await this.write_bytes(send_and_fileinfo);
// send the file data
await this.write_file_data(file.data);
// send the DONE message with the new filetime
const done_and_mtime = Buffer.from('DONE\0\0\0\0');
done_and_mtime.writeUInt32LE(file.mtime, 4);
await this.write_bytes(done_and_mtime);
// read the final status and any error message
const result = await this.read_adb_status(false);
const failmsg = await this.read_le_length_data('latin1');
// finish the transfer mode
await this.write_bytes('QUIT\0\0\0\0');
if (result !== 'OKAY') {
throw new Error(`File transfer failed. ${failmsg}`);
}
return true;
}
/**
* @param {Buffer} data
*/
async write_file_data(data) {
const dtinfo = {
transferred: 0,
transferring: 0,
chunk_size: 10240,
};
for (;;) {
dtinfo.transferred += dtinfo.transferring;
const remaining = data.byteLength - dtinfo.transferred;
if (remaining <= 0 || isNaN(remaining)) {
return dtinfo.transferred;
}
const datalen = Math.min(remaining, dtinfo.chunk_size);
const cmd = Buffer.concat([Buffer.from(`DATA\0\0\0\0`), data.slice(dtinfo.transferred, dtinfo.transferred + datalen)]);
cmd.writeUInt32LE(datalen, 4);
dtinfo.transferring = datalen;
await this.write_bytes(cmd);
}
}
}
module.exports = ADBSocket;