1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-06-28 03:03:27 +01:00

Implement caching of ApkInfo

Allow caching of ApkInfo to prevent the requirement of re-parsing
of APK files.
This commit is contained in:
Marc Bonnici
2020-06-01 10:35:18 +01:00
committed by setrofim
parent 4557da2f80
commit 1425a6f6c9
5 changed files with 87 additions and 26 deletions
wa
framework
instruments
utils

@ -19,8 +19,7 @@ from datetime import datetime
from devlib.utils.android import ApkInfo as _ApkInfo
from wa import settings
from wa.framework.exception import ConfigError
from wa.framework.configuration import settings
from wa.utils.serializer import read_pod, write_pod, Podable
from wa.utils.types import enum
from wa.utils.misc import lock_file
@ -30,7 +29,10 @@ LogcatLogLevel = enum(['verbose', 'debug', 'info', 'warn', 'error', 'assert'], s
log_level_map = ''.join(n[0].upper() for n in LogcatLogLevel.names)
logger = logging.getLogger('logcat')
logcat_logger = logging.getLogger('logcat')
apk_info_cache_logger = logging.getLogger('apk_info_cache')
apk_info_cache = None
class LogcatEvent(object):
@ -81,14 +83,15 @@ class LogcatParser(object):
tag = (parts.pop(0) if parts else '').strip()
except Exception as e: # pylint: disable=broad-except
message = 'Invalid metadata for line:\n\t{}\n\tgot: "{}"'
logger.warning(message.format(line, e))
logcat_logger.warning(message.format(line, e))
return None
return LogcatEvent(timestamp, pid, tid, level, tag, message)
# pylint: disable=protected-access,attribute-defined-outside-init
class ApkInfo(_ApkInfo, Podable):
# Implement ApkInfo as a Podable class.
'''Implement ApkInfo as a Podable class.'''
_pod_serialization_version = 1
@ -132,3 +135,66 @@ class ApkInfo(_ApkInfo, Podable):
pod['_pod_version'] = pod.get('_pod_version', 1)
return pod
class ApkInfoCache:
@staticmethod
def _check_env():
if not os.path.exists(settings.cache_directory):
os.makedirs(settings.cache_directory)
def __init__(self, path=settings.apk_info_cache_file):
self._check_env()
self.path = path
self.last_modified = None
self.cache = {}
self._update_cache()
def store(self, apk_info, apk_id, overwrite=True):
self._update_cache()
if apk_id in self.cache and not overwrite:
raise ValueError('ApkInfo for {} is already in cache.'.format(apk_info.path))
self.cache[apk_id] = apk_info.to_pod()
with lock_file(self.path):
write_pod(self.cache, self.path)
self.last_modified = os.stat(self.path)
def get_info(self, key):
self._update_cache()
pod = self.cache.get(key)
info = ApkInfo.from_pod(pod) if pod else None
return info
def _update_cache(self):
if not os.path.exists(self.path):
return
if self.last_modified != os.stat(self.path):
apk_info_cache_logger.debug('Updating cache {}'.format(self.path))
with lock_file(self.path):
self.cache = read_pod(self.path)
self.last_modified = os.stat(self.path)
def get_cacheable_apk_info(path):
# pylint: disable=global-statement
global apk_info_cache
if not path:
return
stat = os.stat(path)
modified = stat.st_mtime
apk_id = '{}-{}'.format(path, modified)
info = apk_info_cache.get_info(apk_id)
if info:
msg = 'Using ApkInfo ({}) from cache'.format(info.package)
else:
with lock_file(path):
info = ApkInfo(path)
apk_info_cache.store(info, apk_id, overwrite=True)
msg = 'Storing ApkInfo ({}) in cache'.format(info.package)
apk_info_cache_logger.debug(msg)
return info
apk_info_cache = ApkInfoCache()