mirror of
				https://github.com/ARM-software/workload-automation.git
				synced 2025-10-31 07:04:17 +00: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:
		| @@ -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) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user