mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-23 01:48:18 +00:00
Refactored setBreakPointsRequest
Breakpoints are now updated using an async queue Allow source locations inside ANDROID_HOME Fixes #14
This commit is contained in:
@@ -54,6 +54,12 @@ function ensure_path_end_slash(p) {
|
|||||||
return p + (/[\\/]$/.test(p) ? '' : path.sep);
|
return p + (/[\\/]$/.test(p) ? '' : path.sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_subpath_of(fpn, subpath) {
|
||||||
|
if (!subpath || !fpn) return false;
|
||||||
|
subpath = ensure_path_end_slash(''+subpath);
|
||||||
|
return fpn.slice(0,subpath.length) === subpath;
|
||||||
|
}
|
||||||
|
|
||||||
function decode_char(c) {
|
function decode_char(c) {
|
||||||
switch(true) {
|
switch(true) {
|
||||||
case /^\\[^u]$/.test(c):
|
case /^\\[^u]$/.test(c):
|
||||||
@@ -520,11 +526,16 @@ 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 (!pkginfo || !/\.java$/.test(srcfpn)) {
|
// 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)) {
|
||||||
|
// create a fake pkginfo to use to construct the bp
|
||||||
|
pkginfo = { srcroot:this._android_sources_path }
|
||||||
|
}
|
||||||
|
if (!pkginfo || !/\.java$/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 = {
|
response.body = {
|
||||||
breakpoints: args.breakpoints.map(bp => unverified_breakpoint(bp, 'The breakpoint location is outside of the project source tree'))
|
breakpoints: args.breakpoints.map(bp => unverified_breakpoint(bp, 'The breakpoint location is not valid'))
|
||||||
};
|
};
|
||||||
this.sendResponse(response);
|
this.sendResponse(response);
|
||||||
return;
|
return;
|
||||||
@@ -532,7 +543,7 @@ class AndroidDebugSession extends DebugSession {
|
|||||||
|
|
||||||
// our debugger requires a relative fpn beginning with / , rooted at the java source base folder
|
// our debugger requires a relative fpn beginning with / , rooted at the java source base folder
|
||||||
// - it should look like: /some/package/name/abc.java
|
// - it should look like: /some/package/name/abc.java
|
||||||
var relative_fpn = srcfpn.slice(pkginfo.srcroot.length);
|
var relative_fpn = srcfpn.slice(pkginfo.srcroot.match(/^(.*?)[\\/]?$/)[1].length);
|
||||||
|
|
||||||
// delete any existing breakpoints not in the list
|
// delete any existing breakpoints not in the list
|
||||||
var src_line_nums = args.breakpoints.map(bp => bp.line);
|
var src_line_nums = args.breakpoints.map(bp => bp.line);
|
||||||
@@ -543,7 +554,14 @@ class AndroidDebugSession extends DebugSession {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// return the list of new and existing breakpoints
|
// return the list of new and existing breakpoints
|
||||||
var breakpoints = args.breakpoints.map((src_bp,idx) => {
|
// - setting a debugger bp is now asynchronous, so we do this as an orderly queue
|
||||||
|
const _setup_breakpoints = (o, idx, javabp_arr) => {
|
||||||
|
javabp_arr = javabp_arr || [];
|
||||||
|
var src_bp = o.args.breakpoints[idx|=0];
|
||||||
|
if (!src_bp) {
|
||||||
|
// done
|
||||||
|
return $.Deferred().resolveWith(this, [javabp_arr]);
|
||||||
|
}
|
||||||
var dbgline = this.convertClientLineToDebugger(src_bp.line);
|
var dbgline = this.convertClientLineToDebugger(src_bp.line);
|
||||||
var options = {};
|
var options = {};
|
||||||
if (src_bp.hitCondition) {
|
if (src_bp.hitCondition) {
|
||||||
@@ -554,7 +572,8 @@ class AndroidDebugSession extends DebugSession {
|
|||||||
if (!m || hitcount < 0 || hitcount > 0x7fffffff) return unverified_breakpoint(src_bp, 'The breakpoint is configured with an invalid hit count value');
|
if (!m || hitcount < 0 || hitcount > 0x7fffffff) return unverified_breakpoint(src_bp, 'The breakpoint is configured with an invalid hit count value');
|
||||||
options.hitcount = hitcount;
|
options.hitcount = hitcount;
|
||||||
}
|
}
|
||||||
var javabp = this.dbgr.setbreakpoint(relative_fpn, dbgline, options);
|
return this.dbgr.setbreakpoint(o.relative_fpn, dbgline, options)
|
||||||
|
.then(javabp => {
|
||||||
if (!javabp.vsbp) {
|
if (!javabp.vsbp) {
|
||||||
// state is one of: set,notloaded,enabled,removed
|
// state is one of: set,notloaded,enabled,removed
|
||||||
var verified = !!javabp.state.match(/set|enabled/);
|
var verified = !!javabp.state.match(/set|enabled/);
|
||||||
@@ -566,14 +585,38 @@ class AndroidDebugSession extends DebugSession {
|
|||||||
javabp.vsbp = bp;
|
javabp.vsbp = bp;
|
||||||
}
|
}
|
||||||
javabp.vsbp.order = idx;
|
javabp.vsbp.order = idx;
|
||||||
return javabp.vsbp;
|
javabp_arr.push(javabp);
|
||||||
});
|
}).
|
||||||
|
then(javabp => _setup_breakpoints(o, ++idx, javabp_arr));
|
||||||
// send back the actual breakpoint positions
|
|
||||||
response.body = {
|
|
||||||
breakpoints: breakpoints
|
|
||||||
};
|
};
|
||||||
this.sendResponse(response);
|
|
||||||
|
if (!this._set_breakpoints_queue) {
|
||||||
|
this._set_breakpoints_queue = {
|
||||||
|
_dbgr:this,
|
||||||
|
_queue:[],
|
||||||
|
add(item) {
|
||||||
|
if (this._queue.push(item) > 1) return;
|
||||||
|
this._next();
|
||||||
|
},
|
||||||
|
_setup_breakpoints: _setup_breakpoints,
|
||||||
|
_next() {
|
||||||
|
if (!this._queue.length) return; // done
|
||||||
|
this._setup_breakpoints(this._queue[0]).then(javabp_arr => {
|
||||||
|
// send back the VS Breakpoint instances
|
||||||
|
var response = this._queue[0].response;
|
||||||
|
response.body = {
|
||||||
|
breakpoints: javabp_arr.map(javabp => javabp.vsbp)
|
||||||
|
};
|
||||||
|
this._dbgr.sendResponse(response);
|
||||||
|
// .. and do the next one
|
||||||
|
this._queue.shift();
|
||||||
|
this._next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this._set_breakpoints_queue.add({args,response,relative_fpn});
|
||||||
}
|
}
|
||||||
|
|
||||||
setExceptionBreakPointsRequest(response /*: SetExceptionBreakpointsResponse*/, args /*: SetExceptionBreakpointsArguments*/) {
|
setExceptionBreakPointsRequest(response /*: SetExceptionBreakpointsResponse*/, args /*: SetExceptionBreakpointsArguments*/) {
|
||||||
|
|||||||
@@ -137,8 +137,8 @@ Debugger.prototype = {
|
|||||||
adbclient: null,
|
adbclient: null,
|
||||||
stoppedlocation: null,
|
stoppedlocation: null,
|
||||||
classes: {},
|
classes: {},
|
||||||
// classprepare notifier done
|
// classprepare filters
|
||||||
cpndone: false,
|
cpfilters: [],
|
||||||
preparedclasses: [],
|
preparedclasses: [],
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@@ -502,7 +502,7 @@ Debugger.prototype = {
|
|||||||
var cls = this._splitsrcfpn(srcfpn);
|
var cls = this._splitsrcfpn(srcfpn);
|
||||||
var bid = cls.qtype + ':' + line;
|
var bid = cls.qtype + ':' + line;
|
||||||
var newbp = this.breakpoints.bysrcloc[bid];
|
var newbp = this.breakpoints.bysrcloc[bid];
|
||||||
if (newbp) return newbp;
|
if (newbp) return $.Deferred().resolveWith(this, [newbp]);
|
||||||
newbp = {
|
newbp = {
|
||||||
id: bid,
|
id: bid,
|
||||||
srcfpn: srcfpn,
|
srcfpn: srcfpn,
|
||||||
@@ -522,25 +522,25 @@ Debugger.prototype = {
|
|||||||
// what happens next depends upon what state we are in
|
// what happens next depends upon what state we are in
|
||||||
switch (this.status()) {
|
switch (this.status()) {
|
||||||
case 'connected':
|
case 'connected':
|
||||||
//this._changebpstate([newbp], 'set');
|
|
||||||
//this._changebpstate([newbp], 'notloaded');
|
|
||||||
newbp.state = 'notloaded';
|
newbp.state = 'notloaded';
|
||||||
if (this.session.cpndone) {
|
// try and load the class - if the runtime hasn't loaded it yet, this will just return an empty classes object
|
||||||
var bploc = this._findbplocation(this.session.classes, newbp);
|
return this._loadclzinfo('L'+newbp.qtype+';')
|
||||||
if (bploc) {
|
.then(classes => {
|
||||||
this._setupbreakpointsevent([bploc]);
|
if (!Object.keys(classes).length)
|
||||||
}
|
return this._ensureClassPrepareForPackage(newbp.pkg);
|
||||||
}
|
var bploc = this._findbplocation(classes, newbp);
|
||||||
break;
|
if (bploc)
|
||||||
|
return this._setupbreakpointsevent([bploc]);
|
||||||
|
})
|
||||||
|
.then(() => newbp)
|
||||||
case 'connecting':
|
case 'connecting':
|
||||||
case 'disconnected':
|
case 'disconnected':
|
||||||
default:
|
default:
|
||||||
//this._changebpstate([newbp], 'set');
|
|
||||||
newbp.state = 'set';
|
newbp.state = 'set';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return newbp;
|
return $.Deferred().resolveWith(this, [newbp]);
|
||||||
},
|
},
|
||||||
|
|
||||||
clearbreakpoint: function (srcfpn, line) {
|
clearbreakpoint: function (srcfpn, line) {
|
||||||
@@ -1456,29 +1456,28 @@ Debugger.prototype = {
|
|||||||
|
|
||||||
_initbreakpoints: function () {
|
_initbreakpoints: function () {
|
||||||
var deferreds = [{ dbgr: this }];
|
var deferreds = [{ dbgr: this }];
|
||||||
var donetypes = {};
|
|
||||||
// reset any current associations
|
// reset any current associations
|
||||||
this.breakpoints.enabled = {};
|
this.breakpoints.enabled = {};
|
||||||
// set all the breakpoints to the notloaded state
|
// set all the breakpoints to the notloaded state
|
||||||
this._changebpstate(this.breakpoints.all, 'notloaded');
|
this._changebpstate(this.breakpoints.all, 'notloaded');
|
||||||
|
|
||||||
// setup class prepare notifications for all the current packages
|
// setup class prepare notifications for all the packages associated with breakpoints
|
||||||
// when each class is prepared, we initialise any breakpoints for it
|
// when each class is prepared, we initialise any breakpoints for it
|
||||||
for (var pkg in this.session.build.packages) {
|
var cpdefs = this.breakpoints.all.map(bp => this._ensureClassPrepareForPackage(bp.pkg));
|
||||||
try {
|
deferreds = deferreds.concat(cpdefs);
|
||||||
var def = this._setupclassprepareevent(pkg + '.*', _onclassprepared);
|
|
||||||
deferreds.push(def);
|
|
||||||
} catch (e) {
|
|
||||||
D('Ignoring additional class prepared notification for: ' + preppedclass.type.signature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $.when.apply($, deferreds).then(function (x) {
|
return $.when.apply($, deferreds).then(function (x) {
|
||||||
x.dbgr.session.cpndone = true;
|
|
||||||
return $.Deferred().resolveWith(x.dbgr);
|
return $.Deferred().resolveWith(x.dbgr);
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
function _onclassprepared(preppedclass) {
|
_ensureClassPrepareForPackage: function(pkg) {
|
||||||
|
var filter = pkg + '.*';
|
||||||
|
if (this.session.cpfilters.includes(filter))
|
||||||
|
return $.Deferred().resolveWith(this,[]); // already setup
|
||||||
|
|
||||||
|
this.session.cpfilters.push(filter);
|
||||||
|
return this._setupclassprepareevent(filter, preppedclass => {
|
||||||
// if the class prepare events have overlapping packages (mypackage.*, mypackage.another.*), we will get
|
// if the class prepare events have overlapping packages (mypackage.*, mypackage.another.*), we will get
|
||||||
// multiple notifications (which duplicates breakpoints, etc)
|
// multiple notifications (which duplicates breakpoints, etc)
|
||||||
if (this.session.preparedclasses.includes(preppedclass.type.signature)) {
|
if (this.session.preparedclasses.includes(preppedclass.type.signature)) {
|
||||||
@@ -1502,6 +1501,7 @@ Debugger.prototype = {
|
|||||||
bplocs.push(bploc);
|
bplocs.push(bploc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!bplocs.length) return;
|
||||||
// set all the breakpoints in one go...
|
// set all the breakpoints in one go...
|
||||||
return this._setupbreakpointsevent(bplocs);
|
return this._setupbreakpointsevent(bplocs);
|
||||||
})
|
})
|
||||||
@@ -1509,7 +1509,7 @@ Debugger.prototype = {
|
|||||||
// when all the breakpoints for the newly-prepared type have been set...
|
// when all the breakpoints for the newly-prepared type have been set...
|
||||||
this._resumesilent();
|
this._resumesilent();
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
clearBreakOnExceptions: function(extra) {
|
clearBreakOnExceptions: function(extra) {
|
||||||
|
|||||||
Reference in New Issue
Block a user