diff options
Diffstat (limited to 'devtools/client/shared/remote-debugging/adb/adb-addon.js')
-rw-r--r-- | devtools/client/shared/remote-debugging/adb/adb-addon.js | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/devtools/client/shared/remote-debugging/adb/adb-addon.js b/devtools/client/shared/remote-debugging/adb/adb-addon.js new file mode 100644 index 0000000000..ddce411cb3 --- /dev/null +++ b/devtools/client/shared/remote-debugging/adb/adb-addon.js @@ -0,0 +1,186 @@ +/* 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 { AddonManager } = ChromeUtils.importESModule( + "resource://gre/modules/AddonManager.sys.mjs", + // AddonManager is a singleton, never create two instances of it. + { loadInDevToolsLoader: false } +); +const EventEmitter = require("resource://devtools/shared/event-emitter.js"); + +const PREF_ADB_EXTENSION_URL = "devtools.remote.adb.extensionURL"; +const PREF_ADB_EXTENSION_ID = "devtools.remote.adb.extensionID"; + +const ADB_ADDON_STATES = { + DOWNLOADING: "downloading", + INSTALLED: "installed", + INSTALLING: "installing", + PREPARING: "preparing", + UNINSTALLED: "uninstalled", + UNKNOWN: "unknown", +}; +exports.ADB_ADDON_STATES = ADB_ADDON_STATES; + +/** + * Wrapper around the ADB Extension providing ADB binaries for devtools remote debugging. + * Fires the following events: + * - "update": the status of the addon was updated + * - "failure": addon installation failed + * - "progress": addon download in progress + * + * AdbAddon::state can take any of the values from ADB_ADDON_STATES. + */ +class ADBAddon extends EventEmitter { + constructor() { + super(); + + this._status = ADB_ADDON_STATES.UNKNOWN; + + const addonsListener = {}; + addonsListener.onEnabled = + addonsListener.onDisabled = + addonsListener.onInstalled = + addonsListener.onUninstalled = + () => this.updateInstallStatus(); + AddonManager.addAddonListener(addonsListener); + + this.updateInstallStatus(); + } + + set status(value) { + if (this._status != value) { + this._status = value; + this.emit("update"); + } + } + + get status() { + return this._status; + } + + async _getAddon() { + const addonId = Services.prefs.getCharPref(PREF_ADB_EXTENSION_ID); + return AddonManager.getAddonByID(addonId); + } + + async updateInstallStatus() { + const addon = await this._getAddon(); + if (addon && !addon.userDisabled) { + this.status = ADB_ADDON_STATES.INSTALLED; + } else { + this.status = ADB_ADDON_STATES.UNINSTALLED; + } + } + + /** + * Returns the platform specific download link for the ADB extension. + */ + _getXpiLink() { + const platform = Services.appShell.hiddenDOMWindow.navigator.platform; + let OS = ""; + if (platform.includes("Win")) { + OS = "win32"; + } else if (platform.includes("Mac")) { + OS = "mac64"; + } else if (platform.includes("Linux")) { + if (platform.includes("x86_64")) { + OS = "linux64"; + } else { + OS = "linux"; + } + } + + const xpiLink = Services.prefs.getCharPref(PREF_ADB_EXTENSION_URL); + return xpiLink.replace(/#OS#/g, OS); + } + + /** + * Install and enable the adb extension. Returns a promise that resolves when ADB is + * enabled. + * + * @param {String} source + * String passed to the AddonManager for telemetry. + */ + async install(source) { + if (!source) { + throw new Error( + "Missing mandatory `source` parameter for adb-addon.install" + ); + } + + const addon = await this._getAddon(); + if (addon && !addon.userDisabled) { + this.status = ADB_ADDON_STATES.INSTALLED; + return; + } + this.status = ADB_ADDON_STATES.PREPARING; + if (addon?.userDisabled) { + await addon.enable(); + } else { + const install = await AddonManager.getInstallForURL(this._getXpiLink(), { + telemetryInfo: { source }, + }); + install.addListener(this); + install.install(); + } + } + + async uninstall() { + const addon = await this._getAddon(); + addon.uninstall(); + } + + installFailureHandler(install, message) { + this.status = ADB_ADDON_STATES.UNINSTALLED; + this.emit("failure", message); + } + + // Expected AddonManager install listener. + onDownloadStarted() { + this.status = ADB_ADDON_STATES.DOWNLOADING; + } + + // Expected AddonManager install listener. + onDownloadProgress(install) { + if (install.maxProgress == -1) { + this.emit("progress", -1); + } else { + this.emit("progress", install.progress / install.maxProgress); + } + } + + // Expected AddonManager install listener. + onDownloadCancelled(install) { + this.installFailureHandler(install, "Download cancelled"); + } + + // Expected AddonManager install listener. + onDownloadFailed(install) { + this.installFailureHandler(install, "Download failed"); + } + + // Expected AddonManager install listener. + onInstallStarted() { + this.status = ADB_ADDON_STATES.INSTALLING; + } + + // Expected AddonManager install listener. + onInstallCancelled(install) { + this.installFailureHandler(install, "Install cancelled"); + } + + // Expected AddonManager install listener. + onInstallFailed(install) { + this.installFailureHandler(install, "Install failed"); + } + + // Expected AddonManager install listener. + onInstallEnded({ addon }) { + addon.enable(); + } +} + +exports.adbAddon = new ADBAddon(); |