tor-browser

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

adb-process.js (3932B)


      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 { dumpn } = require("resource://devtools/shared/DevToolsUtils.js");
      8 const EventEmitter = require("resource://devtools/shared/event-emitter.js");
      9 const {
     10  getFileForBinary,
     11 } = require("resource://devtools/client/shared/remote-debugging/adb/adb-binary.js");
     12 const { setTimeout } = ChromeUtils.importESModule(
     13  "resource://gre/modules/Timer.sys.mjs"
     14 );
     15 
     16 loader.lazyRequireGetter(
     17  this,
     18  "runCommand",
     19  "resource://devtools/client/shared/remote-debugging/adb/commands/index.js",
     20  true
     21 );
     22 loader.lazyRequireGetter(
     23  this,
     24  "check",
     25  "resource://devtools/client/shared/remote-debugging/adb/adb-running-checker.js",
     26  true
     27 );
     28 
     29 // Waits until a predicate returns true or re-tries the predicate calls
     30 // |retry| times, we wait for 100ms between each calls.
     31 async function waitUntil(predicate, retry = 20) {
     32  let count = 0;
     33  while (count++ < retry) {
     34    if (await predicate()) {
     35      return true;
     36    }
     37    // Wait for 100 milliseconds.
     38    await new Promise(resolve => setTimeout(resolve, 100));
     39  }
     40  // Timed out after trying too many times.
     41  return false;
     42 }
     43 
     44 // Class representing the ADB process.
     45 class AdbProcess extends EventEmitter {
     46  constructor() {
     47    super();
     48 
     49    this._ready = false;
     50    this._didRunInitially = false;
     51  }
     52 
     53  get ready() {
     54    return this._ready;
     55  }
     56 
     57  _getAdbFile() {
     58    if (this._adbFilePromise) {
     59      return this._adbFilePromise;
     60    }
     61    this._adbFilePromise = getFileForBinary();
     62    return this._adbFilePromise;
     63  }
     64 
     65  async _runProcess(process, params) {
     66    return new Promise((resolve, reject) => {
     67      process.runAsync(
     68        params,
     69        params.length,
     70        {
     71          observe(subject, topic) {
     72            switch (topic) {
     73              case "process-finished":
     74                resolve();
     75                break;
     76              case "process-failed":
     77                reject();
     78                break;
     79            }
     80          },
     81        },
     82        false
     83      );
     84    });
     85  }
     86 
     87  // We startup by launching adb in server mode, and setting
     88  // the tcp socket preference to |true|
     89  async start() {
     90    const onSuccessfulStart = () => {
     91      this._ready = true;
     92      this.emit("adb-ready");
     93    };
     94 
     95    const isAdbRunning = await check();
     96    if (isAdbRunning) {
     97      dumpn("Found ADB process running, not restarting");
     98      onSuccessfulStart();
     99      return;
    100    }
    101    dumpn("Didn't find ADB process running, restarting");
    102 
    103    this._didRunInitially = true;
    104    const process = Cc["@mozilla.org/process/util;1"].createInstance(
    105      Ci.nsIProcess
    106    );
    107 
    108    // FIXME: Bug 1481691 - We should avoid extracting files every time.
    109    const adbFile = await this._getAdbFile();
    110    process.init(adbFile);
    111    // Hide command prompt window on Windows
    112    process.startHidden = true;
    113    process.noShell = true;
    114    const params = ["start-server"];
    115    let isStarted = false;
    116    try {
    117      await this._runProcess(process, params);
    118      isStarted = await waitUntil(check);
    119    } catch (e) {}
    120 
    121    if (isStarted) {
    122      onSuccessfulStart();
    123    } else {
    124      this._ready = false;
    125      throw new Error("ADB Process didn't start");
    126    }
    127  }
    128 
    129  /**
    130   * Stop the ADB server, but only if we started it.  If it was started before
    131   * us, we return immediately.
    132   */
    133  async stop() {
    134    if (!this._didRunInitially) {
    135      return; // We didn't start the server, nothing to do
    136    }
    137    await this.kill();
    138  }
    139 
    140  /**
    141   * Kill the ADB server.
    142   */
    143  async kill() {
    144    try {
    145      await runCommand("host:kill");
    146    } catch (e) {
    147      dumpn("Failed to send host:kill command");
    148    }
    149    dumpn("adb server was terminated by host:kill");
    150    this._ready = false;
    151    this._didRunInitially = false;
    152  }
    153 }
    154 
    155 exports.adbProcess = new AdbProcess();