1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-04-15 07:10:56 +01:00

Merge pull request #190 from jimboatarm/upstream-apk-check

Apk version check
This commit is contained in:
setrofim 2016-07-12 17:53:01 +01:00 committed by GitHub
commit 662033399f
6 changed files with 91 additions and 26 deletions

View File

@ -349,18 +349,24 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
timeout=self.default_timeout) timeout=self.default_timeout)
return bool(int(output)) return bool(int(output))
def install(self, filepath, timeout=default_timeout, with_name=None): # pylint: disable=W0221 def install(self, filepath, timeout=default_timeout, with_name=None, replace=False): # pylint: disable=W0221
ext = os.path.splitext(filepath)[1].lower() ext = os.path.splitext(filepath)[1].lower()
if ext == '.apk': if ext == '.apk':
return self.install_apk(filepath, timeout) return self.install_apk(filepath, timeout, replace)
else: else:
return self.install_executable(filepath, with_name) return self.install_executable(filepath, with_name)
def install_apk(self, filepath, timeout=default_timeout): # pylint: disable=W0221 def install_apk(self, filepath, timeout=default_timeout, replace=False): # pylint: disable=W0221
self._check_ready() self._check_ready()
ext = os.path.splitext(filepath)[1].lower() ext = os.path.splitext(filepath)[1].lower()
if ext == '.apk': if ext == '.apk':
return adb_command(self.adb_name, "install '{}'".format(filepath), timeout=timeout) flags = []
if replace:
flags.append('-r') # Replace existing APK
if self.get_sdk_version() >= 23:
flags.append('-g') # Grant all runtime permissions
self.logger.debug("Replace APK = {}, ADB flags = '{}'".format(replace, ' '.join(flags)))
return adb_command(self.adb_name, "install {} '{}'".format(' '.join(flags), filepath), timeout=timeout)
else: else:
raise DeviceError('Can\'t install {}: unsupported format.'.format(filepath)) raise DeviceError('Can\'t install {}: unsupported format.'.format(filepath))

View File

@ -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)

View File

@ -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
@ -155,11 +156,16 @@ class ApkWorkload(Workload):
'''), '''),
Parameter('force_install', kind=boolean, default=False, Parameter('force_install', kind=boolean, default=False,
description=''' description='''
Always re-install the APK, even if matching version is found Always re-install the APK, even if matching version is found already installed
on already installed on the device. on the device. Runs ``adb install -r`` to ensure existing APK is replaced.
'''), '''),
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))
@ -194,7 +202,7 @@ class ApkWorkload(Workload):
self.initialize_with_host_apk(context, installed_version) self.initialize_with_host_apk(context, installed_version)
else: else:
if not installed_version: if not installed_version:
message = '''{} not found found on the device and check_apk is set to "False" message = '''{} not found on the device and check_apk is set to "False"
so host version was not checked.''' so host version was not checked.'''
raise WorkloadError(message.format(self.package)) raise WorkloadError(message.format(self.package))
message = 'Version {} installed on device; skipping host APK check.' message = 'Version {} installed on device; skipping host APK check.'
@ -222,8 +230,8 @@ class ApkWorkload(Workload):
if self.force_install: if self.force_install:
if installed_version: if installed_version:
self.device.uninstall(self.package) self.device.uninstall(self.package)
# It's possible that that the uninstall above fails, which will result in # It's possible that the uninstall above fails, which might result in a warning
# install failing and a warning, hower execution would the 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
@ -249,12 +257,13 @@ class ApkWorkload(Workload):
# As of android API level 23, apps can request permissions at runtime, # As of android API level 23, apps can request permissions at runtime,
# this will grant all of them so requests do not pop up when running the app # this will grant all of them so requests do not pop up when running the app
# This can also be done less "manually" during adb install using the -g flag
if self.device.get_sdk_version() >= 23: if self.device.get_sdk_version() >= 23:
self._grant_requested_permissions() self._grant_requested_permissions()
def install_apk(self, context): def install_apk(self, context):
success = False success = False
output = self.device.install(self.apk_file, self.install_timeout) output = self.device.install(self.apk_file, self.install_timeout, replace=self.force_install)
if 'Failure' in output: if 'Failure' in output:
if 'ALREADY_EXISTS' in output: if 'ALREADY_EXISTS' in output:
self.logger.warn('Using already installed APK (did not unistall properly?)') self.logger.warn('Using already installed APK (did not unistall properly?)')
@ -288,7 +297,7 @@ class ApkWorkload(Workload):
self.device.execute("pm grant {} {}".format(self.package, permission)) self.device.execute("pm grant {} {}".format(self.package, permission))
def do_post_install(self, context): def do_post_install(self, context):
""" May be overwritten by dervied classes.""" """ May be overwritten by derived classes."""
pass pass
def run(self, context): def run(self, context):

View File

@ -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:

View File

@ -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)

View File

@ -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)