22 Commits

Author SHA1 Message Date
Dave Holoway
614fcbd2ba version 0.7.0 2019-08-18 16:08:32 +01:00
Dave Holoway
b04e4328a6 upgrade ws to 7.1.2 (#70) 2019-08-18 16:01:06 +01:00
Dave Holoway
1a00cdb291 Replace new Buffer() constructor calls (#69) 2019-08-18 14:53:54 +01:00
dependabot[bot]
d1fd889433 Bump js-yaml from 3.12.0 to 3.13.1 (#59)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.12.0 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.12.0...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-18 14:36:52 +01:00
dependabot[bot]
a7e4cac6df Bump lodash from 4.17.11 to 4.17.14 (#61)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-18 14:35:30 +01:00
dependabot[bot]
c6df24ab95 Bump tar from 2.2.1 to 2.2.2 (#65)
Bumps [tar](https://github.com/npm/node-tar) from 2.2.1 to 2.2.2.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Commits](https://github.com/npm/node-tar/compare/v2.2.1...v2.2.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-18 14:33:43 +01:00
dependabot[bot]
23184ea4c2 Bump fstream from 1.0.11 to 1.0.12 (#66)
Bumps [fstream](https://github.com/npm/fstream) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/npm/fstream/releases)
- [Commits](https://github.com/npm/fstream/compare/v1.0.11...v1.0.12)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-18 14:31:57 +01:00
NathanMcBride666
b7ba47b811 Added support for kotlin src folder (#62)
Signed-off-by: Nathan McBride <noman@hidden.com>
2019-08-18 14:27:43 +01:00
Dave Holoway
033f5c80ab Update README with info about prelaunch builds (#68) 2019-08-18 14:22:07 +01:00
Dave Holoway
0cbb56ca9b Create LICENSE (#67) 2019-08-18 14:03:12 +01:00
Dave Holoway
684dd39181 Fix logcat not displaying (#64)
* update LogcatContent constructor to use single deviceID argument

* add support for WebviewPanel for displaying logcat data

Fixes #63
2019-08-18 13:22:12 +01:00
lbhnrg2021
52ab704acd Fix breakpoints not triggering on Windows 10 (#55)
* fix-windows-breakpoint

* perform a case-insensitve path search for packages

* revert unnecessary changes to packages
2019-04-24 00:50:23 +01:00
Dave Holoway
45e2dc2fe1 version 0.6.2 2018-12-16 21:10:16 +00:00
Dave Holoway
30ed5dea3b Fix logcat not launching (#50)
* use prepare instead of postinstall as vscode is a dev dependency  only

* add missing uuid dependency
update devDependencies
2018-12-16 21:08:01 +00:00
Dave Holoway
0eb44130a6 Downgrade vulnerable event-stream package (#48)
* regenerate package-lock

* update changelog
2018-12-03 14:05:10 +00:00
Dave Holoway
d1e7c86092 version 0.6 (#46) 2018-11-11 20:42:02 +00:00
Dave Holoway
690f9dc23a update debugger label (#45) 2018-11-11 20:34:43 +00:00
Dave Holoway
27ecd41b68 update default apkFile path (#43) 2018-11-11 20:22:40 +00:00
Dave Holoway
756a1cea29 update package dependencies (#41) 2018-11-11 20:11:21 +00:00
Dave Holoway
fc2ce97a23 breakpoints do not get enabled on startup (#40)
* add more trace around breakpoint config during startup

* use 'changed' instead of 'updated' when sending BreakpointEvents
2018-11-11 19:31:30 +00:00
Dave Holoway
de8abc62bc add trace support (#38)
* add basic support for sending console logs to OutputWindow

* add trace config setting

* standardise logs
2018-11-11 17:57:32 +00:00
Dave Holoway
8cc31476b3 fix breakpoints don't trigger when hit (#37)
* add errorcode to empty jdwp results

* use an empty line table if the command request fails
2018-11-11 15:20:28 +00:00
12 changed files with 2901 additions and 57 deletions

View File

@@ -1,5 +1,26 @@
# Change Log # Change Log
### version 0.7.0
* Fix logcat not displaying
* Fix breakpoints not triggering on Windows
* Added kotlin folder to list of known source locations
* Upgraded dependencies to resolve a number of security vulnerabilites
* Updated README with info about prelaunch build task
* Added MIT license file
### version 0.6.2
* Fix broken logcat command due to missing dependency
### version 0.6.1
* Regenerate package-lock.json to remove event-stream vulnerability - https://github.com/dominictarr/event-stream/issues/116
### version 0.6.0
* Fix issue with breakpoints not enabling correctly
* Fix issue with JDWP failure on breakpoint hit
* Added support for diagnostic logs using trace configuration option
* Updated default apkFile path to match current releases of Android Studio
* Updated package dependencies
### version 0.5.0 ### version 0.5.0
* Debugger support for Kotlin source files * Debugger support for Kotlin source files
* Exception UI * Exception UI

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Dave Holoway
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -20,7 +20,7 @@ You must have [Android SDK Platform Tools](https://developer.android.com/studio/
* This is a preview version so expect the unexpected. Please log any issues you find on [GitHub](https://github.com/adelphes/android-dev-ext/issues). * This is a preview version so expect the unexpected. Please log any issues you find on [GitHub](https://github.com/adelphes/android-dev-ext/issues).
* This extension **will not build your app**. * This extension **will not build your app**.
If you use gradle (or Android Studio), you can build your app from the command-line using `./gradlew assembleDebug`. If you use gradle (or Android Studio), you can build your app from the command-line using `./gradlew assembleDebug`.
> You must use gradle or some other build procedure to create your APK. Once built, the extension can deploy and launch your app, allowing you to debug it in the normal way. > You must use gradle or some other build procedure to create your APK. Once built, the extension can deploy and launch your app, allowing you to debug it in the normal way. See the section below on how to configure a VSCode task to automatically build your app before launching a debug session.
* Some debugger options are yet to be implemented. You cannot set conditional breakpoints and watch expressions must be simple variables. * Some debugger options are yet to be implemented. You cannot set conditional breakpoints and watch expressions must be simple variables.
* If you require a must-have feature that isn't there yet, let us know on [GitHub](https://github.com/adelphes/android-dev-ext/issues). * If you require a must-have feature that isn't there yet, let us know on [GitHub](https://github.com/adelphes/android-dev-ext/issues).
* This extension does not provide any additional code completion or other editing enhancements. * This extension does not provide any additional code completion or other editing enhancements.
@@ -54,6 +54,42 @@ The following settings are used to configure the debugger:
] ]
} }
## Building your app automatically
This extension will not build your App. If you would like to run a build each time a debug session is started, you can add a `preLaunchTask` option to your `launch.json` configuration which invokes a build task.
#### .vscode/launch.json
Add a `preLaunchTask` item to the launch configuration:
```json
{
"version": "0.2.0",
"configurations": [
{
"type": "android",
"request": "launch",
"name": "App Build & Launch",
"preLaunchTask": "run gradle",
}
]
}
```
Add a new task to run the build command:
#### .vscode/tasks.json
```json
{
"version": "2.0.0",
"tasks": [
{
"label": "run gradle",
"type": "shell",
"command": "${workspaceFolder}/gradlew",
"args": ["assembleDebug"]
}
]
}
```
## Questions / Problems ## Questions / Problems
If you run into any problems, tell us on [GitHub](https://github.com/adelphes/android-dev-ext/issues) or contact me on [Twitter](https://twitter.com/daveholoway). If you run into any problems, tell us on [GitHub](https://github.com/adelphes/android-dev-ext/issues) or contact me on [Twitter](https://twitter.com/daveholoway).

2695
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "android-dev-ext", "name": "android-dev-ext",
"displayName": "Android", "displayName": "Android",
"description": "Android debugging support for VS Code", "description": "Android debugging support for VS Code",
"version": "0.5.0", "version": "0.7.0",
"publisher": "adelphes", "publisher": "adelphes",
"preview": true, "preview": true,
"license": "MIT", "license": "MIT",
@@ -43,7 +43,7 @@
"debuggers": [ "debuggers": [
{ {
"type": "android", "type": "android",
"label": "Android Debug", "label": "Android",
"program": "./src/debugMain.js", "program": "./src/debugMain.js",
"runtime": "node", "runtime": "node",
"configurationAttributes": { "configurationAttributes": {
@@ -62,7 +62,7 @@
"apkFile": { "apkFile": {
"type": "string", "type": "string",
"description": "Fully qualified path to the built APK (Android Application Package)", "description": "Fully qualified path to the built APK (Android Application Package)",
"default": "${workspaceRoot}/app/build/outputs/apk/app-debug.apk" "default": "${workspaceRoot}/app/build/outputs/apk/debug/app-debug.apk"
}, },
"adbPort": { "adbPort": {
"type": "integer", "type": "integer",
@@ -93,6 +93,11 @@
"type": "string", "type": "string",
"description": "Target Device ID (as indicated by 'adb devices'). Use this to specify which device is used for deployment when multiple devices are connected.", "description": "Target Device ID (as indicated by 'adb devices'). Use this to specify which device is used for deployment when multiple devices are connected.",
"default": "" "default": ""
},
"trace": {
"type": "boolean",
"description": "Set to true to output debugging logs for diagnostics",
"default": "false"
} }
} }
} }
@@ -100,10 +105,10 @@
"initialConfigurations": [ "initialConfigurations": [
{ {
"type": "android", "type": "android",
"name": "Android Debug", "name": "Android",
"request": "launch", "request": "launch",
"appSrcRoot": "${workspaceRoot}/app/src/main", "appSrcRoot": "${workspaceRoot}/app/src/main",
"apkFile": "${workspaceRoot}/app/build/outputs/apk/app-debug.apk", "apkFile": "${workspaceRoot}/app/build/outputs/apk/debug/app-debug.apk",
"adbPort": 5037 "adbPort": 5037
} }
], ],
@@ -116,7 +121,7 @@
"request": "launch", "request": "launch",
"name": "${2:Launch App}", "name": "${2:Launch App}",
"appSrcRoot": "^\"\\${workspaceRoot}/app/src/main\"", "appSrcRoot": "^\"\\${workspaceRoot}/app/src/main\"",
"apkFile": "^\"\\${workspaceRoot}/app/build/outputs/apk/app-debug.apk\"", "apkFile": "^\"\\${workspaceRoot}/app/build/outputs/apk/debug/app-debug.apk\"",
"adbPort": 5037 "adbPort": 5037
} }
} }
@@ -126,23 +131,24 @@
] ]
}, },
"scripts": { "scripts": {
"postinstall": "node ./node_modules/vscode/bin/install", "prepare": "node ./node_modules/vscode/bin/install",
"test": "node ./node_modules/vscode/bin/test" "test": "node ./node_modules/vscode/bin/test"
}, },
"dependencies": { "dependencies": {
"vscode-debugprotocol": "^1.20.0", "long": "^4.0.0",
"vscode-debugadapter": "^1.20.0", "uuid": "^3.3.2",
"long": "^3.2.0", "vscode-debugadapter": "^1.32.0",
"ws": "^1.1.1", "vscode-debugprotocol": "^1.32.0",
"ws": "^7.1.2",
"xmldom": "^0.1.27", "xmldom": "^0.1.27",
"xpath": "^0.0.23" "xpath": "^0.0.27"
}, },
"devDependencies": { "devDependencies": {
"typescript": "^2.0.3", "@types/mocha": "^5.2.5",
"vscode": "^1.0.0", "@types/node": "^10.12.5",
"mocha": "^2.3.3", "eslint": "^5.9.0",
"eslint": "^3.6.0", "mocha": "^5.2.0",
"@types/node": "^6.0.40", "typescript": "^3.1.6",
"@types/mocha": "^2.2.32" "vscode": "^1.1.26"
} }
} }

View File

@@ -44,7 +44,7 @@ class AndroidContentProvider /*extends TextDocumentContentProvider*/ {
provideLogcatDocumentContent(uri) { provideLogcatDocumentContent(uri) {
// LogcatContent depends upon AndroidContentProvider, so we must delay-load this // LogcatContent depends upon AndroidContentProvider, so we must delay-load this
const { LogcatContent } = require('./logcat'); const { LogcatContent } = require('./logcat');
var doc = this._docs[uri] = new LogcatContent(this, uri); var doc = this._docs[uri] = new LogcatContent(uri.query);
return doc.content; return doc.content;
} }
} }

View File

@@ -17,7 +17,7 @@ const { ADBClient } = require('./adbclient');
const { Debugger } = require('./debugger'); const { Debugger } = require('./debugger');
const $ = require('./jq-promise'); const $ = require('./jq-promise');
const { AndroidThread } = require('./threads'); const { AndroidThread } = require('./threads');
const { D, isEmptyObject } = require('./util'); const { D, onMessagePrint, isEmptyObject } = require('./util');
const { AndroidVariables } = require('./variables'); const { AndroidVariables } = require('./variables');
const { evaluate } = require('./expressions'); const { evaluate } = require('./expressions');
const ws_proxy = require('./wsproxy').proxy.Server(6037, 5037); const ws_proxy = require('./wsproxy').proxy.Server(6037, 5037);
@@ -73,6 +73,9 @@ class AndroidDebugSession extends DebugSession {
// flag to distinguish unexpected disconnection events (initiated from the device) vs user-terminated requests // flag to distinguish unexpected disconnection events (initiated from the device) vs user-terminated requests
this._isDisconnecting = false; this._isDisconnecting = false;
// trace flag for printing diagnostic messages to the client Output Window
this.trace = false;
// this debugger uses one-based lines and columns // this debugger uses one-based lines and columns
this.setDebuggerLinesStartAt1(true); this.setDebuggerLinesStartAt1(true);
this.setDebuggerColumnsStartAt1(true); this.setDebuggerColumnsStartAt1(true);
@@ -106,15 +109,20 @@ class AndroidDebugSession extends DebugSession {
} }
LOG(msg) { LOG(msg) {
if (!this.trace) {
D(msg); D(msg);
}
// VSCode no longer auto-newlines output // VSCode no longer auto-newlines output
this.sendEvent(new OutputEvent(msg + os.EOL)); this.sendEvent(new OutputEvent(msg + os.EOL));
} }
WARN(msg) { WARN(msg) {
D(msg = 'Warning: '+msg); D(msg = 'Warning: '+msg);
// the message will already be sent if trace is enabled
if (!this.trace) {
this.sendEvent(new OutputEvent(msg + os.EOL)); this.sendEvent(new OutputEvent(msg + os.EOL));
} }
}
failRequest(msg, response) { failRequest(msg, response) {
// yeah, it can happen sometimes... // yeah, it can happen sometimes...
@@ -223,6 +231,10 @@ class AndroidDebugSession extends DebugSession {
} }
launchRequest(response/*: DebugProtocol.LaunchResponse*/, args/*: LaunchRequestArguments*/) { launchRequest(response/*: DebugProtocol.LaunchResponse*/, args/*: LaunchRequestArguments*/) {
if (args && args.trace) {
this.trace = args.trace;
onMessagePrint(this.LOG.bind(this));
}
try { D('Launching: ' + JSON.stringify(args)); } catch(ex) {} try { D('Launching: ' + JSON.stringify(args)); } catch(ex) {}
// app_src_root must end in a path-separator for correct validation of sub-paths // app_src_root must end in a path-separator for correct validation of sub-paths
@@ -360,6 +372,9 @@ class AndroidDebugSession extends DebugSession {
this.sendResponse(response); this.sendResponse(response);
return this.dbgr.resume(); return this.dbgr.resume();
}) })
.then(() => {
this.LOG('Application started');
})
.fail(e => { .fail(e => {
// exceptions use message, adbclient uses msg // exceptions use message, adbclient uses msg
this.LOG('Launch failed: '+(e.message||e.msg||'No additional information is available')); this.LOG('Launch failed: '+(e.message||e.msg||'No additional information is available'));
@@ -468,12 +483,12 @@ class AndroidDebugSession extends DebugSession {
} }
catch (err) { continue } catch (err) { continue }
// ignore folders not starting with a known top-level Android folder // ignore folders not starting with a known top-level Android folder
if (!/^(assets|res|src|main|java)([\\/]|$)/.test(p)) continue; if (!/^(assets|res|src|main|java|kotlin)([\\/]|$)/.test(p)) continue;
// is this a package folder // is this a package folder
var pkgmatch = p.match(/^(src|main|java)[\\/](.+)/); var pkgmatch = p.match(/^(src|main|java|kotlin)[\\/](.+)/);
if (pkgmatch && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(pkgmatch[2].split(/[\\/]/).pop())) { if (pkgmatch && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(pkgmatch[2].split(/[\\/]/).pop())) {
// looks good - add it to the list // looks good - add it to the list
const src_folder = pkgmatch[1]; // src, main or java const src_folder = pkgmatch[1]; // src, main, java or kotlin
const pkgname = pkgmatch[2].replace(/[\\/]/g,'.'); const pkgname = pkgmatch[2].replace(/[\\/]/g,'.');
src_packages.packages[pkgname] = { src_packages.packages[pkgname] = {
package: pkgname, package: pkgname,
@@ -521,6 +536,7 @@ class AndroidDebugSession extends DebugSession {
} }
configurationDoneRequest(response/*, args*/) { configurationDoneRequest(response/*, args*/) {
D('configurationDoneRequest');
this.waitForConfigurationDone.resolve(); this.waitForConfigurationDone.resolve();
this.sendResponse(response); this.sendResponse(response);
} }
@@ -551,13 +567,14 @@ class AndroidDebugSession extends DebugSession {
} }
onBreakpointStateChange(e) { onBreakpointStateChange(e) {
D('onBreakpointStateChange');
e.breakpoints.forEach(javabp => { e.breakpoints.forEach(javabp => {
// if there's no associated vsbp we're deleting it, so just ignore the update // if there's no associated vsbp we're deleting it, so just ignore the update
if (!javabp.vsbp) return; if (!javabp.vsbp) return;
var verified = !!javabp.state.match(/set|enabled/); var verified = !!javabp.state.match(/set|enabled/);
javabp.vsbp.verified = verified; javabp.vsbp.verified = verified;
javabp.vsbp.message = null; javabp.vsbp.message = null;
this.sendEvent(new BreakpointEvent('updated', javabp.vsbp)); this.sendEvent(new BreakpointEvent('changed', javabp.vsbp));
}); });
} }
@@ -582,6 +599,14 @@ class AndroidDebugSession extends DebugSession {
return bp; return bp;
} }
const sendBPResponse = (response, breakpoints) => {
D('setBreakPointsRequest response ' + JSON.stringify(breakpoints.map(bp => bp.verified)));
response.body = {
breakpoints,
};
this.sendResponse(response);
}
// the file must lie inside one of the source packages we found (and it must be have a .java extension) // the file must lie inside one of the source packages we found (and it must be have a .java extension)
var srcfolder = path.dirname(srcfpn); var srcfolder = path.dirname(srcfpn);
var pkginfo; var pkginfo;
@@ -589,6 +614,14 @@ class AndroidDebugSession extends DebugSession {
if ((pkginfo = this.src_packages.packages[pkg]).package_path === srcfolder) break; if ((pkginfo = this.src_packages.packages[pkg]).package_path === srcfolder) break;
pkginfo = null; pkginfo = null;
} }
// if we didn't find an exact path match, look for a case-insensitive match
if (!pkginfo) {
for (var pkg in this.src_packages.packages) {
if ((pkginfo = this.src_packages.packages[pkg]).package_path.localeCompare(srcfolder, undefined, { sensitivity: 'base' }) === 0) break;
pkginfo = null;
}
}
// if it's not in our source packages, check if it's in the Android source file cache // if it's not in our source packages, check if it's in the Android source file cache
if (!pkginfo && is_subpath_of(srcfpn, this._android_sources_path)) { if (!pkginfo && is_subpath_of(srcfpn, this._android_sources_path)) {
// create a fake pkginfo to use to construct the bp // create a fake pkginfo to use to construct the bp
@@ -597,10 +630,7 @@ class AndroidDebugSession extends DebugSession {
if (!pkginfo || !/\.(java|kt)$/i.test(srcfpn)) { if (!pkginfo || !/\.(java|kt)$/i.test(srcfpn)) {
// source file is not a java file or is outside of the known source packages // source file is not a java file or is outside of the known source packages
// just send back a list of unverified breakpoints // just send back a list of unverified breakpoints
response.body = { sendBPResponse(response, args.breakpoints.map(bp => unverified_breakpoint(bp, 'The breakpoint location is not valid')));
breakpoints: args.breakpoints.map(bp => unverified_breakpoint(bp, 'The breakpoint location is not valid'))
};
this.sendResponse(response);
return; return;
} }
@@ -667,10 +697,7 @@ class AndroidDebugSession extends DebugSession {
this._setup_breakpoints(this._queue[0]).then(javabp_arr => { this._setup_breakpoints(this._queue[0]).then(javabp_arr => {
// send back the VS Breakpoint instances // send back the VS Breakpoint instances
var response = this._queue[0].response; var response = this._queue[0].response;
response.body = { sendBPResponse(response, javabp_arr.map(javabp => javabp.vsbp));
breakpoints: javabp_arr.map(javabp => javabp.vsbp)
};
this._dbgr.sendResponse(response);
// .. and do the next one // .. and do the next one
this._queue.shift(); this._queue.shift();
this._next(); this._next();

View File

@@ -1425,6 +1425,15 @@ Debugger.prototype = {
cmd: this.JDWP.Commands.lineTable(methodinfo.owningclass, methodinfo), cmd: this.JDWP.Commands.lineTable(methodinfo.owningclass, methodinfo),
}) })
.then(function (linetable, methodinfo) { .then(function (linetable, methodinfo) {
// if the request failed, just return a blank table
if (linetable.errorcode) {
linetable = {
errorcode: linetable.errorcode,
start: '00000000000000000000000000000000',
end: '00000000000000000000000000000000',
lines:[],
}
}
// the linetable does not correlate code indexes with line numbers // the linetable does not correlate code indexes with line numbers
// - location searching relies on the table being ordered by code indexes // - location searching relies on the table being ordered by code indexes
linetable.lines.sort(function (a, b) { linetable.lines.sort(function (a, b) {

View File

@@ -1,5 +1,5 @@
const $ = require('./jq-promise'); const $ = require('./jq-promise');
const { atob,btoa,D,getutf8bytes,fromutf8bytes,intToHex } = require('./util'); const { btoa,D,E,getutf8bytes,fromutf8bytes,intToHex } = require('./util');
/* /*
JDWP - The Java Debug Wire Protocol JDWP - The Java Debug Wire Protocol
*/ */
@@ -96,8 +96,8 @@ function _JDWP() {
return; return;
} }
if (this.errorcode != 0) { if (this.errorcode !== 0) {
console.error("Command failed: error " + this.errorcode, this); E(`JDWP command failed '${this.command.name}'. Error ${this.errorcode}`, this);
} }
if (!this.errorcode && this.command && this.command.replydecodefn) { if (!this.errorcode && this.command && this.command.replydecodefn) {
@@ -109,7 +109,10 @@ function _JDWP() {
return; return;
} }
this.decoded = {empty:true}; this.decoded = {
empty: true,
errorcode: this.errorcode,
};
} }
this.decodereply = function(ths,s) { this.decodereply = function(ths,s) {

View File

@@ -40,7 +40,7 @@ var Deferred = exports.Deferred = function(p, parent) {
var faildef = $.Deferred(null, this); var faildef = $.Deferred(null, this);
var p = this._promise.catch(function(a) { var p = this._promise.catch(function(a) {
if (a.stack) { if (a.stack) {
console.error(a.stack); util.E(a.stack);
a = [a]; a = [a];
} }
if (this.def._context === null && this.def._parent) if (this.def._context === null && this.def._parent)

View File

@@ -15,10 +15,8 @@ const { D } = require('./util');
*/ */
class LogcatContent { class LogcatContent {
constructor(provider/*: AndroidContentProvider*/, uri/*: Uri*/) { constructor(deviceid) {
this._provider = provider; this._logcatid = deviceid;
this._uri = uri;
this._logcatid = uri.query;
this._logs = []; this._logs = [];
this._htmllogs = []; this._htmllogs = [];
this._oldhtmllogs = []; this._oldhtmllogs = [];
@@ -27,7 +25,7 @@ class LogcatContent {
this._refreshRate = 200; // ms this._refreshRate = 200; // ms
this._state = ''; this._state = '';
this._htmltemplate = ''; this._htmltemplate = '';
this._adbclient = new ADBClient(uri.query); this._adbclient = new ADBClient(deviceid);
this._initwait = new Promise((resolve, reject) => { this._initwait = new Promise((resolve, reject) => {
this._state = 'connecting'; this._state = 'connecting';
LogcatContent.initWebSocketServer() LogcatContent.initWebSocketServer()
@@ -79,8 +77,11 @@ class LogcatContent {
}); });
} }
sendClientMessage(msg) { sendClientMessage(msg) {
var clients = LogcatContent._wss.clients.filter(client => client._logcatid === this._logcatid); LogcatContent._wss.clients.forEach(client => {
clients.forEach(client => client.send(msg+'\n')); // include a newline to try and persuade a buffer write if (client._logcatid === this._logcatid) {
client.send(msg + '\n'); // include a newline to try and persuade a buffer write
}
})
} }
sendDisconnectMsg() { sendDisconnectMsg() {
this.sendClientMessage(':disconnect'); this.sendClientMessage(':disconnect');
@@ -113,7 +114,7 @@ class LogcatContent {
} }
updateLogs() { updateLogs() {
// no point in formatting the data if there are no connected clients // no point in formatting the data if there are no connected clients
var clients = LogcatContent._wss.clients.filter(client => client._logcatid === this._logcatid); var clients = [...LogcatContent._wss.clients].filter(client => client._logcatid === this._logcatid);
if (clients.length) { if (clients.length) {
var lines = '<div class="logblock">' + this._htmllogs.join('') + '</div>'; var lines = '<div class="logblock">' + this._htmllogs.join('') + '</div>';
clients.forEach(client => client.send(lines)); clients.forEach(client => client.send(lines));
@@ -189,14 +190,19 @@ LogcatContent.initWebSocketServer = function () {
port: wssport, port: wssport,
retries: 0, retries: 0,
tryCreateWSS() { tryCreateWSS() {
this.wss = new WebSocketServer({ host: '127.0.0.1', port: this.port }, () => { const wsopts = {
host: '127.0.0.1',
port: this.port,
clientTracking: true,
};
this.wss = new WebSocketServer(wsopts, () => {
// success - save the info and resolve the deferred // success - save the info and resolve the deferred
LogcatContent._wssport = this.port; LogcatContent._wssport = this.port;
LogcatContent._wssstartport = this.startport; LogcatContent._wssstartport = this.startport;
LogcatContent._wss = this.wss; LogcatContent._wss = this.wss;
this.wss.on('connection', client => { this.wss.on('connection', (client, req) => {
// the client uses the url path to signify which logcat data it wants // the client uses the url path to signify which logcat data it wants
client._logcatid = client.upgradeReq.url.match(/^\/?(.*)$/)[1]; client._logcatid = req.url.match(/^\/?(.*)$/)[1];
var lc = LogcatContent.byLogcatID[client._logcatid]; var lc = LogcatContent.byLogcatID[client._logcatid];
if (lc) lc.onClientConnect(client); if (lc) lc.onClientConnect(client);
else client.close(); else client.close();
@@ -276,6 +282,21 @@ function openLogcatWindow(vscode) {
.then(devices => { .then(devices => {
if (!Array.isArray(devices)) return; // user cancelled (or no devices connected) if (!Array.isArray(devices)) return; // user cancelled (or no devices connected)
devices.forEach(device => { devices.forEach(device => {
if (vscode.window.createWebviewPanel) {
const panel = vscode.window.createWebviewPanel(
'androidlogcat', // Identifies the type of the webview. Used internally
`logcat-${device.serial}`, // Title of the panel displayed to the user
vscode.ViewColumn.One, // Editor column to show the new webview panel in.
{
enableScripts: true,
}
);
const logcat = new LogcatContent(device.serial);
logcat.content.then(html => {
panel.webview.html = html;
});
return;
}
var uri = AndroidContentProvider.getReadLogcatUri(device.serial); var uri = AndroidContentProvider.getReadLogcatUri(device.serial);
return vscode.commands.executeCommand("vscode.previewHtml",uri,vscode.ViewColumn.Two); return vscode.commands.executeCommand("vscode.previewHtml",uri,vscode.ViewColumn.Two);
}); });

View File

@@ -1,13 +1,18 @@
const crypto = require('crypto'); const crypto = require('crypto');
var nofn = function () { }; var nofn = function () { };
var D = exports.D = console.log.bind(console); const messagePrintCallbacks = new Set();
var E = exports.E = console.error.bind(console); var D = exports.D = (...args) => (console.log(...args), messagePrintCallbacks.forEach(cb => cb(...args)))
var W = exports.W = console.warn.bind(console); var E = exports.E = (...args) => (console.error(...args), messagePrintCallbacks.forEach(cb => cb(...args)))
var W = exports.W = (...args) => (console.warn(...args), messagePrintCallbacks.forEach(cb => cb(...args)))
var DD = nofn, cl = D, printf = D; var DD = nofn, cl = D, printf = D;
var print_jdwp_data = nofn;// _print_jdwp_data; var print_jdwp_data = nofn;// _print_jdwp_data;
var print_packet = nofn;//_print_packet; var print_packet = nofn;//_print_packet;
exports.onMessagePrint = function(cb) {
messagePrintCallbacks.add(cb);
}
Array.first = function (arr, fn, defaultvalue) { Array.first = function (arr, fn, defaultvalue) {
var idx = Array.indexOfFirst(arr, fn); var idx = Array.indexOfFirst(arr, fn);
return idx < 0 ? defaultvalue : arr[idx]; return idx < 0 ? defaultvalue : arr[idx];
@@ -622,9 +627,9 @@ exports.dumparr = function (arr, offset, count) {
} }
exports.btoa = function (arr) { exports.btoa = function (arr) {
return new Buffer(arr, 'binary').toString('base64'); return Buffer.from(arr, 'binary').toString('base64');
} }
exports.atob = function (base64) { exports.atob = function (base64) {
return new Buffer(base64, 'base64').toString('binary'); return Buffer.from(base64, 'base64').toString('binary');
} }