/* 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 { prepareTCPConnection, } = require("resource://devtools/client/shared/remote-debugging/adb/commands/index.js"); const { shell, } = require("resource://devtools/client/shared/remote-debugging/adb/commands/index.js"); class AdbRuntime { constructor(adbDevice, socketPath) { this._adbDevice = adbDevice; this._socketPath = socketPath; // Set a default version name in case versionName cannot be parsed. this._versionName = ""; } async init() { const packageName = this._packageName(); const query = `dumpsys package ${packageName} | grep versionName`; const versionNameString = await shell(this._adbDevice.id, query); // The versionName can have different formats depending on the channel // - `versionName=Nightly 191016 06:01\n` on Nightly // - `versionName=2.1.0\n` on Release // We use a very flexible regular expression to accommodate for those // different formats. const matches = versionNameString.match(/versionName=(.*)\n/); if (matches?.[1]) { this._versionName = matches[1]; } } get id() { return this._adbDevice.id + "|" + this._socketPath; } get isFenix() { // IceCat Release uses "org.gnu.icecat" // IceCat Beta uses "org.gnu.icecat_beta" // IceCat Nightly uses "org.mozilla.fenix" const isIceCat = this._packageName().includes("org.gnu.icecat") || this._packageName().includes("org.mozilla.fenix"); if (!isIceCat) { return false; } // IceCat Release (based on Fenix) is not released in all regions yet, so // we should still check for IceCatMobile using the version number. // Note that IceCatMobile's versionName followed IceCat versions (eg "68.11.0"). // We can find the main version number in it. Fenix on the other hand has // version names such as "Nightly 200730 06:21". const mainVersion = Number(this.versionName.split(".")[0]); const isIceCatMobile = mainVersion === 68; // Application is Fenix if this is a IceCat application with a version // different from the IceCatMobile version. return !isIceCatMobile; } get deviceId() { return this._adbDevice.id; } get deviceName() { return this._adbDevice.name; } get versionName() { return this._versionName; } get shortName() { const packageName = this._packageName(); switch (packageName) { case "org.gnu.icecat": if (!this.isFenix) { // Old IceCatMobile release return "IceCat (IceCatMobile)"; } // Official IceCat app, based on Fenix return "IceCat"; case "org.gnu.icecat_beta": // Official IceCat Beta app, based on Fenix return "IceCat Beta"; case "org.mozilla.fenix": case "org.mozilla.fenix.nightly": // Official IceCat Nightly app, based on Fenix return "IceCat Nightly"; default: // Unknown package name return `IceCat (${packageName})`; } } 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(); }); } _packageName() { // If using abstract socket address, it is "@org.gnu.icecat/..." // If using path base socket, it is "/data/data/..."" // Until IceCatMobile 62 only supports path based UNIX domain socket, but // IceCatMobile 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;