mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-01-19 04:21:17 +00:00
AndroidManager: Added AndroidManager
Replaces AndroidDevice
This commit is contained in:
parent
001239dfe4
commit
a3962b6323
189
wlauto/managers/android.py
Normal file
189
wlauto/managers/android.py
Normal file
@ -0,0 +1,189 @@
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import time
|
||||
import tempfile
|
||||
import shutil
|
||||
import threading
|
||||
|
||||
from wlauto.core.device_manager import DeviceManager
|
||||
from wlauto import Parameter, Alias
|
||||
from wlauto.utils.types import boolean, regex
|
||||
from wlauto.utils.android import adb_command
|
||||
from wlauto.exceptions import WorkerThreadError
|
||||
|
||||
from devlib.target import AndroidTarget
|
||||
|
||||
SCREEN_STATE_REGEX = re.compile('(?:mPowerState|mScreenOn|Display Power: state)=([0-9]+|true|false|ON|OFF)', re.I)
|
||||
SCREEN_SIZE_REGEX = re.compile(r'mUnrestrictedScreen=\(\d+,\d+\)\s+(?P<width>\d+)x(?P<height>\d+)')
|
||||
|
||||
|
||||
class AndroidDevice(DeviceManager):
|
||||
|
||||
name = "android"
|
||||
target_type = AndroidTarget
|
||||
|
||||
aliases = [
|
||||
Alias('generic_android'),
|
||||
]
|
||||
|
||||
parameters = [
|
||||
Parameter('adb_name', default=None, kind=str,
|
||||
description='The unique ID of the device as output by "adb devices".'),
|
||||
Parameter('android_prompt', kind=regex, default=re.compile('^.*(shell|root)@.*:/\S* [#$] ', re.MULTILINE), # ##
|
||||
description='The format of matching the shell prompt in Android.'),
|
||||
Parameter('working_directory', default='/sdcard/wa-working', override=True),
|
||||
Parameter('binaries_directory', default='/data/local/tmp', override=True),
|
||||
Parameter('package_data_directory', default='/data/data',
|
||||
description='Location of of data for an installed package (APK).'),
|
||||
Parameter('external_storage_directory', default='/sdcard',
|
||||
description='Mount point for external storage.'),
|
||||
Parameter('logcat_poll_period', kind=int,
|
||||
description="""
|
||||
If specified and is not ``0``, logcat will be polled every
|
||||
``logcat_poll_period`` seconds, and buffered on the host. This
|
||||
can be used if a lot of output is expected in logcat and the fixed
|
||||
logcat buffer on the device is not big enough. The trade off is that
|
||||
this introduces some minor runtime overhead. Not set by default.
|
||||
"""), # ##
|
||||
Parameter('enable_screen_check', kind=boolean, default=False,
|
||||
description="""
|
||||
Specified whether the device should make sure that the screen is on
|
||||
during initialization.
|
||||
"""),
|
||||
Parameter('swipe_to_unlock', kind=str, default=None,
|
||||
allowed_values=[None, "horizontal", "vertical"],
|
||||
description="""
|
||||
If set a swipe of the specified direction will be performed.
|
||||
This should unlock the screen.
|
||||
"""), # ##
|
||||
]
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(AndroidDevice, self).__init__(**kwargs)
|
||||
self.connection_settings = self._make_connection_settings()
|
||||
|
||||
self.platform = self.platform_type(core_names=self.core_names, # pylint: disable=E1102
|
||||
core_clusters=self.core_clusters)
|
||||
|
||||
self.target = self.target_type(connection_settings=self.connection_settings,
|
||||
connect=False,
|
||||
platform=self.platform,
|
||||
working_directory=self.working_directory,
|
||||
executables_directory=self.binaries_directory,)
|
||||
self._logcat_poller = None
|
||||
|
||||
def connect(self):
|
||||
self.target.connect()
|
||||
|
||||
def initialize(self, context):
|
||||
super(AndroidDevice, self).initialize(context)
|
||||
if self.enable_screen_check:
|
||||
self.target.ensure_screen_is_on()
|
||||
if self.swipe_to_unlock:
|
||||
self.target.swipe_to_unlock(direction=self.swipe_to_unlock)
|
||||
|
||||
def start(self):
|
||||
if self.logcat_poll_period:
|
||||
if self._logcat_poller:
|
||||
self._logcat_poller.close()
|
||||
self._logcat_poller = _LogcatPoller(self, self.logcat_poll_period,
|
||||
timeout=self.default_timeout)
|
||||
self._logcat_poller.start()
|
||||
else:
|
||||
self.target.clear_logcat()
|
||||
|
||||
def _make_connection_settings(self):
|
||||
connection_settings = {}
|
||||
connection_settings['device'] = self.adb_name
|
||||
return connection_settings
|
||||
|
||||
def dump_logcat(self, outfile, filter_spec=None):
|
||||
"""
|
||||
Dump the contents of logcat, for the specified filter spec to the
|
||||
specified output file.
|
||||
See http://developer.android.com/tools/help/logcat.html
|
||||
|
||||
:param outfile: Output file on the host into which the contents of the
|
||||
log will be written.
|
||||
:param filter_spec: Logcat filter specification.
|
||||
see http://developer.android.com/tools/debugging/debugging-log.html#filteringOutput
|
||||
|
||||
"""
|
||||
if self._logcat_poller:
|
||||
return self._logcat_poller.write_log(outfile)
|
||||
else:
|
||||
if filter_spec:
|
||||
command = 'logcat -d -s {} > {}'.format(filter_spec, outfile)
|
||||
else:
|
||||
command = 'logcat -d > {}'.format(outfile)
|
||||
return adb_command(self.adb_name, command)
|
||||
|
||||
|
||||
class _LogcatPoller(threading.Thread):
|
||||
|
||||
join_timeout = 5
|
||||
|
||||
def __init__(self, target, period, timeout=None):
|
||||
super(_LogcatPoller, self).__init__()
|
||||
self.target = target
|
||||
self.logger = target.logger
|
||||
self.period = period
|
||||
self.timeout = timeout
|
||||
self.stop_signal = threading.Event()
|
||||
self.lock = threading.RLock()
|
||||
self.buffer_file = tempfile.mktemp()
|
||||
self.last_poll = 0
|
||||
self.daemon = True
|
||||
self.exc = None
|
||||
|
||||
def run(self):
|
||||
self.logger.debug('Starting logcat polling.')
|
||||
try:
|
||||
while True:
|
||||
if self.stop_signal.is_set():
|
||||
break
|
||||
with self.lock:
|
||||
current_time = time.time()
|
||||
if (current_time - self.last_poll) >= self.period:
|
||||
self._poll()
|
||||
time.sleep(0.5)
|
||||
except Exception: # pylint: disable=W0703
|
||||
self.exc = WorkerThreadError(self.name, sys.exc_info())
|
||||
self.logger.debug('Logcat polling stopped.')
|
||||
|
||||
def stop(self):
|
||||
self.logger.debug('Stopping logcat polling.')
|
||||
self.stop_signal.set()
|
||||
self.join(self.join_timeout)
|
||||
if self.is_alive():
|
||||
self.logger.error('Could not join logcat poller thread.')
|
||||
if self.exc:
|
||||
raise self.exc # pylint: disable=E0702
|
||||
|
||||
def clear_buffer(self):
|
||||
self.logger.debug('Clearing logcat buffer.')
|
||||
with self.lock:
|
||||
self.target.clear_logcat()
|
||||
with open(self.buffer_file, 'w') as _: # NOQA
|
||||
pass
|
||||
|
||||
def write_log(self, outfile):
|
||||
self.logger.debug('Writing logbuffer to {}.'.format(outfile))
|
||||
with self.lock:
|
||||
self._poll()
|
||||
if os.path.isfile(self.buffer_file):
|
||||
shutil.copy(self.buffer_file, outfile)
|
||||
else: # there was no logcat trace at this time
|
||||
with open(outfile, 'w') as _: # NOQA
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
self.logger.debug('Closing logcat poller.')
|
||||
if os.path.isfile(self.buffer_file):
|
||||
os.remove(self.buffer_file)
|
||||
|
||||
def _poll(self):
|
||||
with self.lock:
|
||||
self.last_poll = time.time()
|
||||
self.target.dump_logcat(self.buffer_file, append=True)
|
Loading…
x
Reference in New Issue
Block a user