Bug 1505289 - Move unknown runtime logic to aboutdebugging r=Ola,ladybenko
authorJulian Descottes <jdescottes@mozilla.com>
Mon, 15 Apr 2019 22:23:01 +0000
changeset 469619 88f37063a1ff
parent 469618 10fd2d1f0fa2
child 469620 d864f9d6ce00
push id35878
push userapavel@mozilla.com
push dateTue, 16 Apr 2019 15:43:40 +0000
treeherdermozilla-central@258af4e91151 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersOla, ladybenko
bugs1505289
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1505289 - Move unknown runtime logic to aboutdebugging r=Ola,ladybenko The notion of unknown runtime is only relevant to aboutdebugging As we will complexify this to handle unplugged devices, moving it to aboutdebugging seems reasonable. Differential Revision: https://phabricator.services.mozilla.com/D25779
devtools/client/aboutdebugging-new/aboutdebugging.js
devtools/client/aboutdebugging-new/src/actions/runtimes.js
devtools/client/aboutdebugging-new/src/modules/usb-runtimes.js
devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_usb_unknown_runtime.js
devtools/client/aboutdebugging-new/test/browser/helper-mocks.js
devtools/client/webide/modules/runtimes.js
devtools/shared/adb/adb-runtime.js
devtools/shared/adb/adb.js
--- a/devtools/client/aboutdebugging-new/aboutdebugging.js
+++ b/devtools/client/aboutdebugging-new/aboutdebugging.js
@@ -97,18 +97,19 @@ const AboutDebugging = {
   onAdbAddonUpdated() {
     this.actions.updateAdbAddonStatus(adbAddon.status);
   },
 
   onNetworkLocationsUpdated() {
     this.actions.updateNetworkLocations(getNetworkLocations());
   },
 
-  onUSBRuntimesUpdated() {
-    this.actions.updateUSBRuntimes(getUSBRuntimes());
+  async onUSBRuntimesUpdated() {
+    const runtimes = await getUSBRuntimes();
+    this.actions.updateUSBRuntimes(runtimes);
   },
 
   async destroy() {
     const width = this.getRoundedViewportWidth();
     this.actions.recordTelemetryEvent("close_adbg", { width });
 
     const state = this.store.getState();
     const currentRuntimeId = state.runtimes.selectedRuntimeId;
--- a/devtools/client/aboutdebugging-new/src/actions/runtimes.js
+++ b/devtools/client/aboutdebugging-new/src/actions/runtimes.js
@@ -326,29 +326,29 @@ function updateNetworkRuntimes(locations
     };
   });
   return updateRemoteRuntimes(runtimes, RUNTIMES.NETWORK);
 }
 
 function updateUSBRuntimes(adbRuntimes) {
   const runtimes = adbRuntimes.map(adbRuntime => {
     // Set connectionParameters only for known runtimes.
-    const socketPath = adbRuntime._socketPath;
+    const socketPath = adbRuntime.socketPath;
     const deviceId = adbRuntime.deviceId;
-    const connectionParameters = adbRuntime.isUnknown() ? null : { deviceId, socketPath };
+    const connectionParameters = socketPath ? { deviceId, socketPath } : null;
     return {
       id: adbRuntime.id,
       extra: {
         connectionParameters,
         deviceName: adbRuntime.deviceName,
       },
       isConnecting: false,
       isConnectionFailed: false,
       isConnectionNotResponding: false,
-      isUnknown: adbRuntime.isUnknown(),
+      isUnknown: adbRuntime.isUnknown,
       name: adbRuntime.shortName,
       type: RUNTIMES.USB,
     };
   });
   return updateRemoteRuntimes(runtimes, RUNTIMES.USB);
 }
 
 /**
--- a/devtools/client/aboutdebugging-new/src/modules/usb-runtimes.js
+++ b/devtools/client/aboutdebugging-new/src/modules/usb-runtimes.js
@@ -2,26 +2,66 @@
  * 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/. */
 
 "use strict";
 
 loader.lazyRequireGetter(this, "adb", "devtools/shared/adb/adb", true);
 
 /**
+ * Used to represent a regular runtime returned by ADB.
+ */
+class UsbRuntime {
+  constructor(adbRuntime) {
+    this.id = adbRuntime.id;
+    this.deviceId = adbRuntime.deviceId;
+    this.deviceName = adbRuntime.deviceName;
+    this.shortName = adbRuntime.shortName;
+    this.socketPath = adbRuntime.socketPath;
+    this.isUnknown = false;
+    this.isUnplugged = false;
+  }
+}
+
+/**
+ * Used when a device was detected, meaning USB debugging is enabled on the device, but no
+ * runtime/browser is available for connection.
+ */
+class UnknownUsbRuntime {
+  constructor(adbDevice) {
+    this.id = adbDevice.id + "|unknown";
+    this.deviceId = adbDevice.id;
+    this.deviceName = adbDevice.name;
+    this.shortName = "Unknown runtime";
+    this.socketPath = null;
+    this.isUnknown = true;
+    this.isUnplugged = false;
+  }
+}
+
+/**
  * This module provides a collection of helper methods to detect USB runtimes whom Firefox
  * is running on.
  */
 function addUSBRuntimesObserver(listener) {
   adb.registerListener(listener);
 }
 exports.addUSBRuntimesObserver = addUSBRuntimesObserver;
 
-function getUSBRuntimes() {
-  return adb.getRuntimes();
+async function getUSBRuntimes() {
+  // Get the available runtimes
+  const runtimes = adb.getRuntimes().map(r => new UsbRuntime(r));
+
+  // Get devices found by ADB, but without any available runtime.
+  const runtimeDevices = runtimes.map(r => r.deviceId);
+  const unknownRuntimes = adb.getDevices()
+    .filter(d => !runtimeDevices.includes(d.id))
+    .map(d => new UnknownUsbRuntime(d));
+
+  return runtimes.concat(unknownRuntimes);
 }
 exports.getUSBRuntimes = getUSBRuntimes;
 
 function removeUSBRuntimesObserver(listener) {
   adb.unregisterListener(listener);
 }
 exports.removeUSBRuntimesObserver = removeUSBRuntimesObserver;
 
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_usb_unknown_runtime.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_usb_unknown_runtime.js
@@ -11,17 +11,19 @@ const RUNTIME_NAME = "Firefox 123";
 // - display a specific text ("Waiting for runtime") instead of the runtime name
 add_task(async function() {
   const mocks = new Mocks();
   const { document, tab } = await openAboutDebugging();
 
   info("Create a mocked unknown runtime");
   let isUnknown = true;
   mocks.createUSBRuntime("test_device_id", {
-    isUnknown: () => isUnknown,
+    get isUnknown() {
+      return isUnknown;
+    },
     // Here shortName would rather be Unknown Runtime from adb-runtime, but we only want
     // to check the runtime name does not appear in the UI.
     shortName: RUNTIME_NAME,
   });
   mocks.emitUSBUpdate();
 
   info("Wait until the USB sidebar item appears");
   await waitUntil(() => findSidebarItemByText("test device name", document));
--- a/devtools/client/aboutdebugging-new/test/browser/helper-mocks.js
+++ b/devtools/client/aboutdebugging-new/test/browser/helper-mocks.js
@@ -123,19 +123,21 @@ class Mocks {
    *        - version: {String} Version, for instance "63.0a"
    * @return {Object} Returns the mock client created for this runtime so that methods
    * can be overridden on it.
    */
   createUSBRuntime(id, runtimeInfo = {}) {
     // Add a new runtime to the list of scanned runtimes.
     this._usbRuntimes.push({
       id: id,
-      _socketPath: runtimeInfo.socketPath || "test/path",
+      socketPath: runtimeInfo.socketPath || "test/path",
       deviceName: runtimeInfo.deviceName || "test device name",
-      isUnknown: runtimeInfo.isUnknown || (() => false),
+      get isUnknown() {
+        return runtimeInfo.isUnknown || false;
+      },
       shortName: runtimeInfo.shortName || "testshort",
     });
 
     // Add a valid client that can be returned for this particular runtime id.
     const mockUsbClient = createClientMock();
     mockUsbClient.getDeviceDescription = () => {
       return {
         channel: runtimeInfo.channel || "release",
--- a/devtools/client/webide/modules/runtimes.js
+++ b/devtools/client/webide/modules/runtimes.js
@@ -204,17 +204,17 @@ var UsbScanner = {
   },
   disable() {
     adb.unregisterListener(this._emitUpdated);
   },
   scan() {
     return adb.updateRuntimes();
   },
   listRuntimes() {
-    return adb.getRuntimes().filter(r => !r.isUnknown());
+    return adb.getRuntimes();
   },
   _emitUpdated() {
     this.emit("runtime-list-updated");
   },
 };
 EventEmitter.decorate(UsbScanner);
 UsbScanner.init();
 RuntimeScanners.add(UsbScanner);
--- a/devtools/shared/adb/adb-runtime.js
+++ b/devtools/shared/adb/adb-runtime.js
@@ -26,32 +26,32 @@ class AdbRuntime {
   get deviceName() {
     return this._adbDevice.name;
   }
 
   get shortName() {
     return `Firefox ${this._channel()}`;
   }
 
+  get socketPath() {
+    return this._socketPath;
+  }
+
   get name() {
     return `${this.shortName} on Android (${this.deviceName})`;
   }
 
   connect(connection) {
     return prepareTCPConnection(this.deviceId, this._socketPath).then(port => {
       connection.host = "localhost";
       connection.port = port;
       connection.connect();
     });
   }
 
-  isUnknown() {
-    return false;
-  }
-
   _channel() {
     const packageName = this._packageName();
 
     switch (packageName) {
       case "org.mozilla.firefox":
         return "";
       case "org.mozilla.firefox_beta":
         return "Beta";
@@ -72,36 +72,8 @@ class AdbRuntime {
     // Until Fennec 62 only supports path based UNIX domain socket, but
     // Fennec 63+ supports both path based and abstract socket.
     return this._socketPath.startsWith("@") ?
       this._socketPath.substr(1).split("/")[0] :
       this._socketPath.split("/")[3];
   }
 }
 exports.AdbRuntime = AdbRuntime;
-
-/**
- * UnknownAdbRuntime instance will be used to represent devices which have USB debugging
- * enabled but where Firefox (or another debuggable gecko-based runtime) is either not
- * started or not ready for USB debugging.
- */
-class UnknownAdbRuntime extends AdbRuntime {
-  constructor(adbDevice) {
-    super(adbDevice);
-  }
-
-  get id() {
-    return this._adbDevice.id;
-  }
-
-  get shortName() {
-    return "Unknown runtime";
-  }
-
-  connect(connection) {
-    throw new Error("Cannot connect on unknown runtime");
-  }
-
-  isUnknown() {
-    return true;
-  }
-}
-exports.UnknownAdbRuntime = UnknownAdbRuntime;
--- a/devtools/shared/adb/adb.js
+++ b/devtools/shared/adb/adb.js
@@ -5,17 +5,17 @@
 "use strict";
 
 const { clearInterval, setInterval } = require("resource://gre/modules/Timer.jsm");
 
 const EventEmitter = require("devtools/shared/event-emitter");
 const { adbProcess } = require("devtools/shared/adb/adb-process");
 const { adbAddon } = require("devtools/shared/adb/adb-addon");
 const AdbDevice = require("devtools/shared/adb/adb-device");
-const { AdbRuntime, UnknownAdbRuntime } = require("devtools/shared/adb/adb-runtime");
+const { AdbRuntime } = require("devtools/shared/adb/adb-runtime");
 const { TrackDevicesCommand } = require("devtools/shared/adb/commands/track-devices");
 
 // Duration in milliseconds of the runtime polling. We resort to polling here because we
 // have no event to know when a runtime started on an already discovered ADB device.
 const UPDATE_RUNTIMES_INTERVAL = 3000;
 
 class Adb extends EventEmitter {
   constructor() {
@@ -63,16 +63,20 @@ class Adb extends EventEmitter {
       console.error(e);
     }
   }
 
   getRuntimes() {
     return this._runtimes;
   }
 
+  getDevices() {
+    return [...this._devices.values()];
+  }
+
   async _startTracking() {
     this._isTrackingDevices = true;
     await adbProcess.start();
 
     this._trackDevicesCommand.run();
 
     // Device runtimes are detected by running a shell command and checking for
     // "firefox-debugger-socket" in the list of currently running processes.
@@ -110,16 +114,13 @@ class Adb extends EventEmitter {
 
   _onDeviceDisconnected(deviceId) {
     this._devices.delete(deviceId);
     this.updateRuntimes();
   }
 
   async _getDeviceRuntimes(device) {
     const socketPaths = [...await device.getRuntimeSocketPaths()];
-    if (socketPaths.length === 0) {
-      return [new UnknownAdbRuntime(device)];
-    }
     return socketPaths.map(socketPath => new AdbRuntime(device, socketPath));
   }
 }
 
 exports.adb = new Adb();