mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-02-20 20:09:11 +00:00
commit
63b01e29ee
@ -14,4 +14,4 @@ from wa.framework.plugin import Plugin, Parameter
|
||||
from wa.framework.processor import ResultProcessor
|
||||
from wa.framework.resource import (NO_ONE, JarFile, ApkFile, ReventFile, File,
|
||||
Executable)
|
||||
from wa.framework.workload import Workload, ApkUiautoWorkload
|
||||
from wa.framework.workload import Workload, ApkUiautoWorkload, ReventWorkload
|
||||
|
@ -15,21 +15,24 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
from time import sleep
|
||||
|
||||
|
||||
from wa import Command, settings
|
||||
from wa.framework.configuration import RunConfiguration
|
||||
from wa.framework.resource import Executable, NO_ONE, ResourceResolver
|
||||
from wa import Command
|
||||
from wa.framework import pluginloader
|
||||
from wa.framework.resource import ResourceResolver
|
||||
from wa.framework.target.manager import TargetManager
|
||||
from wa.utils.revent import ReventRecorder
|
||||
|
||||
|
||||
class RecordCommand(Command):
|
||||
|
||||
name = 'record'
|
||||
description = '''Performs a revent recording
|
||||
description = '''
|
||||
Performs a revent recording
|
||||
|
||||
This command helps making revent recordings. It will automatically
|
||||
deploy revent and even has the option of automatically opening apps.
|
||||
deploy revent and has options to automatically open apps and record
|
||||
specified stages of a workload.
|
||||
|
||||
Revent allows you to record raw inputs such as screen swipes or button presses.
|
||||
This can be useful for recording inputs for workloads such as games that don't
|
||||
@ -43,10 +46,18 @@ class RecordCommand(Command):
|
||||
it can be automatically determined. On Android device it will be obtained
|
||||
from ``build.prop``, on Linux devices it is obtained from ``/proc/device-tree/model``.
|
||||
- suffix is used by WA to determine which part of the app execution the
|
||||
recording is for, currently these are either ``setup`` or ``run``. This
|
||||
should be specified with the ``-s`` argument.
|
||||
recording is for, currently these are either ``setup``, ``run``, ``extract_results``
|
||||
or ``teardown``. All stages except ``run`` are optional and these should
|
||||
be specified with the ``-s``, ``-e`` or ``-t`` arguments respectively,
|
||||
or optionally ``-a`` to indicate all stages should be recorded.
|
||||
'''
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(RecordCommand, self).__init__(**kwargs)
|
||||
self.tm = None
|
||||
self.target = None
|
||||
self.revent_recorder = None
|
||||
|
||||
def initialize(self, context):
|
||||
self.parser.add_argument('-d', '--device', metavar='DEVICE',
|
||||
help='''
|
||||
@ -54,39 +65,204 @@ class RecordCommand(Command):
|
||||
take precedence over the device (if any)
|
||||
specified in configuration.
|
||||
''')
|
||||
self.parser.add_argument('-o', '--output', help='Specify the output file', metavar='FILE')
|
||||
self.parser.add_argument('-s', '--setup', help='Record a recording for setup stage',
|
||||
action='store_true')
|
||||
self.parser.add_argument('-e', '--extract_results', help='Record a recording for extract_results stage',
|
||||
action='store_true')
|
||||
self.parser.add_argument('-t', '--teardown', help='Record a recording for teardown stage',
|
||||
action='store_true')
|
||||
self.parser.add_argument('-a', '--all', help='Record recordings for available stages',
|
||||
action='store_true')
|
||||
|
||||
def execute(state, args):
|
||||
# Need validation
|
||||
self.parser.add_argument('-C', '--clear', help='Clear app cache before launching it',
|
||||
action='store_true')
|
||||
group = self.parser.add_mutually_exclusive_group(required=False)
|
||||
group.add_argument('-p', '--package', help='Package to launch before recording')
|
||||
group.add_argument('-w', '--workload', help='Name of a revent workload (mostly games)')
|
||||
|
||||
def validate_args(self, args):
|
||||
if args.clear and not (args.package or args.workload):
|
||||
self.logger.error("Package/Workload must be specified if you want to clear cache")
|
||||
sys.exit()
|
||||
if args.workload and args.output:
|
||||
self.logger.error("Output file cannot be specified with Workload")
|
||||
sys.exit()
|
||||
if not args.workload and (args.setup or args.extract_results or
|
||||
args.teardown or args.all):
|
||||
self.logger.error("Cannot specify a recording stage without a Workload")
|
||||
sys.exit()
|
||||
|
||||
def execute(self, state, args):
|
||||
self.validate_args(args)
|
||||
if args.device:
|
||||
device = args.device
|
||||
device = args.device
|
||||
device_config = {}
|
||||
else:
|
||||
device = state.run_config.device
|
||||
device_config = state.run_config.device_config
|
||||
device_config = state.run_config.device_config or {}
|
||||
|
||||
self.tm = TargetManager(device, device_config)
|
||||
self.target = self.tm.target
|
||||
self.revent_recorder = ReventRecorder(self.target)
|
||||
self.revent_recorder.deploy()
|
||||
|
||||
if args.workload:
|
||||
self.workload_record(args)
|
||||
elif args.package:
|
||||
self.package_record(args)
|
||||
else:
|
||||
self.manual_record(args)
|
||||
|
||||
self.revent_recorder.remove()
|
||||
|
||||
def record(self, revent_file, name, output_path):
|
||||
msg = 'Press Enter when you are ready to record {}...'
|
||||
self.logger.info(msg.format(name))
|
||||
raw_input('')
|
||||
self.revent_recorder.start_record(revent_file)
|
||||
msg = 'Press Enter when you have finished recording {}...'
|
||||
self.logger.info(msg.format(name))
|
||||
raw_input('')
|
||||
self.revent_recorder.stop_record()
|
||||
|
||||
if not os.path.isdir(output_path):
|
||||
os.makedirs(output_path)
|
||||
|
||||
revent_file_name = self.target.path.basename(revent_file)
|
||||
host_path = os.path.join(output_path, revent_file_name)
|
||||
if os.path.exists(host_path):
|
||||
msg = 'Revent file \'{}\' already exists, overwrite? [y/n]'
|
||||
self.logger.info(msg.format(revent_file_name))
|
||||
if raw_input('') == 'y':
|
||||
os.remove(host_path)
|
||||
else:
|
||||
msg = 'Did not pull and overwrite \'{}\''
|
||||
self.logger.warning(msg.format(revent_file_name))
|
||||
return
|
||||
msg = 'Pulling \'{}\' from device'
|
||||
self.logger.info(msg.format(self.target.path.basename(revent_file)))
|
||||
self.target.pull(revent_file, output_path, as_root=self.target.is_rooted)
|
||||
|
||||
def manual_record(self, args):
|
||||
output_path, file_name = self._split_revent_location(args.output)
|
||||
revent_file = self.target.get_workpath(file_name)
|
||||
self.record(revent_file, '', output_path)
|
||||
msg = 'Recording is available at: \'{}\''
|
||||
self.logger.info(msg.format(os.path.join(output_path, file_name)))
|
||||
|
||||
def package_record(self, args):
|
||||
if args.clear:
|
||||
self.target.execute('pm clear {}'.format(args.package))
|
||||
self.logger.info('Starting {}'.format(args.package))
|
||||
cmd = 'monkey -p {} -c android.intent.category.LAUNCHER 1'
|
||||
self.target.execute(cmd.format(args.package))
|
||||
|
||||
output_path, file_name = self._split_revent_location(args.output)
|
||||
revent_file = self.target.get_workpath(file_name)
|
||||
self.record(revent_file, '', output_path)
|
||||
msg = 'Recording is available at: \'{}\''
|
||||
self.logger.info(msg.format(os.path.join(output_path, file_name)))
|
||||
|
||||
def workload_record(self, args):
|
||||
context = LightContext(self.tm)
|
||||
setup_revent = '{}.setup.revent'.format(self.target.model)
|
||||
run_revent = '{}.run.revent'.format(self.target.model)
|
||||
extract_results_revent = '{}.extract_results.revent'.format(self.target.model)
|
||||
teardown_file_revent = '{}.teardown.revent'.format(self.target.model)
|
||||
setup_file = self.target.get_workpath(setup_revent)
|
||||
run_file = self.target.get_workpath(run_revent)
|
||||
extract_results_file = self.target.get_workpath(extract_results_revent)
|
||||
teardown_file = self.target.get_workpath(teardown_file_revent)
|
||||
|
||||
self.logger.info('Deploying {}'.format(args.workload))
|
||||
workload = pluginloader.get_workload(args.workload, self.target)
|
||||
workload.apk.init_resources(context.resolver)
|
||||
workload.apk.setup(context)
|
||||
sleep(workload.loading_time)
|
||||
|
||||
output_path = os.path.join(workload.dependencies_directory,
|
||||
'revent_files')
|
||||
if args.setup or args.all:
|
||||
self.record(setup_file, 'SETUP', output_path)
|
||||
self.record(run_file, 'RUN', output_path)
|
||||
if args.extract_results or args.all:
|
||||
self.record(extract_results_file, 'EXTRACT_RESULTS', output_path)
|
||||
if args.teardown or args.all:
|
||||
self.record(teardown_file, 'TEARDOWN', output_path)
|
||||
self.logger.info('Tearing down {}'.format(args.workload))
|
||||
workload.teardown(context)
|
||||
self.logger.info('Recording(s) are available at: \'{}\''.format(output_path))
|
||||
|
||||
def _split_revent_location(self, output):
|
||||
output_path = None
|
||||
file_name = None
|
||||
if output:
|
||||
output_path, file_name, = os.path.split(output)
|
||||
|
||||
if not file_name:
|
||||
file_name = '{}.revent'.format(self.target.model)
|
||||
if not output_path:
|
||||
output_path = os.getcwdu()
|
||||
|
||||
return output_path, file_name
|
||||
|
||||
class ReplayCommand(Command):
|
||||
|
||||
name = 'replay'
|
||||
description = '''
|
||||
Replay a revent recording
|
||||
|
||||
Revent allows you to record raw inputs such as screen swipes or button presses.
|
||||
See ``wa show record`` to see how to make an revent recording.
|
||||
'''
|
||||
|
||||
def initialize(self, context):
|
||||
self.parser.add_argument('recording', help='The name of the file to replay',
|
||||
metavar='FILE')
|
||||
self.parser.add_argument('-d', '--device', help='The name of the device')
|
||||
self.parser.add_argument('-p', '--package', help='Package to launch before recording')
|
||||
self.parser.add_argument('-C', '--clear', help='Clear app cache before launching it',
|
||||
action="store_true")
|
||||
|
||||
# pylint: disable=W0201
|
||||
def execute(self, state, args):
|
||||
if args.device:
|
||||
device = args.device
|
||||
device_config = {}
|
||||
else:
|
||||
device = state.run_config.device
|
||||
device_config = state.run_config.device_config or {}
|
||||
|
||||
target_manager = TargetManager(device, device_config)
|
||||
self.target = target_manager.target
|
||||
revent_file = self.target.path.join(self.target.working_directory,
|
||||
os.path.split(args.revent)[1])
|
||||
|
||||
self.logger.info("Pushing file to target")
|
||||
self.target.push(args.revent, self.target.working_directory)
|
||||
|
||||
revent_recorder = ReventRecorder(target_manager.target)
|
||||
revent_recorder.deploy()
|
||||
|
||||
if args.clear:
|
||||
self.target.execute('pm clear {}'.format(args.package))
|
||||
|
||||
if args.package:
|
||||
self.logger.info('Starting {}'.format(args.package))
|
||||
cmd = 'monkey -p {} -c android.intent.category.LAUNCHER 1'
|
||||
self.target.execute(cmd.format(args.package))
|
||||
|
||||
self.logger.info("Starting replay")
|
||||
revent_recorder.replay(revent_file)
|
||||
self.logger.info("Finished replay")
|
||||
revent_recorder.remove()
|
||||
|
||||
|
||||
def get_revent_binary(abi):
|
||||
resolver = ResourceResolver()
|
||||
resource = Executable(NO_ONE, abi, 'revent')
|
||||
return resolver.get(resource)
|
||||
|
||||
|
||||
class ReventRecorder(object):
|
||||
|
||||
def __init__(self, target):
|
||||
self.target = target
|
||||
self.executable = None
|
||||
self.deploy()
|
||||
|
||||
def deploy(self):
|
||||
host_executable = get_revent_binary(self.target.abi)
|
||||
self.executable = self.target.install(host_executable)
|
||||
|
||||
def record(self, path):
|
||||
name = os.path.basename(path)
|
||||
target_path = self.target.get_workpath(name)
|
||||
command = '{} record {}'
|
||||
|
||||
def remove(self):
|
||||
if self.executable:
|
||||
self.target.uninstall('revent')
|
||||
# Used to satisfy the workload API
|
||||
class LightContext(object):
|
||||
def __init__(self, tm):
|
||||
self.tm = tm
|
||||
self.resolver = ResourceResolver()
|
||||
self.resolver.load()
|
||||
|
@ -12,8 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
from wlauto.core.configuration.configuration import (settings,
|
||||
RunConfiguration,
|
||||
JobGenerator,
|
||||
ConfigurationPoint)
|
||||
from wlauto.core.configuration.plugin_cache import PluginCache
|
||||
from wa.framework.configuration.core import (settings,
|
||||
RunConfiguration,
|
||||
JobGenerator,
|
||||
ConfigurationPoint)
|
||||
|
@ -1,7 +1,7 @@
|
||||
from wlauto.core.configuration.configuration import MetaConfiguration, RunConfiguration
|
||||
from wlauto.core.configuration.plugin_cache import PluginCache
|
||||
from wlauto.utils.serializer import yaml
|
||||
from wlauto.utils.doc import strip_inlined_text
|
||||
from wa.framework.configuration.core import MetaConfiguration, RunConfiguration
|
||||
from wa.framework.configuration.plugin_cache import PluginCache
|
||||
from wa.utils.serializer import yaml
|
||||
from wa.utils.doc import strip_inlined_text
|
||||
|
||||
DEFAULT_INSTRUMENTS = ['execution_time',
|
||||
'interrupts',
|
||||
|
@ -209,7 +209,7 @@ class Executor(object):
|
||||
"""
|
||||
The ``Executor``'s job is to set up the execution context and pass to a
|
||||
``Runner`` along with a loaded run specification. Once the ``Runner`` has
|
||||
done its thing, the ``Executor`` performs some final reporint before
|
||||
done its thing, the ``Executor`` performs some final reporting before
|
||||
returning.
|
||||
|
||||
The initial context set up involves combining configuration from various
|
||||
@ -225,7 +225,7 @@ class Executor(object):
|
||||
self.error_logged = False
|
||||
self.warning_logged = False
|
||||
pluginloader = None
|
||||
self.device_manager = None
|
||||
self.target_manager = None
|
||||
self.device = None
|
||||
|
||||
def execute(self, config_manager, output):
|
||||
@ -249,12 +249,12 @@ class Executor(object):
|
||||
output.write_config(config)
|
||||
|
||||
self.logger.info('Connecting to target')
|
||||
target_manager = TargetManager(config.run_config.device,
|
||||
self.target_manager = TargetManager(config.run_config.device,
|
||||
config.run_config.device_config)
|
||||
output.write_target_info(target_manager.get_target_info())
|
||||
output.write_target_info(self.target_manager.get_target_info())
|
||||
|
||||
self.logger.info('Initializing execution conetext')
|
||||
context = ExecutionContext(config_manager, target_manager, output)
|
||||
context = ExecutionContext(config_manager, self.target_manager, output)
|
||||
|
||||
self.logger.info('Generating jobs')
|
||||
config_manager.generate_jobs(context)
|
||||
@ -262,7 +262,7 @@ class Executor(object):
|
||||
output.write_state()
|
||||
|
||||
self.logger.info('Installing instrumentation')
|
||||
for instrument in config_manager.get_instruments(target_manager.target):
|
||||
for instrument in config_manager.get_instruments(self.target_manager.target):
|
||||
instrumentation.install(instrument)
|
||||
instrumentation.validate()
|
||||
|
||||
@ -361,6 +361,10 @@ class Runner(object):
|
||||
self.pm.process_run_output(self.context)
|
||||
self.pm.export_run_output(self.context)
|
||||
self.pm.finalize()
|
||||
log.indent()
|
||||
for job in self.context.completed_jobs:
|
||||
job.finalize(self.context)
|
||||
log.dedent()
|
||||
|
||||
def run_next_job(self, context):
|
||||
job = context.start_job()
|
||||
|
@ -31,7 +31,7 @@ import requests
|
||||
|
||||
from devlib.utils.android import ApkInfo
|
||||
|
||||
from wa import Parameter, settings, __file__ as __base_filepath
|
||||
from wa import Parameter, settings, __file__ as _base_filepath
|
||||
from wa.framework.resource import ResourceGetter, SourcePriority, NO_ONE
|
||||
from wa.framework.exception import ResourceError
|
||||
from wa.utils.misc import (ensure_directory_exists as _d,
|
||||
@ -80,7 +80,16 @@ def get_from_location(basepath, resource):
|
||||
path = os.path.join(basepath, 'bin', resource.abi, resource.filename)
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
elif resource.kind in ['apk', 'jar', 'revent']:
|
||||
elif resource.kind == 'revent':
|
||||
path = os.path.join(basepath, 'revent_files')
|
||||
if os.path.exists(path):
|
||||
files = get_by_extension(path, resource.kind)
|
||||
found_resource = get_generic_resource(resource, files)
|
||||
if found_resource:
|
||||
return found_resource
|
||||
files = get_by_extension(basepath, resource.kind)
|
||||
return get_generic_resource(resource, files)
|
||||
elif resource.kind in ['apk', 'jar']:
|
||||
files = get_by_extension(basepath, resource.kind)
|
||||
return get_generic_resource(resource, files)
|
||||
|
||||
@ -96,7 +105,7 @@ class Package(ResourceGetter):
|
||||
|
||||
def get(self, resource):
|
||||
if resource.owner == NO_ONE:
|
||||
basepath = os.path.join(os.path.dirname(__base_filepath), 'assets')
|
||||
basepath = os.path.join(os.path.dirname(_base_filepath), 'assets')
|
||||
else:
|
||||
modname = resource.owner.__module__
|
||||
basepath = os.path.dirname(sys.modules[modname].__file__)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import os
|
||||
|
||||
from wlauto.core.configuration import settings
|
||||
from wa.framework.configuration.core import settings
|
||||
|
||||
def init_user_directory(overwrite_existing=False): # pylint: disable=R0914
|
||||
"""
|
||||
|
@ -26,7 +26,7 @@ from itertools import chain
|
||||
from copy import copy
|
||||
|
||||
from wa.framework.configuration.core import settings, ConfigurationPoint as Parameter
|
||||
from wa.framework.exception import (NotFoundError, PluginLoaderError,
|
||||
from wa.framework.exception import (NotFoundError, PluginLoaderError, TargetError,
|
||||
ValidationError, ConfigError, HostError)
|
||||
from wa.utils import log
|
||||
from wa.utils.misc import (ensure_directory_exists as _d, walk_modules, load_class,
|
||||
@ -430,7 +430,7 @@ class Plugin(object):
|
||||
|
||||
get_module(name, owner, **kwargs)
|
||||
|
||||
and returns an instance of :class:`wlauto.core.plugin.Module`. If the
|
||||
and returns an instance of :class:`wa.core.plugin.Module`. If the
|
||||
module with the specified name is not found, the loader must raise an
|
||||
appropriate exception.
|
||||
|
||||
@ -743,10 +743,10 @@ class PluginLoader(object):
|
||||
self.logger.warning('Got: {}'.format(e))
|
||||
else:
|
||||
msg = 'Failed to load {}'
|
||||
raise LoaderError(msg.format(filepath), sys.exc_info())
|
||||
raise PluginLoaderError(msg.format(filepath), sys.exc_info())
|
||||
except Exception as e:
|
||||
message = 'Problem loading plugins from {}: {}'
|
||||
raise LoaderError(message.format(filepath, e))
|
||||
raise PluginLoaderError(message.format(filepath, e))
|
||||
|
||||
def _discover_in_module(self, module): # NOQA pylint: disable=too-many-branches
|
||||
self.logger.debug('Checking module %s', module.__name__)
|
||||
|
@ -231,7 +231,7 @@ def connect(handler, signal, sender=dispatcher.Any, priority=0):
|
||||
|
||||
.. note:: There is nothing that prevents instrumentation from sending their
|
||||
own signals that are not part of the standard set. However the signal
|
||||
must always be an :class:`wlauto.core.signal.Signal` instance.
|
||||
must always be an :class:`wa.core.signal.Signal` instance.
|
||||
|
||||
:sender: The handler will be invoked only for the signals emitted by this sender. By
|
||||
default, this is set to :class:`louie.dispatcher.Any`, so the handler will
|
||||
@ -270,7 +270,7 @@ def disconnect(handler, signal, sender=dispatcher.Any):
|
||||
|
||||
:handler: The callback to be disconnected.
|
||||
:signal: The signal the handler is to be disconnected form. It will
|
||||
be an :class:`wlauto.core.signal.Signal` instance.
|
||||
be an :class:`wa.core.signal.Signal` instance.
|
||||
:sender: If specified, the handler will only be disconnected from the signal
|
||||
sent by this sender.
|
||||
|
||||
@ -284,7 +284,7 @@ def send(signal, sender=dispatcher.Anonymous, *args, **kwargs):
|
||||
|
||||
Paramters:
|
||||
|
||||
:signal: Signal to be sent. This must be an instance of :class:`wlauto.core.signal.Signal`
|
||||
:signal: Signal to be sent. This must be an instance of :class:`wa.core.signal.Signal`
|
||||
or its subclasses.
|
||||
:sender: The sender of the signal (typically, this would be ``self``). Some handlers may only
|
||||
be subscribed to signals from a particular sender.
|
||||
|
@ -33,6 +33,11 @@ def instantiate_target(tdesc, params, connect=None):
|
||||
|
||||
tp, pp, cp = {}, {}, {}
|
||||
|
||||
for supported_params, new_params in (target_params, tp), (platform_params, pp), (conn_params, cp):
|
||||
for name, value in supported_params.iteritems():
|
||||
if value.default:
|
||||
new_params[name] = value.default
|
||||
|
||||
for name, value in params.iteritems():
|
||||
if name in target_params:
|
||||
tp[name] = value
|
||||
@ -62,6 +67,8 @@ def instantiate_assistant(tdesc, params, target):
|
||||
for param in tdesc.assistant_params:
|
||||
if param.name in params:
|
||||
assistant_params[param.name] = params[param.name]
|
||||
elif param.default:
|
||||
assistant_params[param.name] = param.default
|
||||
return tdesc.assistant(target, **assistant_params)
|
||||
|
||||
|
||||
|
@ -17,8 +17,11 @@ import os
|
||||
import time
|
||||
|
||||
from wa.framework.plugin import TargetedPlugin
|
||||
from wa.framework.resource import ApkFile, JarFile, ReventFile, NO_ONE
|
||||
from wa.framework.resource import (ApkFile, JarFile, ReventFile, NO_ONE,
|
||||
Executable, File)
|
||||
from wa.framework.exception import WorkloadError
|
||||
from wa.utils.revent import ReventRecorder
|
||||
from wa.utils.exec_control import once
|
||||
|
||||
from devlib.utils.android import ApkInfo
|
||||
|
||||
@ -64,7 +67,7 @@ class Workload(TargetedPlugin):
|
||||
def run(self, context):
|
||||
"""
|
||||
Execute the workload. This is the method that performs the actual
|
||||
"work" of the.
|
||||
"work" of the workload.
|
||||
"""
|
||||
pass
|
||||
|
||||
@ -93,25 +96,29 @@ class Workload(TargetedPlugin):
|
||||
return '<Workload {}>'.format(self.name)
|
||||
|
||||
|
||||
class ApkUiautoWorkload(Workload):
|
||||
|
||||
platform = 'android'
|
||||
class ApkUIWorkload(Workload):
|
||||
|
||||
# May be optionally overwritten by subclasses
|
||||
# Times are in seconds
|
||||
loading_time = 10
|
||||
|
||||
def __init__(self, target, **kwargs):
|
||||
super(ApkUiautoWorkload, self).__init__(target, **kwargs)
|
||||
self.apk = ApkHander(self)
|
||||
self.gui = UiAutomatorGUI(self)
|
||||
super(ApkUIWorkload, self).__init__(target, **kwargs)
|
||||
self.apk = None
|
||||
self.gui = None
|
||||
|
||||
def init_resources(self, context):
|
||||
self.apk.init_resources(context.resolver)
|
||||
self.gui.init_resources(context.resolver)
|
||||
self.gui.init_commands()
|
||||
|
||||
@once
|
||||
def initialize(self, context):
|
||||
self.gui.deploy()
|
||||
|
||||
def setup(self, context):
|
||||
self.apk.setup(context)
|
||||
time.sleep(self.loading_time)
|
||||
self.gui.setup()
|
||||
|
||||
def run(self, context):
|
||||
@ -124,10 +131,40 @@ class ApkUiautoWorkload(Workload):
|
||||
self.gui.teardown()
|
||||
self.apk.teardown()
|
||||
|
||||
@once
|
||||
def finalize(self, context):
|
||||
self.gui.remove()
|
||||
|
||||
|
||||
class ApkUiautoWorkload(ApkUIWorkload):
|
||||
|
||||
platform = 'android'
|
||||
|
||||
def __init__(self, target, **kwargs):
|
||||
super(ApkUiautoWorkload, self).__init__(target, **kwargs)
|
||||
self.apk = ApkHander(self)
|
||||
self.gui = UiAutomatorGUI(self)
|
||||
|
||||
|
||||
class ReventWorkload(ApkUIWorkload):
|
||||
|
||||
# May be optionally overwritten by subclasses
|
||||
# Times are in seconds
|
||||
setup_timeout = 5 * 60
|
||||
run_timeout = 10 * 60
|
||||
extract_results_timeout = 5 * 60
|
||||
teardown_timeout = 5 * 60
|
||||
|
||||
def __init__(self, target, **kwargs):
|
||||
super(ReventWorkload, self).__init__(target, **kwargs)
|
||||
self.apk = ApkHander(self)
|
||||
self.gui = ReventGUI(self, target,
|
||||
self.setup_timeout,
|
||||
self.run_timeout,
|
||||
self.extract_results_timeout,
|
||||
self.teardown_timeout)
|
||||
|
||||
|
||||
class UiAutomatorGUI(object):
|
||||
|
||||
stages = ['setup', 'runWorkload', 'extractResults', 'teardown']
|
||||
@ -208,57 +245,92 @@ class UiAutomatorGUI(object):
|
||||
|
||||
class ReventGUI(object):
|
||||
|
||||
def __init__(self, workload, target, setup_timeout=5 * 60, run_timeout=10 * 60):
|
||||
def __init__(self, workload, target, setup_timeout, run_timeout,
|
||||
extract_results_timeout, teardown_timeout):
|
||||
self.workload = workload
|
||||
self.target = target
|
||||
self.setup_timeout = setup_timeout
|
||||
self.run_timeout = run_timeout
|
||||
self.extract_results_timeout = extract_results_timeout
|
||||
self.teardown_timeout = teardown_timeout
|
||||
self.revent_recorder = ReventRecorder(self.target)
|
||||
self.on_target_revent_binary = self.target.get_workpath('revent')
|
||||
self.on_target_setup_revent = self.target.get_workpath('{}.setup.revent'.format(self.target.name))
|
||||
self.on_target_run_revent = self.target.get_workpath('{}.run.revent'.format(self.target.name))
|
||||
self.on_target_setup_revent = self.target.get_workpath('{}.setup.revent'.format(self.target.model))
|
||||
self.on_target_run_revent = self.target.get_workpath('{}.run.revent'.format(self.target.model))
|
||||
self.on_target_extract_results_revent = self.target.get_workpath('{}.extract_results.revent'.format(self.target.model))
|
||||
self.on_target_teardown_revent = self.target.get_workpath('{}.teardown.revent'.format(self.target.model))
|
||||
self.logger = logging.getLogger('revent')
|
||||
self.revent_setup_file = None
|
||||
self.revent_run_file = None
|
||||
self.revent_extract_results_file = None
|
||||
self.revent_teardown_file = None
|
||||
|
||||
def init_resources(self, context):
|
||||
self.revent_setup_file = context.resolver.get(ReventFile(self.workload, 'setup'))
|
||||
self.revent_run_file = context.resolver.get(ReventFile(self.workload, 'run'))
|
||||
def init_resources(self, resolver):
|
||||
self.revent_setup_file = resolver.get(ReventFile(owner=self.workload,
|
||||
stage='setup',
|
||||
target=self.target.model),
|
||||
strict=False)
|
||||
self.revent_run_file = resolver.get(ReventFile(owner=self.workload,
|
||||
stage='run',
|
||||
target=self.target.model))
|
||||
self.revent_extract_results_file = resolver.get(ReventFile(owner=self.workload,
|
||||
stage='extract_results',
|
||||
target=self.target.model),
|
||||
strict=False)
|
||||
self.revent_teardown_file = resolver.get(resource=ReventFile(owner=self.workload,
|
||||
stage='teardown',
|
||||
target=self.target.model),
|
||||
strict=False)
|
||||
|
||||
def setup(self, context):
|
||||
self._check_revent_files(context)
|
||||
self.target.killall('revent')
|
||||
command = '{} replay {}'.format(self.on_target_revent_binary, self.on_target_setup_revent)
|
||||
self.target.execute(command, timeout=self.setup_timeout)
|
||||
def deploy(self):
|
||||
self.revent_recorder.deploy()
|
||||
|
||||
def run(self, context):
|
||||
command = '{} replay {}'.format(self.on_target_revent_binary, self.on_target_run_revent)
|
||||
self.logger.debug('Replaying {}'.format(os.path.basename(self.on_target_run_revent)))
|
||||
self.target.execute(command, timeout=self.run_timeout)
|
||||
def setup(self):
|
||||
self._check_revent_files()
|
||||
self.revent_recorder.replay(self.on_target_setup_revent,
|
||||
timeout=self.setup_timeout)
|
||||
|
||||
def run(self):
|
||||
msg = 'Replaying {}'
|
||||
self.logger.debug(msg.format(os.path.basename(self.on_target_run_revent)))
|
||||
self.revent_recorder.replay(self.on_target_run_revent,
|
||||
timeout=self.run_timeout)
|
||||
self.logger.debug('Replay completed.')
|
||||
|
||||
def teardown(self, context):
|
||||
def extract_results(self):
|
||||
if self.revent_extract_results_file:
|
||||
self.revent_recorder.replay(self.on_target_extract_results_revent,
|
||||
timeout=self.extract_results_timeout)
|
||||
|
||||
def teardown(self):
|
||||
if self.revent_teardown_file:
|
||||
self.revent_recorder.replay(self.on_target_teardown_revent,
|
||||
timeout=self.teardown_timeout)
|
||||
self.target.remove(self.on_target_setup_revent)
|
||||
self.target.remove(self.on_target_run_revent)
|
||||
self.target.remove(self.on_target_extract_results_revent)
|
||||
self.target.remove(self.on_target_teardown_revent)
|
||||
|
||||
def _check_revent_files(self, context):
|
||||
# check the revent binary
|
||||
revent_binary = context.resolver.get(Executable(NO_ONE, self.target.abi, 'revent'))
|
||||
if not os.path.isfile(revent_binary):
|
||||
message = '{} does not exist. '.format(revent_binary)
|
||||
message += 'Please build revent for your system and place it in that location'
|
||||
raise WorkloadError(message)
|
||||
if not self.revent_setup_file:
|
||||
# pylint: disable=too-few-format-args
|
||||
message = '{0}.setup.revent file does not exist, Please provide one for your target, {0}'
|
||||
raise WorkloadError(message.format(self.target.name))
|
||||
def remove(self):
|
||||
self.revent_recorder.remove()
|
||||
|
||||
def init_commands(self):
|
||||
pass
|
||||
|
||||
def _check_revent_files(self):
|
||||
if not self.revent_run_file:
|
||||
# pylint: disable=too-few-format-args
|
||||
message = '{0}.run.revent file does not exist, Please provide one for your target, {0}'
|
||||
raise WorkloadError(message.format(self.target.name))
|
||||
message = '{0}.run.revent file does not exist, ' \
|
||||
'Please provide one for your target, {0}'
|
||||
raise WorkloadError(message.format(self.target.model))
|
||||
|
||||
self.on_target_revent_binary = self.target.install(revent_binary)
|
||||
self.target.push(self.revent_run_file, self.on_target_run_revent)
|
||||
self.target.push(self.revent_setup_file, self.on_target_setup_revent)
|
||||
if self.revent_setup_file:
|
||||
self.target.push(self.revent_setup_file, self.on_target_setup_revent)
|
||||
if self.revent_extract_results_file:
|
||||
self.target.push(self.revent_extract_results_file, self.on_target_extract_results_revent)
|
||||
if self.revent_teardown_file:
|
||||
self.target.push(self.revent_teardown_file, self.on_target_teardown_revent)
|
||||
|
||||
|
||||
class ApkHander(object):
|
||||
@ -280,10 +352,10 @@ class ApkHander(object):
|
||||
self.logcat_log = None
|
||||
|
||||
def init_resources(self, resolver):
|
||||
self.apk_file = resolver.get(ApkFile(self.owner,
|
||||
self.apk_file = resolver.get(ApkFile(self.owner,
|
||||
variant=self.variant,
|
||||
version=self.version),
|
||||
strict=self.strict)
|
||||
version=self.version),
|
||||
strict=self.strict)
|
||||
self.apk_info = ApkInfo(self.apk_file)
|
||||
|
||||
def setup(self, context):
|
||||
@ -332,7 +404,7 @@ class ApkHander(object):
|
||||
|
||||
def start_activity(self):
|
||||
cmd = 'am start -W -n {}/{}'
|
||||
output = self.target.execute(cmd.format(self.apk_info.package,
|
||||
output = self.target.execute(cmd.format(self.apk_info.package,
|
||||
self.apk_info.activity))
|
||||
if 'Error:' in output:
|
||||
# this will dismiss any error dialogs
|
||||
|
@ -22,7 +22,7 @@ from unittest import TestCase
|
||||
|
||||
from nose.tools import assert_equal
|
||||
|
||||
from wlauto.instrumentation.misc import _diff_interrupt_files
|
||||
from wa.instrumentation.misc import _diff_interrupt_files
|
||||
|
||||
|
||||
class InterruptDiffTest(TestCase):
|
||||
|
269
wa/tests/test_exec_control.py
Normal file
269
wa/tests/test_exec_control.py
Normal file
@ -0,0 +1,269 @@
|
||||
# Copyright 2013-2015 ARM Limited
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
|
||||
# pylint: disable=W0231,W0613,E0611,W0603,R0201
|
||||
from unittest import TestCase
|
||||
|
||||
from nose.tools import assert_equal, assert_raises
|
||||
|
||||
from wlauto.utils.exec_control import (init_environment, reset_environment,
|
||||
activate_environment, once,
|
||||
once_per_class, once_per_instance)
|
||||
|
||||
class TestClass(object):
|
||||
|
||||
def __init__(self):
|
||||
self.count = 0
|
||||
|
||||
@once
|
||||
def initilize_once(self):
|
||||
self.count += 1
|
||||
|
||||
@once_per_class
|
||||
def initilize_once_per_class(self):
|
||||
self.count += 1
|
||||
|
||||
@once_per_instance
|
||||
def initilize_once_per_instance(self):
|
||||
self.count += 1
|
||||
|
||||
|
||||
class SubClass(TestClass):
|
||||
|
||||
def __init__(self):
|
||||
super(SubClass, self).__init__()
|
||||
|
||||
|
||||
class SubSubClass(SubClass):
|
||||
|
||||
def __init__(self):
|
||||
super(SubSubClass, self).__init__()
|
||||
|
||||
|
||||
class AnotherClass(object):
|
||||
|
||||
def __init__(self):
|
||||
self.count = 0
|
||||
|
||||
@once
|
||||
def initilize_once(self):
|
||||
self.count += 1
|
||||
|
||||
@once_per_class
|
||||
def initilize_once_per_class(self):
|
||||
self.count += 1
|
||||
|
||||
@once_per_instance
|
||||
def initilize_once_per_instance(self):
|
||||
self.count += 1
|
||||
|
||||
|
||||
class EnvironmentManagementTest(TestCase):
|
||||
|
||||
def test_duplicate_environment(self):
|
||||
init_environment('ENVIRONMENT')
|
||||
assert_raises(ValueError, init_environment, 'ENVIRONMENT')
|
||||
|
||||
def test_reset_missing_environment(self):
|
||||
assert_raises(ValueError, reset_environment, 'MISSING')
|
||||
|
||||
def test_reset_current_environment(self):
|
||||
activate_environment('CURRENT_ENVIRONMENT')
|
||||
t1 = TestClass()
|
||||
t1.initilize_once()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
reset_environment()
|
||||
t1.initilize_once()
|
||||
assert_equal(t1.count, 2)
|
||||
|
||||
def test_switch_environment(self):
|
||||
activate_environment('ENVIRONMENT1')
|
||||
t1 = TestClass()
|
||||
t1.initilize_once()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
activate_environment('ENVIRONMENT2')
|
||||
t1.initilize_once()
|
||||
assert_equal(t1.count, 2)
|
||||
|
||||
activate_environment('ENVIRONMENT1')
|
||||
t1.initilize_once()
|
||||
assert_equal(t1.count, 2)
|
||||
|
||||
def test_reset_environment_name(self):
|
||||
activate_environment('ENVIRONMENT')
|
||||
t1 = TestClass()
|
||||
t1.initilize_once()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
reset_environment('ENVIRONMENT')
|
||||
t1.initilize_once()
|
||||
assert_equal(t1.count, 2)
|
||||
|
||||
|
||||
class OnlyOnceEnvironmentTest(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
activate_environment('TEST_ENVIRONMENT')
|
||||
|
||||
def tearDown(self):
|
||||
reset_environment('TEST_ENVIRONMENT')
|
||||
|
||||
def test_single_instance(self):
|
||||
t1 = TestClass()
|
||||
ac = AnotherClass()
|
||||
|
||||
t1.initilize_once()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
t1.initilize_once()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
ac.initilize_once()
|
||||
assert_equal(ac.count, 1)
|
||||
|
||||
|
||||
def test_mulitple_instances(self):
|
||||
t1 = TestClass()
|
||||
t2 = TestClass()
|
||||
|
||||
t1.initilize_once()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
t2.initilize_once()
|
||||
assert_equal(t2.count, 0)
|
||||
|
||||
|
||||
def test_sub_classes(self):
|
||||
t1 = TestClass()
|
||||
sc = SubClass()
|
||||
ss = SubSubClass()
|
||||
|
||||
t1.initilize_once()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
sc.initilize_once()
|
||||
sc.initilize_once()
|
||||
assert_equal(sc.count, 0)
|
||||
|
||||
ss.initilize_once()
|
||||
ss.initilize_once()
|
||||
assert_equal(ss.count, 0)
|
||||
|
||||
|
||||
class OncePerClassEnvironmentTest(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
activate_environment('TEST_ENVIRONMENT')
|
||||
|
||||
def tearDown(self):
|
||||
reset_environment('TEST_ENVIRONMENT')
|
||||
|
||||
def test_single_instance(self):
|
||||
t1 = TestClass()
|
||||
ac = AnotherClass()
|
||||
|
||||
t1.initilize_once_per_class()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
t1.initilize_once_per_class()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
ac.initilize_once_per_class()
|
||||
assert_equal(ac.count, 1)
|
||||
|
||||
|
||||
def test_mulitple_instances(self):
|
||||
t1 = TestClass()
|
||||
t2 = TestClass()
|
||||
|
||||
t1.initilize_once_per_class()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
t2.initilize_once_per_class()
|
||||
assert_equal(t2.count, 0)
|
||||
|
||||
|
||||
def test_sub_classes(self):
|
||||
t1 = TestClass()
|
||||
sc1 = SubClass()
|
||||
sc2 = SubClass()
|
||||
ss1 = SubSubClass()
|
||||
ss2 = SubSubClass()
|
||||
|
||||
t1.initilize_once_per_class()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
sc1.initilize_once_per_class()
|
||||
sc2.initilize_once_per_class()
|
||||
assert_equal(sc1.count, 1)
|
||||
assert_equal(sc2.count, 0)
|
||||
|
||||
ss1.initilize_once_per_class()
|
||||
ss2.initilize_once_per_class()
|
||||
assert_equal(ss1.count, 1)
|
||||
assert_equal(ss2.count, 0)
|
||||
|
||||
|
||||
class OncePerInstanceEnvironmentTest(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
activate_environment('TEST_ENVIRONMENT')
|
||||
|
||||
def tearDown(self):
|
||||
reset_environment('TEST_ENVIRONMENT')
|
||||
|
||||
def test_single_instance(self):
|
||||
t1 = TestClass()
|
||||
ac = AnotherClass()
|
||||
|
||||
t1.initilize_once_per_instance()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
t1.initilize_once_per_instance()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
ac.initilize_once_per_instance()
|
||||
assert_equal(ac.count, 1)
|
||||
|
||||
|
||||
def test_mulitple_instances(self):
|
||||
t1 = TestClass()
|
||||
t2 = TestClass()
|
||||
|
||||
t1.initilize_once_per_instance()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
t2.initilize_once_per_instance()
|
||||
assert_equal(t2.count, 1)
|
||||
|
||||
|
||||
def test_sub_classes(self):
|
||||
t1 = TestClass()
|
||||
sc = SubClass()
|
||||
ss = SubSubClass()
|
||||
|
||||
t1.initilize_once_per_instance()
|
||||
assert_equal(t1.count, 1)
|
||||
|
||||
sc.initilize_once_per_instance()
|
||||
sc.initilize_once_per_instance()
|
||||
assert_equal(sc.count, 1)
|
||||
|
||||
ss.initilize_once_per_instance()
|
||||
ss.initilize_once_per_instance()
|
||||
assert_equal(ss.count, 1)
|
110
wa/utils/exec_control.py
Normal file
110
wa/utils/exec_control.py
Normal file
@ -0,0 +1,110 @@
|
||||
from inspect import getmro
|
||||
|
||||
# "environment" management:
|
||||
__environments = {}
|
||||
__active_environment = None
|
||||
|
||||
|
||||
def activate_environment(name):
|
||||
"""
|
||||
Sets the current tracking environment to ``name``. If an
|
||||
environment with that name does not already exist, it will be
|
||||
created.
|
||||
"""
|
||||
#pylint: disable=W0603
|
||||
global __active_environment
|
||||
|
||||
if name not in __environments.keys():
|
||||
init_environment(name)
|
||||
__active_environment = name
|
||||
|
||||
def init_environment(name):
|
||||
"""
|
||||
Create a new environment called ``name``, but do not set it as the
|
||||
current environment.
|
||||
|
||||
:raises: ``ValueError`` if an environment with name ``name``
|
||||
already exists.
|
||||
"""
|
||||
if name in __environments.keys():
|
||||
msg = "Environment {} already exists".format(name)
|
||||
raise ValueError(msg)
|
||||
__environments[name] = []
|
||||
|
||||
def reset_environment(name=None):
|
||||
"""
|
||||
Reset method call tracking for environment ``name``. If ``name`` is
|
||||
not specified or is ``None``, reset the current active environment.
|
||||
|
||||
:raises: ``ValueError`` if an environment with name ``name``
|
||||
does not exist.
|
||||
"""
|
||||
|
||||
if name is not None:
|
||||
if name not in __environments.keys():
|
||||
msg = "Environment {} does not exist".format(name)
|
||||
raise ValueError(msg)
|
||||
__environments[name] = []
|
||||
else:
|
||||
if __active_environment is None:
|
||||
activate_environment('default')
|
||||
__environments[__active_environment] = []
|
||||
|
||||
# The decorators:
|
||||
def once_per_instance(method):
|
||||
"""
|
||||
The specified method will be invoked only once for every bound
|
||||
instance within the environment.
|
||||
"""
|
||||
def wrapper(*args, **kwargs):
|
||||
if __active_environment is None:
|
||||
activate_environment('default')
|
||||
func_id = repr(args[0])
|
||||
if func_id in __environments[__active_environment]:
|
||||
return
|
||||
else:
|
||||
__environments[__active_environment].append(func_id)
|
||||
return method(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
def once_per_class(method):
|
||||
"""
|
||||
The specified method will be invoked only once for all instances
|
||||
of a class within the environment.
|
||||
"""
|
||||
def wrapper(*args, **kwargs):
|
||||
if __active_environment is None:
|
||||
activate_environment('default')
|
||||
|
||||
func_id = repr(method.func_name) + repr(args[0].__class__)
|
||||
|
||||
if func_id in __environments[__active_environment]:
|
||||
return
|
||||
else:
|
||||
__environments[__active_environment].append(func_id)
|
||||
return method(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
def once(method):
|
||||
"""
|
||||
The specified method will be invoked only once within the
|
||||
environment.
|
||||
"""
|
||||
def wrapper(*args, **kwargs):
|
||||
if __active_environment is None:
|
||||
activate_environment('default')
|
||||
|
||||
func_id = repr(method.func_name)
|
||||
# Store the least derived class, which isn't object, to account
|
||||
# for subclasses.
|
||||
func_id += repr(getmro(args[0].__class__)[-2])
|
||||
|
||||
if func_id in __environments[__active_environment]:
|
||||
return
|
||||
else:
|
||||
__environments[__active_environment].append(func_id)
|
||||
return method(*args, **kwargs)
|
||||
|
||||
return wrapper
|
@ -54,7 +54,7 @@ from devlib.utils.misc import (ABI_MAP, check_output, walk_modules,
|
||||
check_output_logger = logging.getLogger('check_output')
|
||||
|
||||
|
||||
# Defined here rather than in wlauto.exceptions due to module load dependencies
|
||||
# Defined here rather than in wa.exceptions due to module load dependencies
|
||||
def diff_tokens(before_token, after_token):
|
||||
"""
|
||||
Creates a diff of two tokens.
|
||||
|
@ -16,9 +16,11 @@
|
||||
from __future__ import division
|
||||
import os
|
||||
import struct
|
||||
import signal
|
||||
from datetime import datetime
|
||||
from collections import namedtuple
|
||||
|
||||
from wa.framework.resource import Executable, NO_ONE, ResourceResolver
|
||||
|
||||
GENERAL_MODE = 0
|
||||
GAMEPAD_MODE = 1
|
||||
@ -249,3 +251,38 @@ class ReventRecording(object):
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
|
||||
def get_revent_binary(abi):
|
||||
resolver = ResourceResolver()
|
||||
resolver.load()
|
||||
resource = Executable(NO_ONE, abi, 'revent')
|
||||
return resolver.get(resource)
|
||||
|
||||
|
||||
class ReventRecorder(object):
|
||||
|
||||
def __init__(self, target):
|
||||
self.target = target
|
||||
self.executable = self.target.get_installed('revent')
|
||||
|
||||
def deploy(self):
|
||||
if not self.executable:
|
||||
host_executable = get_revent_binary(self.target.abi)
|
||||
self.executable = self.target.install(host_executable)
|
||||
|
||||
def remove(self):
|
||||
if self.executable:
|
||||
self.target.uninstall('revent')
|
||||
|
||||
def start_record(self, revent_file):
|
||||
command = '{} record -s {}'.format(self.executable, revent_file)
|
||||
self.target.kick_off(command, self.target.is_rooted)
|
||||
|
||||
def stop_record(self):
|
||||
self.target.killall('revent', signal.SIGINT, as_root=self.target.is_rooted)
|
||||
|
||||
def replay(self, revent_file, timeout=None):
|
||||
self.target.killall('revent')
|
||||
command = "{} replay {}".format(self.executable, revent_file)
|
||||
self.target.execute(command, timeout=timeout)
|
||||
|
27
wa/workloads/angrybirds_rio/__init__.py
Normal file
27
wa/workloads/angrybirds_rio/__init__.py
Normal file
@ -0,0 +1,27 @@
|
||||
# Copyright 2013-2015 ARM Limited
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
|
||||
from wa import ReventWorkload
|
||||
|
||||
|
||||
class AngryBirdsRio(ReventWorkload):
|
||||
|
||||
name = 'angrybirds_rio'
|
||||
description = """
|
||||
Angry Birds Rio game.
|
||||
|
||||
The sequel to the very popular Android 2D game.
|
||||
"""
|
Loading…
x
Reference in New Issue
Block a user