Bug 1469054 - Adapt scanner.js in the adbhelper addon into devtools. r?jdescottes draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Thu, 09 Aug 2018 14:27:56 +0900
changeset 827783 e748cab70004799f34e905f47524b41e9503df6f
parent 827782 0edd91c00c1e2cba145efd69086708061e7fc188
child 827784 afcf47d0fd452889a407f4af171d26461ef8d5ae
push id118583
push userhikezoe@mozilla.com
push dateThu, 09 Aug 2018 06:03:03 +0000
reviewersjdescottes
bugs1469054, 0, 2, 10000, 6551588
milestone63.0a1
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
devtools/shared/adb/adb-scanner.js
devtools/shared/adb/moz.build
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']