mirror of
https://github.com/openstf/stf
synced 2025-10-04 10:19:30 +02:00
Wake up and unlock device when it's being used. A bit messy, pending refactor.
This commit is contained in:
parent
999e5113bf
commit
a25df0b293
6 changed files with 183 additions and 20 deletions
|
@ -239,7 +239,7 @@ module.exports = function(options) {
|
||||||
.then(function(port) {
|
.then(function(port) {
|
||||||
var log = logger.createLogger('device:inputAgent')
|
var log = logger.createLogger('device:inputAgent')
|
||||||
return promiseutil.periodicNotify(
|
return promiseutil.periodicNotify(
|
||||||
inputAgent.open(adb, options.serial)
|
inputAgent.openAgent(adb, options.serial)
|
||||||
, 1000
|
, 1000
|
||||||
)
|
)
|
||||||
.progressed(function() {
|
.progressed(function() {
|
||||||
|
@ -264,8 +264,34 @@ module.exports = function(options) {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
.then(function(apk) {
|
||||||
|
log.info('Launching InputService')
|
||||||
|
return inputAgent.stopService(adb, options.serial)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
log.info('Launching input service')
|
return devutil.waitForPortToFree(adb, options.serial, 1100)
|
||||||
|
})
|
||||||
|
.then(function(port) {
|
||||||
|
var log = logger.createLogger('device:inputService')
|
||||||
|
return inputAgent.openService(adb, options.serial)
|
||||||
|
.then(function() {
|
||||||
|
return promiseutil.periodicNotify(
|
||||||
|
devutil.waitForPort(adb, options.serial, port)
|
||||||
|
, 1000
|
||||||
|
)
|
||||||
|
.progressed(function() {
|
||||||
|
log.info('Waiting for InputService')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(function(conn) {
|
||||||
|
services.inputServiceSocket = vitals.register(
|
||||||
|
'device:inputService:socket'
|
||||||
|
, conn
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
log.info('Launching TouchService')
|
||||||
return devutil.ensureUnusedPort(adb, options.serial, 2820)
|
return devutil.ensureUnusedPort(adb, options.serial, 2820)
|
||||||
.then(function(port) {
|
.then(function(port) {
|
||||||
var log = logger.createLogger('device:remote:input')
|
var log = logger.createLogger('device:remote:input')
|
||||||
|
@ -290,7 +316,7 @@ module.exports = function(options) {
|
||||||
return monkey.connectStream(conn)
|
return monkey.connectStream(conn)
|
||||||
})
|
})
|
||||||
.then(function(monkey) {
|
.then(function(monkey) {
|
||||||
services.input = vitals.register(
|
services.touch = vitals.register(
|
||||||
'device:remote:input:monkey'
|
'device:remote:input:monkey'
|
||||||
, Promise.promisifyAll(monkey)
|
, Promise.promisifyAll(monkey)
|
||||||
)
|
)
|
||||||
|
@ -404,25 +430,25 @@ module.exports = function(options) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on(wire.TouchDownMessage, function(channel, message) {
|
.on(wire.TouchDownMessage, function(channel, message) {
|
||||||
services.input.touchDownAsync(message.x, message.y)
|
services.touch.touchDownAsync(message.x, message.y)
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
log.error('touchDown failed', err.stack)
|
log.error('touchDown failed', err.stack)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on(wire.TouchMoveMessage, function(channel, message) {
|
.on(wire.TouchMoveMessage, function(channel, message) {
|
||||||
services.input.touchMoveAsync(message.x, message.y)
|
services.touch.touchMoveAsync(message.x, message.y)
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
log.error('touchMove failed', err.stack)
|
log.error('touchMove failed', err.stack)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on(wire.TouchUpMessage, function(channel, message) {
|
.on(wire.TouchUpMessage, function(channel, message) {
|
||||||
services.input.touchUpAsync(message.x, message.y)
|
services.touch.touchUpAsync(message.x, message.y)
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
log.error('touchUp failed', err.stack)
|
log.error('touchUp failed', err.stack)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on(wire.TapMessage, function(channel, message) {
|
.on(wire.TapMessage, function(channel, message) {
|
||||||
services.input.tapAsync(message.x, message.y)
|
services.touch.tapAsync(message.x, message.y)
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
log.error('tap failed', err.stack)
|
log.error('tap failed', err.stack)
|
||||||
})
|
})
|
||||||
|
@ -593,6 +619,8 @@ module.exports = function(options) {
|
||||||
))
|
))
|
||||||
])
|
])
|
||||||
services.logcat.on('entry', logcatListener)
|
services.logcat.on('entry', logcatListener)
|
||||||
|
inputAgent.acquireWakeLock(services.inputServiceSocket)
|
||||||
|
inputAgent.unlock(services.inputServiceSocket)
|
||||||
owner = newOwner
|
owner = newOwner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,6 +637,8 @@ module.exports = function(options) {
|
||||||
))
|
))
|
||||||
])
|
])
|
||||||
services.logcat.removeListener('entry', logcatListener)
|
services.logcat.removeListener('entry', logcatListener)
|
||||||
|
inputAgent.releaseWakeLock(services.inputServiceSocket)
|
||||||
|
inputAgent.lock(services.inputServiceSocket)
|
||||||
owner = null
|
owner = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,38 +3,106 @@ var util = require('util')
|
||||||
var Promise = require('bluebird')
|
var Promise = require('bluebird')
|
||||||
var ProtoBuf = require('protobufjs')
|
var ProtoBuf = require('protobufjs')
|
||||||
var ByteBuffer = require('protobufjs/node_modules/bytebuffer')
|
var ByteBuffer = require('protobufjs/node_modules/bytebuffer')
|
||||||
var split = require('split')
|
var semver = require('semver')
|
||||||
|
|
||||||
var pathutil = require('../util/pathutil')
|
var pathutil = require('../util/pathutil')
|
||||||
var streamutil = require('../util/streamutil')
|
var streamutil = require('../util/streamutil')
|
||||||
|
|
||||||
|
var SUPPORTED_VERSION = '~0.1.2';
|
||||||
|
|
||||||
|
var pkg = 'jp.co.cyberagent.stf.input.agent'
|
||||||
|
var apk = pathutil.vendor('InputAgent/InputAgent.apk')
|
||||||
var proto = ProtoBuf.loadProtoFile(
|
var proto = ProtoBuf.loadProtoFile(
|
||||||
pathutil.vendor('InputAgent/inputAgentProtocol.proto')
|
pathutil.vendor('InputAgent/proto/agent.proto')
|
||||||
).build().jp.co.cyberagent.stf.input.agent
|
).build().jp.co.cyberagent.stf.input.agent.proto
|
||||||
|
|
||||||
var inputAgent = module.exports = Object.create(null)
|
var inputAgent = module.exports = Object.create(null)
|
||||||
|
|
||||||
inputAgent.open = function(adb, serial) {
|
function IncompatibleVersionError(version) {
|
||||||
return adb.installAsync(serial, pathutil.vendor('InputAgent/InputAgent.apk'))
|
Error.call(this, util.format('Incompatible version %s', version))
|
||||||
.then(function() {
|
this.name = 'IncompatibleVersionError'
|
||||||
return adb.shellAsync(serial, 'pm path jp.co.cyberagent.stf.input.agent')
|
this.version = version
|
||||||
})
|
Error.captureStackTrace(this, IncompatibleVersionError)
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(IncompatibleVersionError, Error)
|
||||||
|
|
||||||
|
inputAgent.IncompatibleVersionError = IncompatibleVersionError
|
||||||
|
|
||||||
|
inputAgent.getInstalledPath = function(adb, serial) {
|
||||||
|
return adb.shellAsync(serial, util.format("pm path '%s'", pkg))
|
||||||
.then(function(out) {
|
.then(function(out) {
|
||||||
return streamutil.findLine(out, (/^package:/))
|
return streamutil.findLine(out, (/^package:/))
|
||||||
.then(function(line) {
|
.then(function(line) {
|
||||||
return line.substr(8)
|
return line.substr(8)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.then(function(apk) {
|
}
|
||||||
|
|
||||||
|
inputAgent.ensureInstalled = function(adb, serial) {
|
||||||
|
return inputAgent.getInstalledPath(adb, serial)
|
||||||
|
.then(function(installedPath) {
|
||||||
|
return adb.shellAsync(serial, util.format(
|
||||||
|
"export CLASSPATH='%s';"
|
||||||
|
+ ' exec app_process /system/bin'
|
||||||
|
+ ' jp.co.cyberagent.stf.input.agent.InputAgent --version'
|
||||||
|
, installedPath
|
||||||
|
))
|
||||||
|
.then(function(out) {
|
||||||
|
return streamutil.readAll(out)
|
||||||
|
.then(function(buffer) {
|
||||||
|
var version = buffer.toString()
|
||||||
|
if (semver.satisfies(version, SUPPORTED_VERSION)) {
|
||||||
|
return installedPath
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Promise.reject(new IncompatibleVersionError(version))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
return adb.installAsync(serial, apk)
|
||||||
|
.then(function() {
|
||||||
|
return inputAgent.getInstalledPath(adb, serial)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
inputAgent.openAgent = function(adb, serial) {
|
||||||
|
return inputAgent.ensureInstalled(adb, serial)
|
||||||
|
.then(function(installedPath) {
|
||||||
return adb.shellAsync(serial, util.format(
|
return adb.shellAsync(serial, util.format(
|
||||||
"export CLASSPATH='%s';"
|
"export CLASSPATH='%s';"
|
||||||
+ ' exec app_process /system/bin'
|
+ ' exec app_process /system/bin'
|
||||||
+ ' jp.co.cyberagent.stf.input.agent.InputAgent'
|
+ ' jp.co.cyberagent.stf.input.agent.InputAgent'
|
||||||
, apk
|
, installedPath
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inputAgent.openService = function(adb, serial) {
|
||||||
|
return inputAgent.ensureInstalled(adb, serial)
|
||||||
|
.then(function() {
|
||||||
|
var intent =
|
||||||
|
'-a jp.co.cyberagent.stf.input.agent.InputService.ACTION_START'
|
||||||
|
return adb.shellAsync(serial, util.format(
|
||||||
|
'am startservice --user 0 %s || am startservice %s'
|
||||||
|
, intent
|
||||||
|
, intent
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
inputAgent.stopService = function(adb, serial) {
|
||||||
|
var intent = '-a jp.co.cyberagent.stf.input.agent.InputService.ACTION_STOP'
|
||||||
|
return adb.shellAsync(serial, util.format(
|
||||||
|
'am startservice --user 0 %s || am startservice %s'
|
||||||
|
, intent
|
||||||
|
, intent
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
inputAgent.sendInputEvent = function(agent, event) {
|
inputAgent.sendInputEvent = function(agent, event) {
|
||||||
var lengthBuffer = new ByteBuffer()
|
var lengthBuffer = new ByteBuffer()
|
||||||
, messageBuffer = new proto.InputEvent(event).encode()
|
, messageBuffer = new proto.InputEvent(event).encode()
|
||||||
|
@ -46,3 +114,23 @@ inputAgent.sendInputEvent = function(agent, event) {
|
||||||
, messageBuffer.toBuffer()
|
, messageBuffer.toBuffer()
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inputAgent.unlock = function(service) {
|
||||||
|
service.write('unlock\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
inputAgent.lock = function(service) {
|
||||||
|
service.write('lock\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
inputAgent.acquireWakeLock = function(service) {
|
||||||
|
service.write('acquire wake lock\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
inputAgent.releaseWakeLock = function(service) {
|
||||||
|
service.write('release wake lock\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
inputAgent.identity = function(service, serial) {
|
||||||
|
service.write(util.format('show identity %s\n', serial));
|
||||||
|
}
|
||||||
|
|
|
@ -91,6 +91,36 @@ devutil.waitForPort = function(adb, serial, port) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
devutil.waitForPortToFree = function(adb, serial, port) {
|
||||||
|
function closedError(err) {
|
||||||
|
return err.message === 'closed'
|
||||||
|
}
|
||||||
|
return adb.openTcpAsync(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(err) {
|
||||||
|
return port
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
devutil.listPidsByComm = function(adb, serial, comm, bin) {
|
devutil.listPidsByComm = function(adb, serial, comm, bin) {
|
||||||
var users = {
|
var users = {
|
||||||
shell: true
|
shell: true
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
|
var util = require('util')
|
||||||
|
|
||||||
var Promise = require('bluebird')
|
var Promise = require('bluebird')
|
||||||
var split = require('split')
|
var split = require('split')
|
||||||
|
|
||||||
|
function NoSuchLineError(message) {
|
||||||
|
Error.call(this, message)
|
||||||
|
this.name = 'NoSuchLineError'
|
||||||
|
Error.captureStackTrace(this, NoSuchLineError)
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(NoSuchLineError, Error)
|
||||||
|
|
||||||
|
module.exports.NoSuchLineError = NoSuchLineError
|
||||||
|
|
||||||
module.exports.readAll = function(stream) {
|
module.exports.readAll = function(stream) {
|
||||||
var resolver = Promise.defer()
|
var resolver = Promise.defer()
|
||||||
, collected = new Buffer(0)
|
, collected = new Buffer(0)
|
||||||
|
@ -41,7 +53,7 @@ module.exports.findLine = function(stream, re) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function endListener() {
|
function endListener() {
|
||||||
resolver.reject(new Error('No matching line found'))
|
resolver.reject(new NoSuchLineError())
|
||||||
}
|
}
|
||||||
|
|
||||||
function lineListener(line) {
|
function lineListener(line) {
|
||||||
|
|
BIN
vendor/InputAgent/InputAgent.apk
vendored
BIN
vendor/InputAgent/InputAgent.apk
vendored
Binary file not shown.
|
@ -1,15 +1,18 @@
|
||||||
package jp.co.cyberagent.stf.input.agent;
|
package jp.co.cyberagent.stf.input.agent.proto;
|
||||||
|
|
||||||
|
option java_outer_classname = "AgentProto";
|
||||||
|
|
||||||
enum InputAction {
|
enum InputAction {
|
||||||
KEYDOWN = 0;
|
KEYDOWN = 0;
|
||||||
KEYUP = 1;
|
KEYUP = 1;
|
||||||
KEYPRESS = 2;
|
KEYPRESS = 2;
|
||||||
TYPE = 3;
|
TYPE = 3;
|
||||||
|
WAKE = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message InputEvent {
|
message InputEvent {
|
||||||
required InputAction action = 1;
|
required InputAction action = 1;
|
||||||
required int32 keyCode = 2;
|
optional int32 keyCode = 2;
|
||||||
optional bool shiftKey = 3;
|
optional bool shiftKey = 3;
|
||||||
optional bool ctrlKey = 4;
|
optional bool ctrlKey = 4;
|
||||||
optional bool altKey = 5;
|
optional bool altKey = 5;
|
Loading…
Add table
Add a link
Reference in a new issue