tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

adb.js (5118B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const { clearInterval, setInterval } = ChromeUtils.importESModule(
      8  "resource://gre/modules/Timer.sys.mjs"
      9 );
     10 
     11 const EventEmitter = require("resource://devtools/shared/event-emitter.js");
     12 const {
     13  adbProcess,
     14 } = require("resource://devtools/client/shared/remote-debugging/adb/adb-process.js");
     15 const {
     16  adbAddon,
     17 } = require("resource://devtools/client/shared/remote-debugging/adb/adb-addon.js");
     18 const AdbDevice = require("resource://devtools/client/shared/remote-debugging/adb/adb-device.js");
     19 const {
     20  AdbRuntime,
     21 } = require("resource://devtools/client/shared/remote-debugging/adb/adb-runtime.js");
     22 const {
     23  TrackDevicesCommand,
     24 } = require("resource://devtools/client/shared/remote-debugging/adb/commands/track-devices.js");
     25 loader.lazyRequireGetter(
     26  this,
     27  "check",
     28  "resource://devtools/client/shared/remote-debugging/adb/adb-running-checker.js",
     29  true
     30 );
     31 
     32 // Duration in milliseconds of the runtime polling. We resort to polling here because we
     33 // have no event to know when a runtime started on an already discovered ADB device.
     34 const UPDATE_RUNTIMES_INTERVAL = 3000;
     35 
     36 class Adb extends EventEmitter {
     37  constructor() {
     38    super();
     39 
     40    this._trackDevicesCommand = new TrackDevicesCommand();
     41 
     42    this._isTrackingDevices = false;
     43    this._isUpdatingRuntimes = false;
     44 
     45    this._listeners = new Set();
     46    this._devices = new Map();
     47    this._runtimes = [];
     48 
     49    this._updateAdbProcess = this._updateAdbProcess.bind(this);
     50    this._onDeviceConnected = this._onDeviceConnected.bind(this);
     51    this._onDeviceDisconnected = this._onDeviceDisconnected.bind(this);
     52    this._onNoDevicesDetected = this._onNoDevicesDetected.bind(this);
     53 
     54    this._trackDevicesCommand.on("device-connected", this._onDeviceConnected);
     55    this._trackDevicesCommand.on(
     56      "device-disconnected",
     57      this._onDeviceDisconnected
     58    );
     59    this._trackDevicesCommand.on(
     60      "no-devices-detected",
     61      this._onNoDevicesDetected
     62    );
     63    adbAddon.on("update", this._updateAdbProcess);
     64  }
     65 
     66  registerListener(listener) {
     67    this._listeners.add(listener);
     68    this.on("runtime-list-updated", listener);
     69    this._updateAdbProcess();
     70  }
     71 
     72  unregisterListener(listener) {
     73    this._listeners.delete(listener);
     74    this.off("runtime-list-updated", listener);
     75    this._updateAdbProcess();
     76  }
     77 
     78  async updateRuntimes() {
     79    try {
     80      const devices = [...this._devices.values()];
     81      const promises = devices.map(d => this._getDeviceRuntimes(d));
     82      const allRuntimes = await Promise.all(promises);
     83 
     84      this._runtimes = allRuntimes.flat();
     85      this.emit("runtime-list-updated");
     86    } catch (e) {
     87      console.error(e);
     88    }
     89  }
     90 
     91  getRuntimes() {
     92    return this._runtimes;
     93  }
     94 
     95  getDevices() {
     96    return [...this._devices.values()];
     97  }
     98 
     99  async isProcessStarted() {
    100    return check();
    101  }
    102 
    103  async _startTracking() {
    104    this._isTrackingDevices = true;
    105    await adbProcess.start();
    106 
    107    this._trackDevicesCommand.run();
    108 
    109    // Device runtimes are detected by running a shell command and checking for
    110    // "firefox-debugger-socket" in the list of currently running processes.
    111    this._timer = setInterval(
    112      this.updateRuntimes.bind(this),
    113      UPDATE_RUNTIMES_INTERVAL
    114    );
    115  }
    116 
    117  async _stopTracking() {
    118    clearInterval(this._timer);
    119    this._isTrackingDevices = false;
    120    this._trackDevicesCommand.stop();
    121 
    122    this._devices = new Map();
    123    this._runtimes = [];
    124    this.updateRuntimes();
    125  }
    126 
    127  _shouldTrack() {
    128    return adbAddon.status === "installed" && this._listeners.size > 0;
    129  }
    130 
    131  /**
    132   * This method will emit "runtime-list-ready" to notify the consumer that the list of
    133   * runtimes is ready to be retrieved.
    134   */
    135  async _updateAdbProcess() {
    136    if (!this._isTrackingDevices && this._shouldTrack()) {
    137      const onRuntimesUpdated = this.once("runtime-list-updated");
    138      this._startTracking();
    139      // If we are starting to track runtimes, the list of runtimes will only be ready
    140      // once the first "runtime-list-updated" event has been processed.
    141      await onRuntimesUpdated;
    142    } else if (this._isTrackingDevices && !this._shouldTrack()) {
    143      this._stopTracking();
    144    }
    145    this.emit("runtime-list-ready");
    146  }
    147 
    148  async _onDeviceConnected(deviceId) {
    149    const adbDevice = new AdbDevice(deviceId);
    150    await adbDevice.initialize();
    151    this._devices.set(deviceId, adbDevice);
    152    this.updateRuntimes();
    153  }
    154 
    155  _onDeviceDisconnected(deviceId) {
    156    this._devices.delete(deviceId);
    157    this.updateRuntimes();
    158  }
    159 
    160  _onNoDevicesDetected() {
    161    this.updateRuntimes();
    162  }
    163 
    164  async _getDeviceRuntimes(device) {
    165    const socketPaths = [...(await device.getRuntimeSocketPaths())];
    166    const runtimes = [];
    167    for (const socketPath of socketPaths) {
    168      const runtime = new AdbRuntime(device, socketPath);
    169      await runtime.init();
    170      runtimes.push(runtime);
    171    }
    172    return runtimes;
    173  }
    174 }
    175 
    176 exports.adb = new Adb();