diff --git a/lib/units/device/resources/minicap.js b/lib/units/device/resources/minicap.js index 52d85a55..133c0689 100644 --- a/lib/units/device/resources/minicap.js +++ b/lib/units/device/resources/minicap.js @@ -1,3 +1,4 @@ +var fs = require('fs') var util = require('util') var path = require('path') @@ -8,16 +9,17 @@ var logger = require('../../../util/logger') var pathutil = require('../../../util/pathutil') var devutil = require('../../../util/devutil') var streamutil = require('../../../util/streamutil') +var Resource = require('./util/resource') module.exports = syrup.serial() .dependency(require('../support/adb')) .dependency(require('../support/properties')) .dependency(require('../support/abi')) .define(function(options, adb, properties, abi) { - logger.createLogger('device:resources:minicap') + var log = logger.createLogger('device:resources:minicap') var resources = { - bin: { + bin: new Resource({ src: pathutil.requiredMatch(abi.all.map(function(supportedAbi) { return pathutil.module(util.format( 'minicap-prebuilt/prebuilt/%s/bin/minicap%s' @@ -25,11 +27,14 @@ module.exports = syrup.serial() , abi.pie ? '' : '-nopie' )) })) - , dest: '/data/local/tmp/minicap' + , dest: [ + '/data/local/tmp/minicap' + , '/data/data/com.android.shell/minicap' + ] , comm: 'minicap' , mode: 0755 - } - , lib: { + }) + , lib: new Resource({ // @todo The lib ABI should match the bin ABI. Currently we don't // have an x86_64 version of the binary while the lib supports it. src: pathutil.requiredMatch(abi.all.reduce(function(all, supportedAbi) { @@ -46,9 +51,13 @@ module.exports = syrup.serial() )) ]) }, [])) - , dest: '/data/local/tmp/minicap.so' + , dest: [ + '/data/local/tmp/minicap.so' + , '/data/data/com.android.shell/minicap.so' + ] + , comm: 'minicap.so' // Not actually used for anything but log output , mode: 0755 - } + }) } function removeResource(res) { @@ -60,7 +69,7 @@ module.exports = syrup.serial() .return(res) } - function installResource(res) { + function pushResource(res) { return adb.push(options.serial, res.src, res.dest, res.mode) .timeout(10000) .then(function(transfer) { @@ -72,10 +81,39 @@ module.exports = syrup.serial() .return(res) } + function installResource(res) { + log.info('Installing "%s" as "%s"', res.comm, res.dest) + + function checkExecutable(res) { + return adb.stat(options.serial, res.dest) + .timeout(5000) + .then(function(stats) { + return (stats.mode & fs.constants.S_IXUSR) === fs.constants.S_IXUSR + }) + } + + return removeResource(res) + .then(pushResource) + .then(function(res) { + return checkExecutable(res).then(function(ok) { + if (!ok) { + log.info( + 'Pushed "%s" not executable, attempting fallback location' + , res.comm + ) + res.shift() + return installResource(res) + } + return res + }) + }) + .return(res) + } + function installAll() { return Promise.all([ - removeResource(resources.bin).then(installResource) - , removeResource(resources.lib).then(installResource) + installResource(resources.bin) + , installResource(resources.lib) ]) } diff --git a/lib/units/device/resources/minirev.js b/lib/units/device/resources/minirev.js index abf3ec04..ef8cd1c1 100644 --- a/lib/units/device/resources/minirev.js +++ b/lib/units/device/resources/minirev.js @@ -1,3 +1,4 @@ +var fs = require('fs') var util = require('util') var Promise = require('bluebird') @@ -7,6 +8,7 @@ var logger = require('../../../util/logger') var pathutil = require('../../../util/pathutil') var devutil = require('../../../util/devutil') var streamutil = require('../../../util/streamutil') +var Resource = require('./util/resource') module.exports = syrup.serial() .dependency(require('../support/adb')) @@ -15,16 +17,19 @@ module.exports = syrup.serial() var log = logger.createLogger('device:resources:minirev') var resources = { - bin: { + bin: new Resource({ src: pathutil.vendor(util.format( 'minirev/%s/minirev%s' , properties['ro.product.cpu.abi'] , properties['ro.build.version.sdk'] < 16 ? '-nopie' : '' )) - , dest: '/data/local/tmp/minirev' + , dest: [ + '/data/local/tmp/minirev' + , '/data/data/com.android.shell/minirev' + ] , comm: 'minirev' , mode: 0755 - } + }) } function removeResource(res) { @@ -36,7 +41,7 @@ module.exports = syrup.serial() .return(res) } - function installResource(res) { + function pushResource(res) { return adb.push(options.serial, res.src, res.dest, res.mode) .timeout(10000) .then(function(transfer) { @@ -48,29 +53,38 @@ module.exports = syrup.serial() .return(res) } - function ensureNotBusy(res) { - return adb.shell(options.serial, [res.dest, '-h']) - .timeout(10000) - .then(function(out) { - // Can be "Text is busy", "text busy" - return streamutil.findLine(out, (/busy/i)) - .timeout(10000) - .then(function() { - log.info('Binary is busy, will retry') - return Promise.delay(1000) - }) - .then(function() { - return ensureNotBusy(res) - }) - .catch(streamutil.NoSuchLineError, function() { - return res - }) + function installResource(res) { + log.info('Installing "%s" as "%s"', res.comm, res.dest) + + function checkExecutable(res) { + return adb.stat(options.serial, res.dest) + .timeout(5000) + .then(function(stats) { + return (stats.mode & fs.constants.S_IXUSR) === fs.constants.S_IXUSR + }) + } + + return removeResource(res) + .then(pushResource) + .then(function(res) { + return checkExecutable(res).then(function(ok) { + if (!ok) { + log.info( + 'Pushed "%s" not executable, attempting fallback location' + , res.comm + ) + res.shift() + return installResource(res) + } + return res + }) }) + .return(res) } function installAll() { return Promise.all([ - removeResource(resources.bin).then(installResource).then(ensureNotBusy) + installResource(resources.bin) ]) } diff --git a/lib/units/device/resources/minitouch.js b/lib/units/device/resources/minitouch.js index f891ffaa..d7920468 100644 --- a/lib/units/device/resources/minitouch.js +++ b/lib/units/device/resources/minitouch.js @@ -1,4 +1,5 @@ var util = require('util') +var fs = require('fs') var Promise = require('bluebird') var syrup = require('stf-syrup') @@ -7,15 +8,16 @@ var logger = require('../../../util/logger') var pathutil = require('../../../util/pathutil') var devutil = require('../../../util/devutil') var streamutil = require('../../../util/streamutil') +var Resource = require('./util/resource') module.exports = syrup.serial() .dependency(require('../support/adb')) .dependency(require('../support/abi')) .define(function(options, adb, abi) { - logger.createLogger('device:resources:minitouch') + var log = logger.createLogger('device:resources:minitouch') var resources = { - bin: { + bin: new Resource({ src: pathutil.requiredMatch(abi.all.map(function(supportedAbi) { return pathutil.vendor(util.format( 'minitouch/%s/minitouch%s' @@ -23,10 +25,13 @@ module.exports = syrup.serial() , abi.pie ? '' : '-nopie' )) })) - , dest: '/data/local/tmp/minitouch' + , dest: [ + '/data/local/tmp/minitouch' + , '/data/data/com.android.shell/minitouch' + ] , comm: 'minitouch' , mode: 0755 - } + }) } function removeResource(res) { @@ -38,7 +43,7 @@ module.exports = syrup.serial() .return(res) } - function installResource(res) { + function pushResource(res) { return adb.push(options.serial, res.src, res.dest, res.mode) .timeout(10000) .then(function(transfer) { @@ -50,9 +55,38 @@ module.exports = syrup.serial() .return(res) } + function installResource(res) { + log.info('Installing "%s" as "%s"', res.comm, res.dest) + + function checkExecutable(res) { + return adb.stat(options.serial, res.dest) + .timeout(5000) + .then(function(stats) { + return (stats.mode & fs.constants.S_IXUSR) === fs.constants.S_IXUSR + }) + } + + return removeResource(res) + .then(pushResource) + .then(function(res) { + return checkExecutable(res).then(function(ok) { + if (!ok) { + log.info( + 'Pushed "%s" not executable, attempting fallback location' + , res.comm + ) + res.shift() + return installResource(res) + } + return res + }) + }) + .return(res) + } + function installAll() { return Promise.all([ - removeResource(resources.bin).then(installResource) + installResource(resources.bin) ]) } diff --git a/lib/units/device/resources/util/resource.js b/lib/units/device/resources/util/resource.js new file mode 100644 index 00000000..a5c2e26d --- /dev/null +++ b/lib/units/device/resources/util/resource.js @@ -0,0 +1,21 @@ +var util = require('util') + +function Resource(options) { + this.src = options.src + this.dest = options.dest.shift() + this.comm = options.comm + this.mode = options.mode + this.fallback = options.dest +} + +Resource.prototype.shift = function() { + if (this.fallback.length === 0) { + throw new Error(util.format( + 'Out of fallback locations for "%s"' + , this.src + )) + } + this.dest = this.fallback.shift() +} + +module.exports = Resource