├── .eslintrc ├── .gitignore ├── .jshintrc ├── Makefile ├── README.md ├── adb-client.js ├── adb-running-checker.js ├── adb-socket.js ├── adb.js ├── binary-manager.js ├── bootstrap.js ├── device.js ├── devtools-import.js ├── devtools-require.js ├── events.js ├── fastboot.js ├── linux ├── LICENSE ├── README ├── adb ├── fastboot └── manifest.json ├── linux64 ├── LICENSE ├── README ├── README.fastboot ├── adb ├── fastboot └── manifest.json ├── mac64 ├── LICENSE ├── README ├── adb ├── fastboot ├── mac-build.patch └── manifest.json ├── main.js ├── scanner.js ├── sign.sh ├── template-install.rdf ├── template-update.rdf ├── unload.js └── win32 ├── AdbWinApi.dll ├── AdbWinUsbApi.dll ├── LICENSE ├── README ├── adb.exe ├── fastboot.exe └── manifest.json /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "plugin:mozilla/recommended" 4 | ], 5 | "plugins": [ 6 | "mozilla" 7 | ], 8 | "globals": { 9 | "exports": true, 10 | "isWorker": true, 11 | "loader": true, 12 | "module": true, 13 | "reportError": true, 14 | "require": true, 15 | }, 16 | "rules": { 17 | "mozilla/no-define-cc-etc": "off", 18 | // Can't use Cc, etc. shortcuts yet, requires Firefox 60 19 | "mozilla/use-cc-etc": "off", 20 | // Can't use ChromeUtils yet, requires Firefox 60 21 | "mozilla/use-chromeutils-import": "off", 22 | "no-unused-vars": ["error", {"vars": "all", "args": "none"}], 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.xpi 2 | update.rdf 3 | install.rdf 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "browser": true, 3 | "devel": true, 4 | "loopfunc": true, 5 | "esnext": true, 6 | "quotmark": true, 7 | "undef": true, 8 | "unused": true, 9 | "maxerr": 10000, 10 | "globals": { 11 | "loader": true, 12 | "require": true, 13 | "module": true, 14 | "exports": true, 15 | "Components": false, 16 | "Cu": true, 17 | "Ci": true, 18 | "Cc": true, 19 | "Cr": true, 20 | "CC": true, 21 | "dump": false, 22 | "Services": true, 23 | "do_check_eq": false, 24 | "do_check_false": false, 25 | "do_check_true": false, 26 | "do_get_file": false, 27 | "do_get_profile": false, 28 | "do_print": false, 29 | "do_register_cleanup": false, 30 | "do_throw": false, 31 | "add_test": false, 32 | "add_task": false, 33 | "run_next_test": false, 34 | "EventUtils": false, 35 | "ok": false, 36 | "is": false, 37 | "isnot": false, 38 | "equal": false, 39 | "deepEqual": false, 40 | "Task": true, 41 | "finish": false, 42 | "setTimeout": true, 43 | "clearTimeout": true 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | FILES=adb.js adb-*.js binary-manager.js bootstrap.js device.js devtools-import.js devtools-require.js events.js fastboot.js main.js scanner.js unload.js 2 | ADDON_NAME=adbhelper 3 | ADDON_VERSION=0.12.2pre 4 | XPI_NAME=$(ADDON_NAME)-$(ADDON_VERSION) 5 | 6 | REMOTE_ROOT_PATH=/pub/labs/fxos-simulator/adb-helper/ 7 | 8 | UPDATE_LINK=https://ftp.mozilla.org$(REMOTE_ROOT_PATH) 9 | UPDATE_URL=$(UPDATE_LINK) 10 | 11 | S3_BASE_URL=s3://net-mozaws-prod-delivery-contrib$(REMOTE_ROOT_PATH) 12 | 13 | XPIS = $(XPI_NAME)-win32.xpi $(XPI_NAME)-linux.xpi $(XPI_NAME)-linux64.xpi $(XPI_NAME)-mac64.xpi 14 | 15 | all: $(XPIS) 16 | 17 | define build-xpi 18 | echo "build xpi for $1"; 19 | sed -e 's#@@UPDATE_URL@@#$(UPDATE_URL)$1/update.rdf#;s#@@ADDON_VERSION@@#$(ADDON_VERSION)#' template-install.rdf > install.rdf 20 | zip $(XPI_NAME)-$1.xpi -r $2 install.rdf 21 | endef 22 | 23 | $(XPI_NAME)-win32.xpi: $(FILES) win32 24 | @$(call build-xpi,win32, $^) 25 | 26 | $(XPI_NAME)-linux.xpi: $(FILES) linux linux64 27 | @$(call build-xpi,linux, $^) 28 | 29 | $(XPI_NAME)-linux64.xpi: $(FILES) linux linux64 30 | @$(call build-xpi,linux64, $^) 31 | 32 | $(XPI_NAME)-mac64.xpi: $(FILES) mac64 33 | @$(call build-xpi,mac64, $^) 34 | 35 | clean: 36 | rm -f adbhelper-*.xpi 37 | rm -f update.rdf install.rdf 38 | 39 | define release 40 | ./sign.sh $(XPI_NAME)-$1.xpi 41 | echo "releasing $1" 42 | aws s3 cp $(XPI_NAME)-$1.xpi $(S3_BASE_URL)$1/$(XPI_NAME)-$1.xpi 43 | # Update the "latest" symbolic link with a copy inside s3 44 | aws s3 cp $(S3_BASE_URL)$1/$(XPI_NAME)-$1.xpi $(S3_BASE_URL)$1/$(ADDON_NAME)-$1-latest.xpi 45 | # Update the update manifest 46 | sed -e 's#@@UPDATE_LINK@@#$(UPDATE_LINK)$1/$(XPI_NAME)-$1.xpi#;s#@@ADDON_VERSION@@#$(ADDON_VERSION)#' template-update.rdf > update.rdf 47 | aws s3 cp --cache-control max-age=3600 update.rdf $(S3_BASE_URL)$1/update.rdf 48 | endef 49 | 50 | release: $(XPIS) 51 | @$(call release,win32) 52 | @$(call release,linux) 53 | @$(call release,linux64) 54 | @$(call release,mac64) 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A Firefox add-on to ease connecting to Firefox for Android. 2 | 3 | Add-on license: http://www.mozilla.org/MPL/ 4 | 5 | ADB license: http://www.apache.org/licenses/LICENSE-2.0.html 6 | 7 | ADB source code: https://android.googlesource.com/platform/system/core/+/master/adb 8 | 9 | ## Building 10 | 11 | To build the add-on, run `make` from the root folder of your clone. 12 | 13 | This will package the add-on for various operating systems: 14 | - adbhelper-X.Y.Z-linux.xpi 15 | - adbhelper-X.Y.Z-linux64.xpi 16 | - adbhelper-X.Y.Z-mac64.xpi 17 | - adbhelper-X.Y.Z-win32.xpi 18 | 19 | ## Testing 20 | 21 | ### Prerequisite: Firefox for Android 22 | 23 | You need a Firefox for Android to connect to. 24 | 25 | If you are already setup to build Firefox and don't want to use a real device, the easiest way is to use an Artifact Build for Firefox for Android. See the [documentation on MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Simple_Firefox_for_Android_build#I_want_to_work_on_the_front-end). 26 | 27 | Once you have Firefox for Android running in a simulator, go to `Settings` > `Advanced` and turn on `Remote Debugging via USB` in the `DevTools` section. 28 | 29 | If you prefer to use a real device, refer to the documentation on MDN for [USB Debugging](https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging/Debugging_Firefox_for_Android_with_WebIDE). 30 | 31 | You are now ready to test ADB Helper. 32 | 33 | ### Test a local build of ADB Helper 34 | 35 | Only Firefox Nightly allows to load unsigned extensions, so make sure to use this distribution channel. 36 | 37 | In about:config, turn the following preferences: 38 | - `xpinstall.signatures.required` should be set to `false` 39 | - `extensions.legacy.enabled` should be set to true 40 | 41 | Drag and drop the xpi file for your current operating system to your browser window. You will get a prompt about installing adbhelper. 42 | 43 | Open WebIDE (Shift+F8). You should see your Firefox for Android runtime listed under "USB Devices". 44 | -------------------------------------------------------------------------------- /adb-client.js: -------------------------------------------------------------------------------- 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 | /* 6 | * A module to track device changes 7 | * Mostly from original `adb.js` 8 | */ 9 | 10 | "use strict"; 11 | 12 | const { Cu } = require("chrome"); 13 | const { AdbSocket } = require("./adb-socket"); 14 | 15 | // Starting with FF57, jsm share the same global and this require pulling it from it. 16 | const { TextEncoder, TextDecoder } = 17 | Cu.getGlobalForObject(Cu.import("resource://gre/modules/Services.jsm", {})); 18 | 19 | const OKAY = 0x59414b4f; 20 | const FAIL = 0x4c494146; 21 | 22 | let _sockets = [ ]; 23 | 24 | // Return buffer, which differs between Gecko versions 25 | function getBuffer(aPacket) { 26 | return aPacket.buffer ? aPacket.buffer : aPacket; 27 | } 28 | 29 | // @param aPacket The packet to get the length from. 30 | // @param aIgnoreResponse True if this packet has no OKAY/FAIL. 31 | // @return A js object { length:...; data:... } 32 | function unpackPacket(aPacket, aIgnoreResponse) { 33 | let buffer = getBuffer(aPacket); 34 | console.debug("Len buffer: " + buffer.byteLength); 35 | if (buffer.byteLength === 4 && !aIgnoreResponse) { 36 | console.debug("Packet empty"); 37 | return { length: 0, data: "" }; 38 | } 39 | let lengthView = new Uint8Array(buffer, aIgnoreResponse ? 0 : 4, 4); 40 | let decoder = new TextDecoder(); 41 | let length = parseInt(decoder.decode(lengthView), 16); 42 | let text = new Uint8Array(buffer, aIgnoreResponse ? 4 : 8, length); 43 | return { length, data: decoder.decode(text) }; 44 | } 45 | 46 | // Checks if the response is expected (defaults to OKAY). 47 | // @return true if response equals expected. 48 | function checkResponse(aPacket, aExpected = OKAY) { 49 | let buffer = getBuffer(aPacket); 50 | let view = new Uint32Array(buffer, 0, 1); 51 | if (view[0] == FAIL) { 52 | console.debug("Response: FAIL"); 53 | } 54 | console.debug("view[0] = " + view[0]); 55 | return view[0] == aExpected; 56 | } 57 | 58 | // @param aCommand A protocol-level command as described in 59 | // http://androidxref.com/4.0.4/xref/system/core/adb/OVERVIEW.TXT and 60 | // http://androidxref.com/4.0.4/xref/system/core/adb/SERVICES.TXT 61 | // @return A 8 bit typed array. 62 | function createRequest(aCommand) { 63 | let length = aCommand.length.toString(16).toUpperCase(); 64 | while (length.length < 4) { 65 | length = "0" + length; 66 | } 67 | 68 | let encoder = new TextEncoder(); 69 | console.debug("Created request: " + length + aCommand); 70 | return encoder.encode(length + aCommand); 71 | } 72 | 73 | function close() { 74 | _sockets.forEach(function(s) { 75 | s.close(); 76 | }); 77 | } 78 | 79 | function connect() { 80 | let tmp = new AdbSocket(); 81 | _sockets.push(tmp); 82 | return tmp; 83 | } 84 | 85 | let client = { 86 | getBuffer, 87 | unpackPacket, 88 | checkResponse, 89 | createRequest, 90 | connect, 91 | close 92 | }; 93 | 94 | module.exports = client; 95 | -------------------------------------------------------------------------------- /adb-running-checker.js: -------------------------------------------------------------------------------- 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 | 6 | /* 7 | * Uses host:version service to detect if ADB is running 8 | * Modified from adb-file-transfer from original ADB 9 | */ 10 | 11 | "use strict"; 12 | 13 | const { Cu } = require("chrome"); 14 | const { PromiseUtils } = Cu.import("resource://gre/modules/PromiseUtils.jsm", {}); 15 | const client = require("./adb-client"); 16 | 17 | exports.check = function check() { 18 | let deferred = PromiseUtils.defer(); 19 | let socket; 20 | let state; 21 | 22 | console.debug("Asking for host:version"); 23 | 24 | let runFSM = function runFSM(aData) { 25 | console.debug("runFSM " + state); 26 | switch (state) { 27 | case "start": 28 | let req = client.createRequest("host:version"); 29 | socket.send(req); 30 | state = "wait-version"; 31 | break; 32 | case "wait-version": 33 | // TODO: Actually check the version number to make sure the daemon 34 | // supports the commands we want to use 35 | let { length, data } = client.unpackPacket(aData); 36 | console.debug("length: ", length, "data: ", data); 37 | socket.close(); 38 | let version = parseInt(data, "16"); 39 | if (version >= 31) { 40 | deferred.resolve(true); 41 | } else { 42 | console.log("killing existing adb as we need version >= 31"); 43 | deferred.resolve(false); 44 | } 45 | break; 46 | default: 47 | console.debug("Unexpected State: " + state); 48 | deferred.resolve(false); 49 | } 50 | }; 51 | 52 | let setupSocket = function() { 53 | socket.s.onerror = function(aEvent) { 54 | console.debug("running checker onerror"); 55 | deferred.resolve(false); 56 | }; 57 | 58 | socket.s.onopen = function(aEvent) { 59 | console.debug("running checker onopen"); 60 | state = "start"; 61 | runFSM(); 62 | }; 63 | 64 | socket.s.onclose = function(aEvent) { 65 | console.debug("running checker onclose"); 66 | }; 67 | 68 | socket.s.ondata = function(aEvent) { 69 | console.debug("running checker ondata"); 70 | runFSM(aEvent.data); 71 | }; 72 | }; 73 | 74 | socket = client.connect(); 75 | setupSocket(); 76 | 77 | return deferred.promise; 78 | }; 79 | -------------------------------------------------------------------------------- /adb-socket.js: -------------------------------------------------------------------------------- 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 { Cu } = require("chrome"); 8 | const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); 9 | 10 | // Starting with FF57, jsm share the same global and this require pulling it from it. 11 | const { TextDecoder } = 12 | Cu.getGlobalForObject(Cu.import("resource://gre/modules/Services.jsm", {})); 13 | 14 | function createTCPSocket(location, port, options) { 15 | // Starting with FF57, jsm share the same global and requires some special code 16 | const { TCPSocket } = Cu.getGlobalForObject(Cu.import("resource://gre/modules/Services.jsm", {})); 17 | 18 | // Starting with FF43, TCPSocket is now exposed via WebIDL 19 | if (TCPSocket) { 20 | return new TCPSocket(location, port, options); 21 | } 22 | 23 | // For FF42 and previous 24 | let scope = Cu.Sandbox(Services.scriptSecurityManager.getSystemPrincipal()); 25 | scope.DOMError = Cu.import("resource://gre/modules/Services.jsm", {}).DOMError; 26 | Services.scriptloader.loadSubScript("resource://gre/components/TCPSocket.js", scope); 27 | scope.TCPSocket.prototype.initWindowless = function() { 28 | return true; 29 | }; 30 | let socket = new scope.TCPSocket(); 31 | return socket.open(location, port, options); 32 | } 33 | exports.createTCPSocket = createTCPSocket; 34 | 35 | // Creates a socket connected to the adb instance. 36 | // This instantiation is sync, and returns before we know if opening the 37 | // connection succeeds. Callers must attach handlers to the s field. 38 | class AdbSocket { 39 | constructor() { 40 | this.s = createTCPSocket("127.0.0.1", 5037, { binaryType: "arraybuffer" }); 41 | } 42 | 43 | /** 44 | * Dump the first few bytes of the given array to the console. 45 | * 46 | * @param {TypedArray} aArray 47 | * the array to dump 48 | */ 49 | _hexdump(aArray) { 50 | let decoder = new TextDecoder("windows-1252"); 51 | let array = new Uint8Array(aArray.buffer); 52 | let s = decoder.decode(array); 53 | let len = array.length; 54 | let dbg = "len=" + len + " "; 55 | let l = len > 20 ? 20 : len; 56 | 57 | for (let i = 0; i < l; i++) { 58 | let c = array[i].toString(16); 59 | if (c.length == 1) 60 | c = "0" + c; 61 | dbg += c; 62 | } 63 | dbg += " "; 64 | for (let i = 0; i < l; i++) { 65 | let c = array[i]; 66 | if (c < 32 || c > 127) { 67 | dbg += "."; 68 | } else { 69 | dbg += s[i]; 70 | } 71 | } 72 | console.debug(dbg); 73 | } 74 | 75 | // debugging version of tcpsocket.send() 76 | send(aArray) { 77 | this._hexdump(aArray); 78 | 79 | this.s.send(aArray.buffer, aArray.byteOffset, aArray.byteLength); 80 | } 81 | 82 | close() { 83 | if (this.s.readyState === "open" || 84 | this.s.readyState === "connecting") { 85 | this.s.close(); 86 | } 87 | } 88 | } 89 | 90 | exports.AdbSocket = AdbSocket; 91 | -------------------------------------------------------------------------------- /adb.js: -------------------------------------------------------------------------------- 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 | // Wrapper around the ADB utility. 6 | 7 | "use strict"; 8 | 9 | // Whether or not this script is being loaded as a CommonJS module 10 | // (from an add-on built using the Add-on SDK). If it isn't a CommonJS Module, 11 | // then it's a JavaScript Module. 12 | 13 | const { Cc, Ci, Cu } = require("chrome"); 14 | const events = require("./events"); 15 | const client = require("./adb-client"); 16 | const { getFileForBinary } = require("./binary-manager"); 17 | const { setTimeout } = Cu.import("resource://gre/modules/Timer.jsm", {}); 18 | const { Subprocess } = Cu.import("resource://gre/modules/Subprocess.jsm", {}); 19 | const { PromiseUtils } = Cu.import("resource://gre/modules/PromiseUtils.jsm", {}); 20 | const env = Cc["@mozilla.org/process/environment;1"]. 21 | getService(Ci.nsIEnvironment); 22 | const { OS } = require("resource://gre/modules/osfile.jsm"); 23 | const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); 24 | 25 | // When loaded as a CommonJS module, get the TextEncoder and TextDecoder 26 | // interfaces from the Services JavaScript Module, since they aren't defined 27 | // in a CommonJS module by default. 28 | // Starting with FF57, jsm share the same global and this require pulling it from it. 29 | const { TextEncoder, TextDecoder } = 30 | Cu.getGlobalForObject(Cu.import("resource://gre/modules/Services.jsm", {})); 31 | 32 | let ready = false; 33 | let didRunInitially = false; 34 | const psRegexNix = /.*? \d+ .*? .*? \d+\s+\d+ .*? .*? .*? .*? adb .*fork\-server/; 35 | const psRegexWin = /adb.exe.*/; 36 | 37 | const OKAY = 0x59414b4f; 38 | // const FAIL = 0x4c494146; 39 | // const STAT = 0x54415453; 40 | const DATA = 0x41544144; 41 | const DONE = 0x454e4f44; 42 | 43 | const ADB = { 44 | get didRunInitially() { 45 | return didRunInitially; 46 | }, 47 | set didRunInitially(newVal) { 48 | didRunInitially = newVal; 49 | }, 50 | 51 | get ready() { 52 | return ready; 53 | }, 54 | set ready(newVal) { 55 | ready = newVal; 56 | }, 57 | 58 | get adbFilePromise() { 59 | if (this._adbFilePromise) { 60 | return this._adbFilePromise; 61 | } 62 | this._adbFilePromise = getFileForBinary("adb"); 63 | return this._adbFilePromise; 64 | }, 65 | 66 | // We startup by launching adb in server mode, and setting 67 | // the tcp socket preference to |true| 68 | start() { 69 | return new Promise(async (resolve, reject) => { 70 | let onSuccessfulStart = () => { 71 | Services.obs.notifyObservers(null, "adb-ready"); 72 | this.ready = true; 73 | resolve(); 74 | }; 75 | 76 | let isAdbRunning = await require("./adb-running-checker").check(); 77 | if (isAdbRunning) { 78 | this.didRunInitially = false; 79 | console.log("Found ADB process running, not restarting"); 80 | onSuccessfulStart(); 81 | return; 82 | } 83 | console.log("Didn't find ADB process running, restarting"); 84 | 85 | this.didRunInitially = true; 86 | let process = Cc["@mozilla.org/process/util;1"] 87 | .createInstance(Ci.nsIProcess); 88 | let adbFile = await this.adbFilePromise; 89 | process.init(adbFile); 90 | // Hide command prompt window on Windows 91 | try { 92 | // startHidden is 55+ 93 | process.startHidden = true; 94 | // noShell attribute is 58+ 95 | process.noShell = true; 96 | } catch (e) { 97 | } 98 | let params = ["start-server"]; 99 | let self = this; 100 | process.runAsync(params, params.length, { 101 | observe(aSubject, aTopic, aData) { 102 | switch (aTopic) { 103 | case "process-finished": 104 | onSuccessfulStart(); 105 | break; 106 | case "process-failed": 107 | self.ready = false; 108 | reject(); 109 | break; 110 | } 111 | } 112 | }, false); 113 | }); 114 | }, 115 | 116 | /** 117 | * Stop the ADB server, but only if we started it. If it was started before 118 | * us, we return immediately. 119 | * 120 | * @param boolean sync 121 | * In case, we do need to kill the server, this param is passed through 122 | * to kill to determine whether it's a sync operation. 123 | */ 124 | stop(sync) { 125 | if (!this.didRunInitially) { 126 | return; // We didn't start the server, nothing to do 127 | } 128 | this.kill(sync); 129 | }, 130 | 131 | /** 132 | * Kill the ADB server. We do this by running ADB again, passing it 133 | * the "kill-server" argument. 134 | * 135 | * @param {Boolean} sync 136 | * Whether or not to kill the server synchronously. In general, 137 | * this should be false. But on Windows, an add-on may fail to update 138 | * if its copy of ADB is running when Firefox tries to update it. 139 | * So add-ons who observe their own updates and kill the ADB server 140 | * beforehand should do so synchronously on Windows to make sure 141 | * the update doesn't race the killing. 142 | */ 143 | async kill(sync) { 144 | let process = Cc["@mozilla.org/process/util;1"] 145 | .createInstance(Ci.nsIProcess); 146 | let adbFile = await this.adbFilePromise; 147 | process.init(adbFile); 148 | // Hide command prompt window on Windows 149 | try { 150 | // startHidden is 55+ 151 | process.startHidden = true; 152 | // noShell attribute is 58+ 153 | process.noShell = true; 154 | } catch (e) { 155 | } 156 | let params = ["kill-server"]; 157 | 158 | if (sync) { 159 | process.run(true, params, params.length); 160 | console.log("adb kill-server: " + process.exitValue); 161 | this.ready = false; 162 | this.didRunInitially = false; 163 | } else { 164 | let self = this; 165 | process.runAsync(params, params.length, { 166 | observe(aSubject, aTopic, aData) { 167 | switch (aTopic) { 168 | case "process-finished": 169 | console.log("adb kill-server: " + process.exitValue); 170 | Services.obs.notifyObservers(null, "adb-killed"); 171 | self.ready = false; 172 | self.didRunInitially = false; 173 | break; 174 | case "process-failed": 175 | console.log("adb kill-server failure: " + process.exitValue); 176 | // It's hard to say whether or not ADB is ready at this point, 177 | // but it seems safer to assume that it isn't, so code that wants 178 | // to use it later will try to restart it. 179 | Services.obs.notifyObservers(null, "adb-killed"); 180 | self.ready = false; 181 | self.didRunInitially = false; 182 | break; 183 | } 184 | } 185 | }, false); 186 | } 187 | }, 188 | 189 | async _isAdbRunning() { 190 | let deferred = PromiseUtils.defer(); 191 | 192 | let ps, args; 193 | let platform = Services.appinfo.OS; 194 | if (platform === "WINNT") { 195 | ps = "C:\\windows\\system32\\tasklist.exe"; 196 | args = []; 197 | } else { 198 | args = ["aux"]; 199 | let psCommand = "ps"; 200 | 201 | let paths = env.get("PATH").split(":"); 202 | let len = paths.length; 203 | for (let i = 0; i < len; i++) { 204 | try { 205 | let fullyQualified = OS.Path.join(paths[i], psCommand); 206 | let isFileExists = await OS.File.exists(fullyQualified); 207 | 208 | if (isFileExists) { 209 | ps = fullyQualified; 210 | break; 211 | } 212 | } catch (e) { 213 | // keep checking PATH if we run into NS_ERROR_FILE_UNRECOGNIZED_PATH 214 | } 215 | } 216 | if (!ps) { 217 | console.log("Error: a task list executable not found on filesystem"); 218 | deferred.resolve(false); // default to restart adb 219 | return deferred.promise; 220 | } 221 | } 222 | 223 | let buffer = []; 224 | 225 | Subprocess.call({ 226 | command: ps, 227 | arguments: args, 228 | stdout(data) { 229 | buffer.push(data); 230 | }, 231 | done() { 232 | let lines = buffer.join("").split("\n"); 233 | let regex = (platform === "WINNT") ? psRegexWin : psRegexNix; 234 | let isAdbRunning = lines.some(function(line) { 235 | return regex.test(line); 236 | }); 237 | deferred.resolve(isAdbRunning); 238 | } 239 | }); 240 | 241 | return deferred.promise; 242 | }, 243 | 244 | // Start tracking devices connecting and disconnecting from the host. 245 | // We can't reuse runCommand here because we keep the socket alive. 246 | // @return The socket used. 247 | trackDevices: function adb_trackDevices() { 248 | console.log("trackDevices"); 249 | let socket = client.connect(); 250 | let waitForFirst = true; 251 | let devices = {}; 252 | 253 | socket.s.onopen = function() { 254 | console.log("trackDevices onopen"); 255 | Services.obs.notifyObservers(null, "adb-track-devices-start"); 256 | let req = client.createRequest("host:track-devices"); 257 | socket.send(req); 258 | 259 | }; 260 | 261 | socket.s.onerror = function(event) { 262 | console.log("trackDevices onerror: " + event.data.name); 263 | Services.obs.notifyObservers(null, "adb-track-devices-stop"); 264 | }; 265 | 266 | socket.s.onclose = function() { 267 | console.log("trackDevices onclose"); 268 | 269 | // Report all devices as disconnected 270 | for (let dev in devices) { 271 | devices[dev] = false; 272 | events.emit(ADB, "device-disconnected", dev); 273 | } 274 | 275 | Services.obs.notifyObservers(null, "adb-track-devices-stop"); 276 | 277 | // When we lose connection to the server, 278 | // and the adb is still on, we most likely got our server killed 279 | // by local adb. So we do try to reconnect to it. 280 | setTimeout(function() { // Give some time to the new adb to start 281 | if (ADB.ready) { // Only try to reconnect/restart if the add-on is still enabled 282 | ADB.start().then(function() { // try to connect to the new local adb server 283 | // or, spawn a new one 284 | ADB.trackDevices(); // Re-track devices 285 | }); 286 | } 287 | }, 2000); 288 | }; 289 | 290 | socket.s.ondata = function(aEvent) { 291 | console.log("trackDevices ondata"); 292 | let data = aEvent.data; 293 | console.log("length=" + data.byteLength); 294 | let dec = new TextDecoder(); 295 | console.log(dec.decode(new Uint8Array(data)).trim()); 296 | 297 | // check the OKAY or FAIL on first packet. 298 | if (waitForFirst) { 299 | if (!client.checkResponse(data, OKAY)) { 300 | socket.close(); 301 | return; 302 | } 303 | } 304 | 305 | let packet = client.unpackPacket(data, !waitForFirst); 306 | waitForFirst = false; 307 | 308 | if (packet.data == "") { 309 | // All devices got disconnected. 310 | for (let dev in devices) { 311 | devices[dev] = false; 312 | events.emit(ADB, "device-disconnected", dev); 313 | } 314 | } else { 315 | // One line per device, each line being $DEVICE\t(offline|device) 316 | let lines = packet.data.split("\n"); 317 | let newDev = {}; 318 | lines.forEach(function(aLine) { 319 | if (aLine.length == 0) { 320 | return; 321 | } 322 | 323 | let [dev, status] = aLine.split("\t"); 324 | newDev[dev] = status !== "offline"; 325 | }); 326 | // Check which device changed state. 327 | for (let dev in newDev) { 328 | if (devices[dev] != newDev[dev]) { 329 | if (dev in devices || newDev[dev]) { 330 | let topic = newDev[dev] ? "device-connected" 331 | : "device-disconnected"; 332 | events.emit(ADB, topic, dev); 333 | } 334 | devices[dev] = newDev[dev]; 335 | } 336 | } 337 | } 338 | }; 339 | }, 340 | 341 | // Sends back an array of device names. 342 | listDevices: function adb_listDevices() { 343 | console.log("listDevices"); 344 | 345 | return this.runCommand("host:devices").then( 346 | function onSuccess(data) { 347 | let lines = data.split("\n"); 348 | let res = []; 349 | lines.forEach(function(aLine) { 350 | if (aLine.length == 0) { 351 | return; 352 | } 353 | let [ device ] = aLine.split("\t"); 354 | res.push(device); 355 | }); 356 | return res; 357 | } 358 | ); 359 | }, 360 | 361 | // sends adb forward aLocalPort aDevicePort 362 | forwardPort: function adb_forwardPort(aLocalPort, aDevicePort) { 363 | console.log("forwardPort " + aLocalPort + " -- " + aDevicePort); 364 | // :forward:; 365 | 366 | return this.runCommand("host:forward:" + aLocalPort + ";" + aDevicePort) 367 | .then(function onSuccess(data) { 368 | return data; 369 | }); 370 | }, 371 | 372 | // Checks a file mode. 373 | // aWhat is one the strings "S_ISDIR" "S_ISCHR" "S_ISBLK" 374 | // "S_ISREG" "S_ISFIFO" "S_ISLNK" "S_ISSOCK" 375 | checkFileMode: function adb_checkFileMode(aMode, aWhat) { 376 | /* Encoding of the file mode. See bits/stat.h */ 377 | const S_IFMT = parseInt("170000", 8); /* These bits determine file type. */ 378 | 379 | /* File types. */ 380 | const S_IFDIR = parseInt("040000", 8); /* Directory. */ 381 | const S_IFCHR = parseInt("020000", 8); /* Character device. */ 382 | const S_IFBLK = parseInt("060000", 8); /* Block device. */ 383 | const S_IFREG = parseInt("100000", 8); /* Regular file. */ 384 | const S_IFIFO = parseInt("010000", 8); /* FIFO. */ 385 | const S_IFLNK = parseInt("120000", 8); /* Symbolic link. */ 386 | const S_IFSOCK = parseInt("140000", 8); /* Socket. */ 387 | 388 | let masks = { 389 | "S_ISDIR": S_IFDIR, 390 | "S_ISCHR": S_IFCHR, 391 | "S_ISBLK": S_IFBLK, 392 | "S_ISREG": S_IFREG, 393 | "S_ISFIFO": S_IFIFO, 394 | "S_ISLNK": S_IFLNK, 395 | "S_ISSOCK": S_IFSOCK 396 | }; 397 | 398 | if (!(aWhat in masks)) { 399 | return false; 400 | } 401 | 402 | return ((aMode & S_IFMT) == masks[aWhat]); 403 | }, 404 | 405 | // pulls a file from the device. 406 | // send "host:transport-any" why?? 407 | // if !OKAY, return 408 | // send "sync:" 409 | // if !OKAY, return 410 | // send STAT + hex4(path.length) + path 411 | // recv STAT + 12 bytes (3 x 32 bits: mode, size, time) 412 | // send RECV + hex4(path.length) + path 413 | // while(needs data): 414 | // recv DATA + hex4 + data 415 | // recv DONE + hex4(0) 416 | // send QUIT + hex4(0) 417 | pull: function adb_pull(aFrom, aDest) { 418 | let deferred = PromiseUtils.defer(); 419 | let socket; 420 | let state; 421 | let fileData = null; 422 | let currentPos = 0; 423 | let chunkSize = 0; 424 | let pkgData; 425 | let headerArray = new Uint32Array(2); 426 | let currentHeaderLength = 0; 427 | 428 | let encoder = new TextEncoder(); 429 | let infoLengthPacket; 430 | 431 | console.log("pulling " + aFrom + " -> " + aDest); 432 | 433 | let shutdown = function() { 434 | console.log("pull shutdown"); 435 | socket.close(); 436 | deferred.reject("BAD_RESPONSE"); 437 | }; 438 | 439 | // extract chunk data header info. to headerArray. 440 | let extractChunkDataHeader = function(data) { 441 | let tmpArray = new Uint8Array(headerArray.buffer); 442 | for (let i = 0; i < 8 - currentHeaderLength; i++) { 443 | tmpArray[currentHeaderLength + i] = data[i]; 444 | } 445 | }; 446 | 447 | // chunk data header is 8 bytes length, 448 | // the first 4 bytes: hex4("DATA"), and 449 | // the second 4 bytes: hex4(chunk size) 450 | let checkChunkDataHeader = function(data) { 451 | if (data.length + currentHeaderLength >= 8) { 452 | extractChunkDataHeader(data); 453 | 454 | if (headerArray[0] != DATA) { 455 | shutdown(); 456 | return false; 457 | } 458 | // remove header info. from socket package data 459 | pkgData = data.subarray(8 - currentHeaderLength, data.length); 460 | chunkSize = headerArray[1]; 461 | currentHeaderLength = 0; 462 | return true; 463 | } 464 | 465 | // If chunk data header info. is separated into more than one 466 | // socket package, keep partial header info. in headerArray. 467 | let tmpArray = new Uint8Array(headerArray.buffer); 468 | for (let i = 0; i < data.length; i++) { 469 | tmpArray[currentHeaderLength + i] = data[i]; 470 | } 471 | currentHeaderLength += data.length; 472 | return true; 473 | }; 474 | 475 | // The last remaining package data contains 8 bytes, 476 | // they are "DONE(0x454e4f44)" and 0x0000. 477 | let checkDone = function(data) { 478 | if (data.length != 8) { 479 | return false; 480 | } 481 | 482 | let doneFlagArray = new Uint32Array(1); 483 | let tmpArray = new Uint8Array(doneFlagArray.buffer); 484 | for (let i = 0; i < 4; i++) { 485 | tmpArray[i] = data[i]; 486 | } 487 | // Check DONE flag 488 | if (doneFlagArray[0] == DONE) { 489 | return true; 490 | } 491 | return false; 492 | }; 493 | 494 | let runFSM = function runFSM(aData) { 495 | console.log("runFSM " + state); 496 | let req; 497 | switch (state) { 498 | case "start": 499 | state = "send-transport"; 500 | runFSM(); 501 | break; 502 | case "send-transport": 503 | req = client.createRequest("host:transport-any"); 504 | socket.send(req); 505 | state = "wait-transport"; 506 | break; 507 | case "wait-transport": 508 | if (!client.checkResponse(aData, OKAY)) { 509 | shutdown(); 510 | return; 511 | } 512 | console.log("transport: OK"); 513 | state = "send-sync"; 514 | runFSM(); 515 | break; 516 | case "send-sync": 517 | req = client.createRequest("sync:"); 518 | socket.send(req); 519 | state = "wait-sync"; 520 | break; 521 | case "wait-sync": 522 | if (!client.checkResponse(aData, OKAY)) { 523 | shutdown(); 524 | return; 525 | } 526 | console.log("sync: OK"); 527 | state = "send-recv"; 528 | runFSM(); 529 | break; 530 | case "send-recv": 531 | infoLengthPacket = new Uint32Array(1); 532 | infoLengthPacket[0] = aFrom.length; 533 | socket.send(encoder.encode("RECV")); 534 | socket.send(infoLengthPacket); 535 | socket.send(encoder.encode(aFrom)); 536 | 537 | state = "wait-recv"; 538 | break; 539 | case "wait-recv": 540 | // After sending "RECV" command, adb server will send chunks data back, 541 | // Handle every single socket package here. 542 | // Note: One socket package maybe contain many chunks, and often 543 | // partial chunk at the end. 544 | pkgData = new Uint8Array(client.getBuffer(aData)); 545 | 546 | // Handle all data in a single socket package. 547 | while (pkgData.length > 0) { 548 | if (chunkSize == 0 && checkDone(pkgData)) { 549 | OS.File.writeAtomic(aDest, fileData, {}).then( 550 | function onSuccess(number) { 551 | console.log(number); 552 | deferred.resolve("SUCCESS"); 553 | }, 554 | function onFailure(reason) { 555 | console.log(reason); 556 | deferred.reject("CANT_ACCESS_FILE"); 557 | } 558 | ); 559 | 560 | state = "send-quit"; 561 | runFSM(); 562 | return; 563 | } 564 | if (chunkSize == 0 && !checkChunkDataHeader(pkgData)) { 565 | shutdown(); 566 | return; 567 | } 568 | // handle full chunk 569 | if (chunkSize > 0 && pkgData.length >= chunkSize) { 570 | let chunkData = pkgData.subarray(0, chunkSize); 571 | let tmpData = new Uint8Array(currentPos + chunkSize); 572 | if (fileData) { 573 | tmpData.set(fileData, 0); 574 | } 575 | tmpData.set(chunkData, currentPos); 576 | fileData = tmpData; 577 | pkgData = pkgData.subarray(chunkSize, pkgData.length); 578 | currentPos += chunkSize; 579 | chunkSize = 0; 580 | } 581 | // handle partial chunk at the end of socket package 582 | if (chunkSize > 0 && pkgData.length > 0 && pkgData.length < chunkSize) { 583 | let tmpData = new Uint8Array(currentPos + pkgData.length); 584 | if (fileData) { 585 | tmpData.set(fileData, 0); 586 | } 587 | tmpData.set(pkgData, currentPos); 588 | fileData = tmpData; 589 | currentPos += pkgData.length; 590 | chunkSize -= pkgData.length; 591 | break; // Break while loop. 592 | } 593 | } 594 | 595 | break; 596 | case "send-quit": 597 | infoLengthPacket = new Uint32Array(1); 598 | infoLengthPacket[0] = 0; 599 | socket.send(encoder.encode("QUIT")); 600 | socket.send(infoLengthPacket); 601 | 602 | state = "end"; 603 | runFSM(); 604 | break; 605 | case "end": 606 | socket.close(); 607 | break; 608 | default: 609 | console.log("pull Unexpected State: " + state); 610 | deferred.reject("UNEXPECTED_STATE"); 611 | } 612 | }; 613 | 614 | let setupSocket = function() { 615 | socket.s.onerror = function(aEvent) { 616 | console.log("pull onerror"); 617 | deferred.reject("SOCKET_ERROR"); 618 | }; 619 | 620 | socket.s.onopen = function(aEvent) { 621 | console.log("pull onopen"); 622 | state = "start"; 623 | runFSM(); 624 | }; 625 | 626 | socket.s.onclose = function(aEvent) { 627 | console.log("pull onclose"); 628 | }; 629 | 630 | socket.s.ondata = function(aEvent) { 631 | console.log("pull ondata:"); 632 | runFSM(aEvent.data); 633 | }; 634 | }; 635 | 636 | socket = client.connect(); 637 | setupSocket(); 638 | 639 | return deferred.promise; 640 | }, 641 | 642 | // pushes a file to the device. 643 | // aFrom and aDest are full paths. 644 | // XXX we should STAT the remote path before sending. 645 | push: function adb_push(aFrom, aDest) { 646 | let deferred = PromiseUtils.defer(); 647 | let socket; 648 | let state; 649 | let fileSize; 650 | let fileData; 651 | let remaining; 652 | let currentPos = 0; 653 | let fileTime; 654 | 655 | console.log("pushing " + aFrom + " -> " + aDest); 656 | 657 | let shutdown = function() { 658 | console.log("push shutdown"); 659 | socket.close(); 660 | deferred.reject("BAD_RESPONSE"); 661 | }; 662 | 663 | let runFSM = function runFSM(aData) { 664 | console.log("runFSM " + state); 665 | let req; 666 | switch (state) { 667 | case "start": 668 | state = "send-transport"; 669 | runFSM(); 670 | break; 671 | case "send-transport": 672 | req = client.createRequest("host:transport-any"); 673 | socket.send(req); 674 | state = "wait-transport"; 675 | break; 676 | case "wait-transport": 677 | if (!client.checkResponse(aData, OKAY)) { 678 | shutdown(); 679 | return; 680 | } 681 | console.log("transport: OK"); 682 | state = "send-sync"; 683 | runFSM(); 684 | break; 685 | case "send-sync": 686 | req = client.createRequest("sync:"); 687 | socket.send(req); 688 | state = "wait-sync"; 689 | break; 690 | case "wait-sync": 691 | if (!client.checkResponse(aData, OKAY)) { 692 | shutdown(); 693 | return; 694 | } 695 | console.log("sync: OK"); 696 | state = "send-send"; 697 | runFSM(); 698 | break; 699 | case "send-send": 700 | // need to send SEND + length($aDest,$fileMode) 701 | // $fileMode is not the octal one there. 702 | let encoder = new TextEncoder(); 703 | 704 | let infoLengthPacket = new Uint32Array(1), info = aDest + ",33204"; 705 | infoLengthPacket[0] = info.length; 706 | socket.send(encoder.encode("SEND")); 707 | socket.send(infoLengthPacket); 708 | socket.send(encoder.encode(info)); 709 | 710 | // now sending file data. 711 | while (remaining > 0) { 712 | let toSend = remaining > 65536 ? 65536 : remaining; 713 | console.log("Sending " + toSend + " bytes"); 714 | 715 | let dataLengthPacket = new Uint32Array(1); 716 | // We have to create a new ArrayBuffer for the fileData slice 717 | // because nsIDOMTCPSocket (or ArrayBufferInputStream) chokes on 718 | // reused buffers, even when we don't modify their contents. 719 | let dataPacket = new Uint8Array(new ArrayBuffer(toSend)); 720 | dataPacket.set(new Uint8Array(fileData.buffer, currentPos, toSend)); 721 | dataLengthPacket[0] = toSend; 722 | socket.send(encoder.encode("DATA")); 723 | socket.send(dataLengthPacket); 724 | socket.send(dataPacket); 725 | 726 | currentPos += toSend; 727 | remaining -= toSend; 728 | } 729 | 730 | // Ending up with DONE + mtime (wtf???) 731 | let fileTimePacket = new Uint32Array(1); 732 | fileTimePacket[0] = fileTime; 733 | socket.send(encoder.encode("DONE")); 734 | socket.send(fileTimePacket); 735 | 736 | state = "wait-done"; 737 | break; 738 | case "wait-done": 739 | if (!client.checkResponse(aData, OKAY)) { 740 | shutdown(); 741 | return; 742 | } 743 | console.log("DONE: OK"); 744 | state = "end"; 745 | runFSM(); 746 | break; 747 | case "end": 748 | socket.close(); 749 | deferred.resolve("SUCCESS"); 750 | break; 751 | default: 752 | console.log("push Unexpected State: " + state); 753 | deferred.reject("UNEXPECTED_STATE"); 754 | } 755 | }; 756 | 757 | let setupSocket = function() { 758 | socket.s.onerror = function(aEvent) { 759 | console.log("push onerror"); 760 | deferred.reject("SOCKET_ERROR"); 761 | }; 762 | 763 | socket.s.onopen = function(aEvent) { 764 | console.log("push onopen"); 765 | state = "start"; 766 | runFSM(); 767 | }; 768 | 769 | socket.s.onclose = function(aEvent) { 770 | console.log("push onclose"); 771 | }; 772 | 773 | socket.s.ondata = function(aEvent) { 774 | console.log("push ondata"); 775 | runFSM(aEvent.data); 776 | }; 777 | }; 778 | // Stat the file, get its size. 779 | OS.File.stat(aFrom).then( 780 | function onSuccess(stat) { 781 | if (stat.isDir) { 782 | // The path represents a directory 783 | deferred.reject("CANT_PUSH_DIR"); 784 | } else { 785 | // The path represents a file, not a directory 786 | fileSize = stat.size; 787 | // We want seconds since epoch 788 | fileTime = stat.lastModificationDate.getTime() / 1000; 789 | remaining = fileSize; 790 | console.log(aFrom + " size is " + fileSize); 791 | let readPromise = OS.File.read(aFrom); 792 | readPromise.then( 793 | function readSuccess(aData) { 794 | fileData = aData; 795 | socket = client.connect(); 796 | setupSocket(); 797 | }, 798 | function readError() { 799 | deferred.reject("READ_FAILED"); 800 | } 801 | ); 802 | } 803 | }, 804 | function onFailure(reason) { 805 | console.log(reason); 806 | deferred.reject("CANT_ACCESS_FILE"); 807 | } 808 | ); 809 | 810 | return deferred.promise; 811 | }, 812 | 813 | // Run a shell command 814 | shell: function adb_shell(aCommand) { 815 | let deferred = PromiseUtils.defer(); 816 | let socket; 817 | let state; 818 | let stdout = ""; 819 | 820 | console.log("shell " + aCommand); 821 | 822 | let shutdown = function() { 823 | console.log("shell shutdown"); 824 | socket.close(); 825 | deferred.reject("BAD_RESPONSE"); 826 | }; 827 | 828 | let runFSM = function runFSM(aData) { 829 | console.log("runFSM " + state); 830 | let req; 831 | let ignoreResponseCode = false; 832 | switch (state) { 833 | case "start": 834 | state = "send-transport"; 835 | runFSM(); 836 | break; 837 | case "send-transport": 838 | req = client.createRequest("host:transport-any"); 839 | socket.send(req); 840 | state = "wait-transport"; 841 | break; 842 | case "wait-transport": 843 | if (!client.checkResponse(aData, OKAY)) { 844 | shutdown(); 845 | return; 846 | } 847 | state = "send-shell"; 848 | runFSM(); 849 | break; 850 | case "send-shell": 851 | req = client.createRequest("shell:" + aCommand); 852 | socket.send(req); 853 | state = "rec-shell"; 854 | break; 855 | case "rec-shell": 856 | if (!client.checkResponse(aData, OKAY)) { 857 | shutdown(); 858 | return; 859 | } 860 | state = "decode-shell"; 861 | if (client.getBuffer(aData).byteLength == 4) { 862 | break; 863 | } 864 | ignoreResponseCode = true; 865 | case "decode-shell": 866 | let decoder = new TextDecoder(); 867 | let text = new Uint8Array(client.getBuffer(aData), ignoreResponseCode ? 4 : 0); 868 | stdout += decoder.decode(text); 869 | break; 870 | default: 871 | console.log("shell Unexpected State: " + state); 872 | deferred.reject("UNEXPECTED_STATE"); 873 | } 874 | }; 875 | 876 | socket = client.connect(); 877 | socket.s.onerror = function(aEvent) { 878 | console.log("shell onerror"); 879 | deferred.reject("SOCKET_ERROR"); 880 | }; 881 | 882 | socket.s.onopen = function(aEvent) { 883 | console.log("shell onopen"); 884 | state = "start"; 885 | runFSM(); 886 | }; 887 | 888 | socket.s.onclose = function(aEvent) { 889 | deferred.resolve(stdout); 890 | console.log("shell onclose"); 891 | }; 892 | 893 | socket.s.ondata = function(aEvent) { 894 | console.log("shell ondata"); 895 | runFSM(aEvent.data); 896 | }; 897 | 898 | return deferred.promise; 899 | }, 900 | 901 | reboot: function adb_reboot() { 902 | return this.shell("reboot"); 903 | }, 904 | 905 | rebootRecovery: function adb_rebootRecovery() { 906 | return this.shell("reboot recovery"); 907 | }, 908 | 909 | rebootBootloader: function adb_rebootBootloader() { 910 | return this.shell("reboot bootloader"); 911 | }, 912 | 913 | root: function adb_root() { 914 | let deferred = PromiseUtils.defer(); 915 | let socket; 916 | let state; 917 | 918 | console.log("root"); 919 | 920 | let shutdown = function() { 921 | console.log("root shutdown"); 922 | socket.close(); 923 | deferred.reject("BAD_RESPONSE"); 924 | }; 925 | 926 | let runFSM = function runFSM(aData) { 927 | console.log("runFSM " + state); 928 | let req; 929 | switch (state) { 930 | case "start": 931 | state = "send-transport"; 932 | runFSM(); 933 | break; 934 | case "send-transport": 935 | req = client.createRequest("host:transport-any"); 936 | socket.send(req); 937 | state = "wait-transport"; 938 | break; 939 | case "wait-transport": 940 | if (!client.checkResponse(aData, OKAY)) { 941 | shutdown(); 942 | return; 943 | } 944 | state = "send-root"; 945 | runFSM(); 946 | break; 947 | case "send-root": 948 | req = client.createRequest("root:"); 949 | socket.send(req); 950 | state = "rec-root"; 951 | break; 952 | case "rec-root": 953 | // Nothing to do 954 | break; 955 | default: 956 | console.log("root Unexpected State: " + state); 957 | deferred.reject("UNEXPECTED_STATE"); 958 | } 959 | }; 960 | 961 | socket = client.connect(); 962 | socket.s.onerror = function(aEvent) { 963 | console.log("root onerror"); 964 | deferred.reject("SOCKET_ERROR"); 965 | }; 966 | 967 | socket.s.onopen = function(aEvent) { 968 | console.log("root onopen"); 969 | state = "start"; 970 | runFSM(); 971 | }; 972 | 973 | socket.s.onclose = function(aEvent) { 974 | deferred.resolve(); 975 | console.log("root onclose"); 976 | }; 977 | 978 | socket.s.ondata = function(aEvent) { 979 | console.log("root ondata"); 980 | runFSM(aEvent.data); 981 | }; 982 | 983 | return deferred.promise; 984 | }, 985 | 986 | // Asynchronously runs an adb command. 987 | // @param aCommand The command as documented in 988 | // http://androidxref.com/4.0.4/xref/system/core/adb/SERVICES.TXT 989 | runCommand: function adb_runCommand(aCommand) { 990 | console.log("runCommand " + aCommand); 991 | let deferred = PromiseUtils.defer(); 992 | if (!this.ready) { 993 | setTimeout(function() { deferred.reject("ADB_NOT_READY"); }); 994 | return deferred.promise; 995 | } 996 | 997 | let socket = client.connect(); 998 | 999 | socket.s.onopen = function() { 1000 | console.log("runCommand onopen"); 1001 | let req = client.createRequest(aCommand); 1002 | socket.send(req); 1003 | 1004 | }; 1005 | 1006 | socket.s.onerror = function() { 1007 | console.log("runCommand onerror"); 1008 | deferred.reject("NETWORK_ERROR"); 1009 | }; 1010 | 1011 | socket.s.onclose = function() { 1012 | console.log("runCommand onclose"); 1013 | }; 1014 | 1015 | socket.s.ondata = function(aEvent) { 1016 | console.log("runCommand ondata"); 1017 | let data = aEvent.data; 1018 | 1019 | let packet = client.unpackPacket(data, false); 1020 | if (!client.checkResponse(data, OKAY)) { 1021 | socket.close(); 1022 | console.log("Error: " + packet.data); 1023 | deferred.reject("PROTOCOL_ERROR"); 1024 | return; 1025 | } 1026 | 1027 | deferred.resolve(packet.data); 1028 | }; 1029 | 1030 | 1031 | return deferred.promise; 1032 | } 1033 | }; 1034 | 1035 | module.exports = ADB; 1036 | -------------------------------------------------------------------------------- /binary-manager.js: -------------------------------------------------------------------------------- 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 { Cu } = require("chrome"); 8 | const { OS } = require("resource://gre/modules/osfile.jsm"); 9 | const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); 10 | const { NetUtil } = require("resource://gre/modules/NetUtil.jsm"); 11 | const { TextDecoder } = 12 | Cu.getGlobalForObject(Cu.import("resource://gre/modules/Services.jsm", {})); 13 | const { FileUtils } = require("resource://gre/modules/FileUtils.jsm"); 14 | 15 | const ADDON_ROOT_PATH = "resource://adbhelperatmozilla.org"; 16 | // Use the "local" profile directory, since it's meant for temporary storage. 17 | const UNPACKED_ROOT_PATH = OS.Path.join(OS.Constants.Path.localProfileDir, "adbhelper"); 18 | const MANIFEST = "manifest.json"; 19 | 20 | function getPlatformDir() { 21 | let { OS: platform, XPCOMABI } = Services.appinfo; 22 | switch (platform) { 23 | case "Linux": 24 | return XPCOMABI.indexOf("x86_64") == 0 ? "linux64" : "linux"; 25 | case "Darwin": 26 | return "mac64"; 27 | case "WINNT": 28 | return "win32"; 29 | default: 30 | throw new Error("Unsupported platform : " + platform); 31 | } 32 | } 33 | 34 | /** 35 | * Read the manifest from inside the add-on. 36 | * Uses NetUtil since data is packed inside the add-on, not a local file. 37 | */ 38 | async function getManifestFromAddon() { 39 | return new Promise((resolve, reject) => { 40 | NetUtil.asyncFetch({ 41 | uri: `${ADDON_ROOT_PATH}/${getPlatformDir()}/${MANIFEST}`, 42 | loadUsingSystemPrincipal: true 43 | }, (input) => { 44 | let data; 45 | try { 46 | let string = NetUtil.readInputStreamToString(input, input.available()); 47 | data = JSON.parse(string); 48 | } catch (e) { 49 | reject(new Error("Could not read manifest in add-on")); 50 | return; 51 | } 52 | resolve(data); 53 | }); 54 | }); 55 | } 56 | 57 | /** 58 | * Read the manifest from the unpacked binary directory. 59 | * Uses OS.File since this is a local file. 60 | */ 61 | async function getManifestFromUnpacked() { 62 | let dirPath = OS.Path.join(UNPACKED_ROOT_PATH, getPlatformDir()); 63 | let manifestPath = OS.Path.join(dirPath, MANIFEST); 64 | if (!await OS.File.exists(manifestPath)) { 65 | throw new Error("Manifest doesn't exist at unpacked path"); 66 | } 67 | let binary = await OS.File.read(manifestPath); 68 | let json = new TextDecoder().decode(binary); 69 | let data; 70 | try { 71 | data = JSON.parse(json); 72 | } catch (e) { 73 | throw new Error("Could not read unpacked manifest"); 74 | } 75 | return data; 76 | } 77 | 78 | /** 79 | * Unpack file from the add-on. 80 | * Uses NetUtil to read and write, since it's required for reading. 81 | * 82 | * @param {string} file 83 | * The base name of the file, such as "adb". 84 | * @param {object} options 85 | * Object with the properties: 86 | * - exec {boolean} 87 | * Whether to mark the file as executable. 88 | */ 89 | async function unpackFile(file, { exec }) { 90 | // Assumes that destination dir already exists. 91 | let filePath = OS.Path.join(UNPACKED_ROOT_PATH, getPlatformDir(), file); 92 | await new Promise((resolve, reject) => { 93 | NetUtil.asyncFetch({ 94 | uri: `${ADDON_ROOT_PATH}/${getPlatformDir()}/${file}`, 95 | loadUsingSystemPrincipal: true 96 | }, (input) => { 97 | try { 98 | // Since we have to use NetUtil to read, probably it's okay to use for 99 | // writing, rather than bouncing to OS.File...? 100 | let outputFile = new FileUtils.File(filePath); 101 | let output = FileUtils.openAtomicFileOutputStream(outputFile); 102 | NetUtil.asyncCopy(input, output, resolve); 103 | } catch (e) { 104 | reject(new Error(`Could not unpack file ${file} in add-on: ${e}`)); 105 | } 106 | }); 107 | }); 108 | // Mark binaries as executable. 109 | if (exec) { 110 | await OS.File.setPermissions(filePath, { unixMode: 0o744 }); 111 | } 112 | } 113 | 114 | /** 115 | * Check state of binary unpacking, including the location and manifest. 116 | */ 117 | async function isUnpacked() { 118 | let dirPath = OS.Path.join(UNPACKED_ROOT_PATH, getPlatformDir()); 119 | let manifestPath = OS.Path.join(dirPath, MANIFEST); 120 | if (!await OS.File.exists(manifestPath)) { 121 | console.log("Needs unpacking, no manifest found"); 122 | return false; 123 | } 124 | let addonManifest = await getManifestFromAddon(); 125 | let unpackedManifest = await getManifestFromUnpacked(); 126 | if (addonManifest.version != unpackedManifest.version) { 127 | console.log( 128 | `Needs unpacking, add-on version ${addonManifest.version} != ` + 129 | `unpacked version ${unpackedManifest.version}` 130 | ); 131 | return false; 132 | } 133 | console.log("Already unpacked"); 134 | return true; 135 | } 136 | 137 | /** 138 | * Unpack binaries for the current OS along with the manifest. 139 | */ 140 | async function unpack() { 141 | let dirPath = OS.Path.join(UNPACKED_ROOT_PATH, getPlatformDir()); 142 | await OS.File.makeDir(dirPath, { from: OS.Constants.Path.localProfileDir }); 143 | let manifest = await getManifestFromAddon(); 144 | for (let file of manifest.files) { 145 | await unpackFile(file, { exec: true }); 146 | } 147 | await unpackFile(MANIFEST, { exec: false }); 148 | } 149 | 150 | /** 151 | * Get a file object for a given named binary that was packed in this add-on. 152 | * 153 | * @param {string} name 154 | * Base name of the binary, such as "adb". 155 | * @return {nsIFile} 156 | * File object for the binary. 157 | */ 158 | async function getFileForBinary(name) { 159 | if (!await isUnpacked()) { 160 | await unpack(); 161 | } 162 | let path = OS.Path.join(UNPACKED_ROOT_PATH, getPlatformDir(), name); 163 | let { OS: platform } = Services.appinfo; 164 | if (platform == "WINNT") { 165 | path += ".exe"; 166 | } 167 | console.log(`Binary path: ${path}`); 168 | return new FileUtils.File(path); 169 | } 170 | 171 | exports.getFileForBinary = getFileForBinary; 172 | -------------------------------------------------------------------------------- /bootstrap.js: -------------------------------------------------------------------------------- 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 | /* exported install, startup, shutdown, uninstall */ 8 | 9 | const Ci = Components.interfaces; 10 | const Cu = Components.utils; 11 | 12 | Cu.import("resource://gre/modules/Services.jsm"); 13 | 14 | const REASON = [ "unknown", "startup", "shutdown", "enable", "disable", 15 | "install", "uninstall", "upgrade", "downgrade" ]; 16 | 17 | // Useful piece of code from :bent 18 | // http://mxr.mozilla.org/mozilla-central/source/dom/workers/test/extensions/bootstrap/bootstrap.js 19 | function registerAddonResourceHandler(data) { 20 | let file = data.installPath; 21 | let fileURI = Services.io.newFileURI(file); 22 | if (!file.isDirectory()) { 23 | fileURI = Services.io.newURI("jar:" + fileURI.spec + "!/"); 24 | } 25 | let resourceName = encodeURIComponent(data.id.replace("@", "at")); 26 | 27 | Services.io.getProtocolHandler("resource"). 28 | QueryInterface(Ci.nsIResProtocolHandler). 29 | setSubstitution(resourceName, fileURI); 30 | 31 | return "resource://" + resourceName + "/"; 32 | } 33 | 34 | function getBaseLoader() { 35 | try { 36 | // >=FF57 use the base-loader from DevTools. 37 | return Cu.import("resource://devtools/shared/base-loader.js", {}); 38 | } catch (e) { 39 | // port); 38 | }, 39 | 40 | type: "adb", 41 | 42 | shell: adb.shell.bind(adb), 43 | forwardPort: adb.forwardPort.bind(adb), 44 | push: adb.push.bind(adb), 45 | pull: adb.pull.bind(adb), 46 | reboot: adb.reboot.bind(adb), 47 | rebootRecovery: adb.rebootRecovery.bind(adb), 48 | rebootBootloader: adb.rebootBootloader.bind(adb), 49 | 50 | isRoot() { 51 | return adb.shell("id").then(stdout => { 52 | if (stdout) { 53 | let uid = stdout.match(/uid=(\d+)/)[1]; 54 | return uid == "0"; 55 | } 56 | return false; 57 | }); 58 | }, 59 | 60 | summonRoot() { 61 | return adb.root(); 62 | }, 63 | 64 | getModel() { 65 | if (this._modelPromise) { 66 | return this._modelPromise; 67 | } 68 | this._modelPromise = this.shell("getprop ro.product.model") 69 | .then(model => model.trim()); 70 | return this._modelPromise; 71 | } 72 | }; 73 | 74 | module.exports = Device; 75 | -------------------------------------------------------------------------------- /devtools-import.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const { Cu } = require("chrome"); 4 | 5 | // In Firefox 44 and later, many DevTools modules were relocated. 6 | // See https://bugzil.la/912121 7 | const PATH_RENAMES = [ 8 | { 9 | regex: /^resource:\/\/devtools\/client\/framework\//, 10 | replacements: [ 11 | "resource:///modules/devtools/client/framework/", 12 | "resource:///modules/devtools/", 13 | ], 14 | }, 15 | { 16 | regex: /^resource:\/\/devtools\/shared\/apps\//, 17 | replacements: [ 18 | "resource://gre/modules/devtools/shared/apps/", 19 | "resource://gre/modules/devtools/", 20 | ], 21 | }, 22 | { 23 | regex: /^resource:\/\/devtools\/shared\//, 24 | replacements: [ 25 | "resource://gre/modules/devtools/shared/", 26 | "resource://gre/modules/devtools/", 27 | ], 28 | }, 29 | ]; 30 | 31 | function scopedImport(path) { 32 | let scope = {}; 33 | Cu.import(path, scope); 34 | return scope; 35 | } 36 | 37 | function devtoolsImport(path) { 38 | try { 39 | return scopedImport(path); 40 | } catch (e) { 41 | // Attempt known renames for 43 and earlier 42 | for (let { regex, replacements } of PATH_RENAMES) { 43 | if (!path.match(regex)) { 44 | continue; 45 | } 46 | for (let replacement of replacements) { 47 | try { 48 | return scopedImport(path.replace(regex, replacement)); 49 | } catch (e) { 50 | // Continue trying other replacements 51 | } 52 | } 53 | } 54 | } 55 | throw new Error(`Unable to import ${path}`); 56 | } 57 | 58 | module.exports = devtoolsImport; 59 | -------------------------------------------------------------------------------- /devtools-require.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const { devtools } = 4 | require("./devtools-import")("resource://devtools/shared/Loader.jsm"); 5 | 6 | // In Firefox 44 and later, many DevTools modules were relocated. 7 | // See https://bugzil.la/912121 8 | const ID_RENAMES = [ 9 | { 10 | regex: /^devtools\/client\/webide\/modules\//, 11 | replacement: "devtools/webide/" 12 | }, 13 | { 14 | regex: /^devtools\/shared\/client\//, 15 | replacement: "devtools/client/" 16 | }, 17 | { 18 | regex: /^devtools\/shared\/styleinspector\//, 19 | replacement: "devtools/styleinspector/" 20 | }, 21 | { 22 | regex: /^devtools\/shared\//, 23 | replacement: "devtools/toolkit/" 24 | }, 25 | ]; 26 | 27 | function devtoolsRequire(id) { 28 | try { 29 | return devtools.require(id); 30 | } catch (e) { 31 | // Attempt known renames for 43 and earlier 32 | for (let { regex, replacement } of ID_RENAMES) { 33 | id = id.replace(regex, replacement); 34 | } 35 | return devtools.require(id); 36 | } 37 | } 38 | 39 | module.exports = devtoolsRequire; 40 | -------------------------------------------------------------------------------- /events.js: -------------------------------------------------------------------------------- 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 | // Note: this module can be replaced once we're not supporting anymore versions of 6 | // Firefox with SDK. 7 | try { 8 | // =FF57, after SDK removal 12 | module.exports = require("./devtools-require")("devtools/shared/event-emitter"); 13 | } 14 | -------------------------------------------------------------------------------- /fastboot.js: -------------------------------------------------------------------------------- 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 | // Wrapper around the fastboot utility. 6 | 7 | "use strict"; 8 | 9 | // Whether or not this script is being loaded as a CommonJS module 10 | // (from an add-on built using the Add-on SDK). If it isn't a CommonJS Module, 11 | // then it's a JavaScript Module. 12 | 13 | const { Cu } = require("chrome"); 14 | const { Subprocess } = Cu.import("resource://gre/modules/Subprocess.jsm", {}); 15 | const { setInterval, clearInterval } = Cu.import("resource://gre/modules/Timer.jsm", {}); 16 | const { PromiseUtils } = Cu.import("resource://gre/modules/PromiseUtils.jsm", {}); 17 | const { getFileForBinary } = require("./binary-manager"); 18 | const { Devices } = 19 | require("./devtools-import")("resource://devtools/shared/apps/Devices.jsm"); 20 | 21 | let fastbootTimer = null; 22 | let fastbootDevices = []; 23 | 24 | const Fastboot = { 25 | get fastbootDevices() { 26 | return fastbootDevices; 27 | }, 28 | set fastbootDevices(newVal) { 29 | fastbootDevices = newVal; 30 | }, 31 | 32 | get fastbootFilePromise() { 33 | if (this._fastbootFilePromise) { 34 | return this._fastbootFilePromise; 35 | } 36 | this._fastbootFilePromise = getFileForBinary("fastboot"); 37 | return this._fastbootFilePromise; 38 | }, 39 | 40 | async do(args, serial) { 41 | let deferred = PromiseUtils.defer(); 42 | let out_buffer = []; 43 | let err_buffer = []; 44 | 45 | if (serial && typeof(serial) === "string") { 46 | args.unshift("-s", serial); 47 | } 48 | 49 | let binary = await this.fastbootFilePromise; 50 | let callPayload = { 51 | command: binary, 52 | arguments: args, 53 | stdout(data) { 54 | out_buffer.push(data); 55 | }, 56 | stderr(data) { 57 | err_buffer.push(data); 58 | }, 59 | done() { 60 | deferred.resolve({ stdout: out_buffer, stderr: err_buffer }); 61 | } 62 | }; 63 | 64 | Subprocess.call(callPayload); 65 | 66 | return deferred.promise; 67 | }, 68 | 69 | startPolling: function fastboot_startPolling() { 70 | console.debug("IN fastboot_startPolling"); 71 | 72 | if (fastbootTimer !== null) { 73 | console.warn("Fastboot poll already running."); 74 | return; 75 | } 76 | 77 | let doPoll = (function() { 78 | this.devices().then((devices) => { 79 | let added = []; 80 | let removed = []; 81 | 82 | if (devices.sort() === this.fastbootDevices.sort()) { 83 | console.debug("No change."); 84 | return; 85 | } 86 | 87 | console.debug("Read devices from fastboot output", devices); 88 | 89 | for (let dev of devices) { 90 | if (!this.fastbootDevices.includes(dev)) { 91 | added.push(dev); 92 | } 93 | } 94 | 95 | console.debug("Fastboot devices added", added); 96 | 97 | for (let dev of this.fastbootDevices) { 98 | // listed in previous devices and not in the current one 99 | if (!devices.includes(dev)) { 100 | removed.push(dev); 101 | } 102 | } 103 | 104 | console.debug("Fastboot devices removed", removed); 105 | 106 | this.fastbootDevices = devices; 107 | 108 | for (let dev of added) { 109 | let fbdevice = new FastbootDevice(dev); 110 | Devices.register(dev, fbdevice); 111 | } 112 | 113 | for (let dev of removed) { 114 | Devices.unregister(dev); 115 | } 116 | }); 117 | }).bind(this); 118 | 119 | console.log("fastboot_polling starting"); 120 | fastbootTimer = setInterval(doPoll, 2000); 121 | }, 122 | 123 | stopPolling: function fastboot_stopPolling() { 124 | console.debug("IN fastboot_stopPolling"); 125 | console.log("fastboot_polling stopping"); 126 | clearInterval(fastbootTimer); 127 | fastbootTimer = null; 128 | }, 129 | 130 | // Sends back an array of device names. 131 | devices: function fastboot_devices() { 132 | return this.do(["devices"]).then( 133 | function onSuccess(data) { 134 | let devices = []; 135 | for (let line of data.stdout) { 136 | let [ sn, mode ] = line.trim().split("\t"); 137 | if (mode === "fastboot") { 138 | devices.push(sn); 139 | } 140 | } 141 | return devices; 142 | }, function onError(error) { 143 | return []; 144 | }); 145 | }, 146 | 147 | getvar: function fastboot_getvar(varname, serial) { 148 | return this.do(["getvar", varname], serial).then( 149 | function onSuccess(data) { 150 | console.debug("getvar", data); 151 | // product: D6603finished. total time: 0.003s 152 | for (let line of data.stderr.join("\n").split("\n")) { 153 | if (line.includes(":")) { 154 | return line.split(":")[1].trim(); 155 | } 156 | } 157 | return ""; 158 | }, function onError(error) { 159 | console.debug("error getvar", error); 160 | return ""; 161 | } 162 | ); 163 | }, 164 | 165 | flash: function fastboot_flash(partition, image, serial) { 166 | return this.do(["flash", partition, image], serial).then( 167 | function onSuccess(data) { 168 | console.debug("flash", partition, image); 169 | // sending 'recovery' (5334 KB)... 170 | // OKAY [ 0.545s] 171 | // writing 'recovery'... 172 | // OKAY [ 0.891s] 173 | // finished. total time: 1.436s 174 | 175 | let flashProgress = { 176 | sending: false, 177 | sendingOk: false, 178 | writing: false, 179 | writingOk: false, 180 | finished: false 181 | }; 182 | 183 | console.debug("fastboot flash reported:", data); 184 | let fullOutput = data.stderr.join("\n").split("\n"); 185 | 186 | console.debug("Will look into", fullOutput); 187 | for (let line of fullOutput) { 188 | console.debug("Read:", line); 189 | if (!line || !line.includes(" ")) { 190 | console.debug("No space ..."); 191 | continue; 192 | } 193 | 194 | let first = line.split(" ")[0]; 195 | console.debug("Checking with:", first); 196 | switch (first) { 197 | case "sending": flashProgress.sending = true; break; 198 | case "writing": flashProgress.writing = true; break; 199 | case "finished.": flashProgress.finished = true; break; 200 | case "OKAY": 201 | if (flashProgress.sending && !flashProgress.writing) { 202 | flashProgress.sendingOk = true; 203 | } else if (flashProgress.sending && flashProgress.writing) { 204 | flashProgress.writingOk = true; 205 | } 206 | break; 207 | default: 208 | console.debug("Unknown state: ", first); 209 | } 210 | } 211 | 212 | return flashProgress; 213 | }, function onError(error) { 214 | console.debug("error flash", error); 215 | return ""; 216 | } 217 | ); 218 | }, 219 | 220 | reboot: function fastboot_reboot(serial) { 221 | return this.do(["reboot"], serial); 222 | } 223 | }; 224 | 225 | // Fastboot object 226 | function FastbootDevice(id) { 227 | this.id = id; 228 | } 229 | 230 | FastbootDevice.prototype = { 231 | 232 | type: "fastboot", 233 | devices: Fastboot.devices.bind(Fastboot), 234 | flash: Fastboot.flash.bind(Fastboot), 235 | getvar: Fastboot.getvar.bind(Fastboot), 236 | reboot: Fastboot.reboot.bind(Fastboot), 237 | 238 | startPolling: Fastboot.startPolling.bind(Fastboot), 239 | stopPolling: Fastboot.stopPolling.bind(Fastboot) 240 | 241 | }; 242 | 243 | module.exports = Fastboot; 244 | -------------------------------------------------------------------------------- /linux/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2006-2009, The Android Open Source Project 3 | Copyright 2006, Brian Swetland 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | See the License for the specific language governing permissions and 12 | limitations under the License. 13 | 14 | 15 | Apache License 16 | Version 2.0, January 2004 17 | http://www.apache.org/licenses/ 18 | 19 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 20 | 21 | 1. Definitions. 22 | 23 | "License" shall mean the terms and conditions for use, reproduction, 24 | and distribution as defined by Sections 1 through 9 of this document. 25 | 26 | "Licensor" shall mean the copyright owner or entity authorized by 27 | the copyright owner that is granting the License. 28 | 29 | "Legal Entity" shall mean the union of the acting entity and all 30 | other entities that control, are controlled by, or are under common 31 | control with that entity. For the purposes of this definition, 32 | "control" means (i) the power, direct or indirect, to cause the 33 | direction or management of such entity, whether by contract or 34 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 35 | outstanding shares, or (iii) beneficial ownership of such entity. 36 | 37 | "You" (or "Your") shall mean an individual or Legal Entity 38 | exercising permissions granted by this License. 39 | 40 | "Source" form shall mean the preferred form for making modifications, 41 | including but not limited to software source code, documentation 42 | source, and configuration files. 43 | 44 | "Object" form shall mean any form resulting from mechanical 45 | transformation or translation of a Source form, including but 46 | not limited to compiled object code, generated documentation, 47 | and conversions to other media types. 48 | 49 | "Work" shall mean the work of authorship, whether in Source or 50 | Object form, made available under the License, as indicated by a 51 | copyright notice that is included in or attached to the work 52 | (an example is provided in the Appendix below). 53 | 54 | "Derivative Works" shall mean any work, whether in Source or Object 55 | form, that is based on (or derived from) the Work and for which the 56 | editorial revisions, annotations, elaborations, or other modifications 57 | represent, as a whole, an original work of authorship. For the purposes 58 | of this License, Derivative Works shall not include works that remain 59 | separable from, or merely link (or bind by name) to the interfaces of, 60 | the Work and Derivative Works thereof. 61 | 62 | "Contribution" shall mean any work of authorship, including 63 | the original version of the Work and any modifications or additions 64 | to that Work or Derivative Works thereof, that is intentionally 65 | submitted to Licensor for inclusion in the Work by the copyright owner 66 | or by an individual or Legal Entity authorized to submit on behalf of 67 | the copyright owner. For the purposes of this definition, "submitted" 68 | means any form of electronic, verbal, or written communication sent 69 | to the Licensor or its representatives, including but not limited to 70 | communication on electronic mailing lists, source code control systems, 71 | and issue tracking systems that are managed by, or on behalf of, the 72 | Licensor for the purpose of discussing and improving the Work, but 73 | excluding communication that is conspicuously marked or otherwise 74 | designated in writing by the copyright owner as "Not a Contribution." 75 | 76 | "Contributor" shall mean Licensor and any individual or Legal Entity 77 | on behalf of whom a Contribution has been received by Licensor and 78 | subsequently incorporated within the Work. 79 | 80 | 2. Grant of Copyright License. Subject to the terms and conditions of 81 | this License, each Contributor hereby grants to You a perpetual, 82 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 83 | copyright license to reproduce, prepare Derivative Works of, 84 | publicly display, publicly perform, sublicense, and distribute the 85 | Work and such Derivative Works in Source or Object form. 86 | 87 | 3. Grant of Patent License. Subject to the terms and conditions of 88 | this License, each Contributor hereby grants to You a perpetual, 89 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 90 | (except as stated in this section) patent license to make, have made, 91 | use, offer to sell, sell, import, and otherwise transfer the Work, 92 | where such license applies only to those patent claims licensable 93 | by such Contributor that are necessarily infringed by their 94 | Contribution(s) alone or by combination of their Contribution(s) 95 | with the Work to which such Contribution(s) was submitted. If You 96 | institute patent litigation against any entity (including a 97 | cross-claim or counterclaim in a lawsuit) alleging that the Work 98 | or a Contribution incorporated within the Work constitutes direct 99 | or contributory patent infringement, then any patent licenses 100 | granted to You under this License for that Work shall terminate 101 | as of the date such litigation is filed. 102 | 103 | 4. Redistribution. You may reproduce and distribute copies of the 104 | Work or Derivative Works thereof in any medium, with or without 105 | modifications, and in Source or Object form, provided that You 106 | meet the following conditions: 107 | 108 | (a) You must give any other recipients of the Work or 109 | Derivative Works a copy of this License; and 110 | 111 | (b) You must cause any modified files to carry prominent notices 112 | stating that You changed the files; and 113 | 114 | (c) You must retain, in the Source form of any Derivative Works 115 | that You distribute, all copyright, patent, trademark, and 116 | attribution notices from the Source form of the Work, 117 | excluding those notices that do not pertain to any part of 118 | the Derivative Works; and 119 | 120 | (d) If the Work includes a "NOTICE" text file as part of its 121 | distribution, then any Derivative Works that You distribute must 122 | include a readable copy of the attribution notices contained 123 | within such NOTICE file, excluding those notices that do not 124 | pertain to any part of the Derivative Works, in at least one 125 | of the following places: within a NOTICE text file distributed 126 | as part of the Derivative Works; within the Source form or 127 | documentation, if provided along with the Derivative Works; or, 128 | within a display generated by the Derivative Works, if and 129 | wherever such third-party notices normally appear. The contents 130 | of the NOTICE file are for informational purposes only and 131 | do not modify the License. You may add Your own attribution 132 | notices within Derivative Works that You distribute, alongside 133 | or as an addendum to the NOTICE text from the Work, provided 134 | that such additional attribution notices cannot be construed 135 | as modifying the License. 136 | 137 | You may add Your own copyright statement to Your modifications and 138 | may provide additional or different license terms and conditions 139 | for use, reproduction, or distribution of Your modifications, or 140 | for any such Derivative Works as a whole, provided Your use, 141 | reproduction, and distribution of the Work otherwise complies with 142 | the conditions stated in this License. 143 | 144 | 5. Submission of Contributions. Unless You explicitly state otherwise, 145 | any Contribution intentionally submitted for inclusion in the Work 146 | by You to the Licensor shall be under the terms and conditions of 147 | this License, without any additional terms or conditions. 148 | Notwithstanding the above, nothing herein shall supersede or modify 149 | the terms of any separate license agreement you may have executed 150 | with Licensor regarding such Contributions. 151 | 152 | 6. Trademarks. This License does not grant permission to use the trade 153 | names, trademarks, service marks, or product names of the Licensor, 154 | except as required for reasonable and customary use in describing the 155 | origin of the Work and reproducing the content of the NOTICE file. 156 | 157 | 7. Disclaimer of Warranty. Unless required by applicable law or 158 | agreed to in writing, Licensor provides the Work (and each 159 | Contributor provides its Contributions) on an "AS IS" BASIS, 160 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 161 | implied, including, without limitation, any warranties or conditions 162 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 163 | PARTICULAR PURPOSE. You are solely responsible for determining the 164 | appropriateness of using or redistributing the Work and assume any 165 | risks associated with Your exercise of permissions under this License. 166 | 167 | 8. Limitation of Liability. In no event and under no legal theory, 168 | whether in tort (including negligence), contract, or otherwise, 169 | unless required by applicable law (such as deliberate and grossly 170 | negligent acts) or agreed to in writing, shall any Contributor be 171 | liable to You for damages, including any direct, indirect, special, 172 | incidental, or consequential damages of any character arising as a 173 | result of this License or out of the use or inability to use the 174 | Work (including but not limited to damages for loss of goodwill, 175 | work stoppage, computer failure or malfunction, or any and all 176 | other commercial damages or losses), even if such Contributor 177 | has been advised of the possibility of such damages. 178 | 179 | 9. Accepting Warranty or Additional Liability. While redistributing 180 | the Work or Derivative Works thereof, You may choose to offer, 181 | and charge a fee for, acceptance of support, warranty, indemnity, 182 | or other liability obligations and/or rights consistent with this 183 | License. However, in accepting such obligations, You may act only 184 | on Your own behalf and on Your sole responsibility, not on behalf 185 | of any other Contributor, and only if You agree to indemnify, 186 | defend, and hold each Contributor harmless for any liability 187 | incurred by, or claims asserted against, such Contributor by reason 188 | of your accepting any such warranty or additional liability. 189 | 190 | END OF TERMS AND CONDITIONS 191 | 192 | -------------------------------------------------------------------------------- /linux/README: -------------------------------------------------------------------------------- 1 | This is the Android Debug Bridge (ADB). It is made available under the terms 2 | of the Apache 2.0 License in LICENSE. Its source code is available 3 | at , and you can reproduce this package by building 4 | the Android SDK per the instructions at that site. 5 | -------------------------------------------------------------------------------- /linux/adb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/adbhelper/0821424b6b895645560089a134054b35b6649ff8/linux/adb -------------------------------------------------------------------------------- /linux/fastboot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/adbhelper/0821424b6b895645560089a134054b35b6649ff8/linux/fastboot -------------------------------------------------------------------------------- /linux/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.12", 3 | "files": [ 4 | "adb", 5 | "fastboot" 6 | ] 7 | } -------------------------------------------------------------------------------- /linux64/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2006-2009, The Android Open Source Project 3 | Copyright 2006, Brian Swetland 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | See the License for the specific language governing permissions and 12 | limitations under the License. 13 | 14 | 15 | Apache License 16 | Version 2.0, January 2004 17 | http://www.apache.org/licenses/ 18 | 19 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 20 | 21 | 1. Definitions. 22 | 23 | "License" shall mean the terms and conditions for use, reproduction, 24 | and distribution as defined by Sections 1 through 9 of this document. 25 | 26 | "Licensor" shall mean the copyright owner or entity authorized by 27 | the copyright owner that is granting the License. 28 | 29 | "Legal Entity" shall mean the union of the acting entity and all 30 | other entities that control, are controlled by, or are under common 31 | control with that entity. For the purposes of this definition, 32 | "control" means (i) the power, direct or indirect, to cause the 33 | direction or management of such entity, whether by contract or 34 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 35 | outstanding shares, or (iii) beneficial ownership of such entity. 36 | 37 | "You" (or "Your") shall mean an individual or Legal Entity 38 | exercising permissions granted by this License. 39 | 40 | "Source" form shall mean the preferred form for making modifications, 41 | including but not limited to software source code, documentation 42 | source, and configuration files. 43 | 44 | "Object" form shall mean any form resulting from mechanical 45 | transformation or translation of a Source form, including but 46 | not limited to compiled object code, generated documentation, 47 | and conversions to other media types. 48 | 49 | "Work" shall mean the work of authorship, whether in Source or 50 | Object form, made available under the License, as indicated by a 51 | copyright notice that is included in or attached to the work 52 | (an example is provided in the Appendix below). 53 | 54 | "Derivative Works" shall mean any work, whether in Source or Object 55 | form, that is based on (or derived from) the Work and for which the 56 | editorial revisions, annotations, elaborations, or other modifications 57 | represent, as a whole, an original work of authorship. For the purposes 58 | of this License, Derivative Works shall not include works that remain 59 | separable from, or merely link (or bind by name) to the interfaces of, 60 | the Work and Derivative Works thereof. 61 | 62 | "Contribution" shall mean any work of authorship, including 63 | the original version of the Work and any modifications or additions 64 | to that Work or Derivative Works thereof, that is intentionally 65 | submitted to Licensor for inclusion in the Work by the copyright owner 66 | or by an individual or Legal Entity authorized to submit on behalf of 67 | the copyright owner. For the purposes of this definition, "submitted" 68 | means any form of electronic, verbal, or written communication sent 69 | to the Licensor or its representatives, including but not limited to 70 | communication on electronic mailing lists, source code control systems, 71 | and issue tracking systems that are managed by, or on behalf of, the 72 | Licensor for the purpose of discussing and improving the Work, but 73 | excluding communication that is conspicuously marked or otherwise 74 | designated in writing by the copyright owner as "Not a Contribution." 75 | 76 | "Contributor" shall mean Licensor and any individual or Legal Entity 77 | on behalf of whom a Contribution has been received by Licensor and 78 | subsequently incorporated within the Work. 79 | 80 | 2. Grant of Copyright License. Subject to the terms and conditions of 81 | this License, each Contributor hereby grants to You a perpetual, 82 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 83 | copyright license to reproduce, prepare Derivative Works of, 84 | publicly display, publicly perform, sublicense, and distribute the 85 | Work and such Derivative Works in Source or Object form. 86 | 87 | 3. Grant of Patent License. Subject to the terms and conditions of 88 | this License, each Contributor hereby grants to You a perpetual, 89 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 90 | (except as stated in this section) patent license to make, have made, 91 | use, offer to sell, sell, import, and otherwise transfer the Work, 92 | where such license applies only to those patent claims licensable 93 | by such Contributor that are necessarily infringed by their 94 | Contribution(s) alone or by combination of their Contribution(s) 95 | with the Work to which such Contribution(s) was submitted. If You 96 | institute patent litigation against any entity (including a 97 | cross-claim or counterclaim in a lawsuit) alleging that the Work 98 | or a Contribution incorporated within the Work constitutes direct 99 | or contributory patent infringement, then any patent licenses 100 | granted to You under this License for that Work shall terminate 101 | as of the date such litigation is filed. 102 | 103 | 4. Redistribution. You may reproduce and distribute copies of the 104 | Work or Derivative Works thereof in any medium, with or without 105 | modifications, and in Source or Object form, provided that You 106 | meet the following conditions: 107 | 108 | (a) You must give any other recipients of the Work or 109 | Derivative Works a copy of this License; and 110 | 111 | (b) You must cause any modified files to carry prominent notices 112 | stating that You changed the files; and 113 | 114 | (c) You must retain, in the Source form of any Derivative Works 115 | that You distribute, all copyright, patent, trademark, and 116 | attribution notices from the Source form of the Work, 117 | excluding those notices that do not pertain to any part of 118 | the Derivative Works; and 119 | 120 | (d) If the Work includes a "NOTICE" text file as part of its 121 | distribution, then any Derivative Works that You distribute must 122 | include a readable copy of the attribution notices contained 123 | within such NOTICE file, excluding those notices that do not 124 | pertain to any part of the Derivative Works, in at least one 125 | of the following places: within a NOTICE text file distributed 126 | as part of the Derivative Works; within the Source form or 127 | documentation, if provided along with the Derivative Works; or, 128 | within a display generated by the Derivative Works, if and 129 | wherever such third-party notices normally appear. The contents 130 | of the NOTICE file are for informational purposes only and 131 | do not modify the License. You may add Your own attribution 132 | notices within Derivative Works that You distribute, alongside 133 | or as an addendum to the NOTICE text from the Work, provided 134 | that such additional attribution notices cannot be construed 135 | as modifying the License. 136 | 137 | You may add Your own copyright statement to Your modifications and 138 | may provide additional or different license terms and conditions 139 | for use, reproduction, or distribution of Your modifications, or 140 | for any such Derivative Works as a whole, provided Your use, 141 | reproduction, and distribution of the Work otherwise complies with 142 | the conditions stated in this License. 143 | 144 | 5. Submission of Contributions. Unless You explicitly state otherwise, 145 | any Contribution intentionally submitted for inclusion in the Work 146 | by You to the Licensor shall be under the terms and conditions of 147 | this License, without any additional terms or conditions. 148 | Notwithstanding the above, nothing herein shall supersede or modify 149 | the terms of any separate license agreement you may have executed 150 | with Licensor regarding such Contributions. 151 | 152 | 6. Trademarks. This License does not grant permission to use the trade 153 | names, trademarks, service marks, or product names of the Licensor, 154 | except as required for reasonable and customary use in describing the 155 | origin of the Work and reproducing the content of the NOTICE file. 156 | 157 | 7. Disclaimer of Warranty. Unless required by applicable law or 158 | agreed to in writing, Licensor provides the Work (and each 159 | Contributor provides its Contributions) on an "AS IS" BASIS, 160 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 161 | implied, including, without limitation, any warranties or conditions 162 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 163 | PARTICULAR PURPOSE. You are solely responsible for determining the 164 | appropriateness of using or redistributing the Work and assume any 165 | risks associated with Your exercise of permissions under this License. 166 | 167 | 8. Limitation of Liability. In no event and under no legal theory, 168 | whether in tort (including negligence), contract, or otherwise, 169 | unless required by applicable law (such as deliberate and grossly 170 | negligent acts) or agreed to in writing, shall any Contributor be 171 | liable to You for damages, including any direct, indirect, special, 172 | incidental, or consequential damages of any character arising as a 173 | result of this License or out of the use or inability to use the 174 | Work (including but not limited to damages for loss of goodwill, 175 | work stoppage, computer failure or malfunction, or any and all 176 | other commercial damages or losses), even if such Contributor 177 | has been advised of the possibility of such damages. 178 | 179 | 9. Accepting Warranty or Additional Liability. While redistributing 180 | the Work or Derivative Works thereof, You may choose to offer, 181 | and charge a fee for, acceptance of support, warranty, indemnity, 182 | or other liability obligations and/or rights consistent with this 183 | License. However, in accepting such obligations, You may act only 184 | on Your own behalf and on Your sole responsibility, not on behalf 185 | of any other Contributor, and only if You agree to indemnify, 186 | defend, and hold each Contributor harmless for any liability 187 | incurred by, or claims asserted against, such Contributor by reason 188 | of your accepting any such warranty or additional liability. 189 | 190 | END OF TERMS AND CONDITIONS 191 | 192 | -------------------------------------------------------------------------------- /linux64/README: -------------------------------------------------------------------------------- 1 | This is the Android Debug Bridge (ADB). It is made available under the terms 2 | of the Apache 2.0 License in LICENSE. Its source code is available originally 3 | at , although this version was built from source 4 | code available at ; 5 | and you can reproduce this package via the following instructions 6 | (for Ubuntu 13.04 Raring): 7 | 8 | 1. sudo apt-get build-dep android-tools-adb 9 | 2. apt-get source android-tools-adb 10 | 3. cd android-tools-4.2.2+git20130218/ 11 | 12 | 4. Apply this patch to debian/makefiles/adb.mk (to link libcrypto statically, 13 | so the executable works on Linux installations with different versions of it): 14 | 15 | --- debian/makefiles/adb.mk 2013-03-26 14:15:41.000000000 -0700 16 | +++ adb-static-crypto.mk 2013-06-06 16:51:52.794521267 -0700 17 | @@ -40,15 +40,16 @@ 18 | CPPFLAGS+= -I. 19 | CPPFLAGS+= -I../include 20 | CPPFLAGS+= -I../../../external/zlib 21 | +CPPFLAGS+= -I/usr/include/openssl 22 | 23 | -LIBS+= -lc -lpthread -lz -lcrypto 24 | +LIBS+= -lc -lpthread -lz -ldl 25 | 26 | OBJS= $(SRCS:.c=.o) 27 | 28 | all: adb 29 | 30 | adb: $(OBJS) 31 | - $(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS) 32 | + $(CC) -o $@ $(LDFLAGS) $(OBJS) /usr/lib/x86_64-linux-gnu/libcrypto.a $(LIBS) 33 | 34 | clean: 35 | rm -rf $(OBJS) adb 36 | 37 | 5. cd core/adb && make -f ../../debian/makefiles/adb.mk 38 | -------------------------------------------------------------------------------- /linux64/README.fastboot: -------------------------------------------------------------------------------- 1 | This is the Fastboot tool. It is made available under the terms 2 | of the Apache 2.0 License in LICENSE. Its source code is available originally 3 | at , although this version was built from source 4 | code available at ; 5 | and you can reproduce this package via the following instructions 6 | (for Ubuntu 14.10 Utopic): 7 | 8 | 1. sudo apt-get build-dep android-tools-adb 9 | 2. apt-get source android-tools-adb 10 | 3. cd android-tools-4.2.2+git20130218/ 11 | 12 | 4. apply the following patch, to statically link selinux (and its deps): 13 | 14 | --- debian/makefiles/fastboot.mk 2015-05-18 19:23:28.126995460 +0200 15 | +++ debian/makefiles/fastboot.mk 2014-03-14 05:05:30.000000000 +0100 16 | @@ -37,12 +37,18 @@ 17 | CPPFLAGS+= -I../../extras/ext4_utils/ 18 | CPPFLAGS+= -I../libsparse/include/ 19 | 20 | -LIBS+= -lz -lselinux 21 | +LIBS+= -lz 22 | +STATIC_LIBS= libselinux.a libsepol.a libpcre.a 23 | 24 | OBJS= $(SRCS:.c=.o) 25 | 26 | +OBJS+= $(STATIC_LIBS) 27 | + 28 | all: fastboot 29 | 30 | +$(STATIC_LIBS): 31 | + cp /usr/lib/x86_64-linux-gnu/$@ . 32 | + 33 | fastboot: $(OBJS) 34 | $(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS) 35 | 36 | 37 | 5. cd core/fastboot && make -f ../../debian/makefiles/fastboot.mk 38 | 6. reducing from ~800K to ~275K: strip fastboot && upx fastboot 39 | -------------------------------------------------------------------------------- /linux64/adb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/adbhelper/0821424b6b895645560089a134054b35b6649ff8/linux64/adb -------------------------------------------------------------------------------- /linux64/fastboot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/adbhelper/0821424b6b895645560089a134054b35b6649ff8/linux64/fastboot -------------------------------------------------------------------------------- /linux64/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.12", 3 | "files": [ 4 | "adb", 5 | "fastboot" 6 | ] 7 | } -------------------------------------------------------------------------------- /mac64/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2006-2009, The Android Open Source Project 3 | Copyright 2006, Brian Swetland 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | See the License for the specific language governing permissions and 12 | limitations under the License. 13 | 14 | 15 | Apache License 16 | Version 2.0, January 2004 17 | http://www.apache.org/licenses/ 18 | 19 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 20 | 21 | 1. Definitions. 22 | 23 | "License" shall mean the terms and conditions for use, reproduction, 24 | and distribution as defined by Sections 1 through 9 of this document. 25 | 26 | "Licensor" shall mean the copyright owner or entity authorized by 27 | the copyright owner that is granting the License. 28 | 29 | "Legal Entity" shall mean the union of the acting entity and all 30 | other entities that control, are controlled by, or are under common 31 | control with that entity. For the purposes of this definition, 32 | "control" means (i) the power, direct or indirect, to cause the 33 | direction or management of such entity, whether by contract or 34 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 35 | outstanding shares, or (iii) beneficial ownership of such entity. 36 | 37 | "You" (or "Your") shall mean an individual or Legal Entity 38 | exercising permissions granted by this License. 39 | 40 | "Source" form shall mean the preferred form for making modifications, 41 | including but not limited to software source code, documentation 42 | source, and configuration files. 43 | 44 | "Object" form shall mean any form resulting from mechanical 45 | transformation or translation of a Source form, including but 46 | not limited to compiled object code, generated documentation, 47 | and conversions to other media types. 48 | 49 | "Work" shall mean the work of authorship, whether in Source or 50 | Object form, made available under the License, as indicated by a 51 | copyright notice that is included in or attached to the work 52 | (an example is provided in the Appendix below). 53 | 54 | "Derivative Works" shall mean any work, whether in Source or Object 55 | form, that is based on (or derived from) the Work and for which the 56 | editorial revisions, annotations, elaborations, or other modifications 57 | represent, as a whole, an original work of authorship. For the purposes 58 | of this License, Derivative Works shall not include works that remain 59 | separable from, or merely link (or bind by name) to the interfaces of, 60 | the Work and Derivative Works thereof. 61 | 62 | "Contribution" shall mean any work of authorship, including 63 | the original version of the Work and any modifications or additions 64 | to that Work or Derivative Works thereof, that is intentionally 65 | submitted to Licensor for inclusion in the Work by the copyright owner 66 | or by an individual or Legal Entity authorized to submit on behalf of 67 | the copyright owner. For the purposes of this definition, "submitted" 68 | means any form of electronic, verbal, or written communication sent 69 | to the Licensor or its representatives, including but not limited to 70 | communication on electronic mailing lists, source code control systems, 71 | and issue tracking systems that are managed by, or on behalf of, the 72 | Licensor for the purpose of discussing and improving the Work, but 73 | excluding communication that is conspicuously marked or otherwise 74 | designated in writing by the copyright owner as "Not a Contribution." 75 | 76 | "Contributor" shall mean Licensor and any individual or Legal Entity 77 | on behalf of whom a Contribution has been received by Licensor and 78 | subsequently incorporated within the Work. 79 | 80 | 2. Grant of Copyright License. Subject to the terms and conditions of 81 | this License, each Contributor hereby grants to You a perpetual, 82 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 83 | copyright license to reproduce, prepare Derivative Works of, 84 | publicly display, publicly perform, sublicense, and distribute the 85 | Work and such Derivative Works in Source or Object form. 86 | 87 | 3. Grant of Patent License. Subject to the terms and conditions of 88 | this License, each Contributor hereby grants to You a perpetual, 89 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 90 | (except as stated in this section) patent license to make, have made, 91 | use, offer to sell, sell, import, and otherwise transfer the Work, 92 | where such license applies only to those patent claims licensable 93 | by such Contributor that are necessarily infringed by their 94 | Contribution(s) alone or by combination of their Contribution(s) 95 | with the Work to which such Contribution(s) was submitted. If You 96 | institute patent litigation against any entity (including a 97 | cross-claim or counterclaim in a lawsuit) alleging that the Work 98 | or a Contribution incorporated within the Work constitutes direct 99 | or contributory patent infringement, then any patent licenses 100 | granted to You under this License for that Work shall terminate 101 | as of the date such litigation is filed. 102 | 103 | 4. Redistribution. You may reproduce and distribute copies of the 104 | Work or Derivative Works thereof in any medium, with or without 105 | modifications, and in Source or Object form, provided that You 106 | meet the following conditions: 107 | 108 | (a) You must give any other recipients of the Work or 109 | Derivative Works a copy of this License; and 110 | 111 | (b) You must cause any modified files to carry prominent notices 112 | stating that You changed the files; and 113 | 114 | (c) You must retain, in the Source form of any Derivative Works 115 | that You distribute, all copyright, patent, trademark, and 116 | attribution notices from the Source form of the Work, 117 | excluding those notices that do not pertain to any part of 118 | the Derivative Works; and 119 | 120 | (d) If the Work includes a "NOTICE" text file as part of its 121 | distribution, then any Derivative Works that You distribute must 122 | include a readable copy of the attribution notices contained 123 | within such NOTICE file, excluding those notices that do not 124 | pertain to any part of the Derivative Works, in at least one 125 | of the following places: within a NOTICE text file distributed 126 | as part of the Derivative Works; within the Source form or 127 | documentation, if provided along with the Derivative Works; or, 128 | within a display generated by the Derivative Works, if and 129 | wherever such third-party notices normally appear. The contents 130 | of the NOTICE file are for informational purposes only and 131 | do not modify the License. You may add Your own attribution 132 | notices within Derivative Works that You distribute, alongside 133 | or as an addendum to the NOTICE text from the Work, provided 134 | that such additional attribution notices cannot be construed 135 | as modifying the License. 136 | 137 | You may add Your own copyright statement to Your modifications and 138 | may provide additional or different license terms and conditions 139 | for use, reproduction, or distribution of Your modifications, or 140 | for any such Derivative Works as a whole, provided Your use, 141 | reproduction, and distribution of the Work otherwise complies with 142 | the conditions stated in this License. 143 | 144 | 5. Submission of Contributions. Unless You explicitly state otherwise, 145 | any Contribution intentionally submitted for inclusion in the Work 146 | by You to the Licensor shall be under the terms and conditions of 147 | this License, without any additional terms or conditions. 148 | Notwithstanding the above, nothing herein shall supersede or modify 149 | the terms of any separate license agreement you may have executed 150 | with Licensor regarding such Contributions. 151 | 152 | 6. Trademarks. This License does not grant permission to use the trade 153 | names, trademarks, service marks, or product names of the Licensor, 154 | except as required for reasonable and customary use in describing the 155 | origin of the Work and reproducing the content of the NOTICE file. 156 | 157 | 7. Disclaimer of Warranty. Unless required by applicable law or 158 | agreed to in writing, Licensor provides the Work (and each 159 | Contributor provides its Contributions) on an "AS IS" BASIS, 160 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 161 | implied, including, without limitation, any warranties or conditions 162 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 163 | PARTICULAR PURPOSE. You are solely responsible for determining the 164 | appropriateness of using or redistributing the Work and assume any 165 | risks associated with Your exercise of permissions under this License. 166 | 167 | 8. Limitation of Liability. In no event and under no legal theory, 168 | whether in tort (including negligence), contract, or otherwise, 169 | unless required by applicable law (such as deliberate and grossly 170 | negligent acts) or agreed to in writing, shall any Contributor be 171 | liable to You for damages, including any direct, indirect, special, 172 | incidental, or consequential damages of any character arising as a 173 | result of this License or out of the use or inability to use the 174 | Work (including but not limited to damages for loss of goodwill, 175 | work stoppage, computer failure or malfunction, or any and all 176 | other commercial damages or losses), even if such Contributor 177 | has been advised of the possibility of such damages. 178 | 179 | 9. Accepting Warranty or Additional Liability. While redistributing 180 | the Work or Derivative Works thereof, You may choose to offer, 181 | and charge a fee for, acceptance of support, warranty, indemnity, 182 | or other liability obligations and/or rights consistent with this 183 | License. However, in accepting such obligations, You may act only 184 | on Your own behalf and on Your sole responsibility, not on behalf 185 | of any other Contributor, and only if You agree to indemnify, 186 | defend, and hold each Contributor harmless for any liability 187 | incurred by, or claims asserted against, such Contributor by reason 188 | of your accepting any such warranty or additional liability. 189 | 190 | END OF TERMS AND CONDITIONS 191 | 192 | -------------------------------------------------------------------------------- /mac64/README: -------------------------------------------------------------------------------- 1 | This is the Android Debug Bridge (ADB). It is made available under the terms 2 | of the Apache 2.0 License in LICENSE. Its source code is available 3 | at , and you can reproduce this package by building 4 | the Android SDK per the instructions at that site. 5 | -------------------------------------------------------------------------------- /mac64/adb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/adbhelper/0821424b6b895645560089a134054b35b6649ff8/mac64/adb -------------------------------------------------------------------------------- /mac64/fastboot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/adbhelper/0821424b6b895645560089a134054b35b6649ff8/mac64/fastboot -------------------------------------------------------------------------------- /mac64/mac-build.patch: -------------------------------------------------------------------------------- 1 | diff -uwr android-tools/debian/makefiles/adb.mk android-tools-patched/debian/makefiles/adb.mk 2 | --- android-tools/debian/makefiles/adb.mk 2014-11-24 21:27:47.000000000 +0100 3 | +++ android-tools-patched/debian/makefiles/adb.mk 2015-05-20 15:21:43.000000000 +0200 4 | @@ -10,13 +10,13 @@ 5 | SRCS+= console.c 6 | SRCS+= file_sync_client.c 7 | SRCS+= fdevent.c 8 | -SRCS+= get_my_path_linux.c 9 | +SRCS+= get_my_path_osx.c 10 | SRCS+= services.c 11 | SRCS+= sockets.c 12 | SRCS+= transport.c 13 | SRCS+= transport_local.c 14 | SRCS+= transport_usb.c 15 | -SRCS+= usb_linux.c 16 | +SRCS+= usb_osx.c 17 | SRCS+= usb_vendors.c 18 | SRCS+= utils.c 19 | 20 | @@ -40,7 +40,7 @@ 21 | CPPFLAGS+= -DADB_HOST=1 22 | CPPFLAGS+= -I$(SRCDIR)/core/adb 23 | CPPFLAGS+= -I$(SRCDIR)/core/include 24 | -CPPFLAGS+= -include /usr/include/android/arch/linux-x86/AndroidConfig.h 25 | +#CPPFLAGS+= -include /usr/include/android/arch/linux-x86/AndroidConfig.h 26 | 27 | LIBS+= -lc -lpthread -lz -lcrypto 28 | 29 | diff -uwr android-tools/debian/makefiles/ext4_utils.mk android-tools-patched/debian/makefiles/ext4_utils.mk 30 | --- android-tools/debian/makefiles/ext4_utils.mk 2014-11-24 21:27:47.000000000 +0100 31 | +++ android-tools-patched/debian/makefiles/ext4_utils.mk 2015-05-20 15:21:52.000000000 +0200 32 | @@ -38,9 +38,9 @@ 33 | CPPFLAGS+= -I/usr/include 34 | CPPFLAGS+= -I$(SRCDIR)/core/include 35 | CPPFLAGS+= -I$(SRCDIR)/core/libsparse/include 36 | -CPPFLAGS+= -include /usr/include/android/arch/linux-x86/AndroidConfig.h 37 | +#CPPFLAGS+= -include /usr/include/android/arch/linux-x86/AndroidConfig.h 38 | 39 | -LIBS+= -lz -lselinux 40 | +LIBS+= -lz 41 | 42 | OBJS= $(SRCS:.c=.o) 43 | 44 | diff -uwr android-tools/debian/makefiles/fastboot.mk android-tools-patched/debian/makefiles/fastboot.mk 45 | --- android-tools/debian/makefiles/fastboot.mk 2014-11-24 21:27:47.000000000 +0100 46 | +++ android-tools-patched/debian/makefiles/fastboot.mk 2015-05-20 15:26:11.000000000 +0200 47 | @@ -7,8 +7,8 @@ 48 | SRCS+= engine.c 49 | SRCS+= fastboot.c 50 | SRCS+= protocol.c 51 | -SRCS+= usb_linux.c 52 | -SRCS+= util_linux.c 53 | +SRCS+= usb_osx.c 54 | +SRCS+= util_osx.c 55 | 56 | VPATH+= $(SRCDIR)/core/libzipfile 57 | SRCS+= centraldir.c 58 | @@ -39,9 +39,9 @@ 59 | CPPFLAGS+= -I$(SRCDIR)/core/mkbootimg 60 | CPPFLAGS+= -I$(SRCDIR)/extras/ext4_utils 61 | CPPFLAGS+= -I$(SRCDIR)/core/libsparse/include 62 | -CPPFLAGS+= -include /usr/include/android/arch/linux-x86/AndroidConfig.h 63 | +#CPPFLAGS+= -include /usr/include/android/arch/linux-x86/AndroidConfig.h 64 | 65 | -LIBS+= -lz -lselinux 66 | +LIBS+= -lz -framework CoreServices -framework IOKit -framework Carbon 67 | 68 | OBJS= $(SRCS:.c=.o) 69 | 70 | diff -uwr android-tools/extras/ext4_utils/make_ext4fs.c android-tools-patched/extras/ext4_utils/make_ext4fs.c 71 | --- android-tools/extras/ext4_utils/make_ext4fs.c 2013-05-29 22:16:54.000000000 +0200 72 | +++ android-tools-patched/extras/ext4_utils/make_ext4fs.c 2015-05-20 15:29:17.000000000 +0200 73 | @@ -59,9 +59,9 @@ 74 | 75 | #else 76 | 77 | -#include 78 | -#include 79 | -#include 80 | +//#include 81 | +//#include 82 | +//#include 83 | 84 | #define O_BINARY 0 85 | 86 | @@ -181,14 +181,14 @@ 87 | #endif 88 | } 89 | #ifndef USE_MINGW 90 | - if (sehnd) { 91 | - if (selabel_lookup(sehnd, &dentries[i].secon, dentries[i].path, stat.st_mode) < 0) { 92 | - error("cannot lookup security context for %s", dentries[i].path); 93 | - } 94 | - 95 | - if (dentries[i].secon && verbose) 96 | - printf("Labeling %s as %s\n", dentries[i].path, dentries[i].secon); 97 | - } 98 | + // if (sehnd) { 99 | + // if (selabel_lookup(sehnd, &dentries[i].secon, dentries[i].path, stat.st_mode) < 0) { 100 | + // error("cannot lookup security context for %s", dentries[i].path); 101 | + // } 102 | + 103 | + // if (dentries[i].secon && verbose) 104 | + // printf("Labeling %s as %s\n", dentries[i].path, dentries[i].secon); 105 | + // } 106 | #endif 107 | 108 | if (S_ISREG(stat.st_mode)) { 109 | @@ -231,10 +231,10 @@ 110 | dentries[0].file_type = EXT4_FT_DIR; 111 | dentries[0].uid = 0; 112 | dentries[0].gid = 0; 113 | - if (sehnd) { 114 | - if (selabel_lookup(sehnd, &dentries[0].secon, dentries[0].path, dentries[0].mode) < 0) 115 | - error("cannot lookup security context for %s", dentries[0].path); 116 | - } 117 | + // if (sehnd) { 118 | + // if (selabel_lookup(sehnd, &dentries[0].secon, dentries[0].path, dentries[0].mode) < 0) 119 | + // error("cannot lookup security context for %s", dentries[0].path); 120 | + // } 121 | entries++; 122 | dirs++; 123 | } 124 | @@ -280,12 +280,12 @@ 125 | * the calls in the proper order. 126 | * Please see xattr_assert_sane() in contents.c 127 | */ 128 | - ret = inode_set_selinux(entry_inode, dentries[i].secon); 129 | - if (ret) 130 | - error("failed to set SELinux context on %s\n", dentries[i].path); 131 | - ret = inode_set_capabilities(entry_inode, dentries[i].capabilities); 132 | - if (ret) 133 | - error("failed to set capability on %s\n", dentries[i].path); 134 | + // ret = inode_set_selinux(entry_inode, dentries[i].secon); 135 | + // if (ret) 136 | + // error("failed to set SELinux context on %s\n", dentries[i].path); 137 | + // ret = inode_set_capabilities(entry_inode, dentries[i].capabilities); 138 | + // if (ret) 139 | + // error("failed to set capability on %s\n", dentries[i].path); 140 | 141 | free(dentries[i].path); 142 | free(dentries[i].full_path); 143 | @@ -576,20 +576,20 @@ 144 | inode_set_permissions(root_inode_num, root_mode, 0, 0, 0); 145 | 146 | #ifndef USE_MINGW 147 | - if (sehnd) { 148 | - char *secontext = NULL; 149 | + // if (sehnd) { 150 | + // char *secontext = NULL; 151 | 152 | - if (selabel_lookup(sehnd, &secontext, mountpoint, S_IFDIR) < 0) { 153 | - error("cannot lookup security context for %s", mountpoint); 154 | - } 155 | - if (secontext) { 156 | - if (verbose) { 157 | - printf("Labeling %s as %s\n", mountpoint, secontext); 158 | - } 159 | - inode_set_selinux(root_inode_num, secontext); 160 | - } 161 | - freecon(secontext); 162 | - } 163 | + // if (selabel_lookup(sehnd, &secontext, mountpoint, S_IFDIR) < 0) { 164 | + // error("cannot lookup security context for %s", mountpoint); 165 | + // } 166 | + // if (secontext) { 167 | + // if (verbose) { 168 | + // printf("Labeling %s as %s\n", mountpoint, secontext); 169 | + // } 170 | + // // inode_set_selinux(root_inode_num, secontext); 171 | + // } 172 | + // freecon(secontext); 173 | + // } 174 | #endif 175 | 176 | ext4_update_free(); 177 | Seulement dans android-tools-patched/: fastboot 178 | -------------------------------------------------------------------------------- /mac64/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.12", 3 | "files": [ 4 | "adb", 5 | "fastboot" 6 | ] 7 | } -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 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 | /* global adb, fastboot, Device */ 8 | 9 | const { Cu } = require("chrome"); 10 | 11 | const { defineLazyGetter } = 12 | require("./devtools-require")("devtools/shared/DevToolsUtils"); 13 | 14 | const events = require("./events"); 15 | const unload = require("./unload"); 16 | 17 | const { Devices } = 18 | require("./devtools-import")("resource://devtools/shared/apps/Devices.jsm"); 19 | const { gDevToolsBrowser } = 20 | require("./devtools-import")("resource://devtools/client/framework/gDevTools.jsm"); 21 | defineLazyGetter(this, "adb", () => { 22 | return require("./adb"); 23 | }); 24 | defineLazyGetter(this, "fastboot", () => { 25 | return require("./fastboot"); 26 | }); 27 | defineLazyGetter(this, "Device", () => { 28 | return require("./device"); 29 | }); 30 | 31 | Cu.import("resource://gre/modules/Services.jsm"); 32 | 33 | // Set this right away on startup 34 | Devices.helperAddonInstalled = true; 35 | unload(() => Devices.helperAddonInstalled = false); 36 | 37 | function onADBStart() { 38 | // As of Firefox 36, WebIDE exposes an API to register new runtimes. 39 | let Runtimes = 40 | require("./devtools-require")("devtools/client/webide/modules/runtimes"); 41 | if (Runtimes && Runtimes.RuntimeScanners) { 42 | let scanner = require("./scanner"); 43 | scanner.register(); 44 | } 45 | 46 | adb.start().then(function() { 47 | adb.trackDevices(); 48 | }); 49 | } 50 | Devices.on("adb-start-polling", onADBStart); 51 | unload(() => Devices.off("adb-start-polling", onADBStart)); 52 | 53 | /** 54 | * For Firefox 41 and earlier, WebIDE does not emit "adb-start-polling" to 55 | * enable this add-on lazily. So, we check for WebIDE startup using a promise 56 | * added in Firefox 39. 57 | * For Firefox 38 and earlier, we don't have the WebIDE promise either, so we 58 | * fallback to starting ADB at startup as we did before. 59 | */ 60 | let version = Number.parseInt(Services.appinfo.version.split(".")[0]); 61 | if (Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}" && version < 42) { 62 | if (gDevToolsBrowser.isWebIDEInitialized) { 63 | gDevToolsBrowser.isWebIDEInitialized.promise.then(onADBStart); 64 | } else { 65 | onADBStart(); 66 | } 67 | } 68 | 69 | function onADBStop() { 70 | adb.stop(true); 71 | } 72 | Devices.on("adb-stop-polling", onADBStop); 73 | unload(() => Devices.off("adb-stop-polling", onADBStop)); 74 | unload(() => onADBStop()); 75 | 76 | function onFastbootStart() { 77 | fastboot.startPolling(); 78 | } 79 | Devices.on("fastboot-start-polling", onFastbootStart); 80 | unload(() => Devices.off("fastboot-start-polling", onFastbootStart)); 81 | 82 | function onFastbootStop() { 83 | fastboot.stopPolling(); 84 | } 85 | Devices.on("fastboot-stop-polling", onFastbootStop); 86 | unload(() => Devices.off("fastboot-stop-polling", onFastbootStop)); 87 | unload(() => onFastbootStop()); 88 | 89 | /** 90 | * It may seem at first that registering devices with Device.jsm is no longer 91 | * needed, since they are now consumed in this same add-on in scanner.js (at 92 | * least for Firefox 36+ with new WebIDE API). However, there are still use 93 | * cases for the Devices.jsm registry, as other add-ons can make use of these 94 | * low-level ADB devices if they know about other new runtimes to support on 95 | * the device. This the approach used in the Valence add-on to find Chrome on 96 | * Android, for example. 97 | */ 98 | function onConnected(deviceId) { 99 | console.log("CONNECTED: " + deviceId); 100 | let device = new Device(deviceId); 101 | Devices.register(deviceId, device); 102 | } 103 | events.on(adb, "device-connected", onConnected); 104 | unload(() => events.off(adb, "device-connected", onConnected)); 105 | 106 | function onDisconnected(deviceId) { 107 | console.log("DISCONNECTED: " + deviceId); 108 | Devices.unregister(deviceId); 109 | } 110 | events.on(adb, "device-disconnected", onDisconnected); 111 | unload(() => events.off(adb, "device-disconnected", onDisconnected)); 112 | -------------------------------------------------------------------------------- /scanner.js: -------------------------------------------------------------------------------- 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 | const { Cu } = require("chrome"); 6 | const EventEmitter = 7 | require("./devtools-require")("devtools/shared/event-emitter"); 8 | const { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); 9 | const unload = require("./unload"); 10 | const { ConnectionManager } = 11 | require("./devtools-require")("devtools/shared/client/connection-manager"); 12 | const { Devices } = 13 | require("./devtools-import")("resource://devtools/shared/apps/Devices.jsm"); 14 | const Runtimes = 15 | require("./devtools-require")("devtools/client/webide/modules/runtimes"); 16 | 17 | let Scanner = { 18 | 19 | _runtimes: [], 20 | 21 | enable() { 22 | this._updateRuntimes = this._updateRuntimes.bind(this); 23 | Devices.on("register", this._updateRuntimes); 24 | Devices.on("unregister", this._updateRuntimes); 25 | Devices.on("addon-status-updated", this._updateRuntimes); 26 | this._updateRuntimes(); 27 | }, 28 | 29 | disable() { 30 | Devices.off("register", this._updateRuntimes); 31 | Devices.off("unregister", this._updateRuntimes); 32 | Devices.off("addon-status-updated", this._updateRuntimes); 33 | }, 34 | 35 | _emitUpdated() { 36 | this.emit("runtime-list-updated"); 37 | }, 38 | 39 | _updateRuntimes() { 40 | if (this._updatingPromise) { 41 | return this._updatingPromise; 42 | } 43 | this._runtimes = []; 44 | let promises = []; 45 | for (let id of Devices.available()) { 46 | let device = Devices.getByName(id); 47 | promises.push(this._detectRuntimes(device)); 48 | } 49 | this._updatingPromise = Promise.all(promises); 50 | this._updatingPromise.then(() => { 51 | this._emitUpdated(); 52 | this._updatingPromise = null; 53 | }, () => { 54 | this._updatingPromise = null; 55 | }); 56 | return this._updatingPromise; 57 | }, 58 | 59 | _detectRuntimes: Task.async(function* (device) { 60 | let model = yield device.getModel(); 61 | let detectedRuntimes = yield FirefoxOSRuntime.detect(device, model); 62 | this._runtimes.push(...detectedRuntimes); 63 | detectedRuntimes = yield FirefoxOnAndroidRuntime.detect(device, model); 64 | this._runtimes.push(...detectedRuntimes); 65 | }), 66 | 67 | scan() { 68 | return this._updateRuntimes(); 69 | }, 70 | 71 | listRuntimes() { 72 | return this._runtimes; 73 | } 74 | 75 | }; 76 | 77 | EventEmitter.decorate(Scanner); 78 | 79 | function Runtime(device, model, socketPath) { 80 | this.device = device; 81 | this._model = model; 82 | this._socketPath = socketPath; 83 | } 84 | 85 | Runtime.prototype = { 86 | type: Runtimes.RuntimeTypes.USB, 87 | connect(connection) { 88 | let port = ConnectionManager.getFreeTCPPort(); 89 | let local = "tcp:" + port; 90 | let remote; 91 | if (this._socketPath.startsWith("@")) { 92 | remote = "localabstract:" + this._socketPath.substring(1); 93 | } else { 94 | remote = "localfilesystem:" + this._socketPath; 95 | } 96 | return this.device.forwardPort(local, remote).then(() => { 97 | connection.host = "localhost"; 98 | connection.port = port; 99 | connection.connect(); 100 | }); 101 | }, 102 | get id() { 103 | return this.device.id + "|" + this._socketPath; 104 | }, 105 | }; 106 | 107 | function FirefoxOSRuntime(device, model) { 108 | Runtime.call(this, device, model, "/data/local/debugger-socket"); 109 | } 110 | 111 | FirefoxOSRuntime.detect = Task.async(function* (device, model) { 112 | let runtimes = []; 113 | let query = "test -f /system/b2g/b2g; echo $?"; 114 | let b2gExists = yield device.shell(query); 115 | // XXX: Sometimes we get an empty response back. Likely a bug in our shell 116 | // code in this add-on. 117 | // There are also some Android devices that do not have `test` installed. 118 | for (let attempts = 3; attempts > 0; attempts--) { 119 | b2gExists = yield device.shell(query); 120 | if (b2gExists.length == 3) { 121 | break; 122 | } 123 | } 124 | if (b2gExists === "0\r\n") { 125 | let runtime = new FirefoxOSRuntime(device, model); 126 | console.log("Found " + runtime.name); 127 | runtimes.push(runtime); 128 | } 129 | return runtimes; 130 | }); 131 | 132 | FirefoxOSRuntime.prototype = Object.create(Runtime.prototype); 133 | 134 | Object.defineProperty(FirefoxOSRuntime.prototype, "name", { 135 | get() { 136 | return this._model || this.device.id; 137 | } 138 | }); 139 | 140 | function FirefoxOnAndroidRuntime(device, model, socketPath) { 141 | Runtime.call(this, device, model, socketPath); 142 | } 143 | 144 | // This requires Unix socket support from Firefox for Android (35+) 145 | FirefoxOnAndroidRuntime.detect = Task.async(function* (device, model) { 146 | let runtimes = []; 147 | // A matching entry looks like: 148 | // 00000000: 00000002 00000000 00010000 0001 01 6551588 /data/data/org.mozilla.fennec/firefox-debugger-socket 149 | let query = "cat /proc/net/unix"; 150 | let rawSocketInfo = yield device.shell(query); 151 | let socketInfos = rawSocketInfo.split(/\r?\n/); 152 | // Filter to lines with "firefox-debugger-socket" 153 | socketInfos = socketInfos.filter(l => l.includes("firefox-debugger-socket")); 154 | // It's possible to have multiple lines with the same path, so de-dupe them 155 | let socketPaths = new Set(); 156 | for (let socketInfo of socketInfos) { 157 | let socketPath = socketInfo.split(" ").pop(); 158 | socketPaths.add(socketPath); 159 | } 160 | for (let socketPath of socketPaths) { 161 | let runtime = new FirefoxOnAndroidRuntime(device, model, socketPath); 162 | console.log("Found " + runtime.name); 163 | runtimes.push(runtime); 164 | } 165 | return runtimes; 166 | }); 167 | 168 | FirefoxOnAndroidRuntime.prototype = Object.create(Runtime.prototype); 169 | 170 | Object.defineProperty(FirefoxOnAndroidRuntime.prototype, "name", { 171 | get() { 172 | // If using abstract socket address, it is "@org.mozilla.firefox/..." 173 | // If using path base socket, it is "/data/data/..."" 174 | // Until Fennec 62 only supports path based UNIX domain socket, but 175 | // Fennec 63+ supports both path based and abstract socket. 176 | const packageName = this._socketPath.startsWith("@") ? 177 | this._socketPath.substr(1).split("/")[0] : 178 | this._socketPath.split("/")[3]; 179 | let channel; 180 | switch (packageName) { 181 | case "org.mozilla.firefox": 182 | channel = ""; 183 | break; 184 | case "org.mozilla.firefox_beta": 185 | channel = " Beta"; 186 | break; 187 | case "org.mozilla.fennec_aurora": 188 | // This package name is now the one for Firefox Nightly distributed 189 | // through the Google Play Store since "dawn project" 190 | // cf. https://bugzilla.mozilla.org/show_bug.cgi?id=1357351#c8 191 | channel = " Nightly"; 192 | break; 193 | case "org.mozilla.fennec": 194 | channel = " Nightly"; 195 | break; 196 | default: 197 | channel = " Custom"; 198 | } 199 | return "Firefox" + channel + " on Android (" + 200 | (this._model || this.device.id) + ")"; 201 | } 202 | }); 203 | 204 | exports.register = function() { 205 | // Only register our |Scanner| if the API exists 206 | if (Runtimes && Runtimes.RuntimeScanners) { 207 | // There may be an older ADB scanner registered by default 208 | // If so, we must disable it to avoid duplicate runtimes 209 | if (Runtimes.DeprecatedAdbScanner) { 210 | Runtimes.RuntimeScanners.remove(Runtimes.DeprecatedAdbScanner); 211 | unload(() => { 212 | Runtimes.RuntimeScanners.add(Runtimes.DeprecatedAdbScanner); 213 | }); 214 | } 215 | // Add our scanner 216 | Runtimes.RuntimeScanners.add(Scanner); 217 | unload(() => { 218 | Runtimes.RuntimeScanners.remove(Scanner); 219 | }); 220 | } 221 | }; 222 | -------------------------------------------------------------------------------- /sign.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Help signing the add-on as "Mozilla Extension" to make it work with Firefox 57+ 4 | # More info on: 5 | # https://mana.mozilla.org/wiki/display/SVCOPS/Sign+a+Mozilla+Internal+Extension 6 | 7 | set -e 8 | 9 | export MOZENV="prod" 10 | 11 | if [ $MOZENV == "prod" ]; then 12 | export AWS_DEFAULT_REGION=us-west-2 13 | else 14 | export AWS_DEFAULT_REGION=us-east-1 15 | fi 16 | 17 | if [ -z $SIGN_AWS_ACCESS_KEY_ID ]; then 18 | echo "You should set SIGN_AWS_ACCESS_KEY_ID variable" 19 | exit 20 | fi 21 | 22 | if [ -z $SIGN_AWS_SECRET_ACCESS_KEY ]; then 23 | echo "You should set SIGN_AWS_SECRET_ACCESS_KEY variable" 24 | exit 25 | fi 26 | 27 | if [ -z $1 ] || [ ! -f $1 ]; then 28 | echo "$0 expects path to xpi file as first argument" 29 | exit 30 | fi 31 | XPI=$1 32 | 33 | if ! [ -x "$(command -v aws)" ]; then 34 | echo "You should setup 'aws' in your environment" 35 | exit 36 | fi 37 | if ! [ -x "$(command -v sign-xpi)" ]; then 38 | echo "You should setup 'sign-xpi' in your environment" 39 | echo "See: https://mana.mozilla.org/wiki/display/SVCOPS/Sign+a+Mozilla+Internal+Extension" 40 | exit 41 | fi 42 | 43 | echo "Signing $XPI" 44 | OLD_AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID 45 | OLD_AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY 46 | export AWS_ACCESS_KEY_ID=$SIGN_AWS_ACCESS_KEY_ID 47 | export AWS_SECRET_ACCESS_KEY=$SIGN_AWS_SECRET_ACCESS_KEY 48 | sign-xpi -t mozillaextension -e $MOZENV -s net-mozaws-$MOZENV-addons-signxpi-input $XPI 49 | aws s3 cp s3://net-mozaws-$MOZENV-addons-signxpi-output/$XPI . 50 | export AWS_ACCESS_KEY_ID=$OLD_AWS_ACCESS_KEY_ID 51 | export AWS_SECRET_ACCESS_KEY=$OLD_AWS_SECRET_ACCESS_KEY 52 | -------------------------------------------------------------------------------- /template-install.rdf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | adbhelper@mozilla.org 5 | @@ADDON_VERSION@@ 6 | 2 7 | true 8 | true 9 | 10 | 11 | 12 | 13 | {ec8030f7-c20a-464f-9b0e-13a3a9e97384} 14 | 40.0a1 15 | * 16 | 17 | 18 | 19 | 20 | 21 | 22 | {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} 23 | 2.45 24 | * 25 | 26 | 27 | 28 | 29 | ADB Helper 30 | An add-on to ease connecting to Firefox for Android. 31 | Mozilla & Android Open Source Project 32 | https://github.com/mozilla/adbhelper 33 | @@UPDATE_URL@@ 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /template-update.rdf: -------------------------------------------------------------------------------- 1 | 2 | 3 |
  • 4 | 5 | @@ADDON_VERSION@@ 6 | 7 | 8 | {ec8030f7-c20a-464f-9b0e-13a3a9e97384} 9 | 26.0a1 10 | 27.0 11 | @@UPDATE_LINK@@ 12 | 13 | 14 | 15 | 16 | {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} 17 | 2.45 18 | * 19 | @@UPDATE_LINK@@ 20 | 21 | 22 | 23 |
  • 24 |
    25 |
    26 | -------------------------------------------------------------------------------- /unload.js: -------------------------------------------------------------------------------- 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 | const { Cu } = require("chrome"); 6 | const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); 7 | const unloadSubject = require("@loader/unload"); 8 | const observers = []; 9 | 10 | Services.obs.addObserver({ 11 | observe(subject, topic, data) { 12 | // If this loader is unload then `subject.wrappedJSObject` will be 13 | // `destructor`. 14 | if (subject.wrappedJSObject === unloadSubject) { 15 | Services.obs.removeObserver(this, "sdk:loader:destroy"); 16 | observers.forEach(observer => { 17 | try { 18 | observer(data); 19 | } catch (error) { 20 | console.exception(error); 21 | } 22 | }); 23 | } 24 | } 25 | // Note that we use strong reference to listener here to make sure it's not 26 | // GC-ed, which may happen otherwise since nothing keeps reference to `onunolad` 27 | // function. 28 | }, "sdk:loader:destroy"); 29 | 30 | function unload(observer) { 31 | if (observers.includes(observer)) { 32 | return; 33 | } 34 | observers.unshift(observer); 35 | } 36 | module.exports = unload; 37 | -------------------------------------------------------------------------------- /win32/AdbWinApi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/adbhelper/0821424b6b895645560089a134054b35b6649ff8/win32/AdbWinApi.dll -------------------------------------------------------------------------------- /win32/AdbWinUsbApi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/adbhelper/0821424b6b895645560089a134054b35b6649ff8/win32/AdbWinUsbApi.dll -------------------------------------------------------------------------------- /win32/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2006-2009, The Android Open Source Project 3 | Copyright 2006, Brian Swetland 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | See the License for the specific language governing permissions and 12 | limitations under the License. 13 | 14 | 15 | Apache License 16 | Version 2.0, January 2004 17 | http://www.apache.org/licenses/ 18 | 19 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 20 | 21 | 1. Definitions. 22 | 23 | "License" shall mean the terms and conditions for use, reproduction, 24 | and distribution as defined by Sections 1 through 9 of this document. 25 | 26 | "Licensor" shall mean the copyright owner or entity authorized by 27 | the copyright owner that is granting the License. 28 | 29 | "Legal Entity" shall mean the union of the acting entity and all 30 | other entities that control, are controlled by, or are under common 31 | control with that entity. For the purposes of this definition, 32 | "control" means (i) the power, direct or indirect, to cause the 33 | direction or management of such entity, whether by contract or 34 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 35 | outstanding shares, or (iii) beneficial ownership of such entity. 36 | 37 | "You" (or "Your") shall mean an individual or Legal Entity 38 | exercising permissions granted by this License. 39 | 40 | "Source" form shall mean the preferred form for making modifications, 41 | including but not limited to software source code, documentation 42 | source, and configuration files. 43 | 44 | "Object" form shall mean any form resulting from mechanical 45 | transformation or translation of a Source form, including but 46 | not limited to compiled object code, generated documentation, 47 | and conversions to other media types. 48 | 49 | "Work" shall mean the work of authorship, whether in Source or 50 | Object form, made available under the License, as indicated by a 51 | copyright notice that is included in or attached to the work 52 | (an example is provided in the Appendix below). 53 | 54 | "Derivative Works" shall mean any work, whether in Source or Object 55 | form, that is based on (or derived from) the Work and for which the 56 | editorial revisions, annotations, elaborations, or other modifications 57 | represent, as a whole, an original work of authorship. For the purposes 58 | of this License, Derivative Works shall not include works that remain 59 | separable from, or merely link (or bind by name) to the interfaces of, 60 | the Work and Derivative Works thereof. 61 | 62 | "Contribution" shall mean any work of authorship, including 63 | the original version of the Work and any modifications or additions 64 | to that Work or Derivative Works thereof, that is intentionally 65 | submitted to Licensor for inclusion in the Work by the copyright owner 66 | or by an individual or Legal Entity authorized to submit on behalf of 67 | the copyright owner. For the purposes of this definition, "submitted" 68 | means any form of electronic, verbal, or written communication sent 69 | to the Licensor or its representatives, including but not limited to 70 | communication on electronic mailing lists, source code control systems, 71 | and issue tracking systems that are managed by, or on behalf of, the 72 | Licensor for the purpose of discussing and improving the Work, but 73 | excluding communication that is conspicuously marked or otherwise 74 | designated in writing by the copyright owner as "Not a Contribution." 75 | 76 | "Contributor" shall mean Licensor and any individual or Legal Entity 77 | on behalf of whom a Contribution has been received by Licensor and 78 | subsequently incorporated within the Work. 79 | 80 | 2. Grant of Copyright License. Subject to the terms and conditions of 81 | this License, each Contributor hereby grants to You a perpetual, 82 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 83 | copyright license to reproduce, prepare Derivative Works of, 84 | publicly display, publicly perform, sublicense, and distribute the 85 | Work and such Derivative Works in Source or Object form. 86 | 87 | 3. Grant of Patent License. Subject to the terms and conditions of 88 | this License, each Contributor hereby grants to You a perpetual, 89 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 90 | (except as stated in this section) patent license to make, have made, 91 | use, offer to sell, sell, import, and otherwise transfer the Work, 92 | where such license applies only to those patent claims licensable 93 | by such Contributor that are necessarily infringed by their 94 | Contribution(s) alone or by combination of their Contribution(s) 95 | with the Work to which such Contribution(s) was submitted. If You 96 | institute patent litigation against any entity (including a 97 | cross-claim or counterclaim in a lawsuit) alleging that the Work 98 | or a Contribution incorporated within the Work constitutes direct 99 | or contributory patent infringement, then any patent licenses 100 | granted to You under this License for that Work shall terminate 101 | as of the date such litigation is filed. 102 | 103 | 4. Redistribution. You may reproduce and distribute copies of the 104 | Work or Derivative Works thereof in any medium, with or without 105 | modifications, and in Source or Object form, provided that You 106 | meet the following conditions: 107 | 108 | (a) You must give any other recipients of the Work or 109 | Derivative Works a copy of this License; and 110 | 111 | (b) You must cause any modified files to carry prominent notices 112 | stating that You changed the files; and 113 | 114 | (c) You must retain, in the Source form of any Derivative Works 115 | that You distribute, all copyright, patent, trademark, and 116 | attribution notices from the Source form of the Work, 117 | excluding those notices that do not pertain to any part of 118 | the Derivative Works; and 119 | 120 | (d) If the Work includes a "NOTICE" text file as part of its 121 | distribution, then any Derivative Works that You distribute must 122 | include a readable copy of the attribution notices contained 123 | within such NOTICE file, excluding those notices that do not 124 | pertain to any part of the Derivative Works, in at least one 125 | of the following places: within a NOTICE text file distributed 126 | as part of the Derivative Works; within the Source form or 127 | documentation, if provided along with the Derivative Works; or, 128 | within a display generated by the Derivative Works, if and 129 | wherever such third-party notices normally appear. The contents 130 | of the NOTICE file are for informational purposes only and 131 | do not modify the License. You may add Your own attribution 132 | notices within Derivative Works that You distribute, alongside 133 | or as an addendum to the NOTICE text from the Work, provided 134 | that such additional attribution notices cannot be construed 135 | as modifying the License. 136 | 137 | You may add Your own copyright statement to Your modifications and 138 | may provide additional or different license terms and conditions 139 | for use, reproduction, or distribution of Your modifications, or 140 | for any such Derivative Works as a whole, provided Your use, 141 | reproduction, and distribution of the Work otherwise complies with 142 | the conditions stated in this License. 143 | 144 | 5. Submission of Contributions. Unless You explicitly state otherwise, 145 | any Contribution intentionally submitted for inclusion in the Work 146 | by You to the Licensor shall be under the terms and conditions of 147 | this License, without any additional terms or conditions. 148 | Notwithstanding the above, nothing herein shall supersede or modify 149 | the terms of any separate license agreement you may have executed 150 | with Licensor regarding such Contributions. 151 | 152 | 6. Trademarks. This License does not grant permission to use the trade 153 | names, trademarks, service marks, or product names of the Licensor, 154 | except as required for reasonable and customary use in describing the 155 | origin of the Work and reproducing the content of the NOTICE file. 156 | 157 | 7. Disclaimer of Warranty. Unless required by applicable law or 158 | agreed to in writing, Licensor provides the Work (and each 159 | Contributor provides its Contributions) on an "AS IS" BASIS, 160 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 161 | implied, including, without limitation, any warranties or conditions 162 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 163 | PARTICULAR PURPOSE. You are solely responsible for determining the 164 | appropriateness of using or redistributing the Work and assume any 165 | risks associated with Your exercise of permissions under this License. 166 | 167 | 8. Limitation of Liability. In no event and under no legal theory, 168 | whether in tort (including negligence), contract, or otherwise, 169 | unless required by applicable law (such as deliberate and grossly 170 | negligent acts) or agreed to in writing, shall any Contributor be 171 | liable to You for damages, including any direct, indirect, special, 172 | incidental, or consequential damages of any character arising as a 173 | result of this License or out of the use or inability to use the 174 | Work (including but not limited to damages for loss of goodwill, 175 | work stoppage, computer failure or malfunction, or any and all 176 | other commercial damages or losses), even if such Contributor 177 | has been advised of the possibility of such damages. 178 | 179 | 9. Accepting Warranty or Additional Liability. While redistributing 180 | the Work or Derivative Works thereof, You may choose to offer, 181 | and charge a fee for, acceptance of support, warranty, indemnity, 182 | or other liability obligations and/or rights consistent with this 183 | License. However, in accepting such obligations, You may act only 184 | on Your own behalf and on Your sole responsibility, not on behalf 185 | of any other Contributor, and only if You agree to indemnify, 186 | defend, and hold each Contributor harmless for any liability 187 | incurred by, or claims asserted against, such Contributor by reason 188 | of your accepting any such warranty or additional liability. 189 | 190 | END OF TERMS AND CONDITIONS 191 | 192 | -------------------------------------------------------------------------------- /win32/README: -------------------------------------------------------------------------------- 1 | This is the Android Debug Bridge (ADB). It is made available under the terms 2 | of the Apache 2.0 License in LICENSE. Its source code is available 3 | at , and you can reproduce this package by building 4 | the Android SDK per the instructions at that site. 5 | -------------------------------------------------------------------------------- /win32/adb.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/adbhelper/0821424b6b895645560089a134054b35b6649ff8/win32/adb.exe -------------------------------------------------------------------------------- /win32/fastboot.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/adbhelper/0821424b6b895645560089a134054b35b6649ff8/win32/fastboot.exe -------------------------------------------------------------------------------- /win32/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.12", 3 | "files": [ 4 | "adb.exe", 5 | "AdbWinApi.dll", 6 | "AdbWinUsbApi.dll", 7 | "fastboot.exe" 8 | ] 9 | } --------------------------------------------------------------------------------