1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-07-20 05:53:29 +01:00

Check APK version and ABI when installing

- Check the APK's versionName property against the workload's
  expected version if specified
- If workload specifies check_abi param, try to get APK from
  ABI-specific path on the host
- Add variant_name param to APK resource-getter for backwards
  compatibility of dex2oat and peacekeeper
This commit is contained in:
muendelezaji
2016-06-22 19:34:04 +01:00
parent fab6a977aa
commit bb33123b17
6 changed files with 76 additions and 18 deletions
wlauto
common
resource_getters
workloads
dex2oat
peacekeeper

@@ -362,9 +362,9 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
if ext == '.apk': if ext == '.apk':
flags = [] flags = []
if replace: if replace:
flags.append('-r') # Replace existing APK flags.append('-r') # Replace existing APK
if self.get_sdk_version() >= 23: if self.get_sdk_version() >= 23:
flags.append('-g') # Grant all runtime permissions flags.append('-g') # Grant all runtime permissions
self.logger.debug("Replace APK = {}, ADB flags = '{}'".format(replace, ' '.join(flags))) self.logger.debug("Replace APK = {}, ADB flags = '{}'".format(replace, ' '.join(flags)))
return adb_command(self.adb_name, "install {} '{}'".format(' '.join(flags), filepath), timeout=timeout) return adb_command(self.adb_name, "install {} '{}'".format(' '.join(flags), filepath), timeout=timeout)
else: else:

@@ -34,3 +34,10 @@ class JarFile(FileResource):
class ApkFile(FileResource): class ApkFile(FileResource):
name = 'apk' name = 'apk'
def __init__(self, owner, platform=None):
super(ApkFile, self).__init__(owner)
self.platform = platform
def __str__(self):
return '<{}\'s {} APK>'.format(self.owner, self.platform)

@@ -20,6 +20,7 @@ import time
from wlauto.core.extension import Parameter from wlauto.core.extension import Parameter
from wlauto.core.workload import Workload from wlauto.core.workload import Workload
from wlauto.core.resource import NO_ONE from wlauto.core.resource import NO_ONE
from wlauto.common.android.resources import ApkFile
from wlauto.common.resources import ExtensionAsset, Executable from wlauto.common.resources import ExtensionAsset, Executable
from wlauto.exceptions import WorkloadError, ResourceError, ConfigError from wlauto.exceptions import WorkloadError, ResourceError, ConfigError
from wlauto.utils.android import ApkInfo, ANDROID_NORMAL_PERMISSIONS from wlauto.utils.android import ApkInfo, ANDROID_NORMAL_PERMISSIONS
@@ -160,6 +161,11 @@ class ApkWorkload(Workload):
'''), '''),
Parameter('uninstall_apk', kind=boolean, default=False, Parameter('uninstall_apk', kind=boolean, default=False,
description='If ``True``, will uninstall workload\'s APK as part of teardown.'), description='If ``True``, will uninstall workload\'s APK as part of teardown.'),
Parameter('check_abi', kind=bool, default=False,
description='''
If ``True``, workload will check that the APK matches the target
device ABI, otherwise any APK found will be used.
'''),
] ]
def __init__(self, device, _call_super=True, **kwargs): def __init__(self, device, _call_super=True, **kwargs):
@@ -169,12 +175,14 @@ class ApkWorkload(Workload):
self.apk_version = None self.apk_version = None
self.logcat_log = None self.logcat_log = None
def init_resources(self, context): def initialize(self, context):
self.apk_file = context.resolver.get(wlauto.common.android.resources.ApkFile(self), # Get APK for the correct version and device ABI
self.apk_file = context.resolver.get(ApkFile(self, self.device.abi),
version=getattr(self, 'version', None), version=getattr(self, 'version', None),
check_abi=getattr(self, 'check_abi', False),
variant_name=getattr(self, 'variant_name', None),
strict=self.check_apk) strict=self.check_apk)
# Validate the APK
def validate(self):
if self.check_apk: if self.check_apk:
if not self.apk_file: if not self.apk_file:
raise WorkloadError('No APK file found for workload {}.'.format(self.name)) raise WorkloadError('No APK file found for workload {}.'.format(self.name))
@@ -223,7 +231,7 @@ class ApkWorkload(Workload):
if installed_version: if installed_version:
self.device.uninstall(self.package) self.device.uninstall(self.package)
# It's possible that the uninstall above fails, which might result in a warning # It's possible that the uninstall above fails, which might result in a warning
# and/or failure during installation. Hower execution should proceed, so need # and/or failure during installation. However execution should proceed, so need
# to make sure that the right apk_vesion is reported in the end. # to make sure that the right apk_vesion is reported in the end.
if self.install_apk(context): if self.install_apk(context):
self.apk_version = host_version self.apk_version = host_version

@@ -30,6 +30,7 @@ import requests
from wlauto import ResourceGetter, GetterPriority, Parameter, NO_ONE, settings, __file__ as __base_filepath from wlauto import ResourceGetter, GetterPriority, Parameter, NO_ONE, settings, __file__ as __base_filepath
from wlauto.exceptions import ResourceError from wlauto.exceptions import ResourceError
from wlauto.utils.android import ApkInfo
from wlauto.utils.misc import ensure_directory_exists as _d, ensure_file_directory_exists as _f, sha256, urljoin from wlauto.utils.misc import ensure_directory_exists as _d, ensure_file_directory_exists as _f, sha256, urljoin
from wlauto.utils.types import boolean from wlauto.utils.types import boolean
@@ -61,9 +62,11 @@ class PackageFileGetter(ResourceGetter):
class EnvironmentFileGetter(ResourceGetter): class EnvironmentFileGetter(ResourceGetter):
name = 'environment_file' name = 'environment_file'
description = """Looks for exactly one file with the specified extension in the owner's directory. If a version description = """
Looks for exactly one file with the specified extension in the owner's directory. If a version
is specified on invocation of get, it will filter the discovered file based on that version. is specified on invocation of get, it will filter the discovered file based on that version.
Versions are treated as case-insensitive.""" Versions are treated as case-insensitive.
"""
extension = None extension = None
@@ -102,6 +105,22 @@ class PackageApkGetter(PackageFileGetter):
name = 'package_apk' name = 'package_apk'
extension = 'apk' extension = 'apk'
description = """
Uses the same dependency resolution mechanism as ``PackageFileGetter`` with one addition.
If an ABI is specified in the resource request, then the getter will try to locate the file in
the ABI-specific folder in the form ``<root>/apk/<abi>/<apk_name>``. Where ``root`` is the base
resource location e.g. ``~/.workload_automation/dependencies/<extension_name>`` and ``<abi>``
is the ABI for which the APK has been compiled, as returned by ``resource.platform``.
"""
def get(self, resource, **kwargs):
resource_dir = os.path.dirname(sys.modules[resource.owner.__module__].__file__)
version = kwargs.get('version')
variant = kwargs.get('variant_name')
if kwargs.get('check_abi', False):
resource_dir = os.path.join(resource_dir, self.extension, resource.platform)
return get_from_location_by_extension(resource, resource_dir, self.extension, version, variant=variant)
class PackageJarGetter(PackageFileGetter): class PackageJarGetter(PackageFileGetter):
name = 'package_jar' name = 'package_jar'
@@ -120,6 +139,22 @@ class EnvironmentApkGetter(EnvironmentFileGetter):
name = 'environment_apk' name = 'environment_apk'
extension = 'apk' extension = 'apk'
description = """
Uses the same dependency resolution mechanism as ``EnvironmentFileGetter`` with one addition.
If an ABI is specified in the resource request, then the getter will try to locate the file in
the ABI-specific folder in the form ``<root>/apk/<abi>/<apk_name>``. Where ``root`` is the base
resource location e.g. ``~/.workload_automation/dependencies/<extension_name>`` and ``<abi>``
is the ABI for which the APK has been compiled, as returned by ``resource.platform``.
"""
def get(self, resource, **kwargs):
resource_dir = resource.owner.dependencies_directory
version = kwargs.get('version')
variant = kwargs.get('variant_name')
if kwargs.get('check_abi', False):
resource_dir = os.path.join(resource_dir, self.extension, resource.platform)
return get_from_location_by_extension(resource, resource_dir, self.extension, version, variant=variant)
class EnvironmentJarGetter(EnvironmentFileGetter): class EnvironmentJarGetter(EnvironmentFileGetter):
name = 'environment_jar' name = 'environment_jar'
@@ -427,6 +462,10 @@ class RemoteFilerGetter(ResourceGetter):
if resource.owner: if resource.owner:
remote_path = os.path.join(self.remote_path, resource.owner.name) remote_path = os.path.join(self.remote_path, resource.owner.name)
local_path = os.path.join(settings.environment_root, '__filer', resource.owner.dependencies_directory) local_path = os.path.join(settings.environment_root, '__filer', resource.owner.dependencies_directory)
if resource.name == 'apk' and kwargs.get('check_abi', False):
local_path = os.path.join(local_path, 'apk', resource.platform)
message = 'resource={}, version={}, remote_path={}, local_path={}'
self.logger.debug(message.format(resource, version, remote_path, local_path))
return self.try_get_resource(resource, version, remote_path, local_path) return self.try_get_resource(resource, version, remote_path, local_path)
else: else:
result = None result = None
@@ -489,24 +528,28 @@ class RemoteFilerGetter(ResourceGetter):
# Utility functions # Utility functions
def get_from_location_by_extension(resource, location, extension, version=None): def get_from_location_by_extension(resource, location, extension, version=None, variant=None):
try: try:
found_files = [os.path.join(location, f) for f in os.listdir(location)] found_files = [os.path.join(location, f) for f in os.listdir(location)]
except OSError: except OSError:
return None return None
try: try:
return get_from_list_by_extension(resource, found_files, extension, version) return get_from_list_by_extension(resource, found_files, extension, version, variant=variant)
except ResourceError: except ResourceError:
raise ResourceError('More than one .{} found in {} for {}.'.format(extension, raise ResourceError('More than one .{} found in {} for {}.'.format(extension,
location, location,
resource.owner.name)) resource.owner.name))
def get_from_list_by_extension(resource, filelist, extension, version=None): def get_from_list_by_extension(resource, filelist, extension, version=None, variant=None):
filelist = [ff for ff in filelist filelist = [ff for ff in filelist if os.path.splitext(ff)[1].lower().endswith(extension)]
if os.path.splitext(ff)[1].lower().endswith(extension)] if variant:
filelist = [ff for ff in filelist if variant.lower() in os.path.basename(ff).lower()]
if version: if version:
filelist = [ff for ff in filelist if version.lower() in os.path.basename(ff).lower()] if extension == 'apk':
filelist = [ff for ff in filelist if version.lower() in ApkInfo(ff).version_name.lower()]
else:
filelist = [ff for ff in filelist if version.lower() in os.path.basename(ff).lower()]
if len(filelist) == 1: if len(filelist) == 1:
return filelist[0] return filelist[0]
elif not filelist: elif not filelist:

@@ -53,7 +53,8 @@ class Dex2oatBenchmark(Workload):
def init_resources(self, context): def init_resources(self, context):
# TODO: find a better APK to use for this. # TODO: find a better APK to use for this.
peacekeeper = ExtensionLoader().get_workload('peacekeeper', self.device) peacekeeper = ExtensionLoader().get_workload('peacekeeper', self.device)
self.apk_file = context.resolver.get(wlauto.common.android.resources.ApkFile(peacekeeper), version='chrome') self.apk_file = context.resolver.get(wlauto.common.android.resources.ApkFile(peacekeeper),
variant_name='chrome')
self.package = ApkInfo(self.apk_file).package self.package = ApkInfo(self.apk_file).package
def setup(self, context): def setup(self, context):
@@ -119,4 +120,3 @@ class Dex2oatBenchmark(Workload):
def teardown(self, context): def teardown(self, context):
self.device.delete_file(self.on_device_oat) self.device.delete_file(self.on_device_oat)

@@ -63,7 +63,7 @@ class Peacekeeper(AndroidUiAutoBenchmark):
def __init__(self, device, **kwargs): def __init__(self, device, **kwargs):
super(Peacekeeper, self).__init__(device, **kwargs) super(Peacekeeper, self).__init__(device, **kwargs)
self.version = self.browser self.variant_name = self.browser
def update_result(self, context): def update_result(self, context):
super(Peacekeeper, self).update_result(context) super(Peacekeeper, self).update_result(context)