diff options
Diffstat (limited to 'devtools/client/shared/remote-debugging/adb/adb-process.js')
-rw-r--r-- | devtools/client/shared/remote-debugging/adb/adb-process.js | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/devtools/client/shared/remote-debugging/adb/adb-process.js b/devtools/client/shared/remote-debugging/adb/adb-process.js new file mode 100644 index 0000000000..ade509125e --- /dev/null +++ b/devtools/client/shared/remote-debugging/adb/adb-process.js @@ -0,0 +1,155 @@ +/* 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/. */ + +"use strict"; + +const { dumpn } = require("resource://devtools/shared/DevToolsUtils.js"); +const EventEmitter = require("resource://devtools/shared/event-emitter.js"); +const { + getFileForBinary, +} = require("resource://devtools/client/shared/remote-debugging/adb/adb-binary.js"); +const { setTimeout } = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" +); + +loader.lazyRequireGetter( + this, + "runCommand", + "resource://devtools/client/shared/remote-debugging/adb/commands/index.js", + true +); +loader.lazyRequireGetter( + this, + "check", + "resource://devtools/client/shared/remote-debugging/adb/adb-running-checker.js", + true +); + +// Waits until a predicate returns true or re-tries the predicate calls +// |retry| times, we wait for 100ms between each calls. +async function waitUntil(predicate, retry = 20) { + let count = 0; + while (count++ < retry) { + if (await predicate()) { + return true; + } + // Wait for 100 milliseconds. + await new Promise(resolve => setTimeout(resolve, 100)); + } + // Timed out after trying too many times. + return false; +} + +// Class representing the ADB process. +class AdbProcess extends EventEmitter { + constructor() { + super(); + + this._ready = false; + this._didRunInitially = false; + } + + get ready() { + return this._ready; + } + + _getAdbFile() { + if (this._adbFilePromise) { + return this._adbFilePromise; + } + this._adbFilePromise = getFileForBinary(); + return this._adbFilePromise; + } + + async _runProcess(process, params) { + return new Promise((resolve, reject) => { + process.runAsync( + params, + params.length, + { + observe(subject, topic, data) { + switch (topic) { + case "process-finished": + resolve(); + break; + case "process-failed": + reject(); + break; + } + }, + }, + false + ); + }); + } + + // We startup by launching adb in server mode, and setting + // the tcp socket preference to |true| + async start() { + const onSuccessfulStart = () => { + this._ready = true; + this.emit("adb-ready"); + }; + + const isAdbRunning = await check(); + if (isAdbRunning) { + dumpn("Found ADB process running, not restarting"); + onSuccessfulStart(); + return; + } + dumpn("Didn't find ADB process running, restarting"); + + this._didRunInitially = true; + const process = Cc["@mozilla.org/process/util;1"].createInstance( + Ci.nsIProcess + ); + + // FIXME: Bug 1481691 - We should avoid extracting files every time. + const adbFile = await this._getAdbFile(); + process.init(adbFile); + // Hide command prompt window on Windows + process.startHidden = true; + process.noShell = true; + const params = ["start-server"]; + let isStarted = false; + try { + await this._runProcess(process, params); + isStarted = await waitUntil(check); + } catch (e) {} + + if (isStarted) { + onSuccessfulStart(); + } else { + this._ready = false; + throw new Error("ADB Process didn't start"); + } + } + + /** + * Stop the ADB server, but only if we started it. If it was started before + * us, we return immediately. + */ + async stop() { + if (!this._didRunInitially) { + return; // We didn't start the server, nothing to do + } + await this.kill(); + } + + /** + * Kill the ADB server. + */ + async kill() { + try { + await runCommand("host:kill"); + } catch (e) { + dumpn("Failed to send host:kill command"); + } + dumpn("adb server was terminated by host:kill"); + this._ready = false; + this._didRunInitially = false; + } +} + +exports.adbProcess = new AdbProcess(); |