2018-08-09 05:27:55 +00:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
// Wrapper around the ADB utility.
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
const { Cc, Ci } = require("chrome");
|
|
|
|
const EventEmitter = require("devtools/shared/event-emitter");
|
|
|
|
const client = require("./adb-client");
|
|
|
|
const { getFileForBinary } = require("./adb-binary");
|
|
|
|
const { setTimeout } = require("resource://gre/modules/Timer.jsm");
|
|
|
|
const { PromiseUtils } = require("resource://gre/modules/PromiseUtils.jsm");
|
|
|
|
const { OS } = require("resource://gre/modules/osfile.jsm");
|
|
|
|
const { Services } = require("resource://gre/modules/Services.jsm");
|
2018-08-09 05:27:55 +00:00
|
|
|
loader.lazyRequireGetter(this, "check",
|
|
|
|
"devtools/shared/adb/adb-running-checker", true);
|
2018-08-09 05:27:55 +00:00
|
|
|
|
|
|
|
let ready = false;
|
|
|
|
let didRunInitially = false;
|
|
|
|
|
|
|
|
const OKAY = 0x59414b4f;
|
|
|
|
// const FAIL = 0x4c494146;
|
|
|
|
// const STAT = 0x54415453;
|
|
|
|
const DATA = 0x41544144;
|
|
|
|
const DONE = 0x454e4f44;
|
|
|
|
|
|
|
|
const ADB = {
|
|
|
|
get didRunInitially() {
|
|
|
|
return didRunInitially;
|
|
|
|
},
|
|
|
|
set didRunInitially(newVal) {
|
|
|
|
didRunInitially = newVal;
|
|
|
|
},
|
|
|
|
|
|
|
|
get ready() {
|
|
|
|
return ready;
|
|
|
|
},
|
|
|
|
set ready(newVal) {
|
|
|
|
ready = newVal;
|
|
|
|
},
|
|
|
|
|
|
|
|
get adbFilePromise() {
|
|
|
|
if (this._adbFilePromise) {
|
|
|
|
return this._adbFilePromise;
|
|
|
|
}
|
|
|
|
this._adbFilePromise = getFileForBinary();
|
|
|
|
return this._adbFilePromise;
|
|
|
|
},
|
|
|
|
|
|
|
|
// We startup by launching adb in server mode, and setting
|
|
|
|
// the tcp socket preference to |true|
|
|
|
|
start() {
|
|
|
|
return new Promise(async (resolve, reject) => {
|
2018-08-09 05:27:55 +00:00
|
|
|
const onSuccessfulStart = () => {
|
2018-08-09 05:27:55 +00:00
|
|
|
Services.obs.notifyObservers(null, "adb-ready");
|
|
|
|
this.ready = true;
|
|
|
|
resolve();
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const isAdbRunning = await check();
|
2018-08-09 05:27:55 +00:00
|
|
|
if (isAdbRunning) {
|
|
|
|
this.didRunInitially = false;
|
|
|
|
console.log("Found ADB process running, not restarting");
|
|
|
|
onSuccessfulStart();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
console.log("Didn't find ADB process running, restarting");
|
|
|
|
|
|
|
|
this.didRunInitially = true;
|
2018-08-09 05:27:55 +00:00
|
|
|
const process = Cc["@mozilla.org/process/util;1"]
|
2018-08-09 05:27:55 +00:00
|
|
|
.createInstance(Ci.nsIProcess);
|
|
|
|
// FIXME: Bug 1481691 - We should avoid extracting files every time.
|
2018-08-09 05:27:55 +00:00
|
|
|
const adbFile = await this.adbFilePromise;
|
2018-08-09 05:27:55 +00:00
|
|
|
process.init(adbFile);
|
|
|
|
// Hide command prompt window on Windows
|
|
|
|
try {
|
|
|
|
// startHidden is 55+
|
|
|
|
process.startHidden = true;
|
|
|
|
// noShell attribute is 58+
|
|
|
|
process.noShell = true;
|
|
|
|
} catch (e) {
|
|
|
|
}
|
2018-08-09 05:27:55 +00:00
|
|
|
const params = ["start-server"];
|
|
|
|
const self = this;
|
2018-08-09 05:27:55 +00:00
|
|
|
process.runAsync(params, params.length, {
|
2018-08-09 05:27:55 +00:00
|
|
|
observe(subject, topic, data) {
|
|
|
|
switch (topic) {
|
2018-08-09 05:27:55 +00:00
|
|
|
case "process-finished":
|
|
|
|
onSuccessfulStart();
|
|
|
|
break;
|
|
|
|
case "process-failed":
|
|
|
|
self.ready = false;
|
|
|
|
reject();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, false);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop the ADB server, but only if we started it. If it was started before
|
|
|
|
* us, we return immediately.
|
|
|
|
*
|
|
|
|
* @param boolean sync
|
|
|
|
* In case, we do need to kill the server, this param is passed through
|
|
|
|
* to kill to determine whether it's a sync operation.
|
|
|
|
*/
|
|
|
|
async stop(sync) {
|
|
|
|
if (!this.didRunInitially) {
|
|
|
|
return; // We didn't start the server, nothing to do
|
|
|
|
}
|
|
|
|
await this.kill(sync);
|
2018-08-09 05:27:55 +00:00
|
|
|
// Make sure the ADB server stops listening.
|
|
|
|
//
|
|
|
|
// kill() above doesn't mean that the ADB server stops, it just means that
|
|
|
|
// 'adb kill-server' command finished, so that it's possible that the ADB
|
|
|
|
// server is still alive there.
|
|
|
|
while (true) {
|
|
|
|
const isAdbRunning = await check();
|
|
|
|
if (!isAdbRunning) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-08-09 05:27:55 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Kill the ADB server. We do this by running ADB again, passing it
|
|
|
|
* the "kill-server" argument.
|
|
|
|
*
|
|
|
|
* @param {Boolean} sync
|
|
|
|
* Whether or not to kill the server synchronously. In general,
|
|
|
|
* this should be false. But on Windows, an add-on may fail to update
|
|
|
|
* if its copy of ADB is running when Firefox tries to update it.
|
|
|
|
* So add-ons who observe their own updates and kill the ADB server
|
|
|
|
* beforehand should do so synchronously on Windows to make sure
|
|
|
|
* the update doesn't race the killing.
|
|
|
|
*/
|
|
|
|
async kill(sync) {
|
2018-08-09 05:27:55 +00:00
|
|
|
const process = Cc["@mozilla.org/process/util;1"]
|
2018-08-09 05:27:55 +00:00
|
|
|
.createInstance(Ci.nsIProcess);
|
2018-08-09 05:27:55 +00:00
|
|
|
const adbFile = await this.adbFilePromise;
|
2018-08-09 05:27:55 +00:00
|
|
|
process.init(adbFile);
|
|
|
|
// Hide command prompt window on Windows
|
|
|
|
try {
|
|
|
|
// startHidden is 55+
|
|
|
|
process.startHidden = true;
|
|
|
|
// noShell attribute is 58+
|
|
|
|
process.noShell = true;
|
|
|
|
} catch (e) {
|
|
|
|
}
|
2018-08-09 05:27:55 +00:00
|
|
|
const params = ["kill-server"];
|
2018-08-09 05:27:55 +00:00
|
|
|
|
|
|
|
if (sync) {
|
|
|
|
process.run(true, params, params.length);
|
|
|
|
console.log("adb kill-server: " + process.exitValue);
|
|
|
|
this.ready = false;
|
|
|
|
this.didRunInitially = false;
|
|
|
|
} else {
|
2018-08-09 05:27:55 +00:00
|
|
|
const self = this;
|
2018-08-09 05:27:55 +00:00
|
|
|
process.runAsync(params, params.length, {
|
2018-08-09 05:27:55 +00:00
|
|
|
observe(subject, topic, data) {
|
|
|
|
switch (topic) {
|
2018-08-09 05:27:55 +00:00
|
|
|
case "process-finished":
|
|
|
|
console.log("adb kill-server: " + process.exitValue);
|
|
|
|
Services.obs.notifyObservers(null, "adb-killed");
|
|
|
|
self.ready = false;
|
|
|
|
self.didRunInitially = false;
|
|
|
|
break;
|
|
|
|
case "process-failed":
|
|
|
|
console.log("adb kill-server failure: " + process.exitValue);
|
|
|
|
// It's hard to say whether or not ADB is ready at this point,
|
|
|
|
// but it seems safer to assume that it isn't, so code that wants
|
|
|
|
// to use it later will try to restart it.
|
|
|
|
Services.obs.notifyObservers(null, "adb-killed");
|
|
|
|
self.ready = false;
|
|
|
|
self.didRunInitially = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, false);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// Start tracking devices connecting and disconnecting from the host.
|
|
|
|
// We can't reuse runCommand here because we keep the socket alive.
|
|
|
|
// @return The socket used.
|
|
|
|
trackDevices: function adb_trackDevices() {
|
|
|
|
console.log("trackDevices");
|
2018-08-09 05:27:55 +00:00
|
|
|
const socket = client.connect();
|
2018-08-09 05:27:55 +00:00
|
|
|
let waitForFirst = true;
|
2018-08-09 05:27:55 +00:00
|
|
|
const devices = {};
|
2018-08-09 05:27:55 +00:00
|
|
|
|
|
|
|
socket.s.onopen = function() {
|
|
|
|
console.log("trackDevices onopen");
|
|
|
|
Services.obs.notifyObservers(null, "adb-track-devices-start");
|
2018-08-09 05:27:55 +00:00
|
|
|
const req = client.createRequest("host:track-devices");
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.send(req);
|
|
|
|
};
|
|
|
|
|
|
|
|
socket.s.onerror = function(event) {
|
|
|
|
console.log("trackDevices onerror: " + event);
|
|
|
|
Services.obs.notifyObservers(null, "adb-track-devices-stop");
|
|
|
|
};
|
|
|
|
|
|
|
|
socket.s.onclose = function() {
|
|
|
|
console.log("trackDevices onclose");
|
|
|
|
|
|
|
|
// Report all devices as disconnected
|
2018-08-09 05:27:55 +00:00
|
|
|
for (const dev in devices) {
|
2018-08-09 05:27:55 +00:00
|
|
|
devices[dev] = false;
|
|
|
|
EventEmitter.emit(ADB, "device-disconnected", dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
Services.obs.notifyObservers(null, "adb-track-devices-stop");
|
|
|
|
|
|
|
|
// When we lose connection to the server,
|
|
|
|
// and the adb is still on, we most likely got our server killed
|
|
|
|
// by local adb. So we do try to reconnect to it.
|
|
|
|
setTimeout(function() { // Give some time to the new adb to start
|
|
|
|
if (ADB.ready) { // Only try to reconnect/restart if the add-on is still enabled
|
|
|
|
ADB.start().then(function() { // try to connect to the new local adb server
|
|
|
|
// or, spawn a new one
|
|
|
|
ADB.trackDevices(); // Re-track devices
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}, 2000);
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.ondata = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("trackDevices ondata");
|
2018-08-09 05:27:55 +00:00
|
|
|
const data = event.data;
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("length=" + data.byteLength);
|
2018-08-09 05:27:55 +00:00
|
|
|
const dec = new TextDecoder();
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log(dec.decode(new Uint8Array(data)).trim());
|
|
|
|
|
|
|
|
// check the OKAY or FAIL on first packet.
|
|
|
|
if (waitForFirst) {
|
|
|
|
if (!client.checkResponse(data, OKAY)) {
|
|
|
|
socket.close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const packet = client.unpackPacket(data, !waitForFirst);
|
2018-08-09 05:27:55 +00:00
|
|
|
waitForFirst = false;
|
|
|
|
|
|
|
|
if (packet.data == "") {
|
|
|
|
// All devices got disconnected.
|
2018-08-09 05:27:55 +00:00
|
|
|
for (const dev in devices) {
|
2018-08-09 05:27:55 +00:00
|
|
|
devices[dev] = false;
|
|
|
|
EventEmitter.emit(ADB, "device-disconnected", dev);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// One line per device, each line being $DEVICE\t(offline|device)
|
2018-08-09 05:27:55 +00:00
|
|
|
const lines = packet.data.split("\n");
|
|
|
|
const newDev = {};
|
2018-08-09 05:27:55 +00:00
|
|
|
lines.forEach(function(line) {
|
|
|
|
if (line.length == 0) {
|
2018-08-09 05:27:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const [dev, status] = line.split("\t");
|
2018-08-09 05:27:55 +00:00
|
|
|
newDev[dev] = status !== "offline";
|
|
|
|
});
|
|
|
|
// Check which device changed state.
|
2018-08-09 05:27:55 +00:00
|
|
|
for (const dev in newDev) {
|
2018-08-09 05:27:55 +00:00
|
|
|
if (devices[dev] != newDev[dev]) {
|
|
|
|
if (dev in devices || newDev[dev]) {
|
2018-08-09 05:27:55 +00:00
|
|
|
const topic = newDev[dev] ? "device-connected"
|
|
|
|
: "device-disconnected";
|
2018-08-09 05:27:55 +00:00
|
|
|
EventEmitter.emit(ADB, topic, dev);
|
|
|
|
}
|
|
|
|
devices[dev] = newDev[dev];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
// Sends back an array of device names.
|
|
|
|
listDevices: function adb_listDevices() {
|
|
|
|
console.log("listDevices");
|
|
|
|
|
|
|
|
return this.runCommand("host:devices").then(
|
|
|
|
function onSuccess(data) {
|
2018-08-09 05:27:55 +00:00
|
|
|
const lines = data.split("\n");
|
|
|
|
const res = [];
|
2018-08-09 05:27:55 +00:00
|
|
|
lines.forEach(function(line) {
|
|
|
|
if (line.length == 0) {
|
2018-08-09 05:27:55 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-08-09 05:27:55 +00:00
|
|
|
const [ device ] = line.split("\t");
|
2018-08-09 05:27:55 +00:00
|
|
|
res.push(device);
|
|
|
|
});
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
// sends adb forward localPort devicePort
|
|
|
|
forwardPort: function adb_forwardPort(localPort, devicePort) {
|
|
|
|
console.log("forwardPort " + localPort + " -- " + devicePort);
|
2018-08-09 05:27:55 +00:00
|
|
|
// <host-prefix>:forward:<local>;<remote>
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
return this.runCommand("host:forward:" + localPort + ";" + devicePort)
|
2018-08-09 05:27:55 +00:00
|
|
|
.then(function onSuccess(data) {
|
|
|
|
return data;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
// pulls a file from the device.
|
|
|
|
// send "host:transport-any" why??
|
|
|
|
// if !OKAY, return
|
|
|
|
// send "sync:"
|
|
|
|
// if !OKAY, return
|
|
|
|
// send STAT + hex4(path.length) + path
|
|
|
|
// recv STAT + 12 bytes (3 x 32 bits: mode, size, time)
|
|
|
|
// send RECV + hex4(path.length) + path
|
|
|
|
// while(needs data):
|
|
|
|
// recv DATA + hex4 + data
|
|
|
|
// recv DONE + hex4(0)
|
|
|
|
// send QUIT + hex4(0)
|
2018-08-09 05:27:55 +00:00
|
|
|
pull: function adb_pull(from, dest) {
|
2018-08-09 05:27:55 +00:00
|
|
|
const deferred = PromiseUtils.defer();
|
2018-08-09 05:27:55 +00:00
|
|
|
let state;
|
|
|
|
let fileData = null;
|
|
|
|
let currentPos = 0;
|
|
|
|
let chunkSize = 0;
|
|
|
|
let pkgData;
|
2018-08-09 05:27:55 +00:00
|
|
|
const headerArray = new Uint32Array(2);
|
2018-08-09 05:27:55 +00:00
|
|
|
let currentHeaderLength = 0;
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const encoder = new TextEncoder();
|
2018-08-09 05:27:55 +00:00
|
|
|
let infoLengthPacket;
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("pulling " + from + " -> " + dest);
|
2018-08-09 05:27:55 +00:00
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const shutdown = function() {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("pull shutdown");
|
|
|
|
socket.close();
|
|
|
|
deferred.reject("BAD_RESPONSE");
|
|
|
|
};
|
|
|
|
|
|
|
|
// extract chunk data header info. to headerArray.
|
2018-08-09 05:27:55 +00:00
|
|
|
const extractChunkDataHeader = function(data) {
|
|
|
|
const tmpArray = new Uint8Array(headerArray.buffer);
|
2018-08-09 05:27:55 +00:00
|
|
|
for (let i = 0; i < 8 - currentHeaderLength; i++) {
|
|
|
|
tmpArray[currentHeaderLength + i] = data[i];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// chunk data header is 8 bytes length,
|
|
|
|
// the first 4 bytes: hex4("DATA"), and
|
|
|
|
// the second 4 bytes: hex4(chunk size)
|
2018-08-09 05:27:55 +00:00
|
|
|
const checkChunkDataHeader = function(data) {
|
2018-08-09 05:27:55 +00:00
|
|
|
if (data.length + currentHeaderLength >= 8) {
|
|
|
|
extractChunkDataHeader(data);
|
|
|
|
|
|
|
|
if (headerArray[0] != DATA) {
|
|
|
|
shutdown();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// remove header info. from socket package data
|
|
|
|
pkgData = data.subarray(8 - currentHeaderLength, data.length);
|
|
|
|
chunkSize = headerArray[1];
|
|
|
|
currentHeaderLength = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If chunk data header info. is separated into more than one
|
|
|
|
// socket package, keep partial header info. in headerArray.
|
2018-08-09 05:27:55 +00:00
|
|
|
const tmpArray = new Uint8Array(headerArray.buffer);
|
2018-08-09 05:27:55 +00:00
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
|
|
tmpArray[currentHeaderLength + i] = data[i];
|
|
|
|
}
|
|
|
|
currentHeaderLength += data.length;
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
// The last remaining package data contains 8 bytes,
|
|
|
|
// they are "DONE(0x454e4f44)" and 0x0000.
|
2018-08-09 05:27:55 +00:00
|
|
|
const checkDone = function(data) {
|
2018-08-09 05:27:55 +00:00
|
|
|
if (data.length != 8) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const doneFlagArray = new Uint32Array(1);
|
|
|
|
const tmpArray = new Uint8Array(doneFlagArray.buffer);
|
2018-08-09 05:27:55 +00:00
|
|
|
for (let i = 0; i < 4; i++) {
|
|
|
|
tmpArray[i] = data[i];
|
|
|
|
}
|
|
|
|
// Check DONE flag
|
|
|
|
if (doneFlagArray[0] == DONE) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const runFSM = function runFSM(data) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("runFSM " + state);
|
|
|
|
let req;
|
|
|
|
switch (state) {
|
|
|
|
case "start":
|
|
|
|
state = "send-transport";
|
|
|
|
runFSM();
|
|
|
|
break;
|
|
|
|
case "send-transport":
|
|
|
|
req = client.createRequest("host:transport-any");
|
|
|
|
socket.send(req);
|
|
|
|
state = "wait-transport";
|
|
|
|
break;
|
|
|
|
case "wait-transport":
|
2018-08-09 05:27:55 +00:00
|
|
|
if (!client.checkResponse(data, OKAY)) {
|
2018-08-09 05:27:55 +00:00
|
|
|
shutdown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
console.log("transport: OK");
|
|
|
|
state = "send-sync";
|
|
|
|
runFSM();
|
|
|
|
break;
|
|
|
|
case "send-sync":
|
|
|
|
req = client.createRequest("sync:");
|
|
|
|
socket.send(req);
|
|
|
|
state = "wait-sync";
|
|
|
|
break;
|
|
|
|
case "wait-sync":
|
2018-08-09 05:27:55 +00:00
|
|
|
if (!client.checkResponse(data, OKAY)) {
|
2018-08-09 05:27:55 +00:00
|
|
|
shutdown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
console.log("sync: OK");
|
|
|
|
state = "send-recv";
|
|
|
|
runFSM();
|
|
|
|
break;
|
|
|
|
case "send-recv":
|
|
|
|
infoLengthPacket = new Uint32Array(1);
|
2018-08-09 05:27:55 +00:00
|
|
|
infoLengthPacket[0] = from.length;
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.send(encoder.encode("RECV"));
|
|
|
|
socket.send(infoLengthPacket);
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.send(encoder.encode(from));
|
2018-08-09 05:27:55 +00:00
|
|
|
|
|
|
|
state = "wait-recv";
|
|
|
|
break;
|
|
|
|
case "wait-recv":
|
|
|
|
// After sending "RECV" command, adb server will send chunks data back,
|
|
|
|
// Handle every single socket package here.
|
|
|
|
// Note: One socket package maybe contain many chunks, and often
|
|
|
|
// partial chunk at the end.
|
2018-08-09 05:27:55 +00:00
|
|
|
pkgData = new Uint8Array(client.getBuffer(data));
|
2018-08-09 05:27:55 +00:00
|
|
|
|
|
|
|
// Handle all data in a single socket package.
|
|
|
|
while (pkgData.length > 0) {
|
|
|
|
if (chunkSize == 0 && checkDone(pkgData)) {
|
2018-08-09 05:27:55 +00:00
|
|
|
OS.File.writeAtomic(dest, fileData, {}).then(
|
2018-08-09 05:27:55 +00:00
|
|
|
function onSuccess(number) {
|
|
|
|
console.log(number);
|
|
|
|
deferred.resolve("SUCCESS");
|
|
|
|
},
|
|
|
|
function onFailure(reason) {
|
|
|
|
console.log(reason);
|
|
|
|
deferred.reject("CANT_ACCESS_FILE");
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
state = "send-quit";
|
|
|
|
runFSM();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (chunkSize == 0 && !checkChunkDataHeader(pkgData)) {
|
|
|
|
shutdown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// handle full chunk
|
|
|
|
if (chunkSize > 0 && pkgData.length >= chunkSize) {
|
2018-08-09 05:27:55 +00:00
|
|
|
const chunkData = pkgData.subarray(0, chunkSize);
|
|
|
|
const tmpData = new Uint8Array(currentPos + chunkSize);
|
2018-08-09 05:27:55 +00:00
|
|
|
if (fileData) {
|
|
|
|
tmpData.set(fileData, 0);
|
|
|
|
}
|
|
|
|
tmpData.set(chunkData, currentPos);
|
|
|
|
fileData = tmpData;
|
|
|
|
pkgData = pkgData.subarray(chunkSize, pkgData.length);
|
|
|
|
currentPos += chunkSize;
|
|
|
|
chunkSize = 0;
|
|
|
|
}
|
|
|
|
// handle partial chunk at the end of socket package
|
|
|
|
if (chunkSize > 0 && pkgData.length > 0 && pkgData.length < chunkSize) {
|
2018-08-09 05:27:55 +00:00
|
|
|
const tmpData = new Uint8Array(currentPos + pkgData.length);
|
2018-08-09 05:27:55 +00:00
|
|
|
if (fileData) {
|
|
|
|
tmpData.set(fileData, 0);
|
|
|
|
}
|
|
|
|
tmpData.set(pkgData, currentPos);
|
|
|
|
fileData = tmpData;
|
|
|
|
currentPos += pkgData.length;
|
|
|
|
chunkSize -= pkgData.length;
|
|
|
|
break; // Break while loop.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case "send-quit":
|
|
|
|
infoLengthPacket = new Uint32Array(1);
|
|
|
|
infoLengthPacket[0] = 0;
|
|
|
|
socket.send(encoder.encode("QUIT"));
|
|
|
|
socket.send(infoLengthPacket);
|
|
|
|
|
|
|
|
state = "end";
|
|
|
|
runFSM();
|
|
|
|
break;
|
|
|
|
case "end":
|
|
|
|
socket.close();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
console.log("pull Unexpected State: " + state);
|
|
|
|
deferred.reject("UNEXPECTED_STATE");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const setupSocket = function() {
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onerror = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("pull onerror");
|
|
|
|
deferred.reject("SOCKET_ERROR");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onopen = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("pull onopen");
|
|
|
|
state = "start";
|
|
|
|
runFSM();
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onclose = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("pull onclose");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.ondata = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("pull ondata:");
|
2018-08-09 05:27:55 +00:00
|
|
|
runFSM(event.data);
|
2018-08-09 05:27:55 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const socket = client.connect();
|
2018-08-09 05:27:55 +00:00
|
|
|
setupSocket();
|
|
|
|
|
|
|
|
return deferred.promise;
|
|
|
|
},
|
|
|
|
|
|
|
|
// pushes a file to the device.
|
2018-08-09 05:27:55 +00:00
|
|
|
// from and dest are full paths.
|
2018-08-09 05:27:55 +00:00
|
|
|
// XXX we should STAT the remote path before sending.
|
2018-08-09 05:27:55 +00:00
|
|
|
push: function adb_push(from, dest) {
|
2018-08-09 05:27:55 +00:00
|
|
|
const deferred = PromiseUtils.defer();
|
2018-08-09 05:27:55 +00:00
|
|
|
let socket;
|
|
|
|
let state;
|
|
|
|
let fileSize;
|
|
|
|
let fileData;
|
|
|
|
let remaining;
|
|
|
|
let currentPos = 0;
|
|
|
|
let fileTime;
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("pushing " + from + " -> " + dest);
|
2018-08-09 05:27:55 +00:00
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const shutdown = function() {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("push shutdown");
|
|
|
|
socket.close();
|
|
|
|
deferred.reject("BAD_RESPONSE");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const runFSM = function runFSM(data) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("runFSM " + state);
|
|
|
|
let req;
|
|
|
|
switch (state) {
|
|
|
|
case "start":
|
|
|
|
state = "send-transport";
|
|
|
|
runFSM();
|
|
|
|
break;
|
|
|
|
case "send-transport":
|
|
|
|
req = client.createRequest("host:transport-any");
|
|
|
|
socket.send(req);
|
|
|
|
state = "wait-transport";
|
|
|
|
break;
|
|
|
|
case "wait-transport":
|
2018-08-09 05:27:55 +00:00
|
|
|
if (!client.checkResponse(data, OKAY)) {
|
2018-08-09 05:27:55 +00:00
|
|
|
shutdown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
console.log("transport: OK");
|
|
|
|
state = "send-sync";
|
|
|
|
runFSM();
|
|
|
|
break;
|
|
|
|
case "send-sync":
|
|
|
|
req = client.createRequest("sync:");
|
|
|
|
socket.send(req);
|
|
|
|
state = "wait-sync";
|
|
|
|
break;
|
|
|
|
case "wait-sync":
|
2018-08-09 05:27:55 +00:00
|
|
|
if (!client.checkResponse(data, OKAY)) {
|
2018-08-09 05:27:55 +00:00
|
|
|
shutdown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
console.log("sync: OK");
|
|
|
|
state = "send-send";
|
|
|
|
runFSM();
|
|
|
|
break;
|
|
|
|
case "send-send":
|
2018-08-09 05:27:55 +00:00
|
|
|
// need to send SEND + length($dest,$fileMode)
|
2018-08-09 05:27:55 +00:00
|
|
|
// $fileMode is not the octal one there.
|
2018-08-09 05:27:55 +00:00
|
|
|
const encoder = new TextEncoder();
|
2018-08-09 05:27:55 +00:00
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const infoLengthPacket = new Uint32Array(1), info = dest + ",33204";
|
2018-08-09 05:27:55 +00:00
|
|
|
infoLengthPacket[0] = info.length;
|
|
|
|
socket.send(encoder.encode("SEND"));
|
|
|
|
socket.send(infoLengthPacket);
|
|
|
|
socket.send(encoder.encode(info));
|
|
|
|
|
|
|
|
// now sending file data.
|
|
|
|
while (remaining > 0) {
|
2018-08-09 05:27:55 +00:00
|
|
|
const toSend = remaining > 65536 ? 65536 : remaining;
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("Sending " + toSend + " bytes");
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const dataLengthPacket = new Uint32Array(1);
|
2018-08-09 05:27:55 +00:00
|
|
|
// We have to create a new ArrayBuffer for the fileData slice
|
|
|
|
// because nsIDOMTCPSocket (or ArrayBufferInputStream) chokes on
|
|
|
|
// reused buffers, even when we don't modify their contents.
|
2018-08-09 05:27:55 +00:00
|
|
|
const dataPacket = new Uint8Array(new ArrayBuffer(toSend));
|
2018-08-09 05:27:55 +00:00
|
|
|
dataPacket.set(new Uint8Array(fileData.buffer, currentPos, toSend));
|
|
|
|
dataLengthPacket[0] = toSend;
|
|
|
|
socket.send(encoder.encode("DATA"));
|
|
|
|
socket.send(dataLengthPacket);
|
|
|
|
socket.send(dataPacket);
|
|
|
|
|
|
|
|
currentPos += toSend;
|
|
|
|
remaining -= toSend;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ending up with DONE + mtime (wtf???)
|
2018-08-09 05:27:55 +00:00
|
|
|
const fileTimePacket = new Uint32Array(1);
|
2018-08-09 05:27:55 +00:00
|
|
|
fileTimePacket[0] = fileTime;
|
|
|
|
socket.send(encoder.encode("DONE"));
|
|
|
|
socket.send(fileTimePacket);
|
|
|
|
|
|
|
|
state = "wait-done";
|
|
|
|
break;
|
|
|
|
case "wait-done":
|
2018-08-09 05:27:55 +00:00
|
|
|
if (!client.checkResponse(data, OKAY)) {
|
2018-08-09 05:27:55 +00:00
|
|
|
shutdown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
console.log("DONE: OK");
|
|
|
|
state = "end";
|
|
|
|
runFSM();
|
|
|
|
break;
|
|
|
|
case "end":
|
|
|
|
socket.close();
|
|
|
|
deferred.resolve("SUCCESS");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
console.log("push Unexpected State: " + state);
|
|
|
|
deferred.reject("UNEXPECTED_STATE");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const setupSocket = function() {
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onerror = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("push onerror");
|
|
|
|
deferred.reject("SOCKET_ERROR");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onopen = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("push onopen");
|
|
|
|
state = "start";
|
|
|
|
runFSM();
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onclose = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("push onclose");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.ondata = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("push ondata");
|
2018-08-09 05:27:55 +00:00
|
|
|
runFSM(event.data);
|
2018-08-09 05:27:55 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
// Stat the file, get its size.
|
2018-08-09 05:27:55 +00:00
|
|
|
OS.File.stat(from).then(
|
2018-08-09 05:27:55 +00:00
|
|
|
function onSuccess(stat) {
|
|
|
|
if (stat.isDir) {
|
|
|
|
// The path represents a directory
|
|
|
|
deferred.reject("CANT_PUSH_DIR");
|
|
|
|
} else {
|
|
|
|
// The path represents a file, not a directory
|
|
|
|
fileSize = stat.size;
|
|
|
|
// We want seconds since epoch
|
|
|
|
fileTime = stat.lastModificationDate.getTime() / 1000;
|
|
|
|
remaining = fileSize;
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log(from + " size is " + fileSize);
|
|
|
|
const readPromise = OS.File.read(from);
|
2018-08-09 05:27:55 +00:00
|
|
|
readPromise.then(
|
2018-08-09 05:27:55 +00:00
|
|
|
function readSuccess(data) {
|
|
|
|
fileData = data;
|
2018-08-09 05:27:55 +00:00
|
|
|
socket = client.connect();
|
|
|
|
setupSocket();
|
|
|
|
},
|
|
|
|
function readError() {
|
|
|
|
deferred.reject("READ_FAILED");
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
function onFailure(reason) {
|
|
|
|
console.log(reason);
|
|
|
|
deferred.reject("CANT_ACCESS_FILE");
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
return deferred.promise;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Run a shell command
|
2018-08-09 05:27:55 +00:00
|
|
|
shell: function adb_shell(command) {
|
2018-08-09 05:27:55 +00:00
|
|
|
const deferred = PromiseUtils.defer();
|
2018-08-09 05:27:55 +00:00
|
|
|
let state;
|
|
|
|
let stdout = "";
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("shell " + command);
|
2018-08-09 05:27:55 +00:00
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const shutdown = function() {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("shell shutdown");
|
|
|
|
socket.close();
|
|
|
|
deferred.reject("BAD_RESPONSE");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const runFSM = function runFSM(data) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("runFSM " + state);
|
|
|
|
let req;
|
|
|
|
let ignoreResponseCode = false;
|
|
|
|
switch (state) {
|
|
|
|
case "start":
|
|
|
|
state = "send-transport";
|
|
|
|
runFSM();
|
2018-08-09 05:27:55 +00:00
|
|
|
break;
|
2018-08-09 05:27:55 +00:00
|
|
|
case "send-transport":
|
|
|
|
req = client.createRequest("host:transport-any");
|
|
|
|
socket.send(req);
|
|
|
|
state = "wait-transport";
|
2018-08-09 05:27:55 +00:00
|
|
|
break;
|
2018-08-09 05:27:55 +00:00
|
|
|
case "wait-transport":
|
2018-08-09 05:27:55 +00:00
|
|
|
if (!client.checkResponse(data, OKAY)) {
|
2018-08-09 05:27:55 +00:00
|
|
|
shutdown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
state = "send-shell";
|
|
|
|
runFSM();
|
2018-08-09 05:27:55 +00:00
|
|
|
break;
|
2018-08-09 05:27:55 +00:00
|
|
|
case "send-shell":
|
2018-08-09 05:27:55 +00:00
|
|
|
req = client.createRequest("shell:" + command);
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.send(req);
|
|
|
|
state = "rec-shell";
|
2018-08-09 05:27:55 +00:00
|
|
|
break;
|
2018-08-09 05:27:55 +00:00
|
|
|
case "rec-shell":
|
2018-08-09 05:27:55 +00:00
|
|
|
if (!client.checkResponse(data, OKAY)) {
|
2018-08-09 05:27:55 +00:00
|
|
|
shutdown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
state = "decode-shell";
|
2018-08-09 05:27:55 +00:00
|
|
|
if (client.getBuffer(data).byteLength == 4) {
|
2018-08-09 05:27:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
ignoreResponseCode = true;
|
|
|
|
case "decode-shell":
|
2018-08-09 05:27:55 +00:00
|
|
|
const decoder = new TextDecoder();
|
2018-08-09 05:27:55 +00:00
|
|
|
const text = new Uint8Array(client.getBuffer(data),
|
2018-08-09 05:27:55 +00:00
|
|
|
ignoreResponseCode ? 4 : 0);
|
2018-08-09 05:27:55 +00:00
|
|
|
stdout += decoder.decode(text);
|
2018-08-09 05:27:55 +00:00
|
|
|
break;
|
2018-08-09 05:27:55 +00:00
|
|
|
default:
|
|
|
|
console.log("shell Unexpected State: " + state);
|
|
|
|
deferred.reject("UNEXPECTED_STATE");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const socket = client.connect();
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onerror = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("shell onerror");
|
|
|
|
deferred.reject("SOCKET_ERROR");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onopen = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("shell onopen");
|
|
|
|
state = "start";
|
|
|
|
runFSM();
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onclose = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
deferred.resolve(stdout);
|
|
|
|
console.log("shell onclose");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.ondata = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("shell ondata");
|
2018-08-09 05:27:55 +00:00
|
|
|
runFSM(event.data);
|
2018-08-09 05:27:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
return deferred.promise;
|
|
|
|
},
|
|
|
|
|
|
|
|
reboot: function adb_reboot() {
|
|
|
|
return this.shell("reboot");
|
|
|
|
},
|
|
|
|
|
|
|
|
rebootRecovery: function adb_rebootRecovery() {
|
|
|
|
return this.shell("reboot recovery");
|
|
|
|
},
|
|
|
|
|
|
|
|
rebootBootloader: function adb_rebootBootloader() {
|
|
|
|
return this.shell("reboot bootloader");
|
|
|
|
},
|
|
|
|
|
|
|
|
root: function adb_root() {
|
2018-08-09 05:27:55 +00:00
|
|
|
const deferred = PromiseUtils.defer();
|
2018-08-09 05:27:55 +00:00
|
|
|
let state;
|
|
|
|
|
|
|
|
console.log("root");
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const shutdown = function() {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("root shutdown");
|
|
|
|
socket.close();
|
|
|
|
deferred.reject("BAD_RESPONSE");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const runFSM = function runFSM(data) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("runFSM " + state);
|
|
|
|
let req;
|
|
|
|
switch (state) {
|
|
|
|
case "start":
|
|
|
|
state = "send-transport";
|
|
|
|
runFSM();
|
2018-08-09 05:27:55 +00:00
|
|
|
break;
|
2018-08-09 05:27:55 +00:00
|
|
|
case "send-transport":
|
|
|
|
req = client.createRequest("host:transport-any");
|
|
|
|
socket.send(req);
|
|
|
|
state = "wait-transport";
|
2018-08-09 05:27:55 +00:00
|
|
|
break;
|
2018-08-09 05:27:55 +00:00
|
|
|
case "wait-transport":
|
2018-08-09 05:27:55 +00:00
|
|
|
if (!client.checkResponse(data, OKAY)) {
|
2018-08-09 05:27:55 +00:00
|
|
|
shutdown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
state = "send-root";
|
|
|
|
runFSM();
|
2018-08-09 05:27:55 +00:00
|
|
|
break;
|
2018-08-09 05:27:55 +00:00
|
|
|
case "send-root":
|
|
|
|
req = client.createRequest("root:");
|
|
|
|
socket.send(req);
|
|
|
|
state = "rec-root";
|
2018-08-09 05:27:55 +00:00
|
|
|
break;
|
2018-08-09 05:27:55 +00:00
|
|
|
case "rec-root":
|
|
|
|
// Nothing to do
|
2018-08-09 05:27:55 +00:00
|
|
|
break;
|
2018-08-09 05:27:55 +00:00
|
|
|
default:
|
|
|
|
console.log("root Unexpected State: " + state);
|
|
|
|
deferred.reject("UNEXPECTED_STATE");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const socket = client.connect();
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onerror = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("root onerror");
|
|
|
|
deferred.reject("SOCKET_ERROR");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onopen = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("root onopen");
|
|
|
|
state = "start";
|
|
|
|
runFSM();
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.onclose = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
deferred.resolve();
|
|
|
|
console.log("root onclose");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.ondata = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("root ondata");
|
2018-08-09 05:27:55 +00:00
|
|
|
runFSM(event.data);
|
2018-08-09 05:27:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
return deferred.promise;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Asynchronously runs an adb command.
|
2018-08-09 05:27:55 +00:00
|
|
|
// @param command The command as documented in
|
2018-08-09 05:27:55 +00:00
|
|
|
// http://androidxref.com/4.0.4/xref/system/core/adb/SERVICES.TXT
|
2018-08-09 05:27:55 +00:00
|
|
|
runCommand: function adb_runCommand(command) {
|
|
|
|
console.log("runCommand " + command);
|
2018-08-09 05:27:55 +00:00
|
|
|
const deferred = PromiseUtils.defer();
|
2018-08-09 05:27:55 +00:00
|
|
|
if (!this.ready) {
|
2018-08-09 05:27:55 +00:00
|
|
|
setTimeout(function() {
|
|
|
|
deferred.reject("ADB_NOT_READY");
|
|
|
|
});
|
2018-08-09 05:27:55 +00:00
|
|
|
return deferred.promise;
|
|
|
|
}
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const socket = client.connect();
|
2018-08-09 05:27:55 +00:00
|
|
|
|
|
|
|
socket.s.onopen = function() {
|
|
|
|
console.log("runCommand onopen");
|
2018-08-09 05:27:55 +00:00
|
|
|
const req = client.createRequest(command);
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.send(req);
|
|
|
|
};
|
|
|
|
|
|
|
|
socket.s.onerror = function() {
|
|
|
|
console.log("runCommand onerror");
|
|
|
|
deferred.reject("NETWORK_ERROR");
|
|
|
|
};
|
|
|
|
|
|
|
|
socket.s.onclose = function() {
|
|
|
|
console.log("runCommand onclose");
|
|
|
|
};
|
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
socket.s.ondata = function(event) {
|
2018-08-09 05:27:55 +00:00
|
|
|
console.log("runCommand ondata");
|
2018-08-09 05:27:55 +00:00
|
|
|
const data = event.data;
|
2018-08-09 05:27:55 +00:00
|
|
|
|
2018-08-09 05:27:55 +00:00
|
|
|
const packet = client.unpackPacket(data, false);
|
2018-08-09 05:27:55 +00:00
|
|
|
if (!client.checkResponse(data, OKAY)) {
|
|
|
|
socket.close();
|
|
|
|
console.log("Error: " + packet.data);
|
|
|
|
deferred.reject("PROTOCOL_ERROR");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
deferred.resolve(packet.data);
|
|
|
|
};
|
|
|
|
|
|
|
|
return deferred.promise;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.ADB = ADB;
|