| var util = require('util') |
| |
| var split = require('split') |
| var Promise = require('bluebird') |
| |
| var devutil = module.exports = Object.create(null) |
| |
| function closedError(err) { |
| return err.message.indexOf('closed') !== -1 |
| } |
| |
| devutil.ensureUnusedPort = function(adb, serial, port) { |
| return adb.openTcp(serial, port) |
| .then(function(conn) { |
| conn.end() |
| throw new Error(util.format('Port "%d" should be unused', port)) |
| }) |
| .catch(closedError, function() { |
| return Promise.resolve(port) |
| }) |
| } |
| |
| devutil.waitForPort = function(adb, serial, port) { |
| return adb.openTcp(serial, port) |
| .then(function(conn) { |
| conn.port = port |
| return conn |
| }) |
| .catch(closedError, function() { |
| return Promise.delay(100) |
| .then(function() { |
| return devutil.waitForPort(adb, serial, port) |
| }) |
| }) |
| } |
| |
| devutil.waitForPortToFree = function(adb, serial, port) { |
| return adb.openTcp(serial, port) |
| .then(function(conn) { |
| var resolver = Promise.defer() |
| |
| function endListener() { |
| resolver.resolve(port) |
| } |
| |
| function errorListener(err) { |
| resolver.reject(err) |
| } |
| |
| conn.on('end', endListener) |
| conn.on('error', errorListener) |
| |
| return resolver.promise.finally(function() { |
| conn.removeListener('end', endListener) |
| conn.removeListener('error', errorListener) |
| conn.end() |
| }) |
| }) |
| .catch(closedError, function() { |
| return port |
| }) |
| } |
| |
| devutil.listPidsByComm = function(adb, serial, comm, bin) { |
| var users = { |
| shell: true |
| } |
| |
| return adb.shell(serial, ['ps', comm]) |
| .then(function(out) { |
| return new Promise(function(resolve) { |
| var header = false |
| var pids = [] |
| out.pipe(split()) |
| .on('data', function(chunk) { |
| if (header) { |
| header = false |
| } |
| else { |
| var cols = chunk.toString().split(/\s+/) |
| if (cols.pop() === bin && users[cols[0]]) { |
| pids.push(Number(cols[1])) |
| } |
| } |
| }) |
| .on('end', function() { |
| resolve(pids) |
| }) |
| }) |
| }) |
| } |
| |
| devutil.waitForProcsToDie = function(adb, serial, comm, bin) { |
| return devutil.listPidsByComm(adb, serial, comm, bin) |
| .then(function(pids) { |
| if (pids.length) { |
| return Promise.delay(100) |
| .then(function() { |
| return devutil.waitForProcsToDie(adb, serial, comm, bin) |
| }) |
| } |
| }) |
| } |
| |
| devutil.killProcsByComm = function(adb, serial, comm, bin, mode) { |
| return devutil.listPidsByComm(adb, serial, comm, bin, mode) |
| .then(function(pids) { |
| if (!pids.length) { |
| return Promise.resolve() |
| } |
| return adb.shell(serial, ['kill', mode || -15].concat(pids)) |
| .then(function(out) { |
| return new Promise(function(resolve) { |
| out.on('end', resolve) |
| }) |
| }) |
| .then(function() { |
| return devutil.waitForProcsToDie(adb, serial, comm, bin) |
| }) |
| .timeout(2000) |
| .catch(function() { |
| return devutil.killProcsByComm(adb, serial, comm, bin, -9) |
| }) |
| }) |
| } |
| |
| devutil.makeIdentity = function(serial, properties) { |
| var model = properties['ro.product.model'] |
| var brand = properties['ro.product.brand'] |
| var manufacturer = properties['ro.product.manufacturer'] |
| var operator = properties['gsm.sim.operator.alpha'] || |
| properties['gsm.operator.alpha'] |
| var version = properties['ro.build.version.release'] |
| var sdk = properties['ro.build.version.sdk'] |
| var abi = properties['ro.product.cpu.abi'] |
| var product = properties['ro.product.name'] |
| |
| // Remove brand prefix for consistency |
| if (model.substr(0, brand.length) === brand) { |
| model = model.substr(brand.length) |
| } |
| |
| // Remove manufacturer prefix for consistency |
| if (model.substr(0, manufacturer.length) === manufacturer) { |
| model = model.substr(manufacturer.length) |
| } |
| |
| // Clean up remaining model name |
| // model = model.replace(/[_ ]/g, '') |
| return { |
| serial: serial |
| , platform: 'Android' |
| , manufacturer: manufacturer.toUpperCase() |
| , operator: operator || null |
| , model: model |
| , version: version |
| , abi: abi |
| , sdk: sdk |
| , product: product |
| } |
| } |