1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-01-19 04:21:17 +00:00

AndroidWorkload: Modified workload to properly check for an apks abi

Previously when retrieving apks only it's name would be used to choose
an apk. Now the native code reported by the apk is used to determine
the correct version to run for the specific device. It tries to
match the primary abi of device with native code before falling back to
using a compatible apk.

When using the check_abi parameter it no longer relies on naming convention
and only allows apks with native code supporting a devices primary abi to be
used.

Updated the relevant documentation.
This commit is contained in:
Marc Bonnici 2016-12-07 16:34:15 +00:00
parent f467f6f991
commit a8a8d21de6
4 changed files with 50 additions and 24 deletions

View File

@ -18,8 +18,8 @@ All ApkWorkloads have parameters that affect the way in which APK files are reso
.. confval:: check_abi .. confval:: check_abi
If this setting is enabled WA's resource resolvers will look for the devices ABI within the file name If this setting is enabled WA's resource resolvers will look for the devices ABI with any native
e.g. ``calculator_arm65.apk``. By default this setting is disabled since most apks will work across all code present in the apk. By default this setting is disabled since most apks will work across all
devices. You may wish to enable this feature when working with devices that support multiple ABI's (like devices. You may wish to enable this feature when working with devices that support multiple ABI's (like
64-bit devices that can run 32-bit APK files) and are specifically trying to test one or the other. 64-bit devices that can run 32-bit APK files) and are specifically trying to test one or the other.

View File

@ -30,7 +30,7 @@ from wlauto.common.resources import Executable
from wlauto.core.resource import NO_ONE from wlauto.core.resource import NO_ONE
from wlauto.common.linux.device import BaseLinuxDevice, PsEntry from wlauto.common.linux.device import BaseLinuxDevice, PsEntry
from wlauto.exceptions import DeviceError, WorkerThreadError, TimeoutError, DeviceNotRespondingError from wlauto.exceptions import DeviceError, WorkerThreadError, TimeoutError, DeviceNotRespondingError
from wlauto.utils.misc import convert_new_lines from wlauto.utils.misc import convert_new_lines, ABI_MAP
from wlauto.utils.types import boolean, regex from wlauto.utils.types import boolean, regex
from wlauto.utils.android import (adb_shell, adb_background_shell, adb_list_devices, from wlauto.utils.android import (adb_shell, adb_background_shell, adb_list_devices,
adb_command, AndroidProperties, ANDROID_VERSION_MAP) adb_command, AndroidProperties, ANDROID_VERSION_MAP)
@ -108,7 +108,11 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
@property @property
def abi(self): def abi(self):
return self.getprop()['ro.product.cpu.abi'].split('-')[0] val = self.getprop()['ro.product.cpu.abi'].split('-')[0]
for abi, architectures in ABI_MAP.iteritems():
if val in architectures:
return abi
return val
@property @property
def supported_eabi(self): def supported_eabi(self):
@ -120,7 +124,18 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
for eabi in props['ro.product.cpu.abilist'].split(','): for eabi in props['ro.product.cpu.abilist'].split(','):
if eabi not in result: if eabi not in result:
result.append(eabi) result.append(eabi)
return result
mapped_result = []
for supported_eabi in result:
for abi, architectures in ABI_MAP.iteritems():
found = False
if supported_eabi in architectures and abi not in mapped_result:
mapped_result.append(abi)
found = True
break
if not found and supported_eabi not in mapped_result:
mapped_result.append(supported_eabi)
return mapped_result
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(AndroidDevice, self).__init__(**kwargs) super(AndroidDevice, self).__init__(**kwargs)

View File

@ -200,8 +200,9 @@ class ApkWorkload(Workload):
self.apk_version = None self.apk_version = None
self.logcat_log = None self.logcat_log = None
self.exact_apk_version = None self.exact_apk_version = None
self.check_abi = kwargs.get('check_abi')
def setup(self, context): def setup(self, context): # pylint: disable=too-many-branches
Workload.setup(self, context) Workload.setup(self, context)
# Get target version # Get target version
@ -213,9 +214,25 @@ class ApkWorkload(Workload):
# Get host version # Get host version
self.apk_file = context.resolver.get(ApkFile(self, self.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), variant_name=getattr(self, 'variant_name', None),
strict=False) strict=False)
# Get target abi
target_abi = self.device.get_installed_package_abi(self.package)
if target_abi:
self.logger.debug("Found apk with primary abi '{}' on target device".format(target_abi))
# Get host version, primary abi is first, and then try to find supported.
for abi in self.device.supported_eabi:
self.apk_file = context.resolver.get(ApkFile(self, abi),
version=getattr(self, 'version', None),
variant_name=getattr(self, 'variant_name', None),
strict=False)
# Stop if apk found, or if check_abi is set only look for primary abi.
if self.apk_file or self.check_abi:
break
host_version = None host_version = None
if self.apk_file is not None: if self.apk_file is not None:
host_version = ApkInfo(self.apk_file).version_name host_version = ApkInfo(self.apk_file).version_name
@ -233,6 +250,12 @@ class ApkWorkload(Workload):
msg = "APK version '{}' not found on the host '{}' or target '{}'" msg = "APK version '{}' not found on the host '{}' or target '{}'"
raise ResourceError(msg.format(self.exact_apk_version, host_version, target_version)) raise ResourceError(msg.format(self.exact_apk_version, host_version, target_version))
# Error if check_abi and suitable apk not found on host and incorrect version on device
if self.check_abi and host_version is None:
if target_abi != self.device.abi:
msg = "APK abi '{}' not found on the host and target is '{}'"
raise ResourceError(msg.format(self.device.abi, target_abi))
# Ensure the apk is setup on the device # Ensure the apk is setup on the device
if self.force_install: if self.force_install:
self.force_install_apk(context, host_version) self.force_install_apk(context, host_version)

View File

@ -112,19 +112,13 @@ class PackageApkGetter(PackageFileGetter):
extension = 'apk' extension = 'apk'
description = """ description = """
Uses the same dependency resolution mechanism as ``PackageFileGetter`` with one addition. Uses the same dependency resolution mechanism as ``PackageFileGetter``.
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): def get(self, resource, **kwargs):
resource_dir = os.path.dirname(sys.modules[resource.owner.__module__].__file__) resource_dir = os.path.dirname(sys.modules[resource.owner.__module__].__file__)
version = kwargs.get('version') version = kwargs.get('version')
variant = kwargs.get('variant_name') 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) return get_from_location_by_extension(resource, resource_dir, self.extension, version, variant=variant)
@ -146,19 +140,13 @@ class EnvironmentApkGetter(EnvironmentFileGetter):
extension = 'apk' extension = 'apk'
description = """ description = """
Uses the same dependency resolution mechanism as ``EnvironmentFileGetter`` with one addition. Uses the same dependency resolution mechanism as ``EnvironmentFileGetter``.
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): def get(self, resource, **kwargs):
resource_dir = resource.owner.dependencies_directory resource_dir = resource.owner.dependencies_directory
version = kwargs.get('version') version = kwargs.get('version')
variant = kwargs.get('variant_name') 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) return get_from_location_by_extension(resource, resource_dir, self.extension, version, variant=variant)
@ -478,8 +466,6 @@ 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={}' message = 'resource={}, version={}, remote_path={}, local_path={}'
self.logger.debug(message.format(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)
@ -574,6 +560,8 @@ def get_from_list_by_extension(resource, filelist, extension, version=None, vari
filelist = [ff for ff in filelist if version.lower() in ApkInfo(ff).version_name.lower()] filelist = [ff for ff in filelist if version.lower() in ApkInfo(ff).version_name.lower()]
else: else:
filelist = [ff for ff in filelist if version.lower() in os.path.basename(ff).lower()] 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 not ApkInfo(ff).native_code or resource.platform in ApkInfo(ff).native_code]
if len(filelist) == 1: if len(filelist) == 1:
return filelist[0] return filelist[0]
elif not filelist: elif not filelist: