1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-01-31 10:11:17 +00:00

Merge pull request #458 from sdpenguin/revent_integrated

ReventWorkload becomes an Linux (not Android) workload + fixes.
This commit is contained in:
setrofim 2017-08-09 14:22:35 +01:00 committed by GitHub
commit 3f7d44de28
5 changed files with 199 additions and 106 deletions

View File

@ -74,7 +74,7 @@ class RecordCommand(ReventCommand):
name = 'record'
description = '''Performs a revent recording
This command helps making revent recordings. It will automatically
This command helps create revent recordings. It will automatically
deploy revent and even has the option of automatically opening apps.
Revent allows you to record raw inputs such as screen swipes or button presses.
@ -82,14 +82,14 @@ class RecordCommand(ReventCommand):
have XML UI layouts that can be used with UIAutomator. As a drawback from this,
revent recordings are specific to the device type they were recorded on.
WA uses two parts to the names of revent recordings in the format,
{device_name}.{suffix}.revent.
WA uses two parts to form the names of revent recordings in the format,
{device_name}.{suffix}.revent
- device_name can either be specified manually with the ``-d`` argument or
it can be automatically determined. On Android device it will be obtained
else the name of the device will be automatically determined. On an Android device it is 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
recording is for, currently either ``setup``, ``run`` or ``teardown``. This
should be specified with the ``-s`` argument.

View File

@ -16,22 +16,19 @@
import os
import sys
import time
from math import ceil
from distutils.version import LooseVersion
from wlauto.core.extension import Parameter, ExtensionMeta, ListCollection
from wlauto.core.workload import Workload
from wlauto.core.resource import NO_ONE
from wlauto.common.android.resources import ApkFile, ReventFile
from wlauto.common.resources import ExtensionAsset, Executable, File
from wlauto.common.android.resources import ApkFile
from wlauto.common.resources import ExtensionAsset, File
from wlauto.exceptions import WorkloadError, ResourceError, DeviceError
from wlauto.utils.android import (ApkInfo, ANDROID_NORMAL_PERMISSIONS,
ANDROID_UNCHANGEABLE_PERMISSIONS, UNSUPPORTED_PACKAGES)
from wlauto.utils.types import boolean, ParameterDict
from wlauto.utils.revent import ReventRecording
import wlauto.utils.statedetect as state_detector
import wlauto.common.android.resources
from wlauto.common.linux.workload import ReventWorkload
DELAY = 5
@ -481,102 +478,8 @@ class ApkWorkload(Workload):
if self.uninstall_apk:
self.device.uninstall(self.package)
AndroidBenchmark = ApkWorkload # backward compatibility
class ReventWorkload(Workload):
# pylint: disable=attribute-defined-outside-init
def __init__(self, device, _call_super=True, **kwargs):
if _call_super:
Workload.__init__(self, device, **kwargs)
devpath = self.device.path
self.on_device_revent_binary = devpath.join(self.device.binaries_directory, 'revent')
self.setup_timeout = kwargs.get('setup_timeout', None)
self.run_timeout = kwargs.get('run_timeout', None)
self.revent_setup_file = None
self.revent_run_file = None
self.on_device_setup_revent = None
self.on_device_run_revent = None
self.statedefs_dir = None
if self.check_states:
state_detector.check_match_state_dependencies()
def setup(self, context):
self.revent_setup_file = context.resolver.get(ReventFile(self, 'setup'))
self.revent_run_file = context.resolver.get(ReventFile(self, 'run'))
devpath = self.device.path
self.on_device_setup_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_setup_file)[-1])
self.on_device_run_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_run_file)[-1])
self._check_revent_files(context)
default_setup_timeout = ceil(ReventRecording(self.revent_setup_file).duration) + 30
default_run_timeout = ceil(ReventRecording(self.revent_run_file).duration) + 30
self.setup_timeout = self.setup_timeout or default_setup_timeout
self.run_timeout = self.run_timeout or default_run_timeout
Workload.setup(self, context)
self.device.killall('revent')
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_setup_revent)
self.device.execute(command, timeout=self.setup_timeout)
def run(self, context):
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_run_revent)
self.logger.debug('Replaying {}'.format(os.path.basename(self.on_device_run_revent)))
self.device.execute(command, timeout=self.run_timeout)
self.logger.debug('Replay completed.')
def update_result(self, context):
pass
def teardown(self, context):
self.device.killall('revent')
self.device.delete_file(self.on_device_setup_revent)
self.device.delete_file(self.on_device_run_revent)
def _check_revent_files(self, context):
# check the revent binary
revent_binary = context.resolver.get(Executable(NO_ONE, self.device.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 device, {0}'.format(self.device.name)
raise WorkloadError(message)
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 device, {0}'.format(self.device.name)
raise WorkloadError(message)
self.on_device_revent_binary = self.device.install_executable(revent_binary)
self.device.push_file(self.revent_run_file, self.on_device_run_revent)
self.device.push_file(self.revent_setup_file, self.on_device_setup_revent)
def _check_statedetection_files(self, context):
try:
self.statedefs_dir = context.resolver.get(File(self, 'state_definitions'))
except ResourceError:
self.logger.warning("State definitions directory not found. Disabling state detection.")
self.check_states = False
def check_state(self, context, phase):
try:
self.logger.info("\tChecking workload state...")
screenshotPath = os.path.join(context.output_directory, "screen.png")
self.device.capture_screen(screenshotPath)
stateCheck = state_detector.verify_state(screenshotPath, self.statedefs_dir, phase)
if not stateCheck:
raise WorkloadError("Unexpected state after setup")
except state_detector.StateDefinitionError as e:
msg = "State definitions or template files missing or invalid ({}). Skipping state detection."
self.logger.warning(msg.format(e.message))
class AndroidUiAutoBenchmark(UiAutomatorWorkload, AndroidBenchmark):
supported_platforms = ['android']
@ -731,6 +634,7 @@ class GameWorkload(ApkWorkload, ReventWorkload):
view = 'SurfaceView'
loading_time = 10
supported_platforms = ['android']
setup_required = True
parameters = [
Parameter('install_timeout', default=500, override=True),
@ -749,6 +653,8 @@ class GameWorkload(ApkWorkload, ReventWorkload):
def __init__(self, device, **kwargs): # pylint: disable=W0613
ApkWorkload.__init__(self, device, **kwargs)
ReventWorkload.__init__(self, device, _call_super=False, **kwargs)
if self.check_states:
state_detector.check_match_state_dependencies()
self.logcat_process = None
self.module_dir = os.path.dirname(sys.modules[self.__module__].__file__)
self.revent_dir = os.path.join(self.module_dir, 'revent_files')
@ -823,3 +729,22 @@ class GameWorkload(ApkWorkload, ReventWorkload):
self.device.busybox,
ondevice_cache)
self.device.execute(deploy_command, timeout=timeout, as_root=True)
def _check_statedetection_files(self, context):
try:
self.statedefs_dir = context.resolver.get(File(self, 'state_definitions'))
except ResourceError:
self.logger.warning("State definitions directory not found. Disabling state detection.")
self.check_states = False # pylint: disable=W0201
def check_state(self, context, phase):
try:
self.logger.info("\tChecking workload state...")
screenshotPath = os.path.join(context.output_directory, "screen.png")
self.device.capture_screen(screenshotPath)
stateCheck = state_detector.verify_state(screenshotPath, self.statedefs_dir, phase)
if not stateCheck:
raise WorkloadError("Unexpected state after setup")
except state_detector.StateDefinitionError as e:
msg = "State definitions or template files missing or invalid ({}). Skipping state detection."
self.logger.warning(msg.format(e.message))

View File

@ -590,7 +590,8 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
def get_device_model(self):
if self.file_exists("/proc/device-tree/model"):
raw_model = self.execute("cat /proc/device-tree/model")
return '_'.join(raw_model.split()[:2])
device_model_to_return = '_'.join(raw_model.split()[:2])
return device_model_to_return.rstrip(' \t\r\n\0')
# Right now we don't know any other way to get device model
# info in linux on arm platforms
return None

View File

@ -0,0 +1,165 @@
# Copyright 2017 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.
#
import os
from math import ceil
from wlauto.core.extension import Parameter
from wlauto.core.workload import Workload
from wlauto.core.resource import NO_ONE
from wlauto.common.resources import Executable
from wlauto.common.android.resources import ReventFile
from wlauto.exceptions import WorkloadError
from wlauto.utils.revent import ReventRecording
class ReventWorkload(Workload):
# pylint: disable=attribute-defined-outside-init
description = """
A workload for playing back revent recordings. You can supply three
different files:
1. {device_model}.setup.revent
2. {device_model}.run.revent
3. {device_model}.teardown.revent
You may generate these files using the wa record command using the -s flag
to specify the stage (``setup``, ``run``, ``teardown``)
You may also supply an 'idle_time' in seconds in place of the run file.
The ``run`` file may only be omitted if you choose to run this way, but
while running idle may supply ``setup`` and ``teardown`` files.
To use a ``setup`` or ``teardown`` file set the setup_required and/or
teardown_required class attributes to True (default: False).
N.B. This is the default description. You may overwrite this for your
workload to include more specific information.
"""
setup_required = False
teardown_required = False
parameters = [
Parameter(
'idle_time', kind=int, default=None,
description='''
The time you wish the device to remain idle for (if a value is
given then this overrides any .run revent file).
'''),
]
def __init__(self, device, _call_super=True, **kwargs):
if _call_super:
Workload.__init__(self, device, **kwargs)
self.setup_timeout = kwargs.get('setup_timeout', None)
self.run_timeout = kwargs.get('run_timeout', None)
self.teardown_timeout = kwargs.get('teardown_timeout', None)
self.revent_setup_file = None
self.revent_run_file = None
self.revent_teardown_file = None
self.on_device_setup_revent = None
self.on_device_run_revent = None
self.on_device_teardown_revent = None
self.statedefs_dir = None
def initialize(self, context):
devpath = self.device.path
self.on_device_revent_binary = devpath.join(self.device.binaries_directory, 'revent')
def setup(self, context):
devpath = self.device.path
if self.setup_required:
self.revent_setup_file = context.resolver.get(ReventFile(self, 'setup'))
if self.revent_setup_file:
self.on_device_setup_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_setup_file)[-1])
duration = ReventRecording(self.revent_setup_file).duration
self.default_setup_timeout = ceil(duration) + 30
if not self.idle_time:
self.revent_run_file = context.resolver.get(ReventFile(self, 'run'))
if self.revent_run_file:
self.on_device_run_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_run_file)[-1])
self.default_run_timeout = ceil(ReventRecording(self.revent_run_file).duration) + 30
if self.teardown_required:
self.revent_teardown_file = context.resolver.get(ReventFile(self, 'teardown'))
if self.revent_teardown_file:
self.on_device_teardown_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_teardown_file)[-1])
duration = ReventRecording(self.revent_teardown_file).duration
self.default_teardown_timeout = ceil(duration) + 30
self._check_revent_files(context)
Workload.setup(self, context)
if self.revent_setup_file is not None:
self.setup_timeout = self.setup_timeout or self.default_setup_timeout
self.device.killall('revent')
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_setup_revent)
self.device.execute(command, timeout=self.setup_timeout)
self.logger.debug('Revent setup completed.')
def run(self, context):
if not self.idle_time:
self.run_timeout = self.run_timeout or self.default_run_timeout
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_run_revent)
self.logger.debug('Replaying {}'.format(os.path.basename(self.on_device_run_revent)))
self.device.execute(command, timeout=self.run_timeout)
self.logger.debug('Replay completed.')
else:
self.logger.info('Idling for ' + str(self.idle_time) + ' seconds.')
self.device.sleep(self.idle_time)
self.logger.info('Successfully did nothing for ' + str(self.idle_time) + ' seconds!')
def update_result(self, context):
pass
def teardown(self, context):
if self.revent_teardown_file is not None:
self.teardown_timeout = self.teardown_timeout or self.default_teardown_timeout
command = '{} replay {}'.format(self.on_device_revent_binary,
self.on_device_teardown_revent)
self.device.execute(command, timeout=self.teardown_timeout)
self.logger.debug('Replay completed.')
self.device.killall('revent')
if self.revent_setup_file is not None:
self.device.delete_file(self.on_device_setup_revent)
if not self.idle_time:
self.device.delete_file(self.on_device_run_revent)
if self.revent_teardown_file is not None:
self.device.delete_file(self.on_device_teardown_revent)
def _check_revent_files(self, context):
# check the revent binary
revent_binary = context.resolver.get(Executable(NO_ONE, self.device.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_run_file and not self.idle_time:
# pylint: disable=too-few-format-args
message = 'It seems a {0}.run.revent file does not exist, '\
'Please provide one for your device: {0}.'
raise WorkloadError(message.format(self.device.name))
self.on_device_revent_binary = self.device.install_executable(revent_binary)
if self.revent_setup_file is not None:
self.device.push_file(self.revent_setup_file, self.on_device_setup_revent)
if not self.idle_time:
self.device.push_file(self.revent_run_file, self.on_device_run_revent)
if self.revent_teardown_file is not None:
self.device.push_file(self.revent_teardown_file, self.on_device_teardown_revent)

View File

@ -90,12 +90,14 @@ class ReventGetter(ResourceGetter):
self.resolver.register(self, 'revent', GetterPriority.package)
def get(self, resource, **kwargs):
# name format: [model/device_name.stage.revent]
device_model = resource.owner.device.get_device_model()
wa_device_name = resource.owner.device.name
for name in [device_model, wa_device_name]:
if not name:
continue
filename = '.'.join([name, resource.stage, 'revent']).lower()
self.logger.debug('Trying to get {0}.'.format(str(filename)))
location = _d(os.path.join(self.get_base_location(resource), 'revent_files'))
for candidate in os.listdir(location):
if candidate.lower() == filename.lower():