Bug 1469054 - Adapt scanner.js in the adbhelper addon into devtools. r?jdescottes
A big difference between them is ADBScanner object itself is exported instead of
exporting unregister() method, since in the new about:debugging we have a toggle
button to install the new adbhelper extension, so that we should observe
uninstalling/installing the new adbhelper extension there, which means when the
adbhelper is removed we have to unregister this scanner there.
The diff;
--- /home/hiro/adbhelper/scanner.js 2018-08-06 09:47:24.199685034 +0900
+++ devtools/shared/adb/adb-scanner.js 2018-08-06 11:52:05.423496900 +0900
@@ -2,19 +2,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-const { Cu } = require("chrome");
-const EventEmitter =
- require("./devtools-require")("devtools/shared/event-emitter");
-const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
-const unload = require("./unload");
+"use strict";
+
+const EventEmitter = require("devtools/shared/event-emitter");
const { ConnectionManager } =
- require("./devtools-require")("devtools/shared/client/connection-manager");
+ require("devtools/shared/client/connection-manager");
const { Devices } =
- require("./devtools-import")("resource://devtools/shared/apps/Devices.jsm");
-const Runtimes =
- require("./devtools-require")("devtools/client/webide/modules/runtimes");
+ require("devtools/shared/apps/Devices.jsm");
+const { RuntimeTypes } =
+ require("devtools/client/webide/modules/runtime-types");
-let Scanner = {
+const ADBScanner = {
_runtimes: [],
@@ -41,9 +39,9 @@ let Scanner = {
return this._updatingPromise;
}
this._runtimes = [];
- let promises = [];
- for (let id of Devices.available()) {
- let device = Devices.getByName(id);
+ const promises = [];
+ for (const id of Devices.available()) {
+ const device = Devices.getByName(id);
promises.push(this._detectRuntimes(device));
}
this._updatingPromise = Promise.all(promises);
@@ -56,13 +54,13 @@ let Scanner = {
return this._updatingPromise;
},
- _detectRuntimes: Task.async(function* (device) {
- let model = yield device.getModel();
- let detectedRuntimes = yield FirefoxOSRuntime.detect(device, model);
+ _detectRuntimes: async function(device) {
+ const model = await device.getModel();
+ let detectedRuntimes = await FirefoxOSRuntime.detect(device, model);
this._runtimes.push(...detectedRuntimes);
- detectedRuntimes = yield FirefoxOnAndroidRuntime.detect(device, model);
+ detectedRuntimes = await FirefoxOnAndroidRuntime.detect(device, model);
this._runtimes.push(...detectedRuntimes);
- }),
+ },
scan() {
return this._updateRuntimes();
@@ -74,7 +72,7 @@ let Scanner = {
};
-EventEmitter.decorate(Scanner);
+EventEmitter.decorate(ADBScanner);
function Runtime(device, model, socketPath) {
this.device = device;
@@ -83,15 +81,15 @@ function Runtime(device, model, socketPa
}
Runtime.prototype = {
- type: Runtimes.RuntimeTypes.USB,
+ type: RuntimeTypes.USB,
connect(connection) {
- let port = ConnectionManager.getFreeTCPPort();
- let local = "tcp:" + port;
+ const port = ConnectionManager.getFreeTCPPort();
+ const local = "tcp:" + port;
let remote;
if (this._socketPath.startsWith("@")) {
- remote = "localabstract:" + this._socketPath.substring(1);
+ remote = "localabstract:" + this._socketPath.substring(1);
} else {
- remote = "localfilesystem:" + this._socketPath;
+ remote = "localfilesystem:" + this._socketPath;
}
return this.device.forwardPort(local, remote).then(() => {
connection.host = "localhost";
@@ -108,26 +106,26 @@ function FirefoxOSRuntime(device, model)
Runtime.call(this, device, model, "/data/local/debugger-socket");
}
-FirefoxOSRuntime.detect = Task.async(function* (device, model) {
- let runtimes = [];
- let query = "test -f /system/b2g/b2g; echo $?";
- let b2gExists = yield device.shell(query);
+FirefoxOSRuntime.detect = async function(device, model) {
+ const runtimes = [];
+ const query = "test -f /system/b2g/b2g; echo $?";
+ let b2gExists = await device.shell(query);
// XXX: Sometimes we get an empty response back. Likely a bug in our shell
// code in this add-on.
// There are also some Android devices that do not have `test` installed.
for (let attempts = 3; attempts > 0; attempts--) {
- b2gExists = yield device.shell(query);
+ b2gExists = await device.shell(query);
if (b2gExists.length == 3) {
break;
}
}
if (b2gExists === "0\r\n") {
- let runtime = new FirefoxOSRuntime(device, model);
+ const runtime = new FirefoxOSRuntime(device, model);
console.log("Found " + runtime.name);
runtimes.push(runtime);
}
return runtimes;
-});
+};
FirefoxOSRuntime.prototype = Object.create(Runtime.prototype);
@@ -142,28 +140,29 @@ function FirefoxOnAndroidRuntime(device,
}
// This requires Unix socket support from Firefox for Android (35+)
-FirefoxOnAndroidRuntime.detect = Task.async(function* (device, model) {
- let runtimes = [];
+FirefoxOnAndroidRuntime.detect = async function(device, model) {
+ const runtimes = [];
// A matching entry looks like:
- // 00000000: 00000002 00000000 00010000 0001 01 6551588 /data/data/org.mozilla.fennec/firefox-debugger-socket
- let query = "cat /proc/net/unix";
- let rawSocketInfo = yield device.shell(query);
+ // 00000000: 00000002 00000000 00010000 0001 01 6551588
+ // /data/data/org.mozilla.fennec/firefox-debugger-socket
+ const query = "cat /proc/net/unix";
+ const rawSocketInfo = await device.shell(query);
let socketInfos = rawSocketInfo.split(/\r?\n/);
// Filter to lines with "firefox-debugger-socket"
socketInfos = socketInfos.filter(l => l.includes("firefox-debugger-socket"));
// It's possible to have multiple lines with the same path, so de-dupe them
- let socketPaths = new Set();
- for (let socketInfo of socketInfos) {
- let socketPath = socketInfo.split(" ").pop();
+ const socketPaths = new Set();
+ for (const socketInfo of socketInfos) {
+ const socketPath = socketInfo.split(" ").pop();
socketPaths.add(socketPath);
}
- for (let socketPath of socketPaths) {
- let runtime = new FirefoxOnAndroidRuntime(device, model, socketPath);
+ for (const socketPath of socketPaths) {
+ const runtime = new FirefoxOnAndroidRuntime(device, model, socketPath);
console.log("Found " + runtime.name);
runtimes.push(runtime);
}
return runtimes;
-});
+};
FirefoxOnAndroidRuntime.prototype = Object.create(Runtime.prototype);
@@ -201,21 +200,4 @@ Object.defineProperty(FirefoxOnAndroidRu
}
});
-exports.register = function() {
- // Only register our |Scanner| if the API exists
- if (Runtimes && Runtimes.RuntimeScanners) {
- // There may be an older ADB scanner registered by default
- // If so, we must disable it to avoid duplicate runtimes
- if (Runtimes.DeprecatedAdbScanner) {
- Runtimes.RuntimeScanners.remove(Runtimes.DeprecatedAdbScanner);
- unload(() => {
- Runtimes.RuntimeScanners.add(Runtimes.DeprecatedAdbScanner);
- });
- }
- // Add our scanner
- Runtimes.RuntimeScanners.add(Scanner);
- unload(() => {
- Runtimes.RuntimeScanners.remove(Scanner);
- });
- }
-};
+exports.ADBScanner = ADBScanner;
MozReview-Commit-ID: 2PC1ochp19E
new file mode 100644
--- /dev/null
+++ b/devtools/shared/adb/adb-scanner.js
@@ -0,0 +1,212 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const EventEmitter = require("devtools/shared/event-emitter");
+const { ConnectionManager } =
+ require("devtools/shared/client/connection-manager");
+const { Devices } =
+ require("devtools/shared/apps/Devices.jsm");
+const { RuntimeTypes } =
+ require("devtools/client/webide/modules/runtime-types");
+
+let Scanner = {
+
+ _runtimes: [],
+
+ enable() {
+ this._updateRuntimes = this._updateRuntimes.bind(this);
+ Devices.on("register", this._updateRuntimes);
+ Devices.on("unregister", this._updateRuntimes);
+ Devices.on("addon-status-updated", this._updateRuntimes);
+ this._updateRuntimes();
+ },
+
+ disable() {
+ Devices.off("register", this._updateRuntimes);
+ Devices.off("unregister", this._updateRuntimes);
+ Devices.off("addon-status-updated", this._updateRuntimes);
+ },
+
+ _emitUpdated() {
+ this.emit("runtime-list-updated");
+ },
+
+ _updateRuntimes() {
+ if (this._updatingPromise) {
+ return this._updatingPromise;
+ }
+ this._runtimes = [];
+ let promises = [];
+ for (let id of Devices.available()) {
+ let device = Devices.getByName(id);
+ promises.push(this._detectRuntimes(device));
+ }
+ this._updatingPromise = Promise.all(promises);
+ this._updatingPromise.then(() => {
+ this._emitUpdated();
+ this._updatingPromise = null;
+ }, () => {
+ this._updatingPromise = null;
+ });
+ return this._updatingPromise;
+ },
+
+ _detectRuntimes: async function(device) {
+ let model = await device.getModel();
+ let detectedRuntimes = await FirefoxOSRuntime.detect(device, model);
+ this._runtimes.push(...detectedRuntimes);
+ detectedRuntimes = await FirefoxOnAndroidRuntime.detect(device, model);
+ this._runtimes.push(...detectedRuntimes);
+ },
+
+ scan() {
+ return this._updateRuntimes();
+ },
+
+ listRuntimes() {
+ return this._runtimes;
+ }
+
+};
+
+EventEmitter.decorate(Scanner);
+
+function Runtime(device, model, socketPath) {
+ this.device = device;
+ this._model = model;
+ this._socketPath = socketPath;
+}
+
+Runtime.prototype = {
+ type: RuntimeTypes.USB,
+ connect(connection) {
+ let port = ConnectionManager.getFreeTCPPort();
+ let local = "tcp:" + port;
+ let remote;
+ if (this._socketPath.startsWith("@")) {
+ remote = "localabstract:" + this._socketPath.substring(1);
+ } else {
+ remote = "localfilesystem:" + this._socketPath;
+ }
+ return this.device.forwardPort(local, remote).then(() => {
+ connection.host = "localhost";
+ connection.port = port;
+ connection.connect();
+ });
+ },
+ get id() {
+ return this.device.id + "|" + this._socketPath;
+ },
+};
+
+// FIXME: Bug 1481691 - Drop code for support FirefoxOS.
+function FirefoxOSRuntime(device, model) {
+ Runtime.call(this, device, model, "/data/local/debugger-socket");
+}
+
+FirefoxOSRuntime.detect = async function(device, model) {
+ let runtimes = [];
+ let query = "test -f /system/b2g/b2g; echo $?";
+ let b2gExists = await device.shell(query);
+ // XXX: Sometimes we get an empty response back. Likely a bug in our shell
+ // code in this add-on.
+ // There are also some Android devices that do not have `test` installed.
+ for (let attempts = 3; attempts > 0; attempts--) {
+ b2gExists = await device.shell(query);
+ if (b2gExists.length == 3) {
+ break;
+ }
+ }
+ if (b2gExists === "0\r\n") {
+ let runtime = new FirefoxOSRuntime(device, model);
+ console.log("Found " + runtime.name);
+ runtimes.push(runtime);
+ }
+ return runtimes;
+};
+
+FirefoxOSRuntime.prototype = Object.create(Runtime.prototype);
+
+Object.defineProperty(FirefoxOSRuntime.prototype, "name", {
+ get() {
+ return this._model || this.device.id;
+ }
+});
+
+function FirefoxOnAndroidRuntime(device, model, socketPath) {
+ Runtime.call(this, device, model, socketPath);
+}
+
+// This requires Unix socket support from Firefox for Android (35+)
+FirefoxOnAndroidRuntime.detect = async function(device, model) {
+ let runtimes = [];
+ // A matching entry looks like:
+ // 00000000: 00000002 00000000 00010000 0001 01 6551588 /data/data/org.mozilla.fennec/firefox-debugger-socket
+ let query = "cat /proc/net/unix";
+ let rawSocketInfo = await device.shell(query);
+ let socketInfos = rawSocketInfo.split(/\r?\n/);
+ // Filter to lines with "firefox-debugger-socket"
+ socketInfos = socketInfos.filter(l => l.includes("firefox-debugger-socket"));
+ // It's possible to have multiple lines with the same path, so de-dupe them
+ let socketPaths = new Set();
+ for (let socketInfo of socketInfos) {
+ let socketPath = socketInfo.split(" ").pop();
+ socketPaths.add(socketPath);
+ }
+ for (let socketPath of socketPaths) {
+ let runtime = new FirefoxOnAndroidRuntime(device, model, socketPath);
+ console.log("Found " + runtime.name);
+ runtimes.push(runtime);
+ }
+ return runtimes;
+};
+
+FirefoxOnAndroidRuntime.prototype = Object.create(Runtime.prototype);
+
+Object.defineProperty(FirefoxOnAndroidRuntime.prototype, "name", {
+ get() {
+ // If using abstract socket address, it is "@org.mozilla.firefox/..."
+ // If using path base socket, it is "/data/data/<package>...""
+ // Until Fennec 62 only supports path based UNIX domain socket, but
+ // Fennec 63+ supports both path based and abstract socket.
+ const packageName = this._socketPath.startsWith("@") ?
+ this._socketPath.substr(1).split("/")[0] :
+ this._socketPath.split("/")[3];
+ let channel;
+ switch (packageName) {
+ case "org.mozilla.firefox":
+ channel = "";
+ break;
+ case "org.mozilla.firefox_beta":
+ channel = " Beta";
+ break;
+ case "org.mozilla.fennec_aurora":
+ // This package name is now the one for Firefox Nightly distributed
+ // through the Google Play Store since "dawn project"
+ // cf. https://bugzilla.mozilla.org/show_bug.cgi?id=1357351#c8
+ channel = " Nightly";
+ break;
+ case "org.mozilla.fennec":
+ channel = " Nightly";
+ break;
+ default:
+ channel = " Custom";
+ }
+ return "Firefox" + channel + " on Android (" +
+ (this._model || this.device.id) + ")";
+ }
+});
+
+exports.register = function() {
+ // Only register our |Scanner| if the API exists
+ if (Runtimes && Runtimes.RuntimeScanners) {
+ Runtimes.RuntimeScanners.add(Scanner);
+ }
+};
+
+exports.unregister = function() {
+ if (Runtimes && Runtimes.RuntimeScanners) {
+ Runtimes.RuntimeScanners.remove(Scanner);
+ }
+};
--- a/devtools/shared/adb/moz.build
+++ b/devtools/shared/adb/moz.build
@@ -1,16 +1,17 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'adb-binary.js',
'adb-client.js',
'adb-running-checker.js',
+ 'adb-scanner.js',
'adb-socket.js',
'adb.js',
)
with Files('**'):
BUG_COMPONENT = ('DevTools', 'about:debugging')
XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini']