Support HAL callback with args.
-Rename vts_tcp_server to callback_server.
-Clean up existing code to properly manage the lifecycle of each
component.
+ Properly shut down the server.
+ Properly cleans up resources held by AndroidDevice, including
hal and callback server.
-Add input args support to callback functions.
-Improve resource management in android_device controller module.
-Update the generated AndroidSystemControlMessage_pb2.py
-Fix a bug in mirror_object's arg parsing.
Bug=29420383
Change-Id: Iaa2ce3526dad5c240aceafc4fb7d285c8bb3ee9c
diff --git a/utils/python/controllers/android_device.py b/utils/python/controllers/android_device.py
index 431cf07..b739ac8 100644
--- a/utils/python/controllers/android_device.py
+++ b/utils/python/controllers/android_device.py
@@ -61,6 +61,15 @@
def create(configs):
+ """Creates AndroidDevice controller objects.
+
+ Args:
+ configs: A list of dicts, each representing a configuration for an
+ Android device.
+
+ Returns:
+ A list of AndroidDevice objects.
+ """
if not configs:
raise AndroidDeviceError(ANDROID_DEVICE_EMPTY_CONFIG_MSG)
elif configs == ANDROID_DEVICE_PICK_ALL_TOKEN:
@@ -77,19 +86,43 @@
for ad in ads:
if ad.serial not in connected_ads:
- raise AndroidDeviceError(
- ("Android device %s is specified in config"
- " but is not attached.") % ad.serial)
- ad.startAdbLogcat()
- ad.startVtsAgent()
+ raise DoesNotExistError(("Android device %s is specified in config"
+ " but is not attached.") % ad.serial)
+ _startServicesOnAds(ads)
return ads
def destroy(ads):
+ """Cleans up AndroidDevice objects.
+
+ Args:
+ ads: A list of AndroidDevice objects.
+ """
for ad in ads:
- ad.stopVtsAgent()
- if ad.adb_logcat_process:
- ad.stopAdbLogcat()
+ try:
+ ad.cleanUp()
+ except:
+ ad.log.exception("Failed to clean up properly.")
+
+
+def _startServicesOnAds(ads):
+ """Starts long running services on multiple AndroidDevice objects.
+
+ If any one AndroidDevice object fails to start services, cleans up all
+ existing AndroidDevice objects and their services.
+
+ Args:
+ ads: A list of AndroidDevice objects whose services to start.
+ """
+ running_ads = []
+ for ad in ads:
+ running_ads.append(ad)
+ try:
+ ad.start_services()
+ except:
+ ad.log.exception("Failed to start some services, abort!")
+ destroy(running_ads)
+ raise
def _parse_device_list(device_list_str, key):
@@ -272,10 +305,8 @@
class AndroidDevice(object):
"""Class representing an android device.
- Each object of this class represents one Android device in ACTS, including
- handles to adb, fastboot, and sl4a clients. In addition to direct adb
- commands, this object also uses adb port forwarding to talk to the Android
- device.
+ Each object of this class represents one Android device. The object holds
+ handles to adb, fastboot, and various RPC clients.
Attributes:
serial: A string that's the serial number of the Androi device.
@@ -298,6 +329,10 @@
(to send commands and receive responses).
host_callback_port: the host-side port for agent to runner sessions
(to get callbacks from agent).
+ hal: HalMirror, in charge of all communications with the HAL layer.
+ lib: LibMirror, in charge of all communications with static and shared
+ native libs.
+ shell: ShellMirror, in charge of all communications with shell.
"""
def __init__(self, serial="", device_port=5001, device_callback_port=5010):
@@ -320,16 +355,20 @@
self.adb.tcp_forward(self.host_command_port, self.device_command_port)
self.adb.reverse_tcp_forward(self.device_callback_port,
self.host_callback_port)
- self.hal = hal_mirror.HalMirror(self.host_command_port,
- self.host_callback_port)
+ self.hal = None
self.lib = lib_mirror.LibMirror(self.host_command_port)
self.shell = shell_mirror.ShellMirror(self.host_command_port)
def __del__(self):
+ self.cleanUp()
+
+ def cleanUp(self):
+ """Cleans up the AndroidDevice object and releases any resources it
+ claimed.
+ """
+ self.stopServices()
if self.host_command_port:
self.adb.forward("--remove tcp:%s" % self.host_command_port)
- if self.adb_logcat_process:
- self.stopAdbLogcat()
@property
def isBootloaderMode(self):
@@ -501,6 +540,31 @@
if has_vts_agent:
self.startVtsAgent()
+ def startServices(self):
+ """Starts long running services on the android device.
+
+ 1. Start adb logcat capture.
+ 2. Start VtsAgent.
+ 3. Create HalMirror
+ """
+ try:
+ self.startAdbLogcat()
+ except:
+ self.log.exception("Failed to start adb logcat!")
+ raise
+ self.startVtsAgent()
+ self.hal = hal_mirror.HalMirror(self.host_command_port,
+ self.host_callback_port)
+
+ def stopServices(self):
+ """Stops long running services on the android device.
+ """
+ if self.adb_logcat_process:
+ self.stopAdbLogcat()
+ self.stopVtsAgent()
+ if self.hal:
+ self.hal.CleanUp()
+
def startVtsAgent(self):
"""Start HAL agent on the AndroidDevice.
@@ -514,7 +578,8 @@
cleanup_commands = [
"rm -f /data/local/tmp/vts_driver_*",
- "rm -f /data/local/tmp/vts_agent_callback*"]
+ "rm -f /data/local/tmp/vts_agent_callback*"
+ ]
kill_commands = ["killall vts_hal_agent", "killall fuzzer32",
"killall fuzzer64", "killall vts_shell_driver32",
"killall vts_shell_driver64"]
@@ -524,14 +589,16 @@
"chmod 755 %s/32/fuzzer32" % DEFAULT_AGENT_BASE_DIR,
"chmod 755 %s/64/fuzzer64" % DEFAULT_AGENT_BASE_DIR,
"chmod 755 %s/32/vts_shell_driver32" % DEFAULT_AGENT_BASE_DIR,
- "chmod 755 %s/64/vts_shell_driver64" % DEFAULT_AGENT_BASE_DIR]
+ "chmod 755 %s/64/vts_shell_driver64" % DEFAULT_AGENT_BASE_DIR
+ ]
cleanup_commands.extend(chmod_commands)
for cmd in cleanup_commands:
try:
self.adb.shell(cmd)
except adb.AdbError as e:
self.log.warning(
- "A command to setup the env to start the VTS Agent failed %s", e)
+ "A command to setup the env to start the VTS Agent failed %s",
+ e)
vts_agent_log_path = os.path.join(self.log_path, "vts_agent.log")
cmd = (
'adb -s {s} shell LD_LIBRARY_PATH={path}/64 {path}/64/vts_hal_agent'
@@ -541,7 +608,8 @@
path=DEFAULT_AGENT_BASE_DIR,
log=vts_agent_log_path)
self.vts_agent_process = utils.start_standing_subprocess(
- cmd, check_health_delay=1)
+ cmd,
+ check_health_delay=1)
def stopVtsAgent(self):
"""Stop the HAL agent running on the AndroidDevice.
diff --git a/utils/python/mirror/hal_mirror.py b/utils/python/mirror/hal_mirror.py
index 6660a3d..9e4a6d8 100644
--- a/utils/python/mirror/hal_mirror.py
+++ b/utils/python/mirror/hal_mirror.py
@@ -57,26 +57,33 @@
One can use this class to create and destroy a HAL mirror object.
Attributes:
+ _hal_level_mirrors: dict, key is HAL handler name, value is HAL
+ mirror object.
+ _callback_server: VtsTcpServer, the server that receives and handles
+ callback messages from target side.
_host_command_port: int, the host-side port for command-response
sessions.
_host_callback_port: int, the host-side port for callback sessions.
- _hal_level_mirrors: dict, key is HAL handler name, value is HAL
- mirror object.
- _host_port: int, the port number on the host side to use.
- _callback_server: the instance of a callback server.
- _callback_port: int, the port number of a host-side callback server.
"""
+
def __init__(self, host_command_port, host_callback_port):
self._hal_level_mirrors = {}
self._host_command_port = host_command_port
self._host_callback_port = host_callback_port
self._callback_server = None
- self._callback_port = 0
def __del__(self):
- for hal_mirror_name in self._hal_level_mirrors:
- self.RemoveHal(hal_mirror_name)
+ self.CleanUp()
+
+ def CleanUp(self):
+ """Shutdown services and release resources held by the HalMirror.
+ """
+ for hal_mirror_name in self._hal_level_mirrors.values():
+ hal_mirror_name.CleanUp()
self._hal_level_mirrors = {}
+ if self._callback_server:
+ self._callback_server.Stop()
+ self._callback_server = None
def InitConventionalHal(self,
target_type,
@@ -160,8 +167,22 @@
bits=bits)
def RemoveHal(self, handler_name):
- hal_level_mirror = self._hal_level_mirrors[handler_name]
- hal_level_mirror.CleanUp()
+ self._hal_level_mirrors[handler_name].CleanUp()
+ self._hal_level_mirrors.pop(handler_name)
+
+ def _StartCallbackServer(self):
+ """Starts the callback server.
+
+ Raises:
+ errors.ComponentLoadingError is raised if the callback server fails
+ to start.
+ """
+ self._callback_server = vts_tcp_server.VtsTcpServer()
+ _, port = self._callback_server.Start(self.host_callback_port)
+ if port != self.host_callback_port:
+ raise errors.ComponentLoadingError(
+ "Failed to start a callback TcpServer at port %s" %
+ self._host_callback_port)
def _CreateMirrorObject(self,
target_class,
@@ -173,6 +194,8 @@
"""Initiates the driver for a HAL on the target device and creates a top
level MirroObject for it.
+ Also starts the callback server to listen for callback invocations.
+
Args:
target_class: string, the target class name (e.g., hal).
target_type: string, the target type name (e.g., light, camera).
@@ -188,14 +211,10 @@
create a MirrorObject.
"""
if bits not in [32, 64]:
- raise error.ComponentLoadingError("Invalid value for bits: %s" % bits)
+ raise error.ComponentLoadingError("Invalid value for bits: %s" %
+ bits)
+ self._StartCallbackServer()
client = vts_tcp_client.VtsTcpClient()
- callback_server = vts_tcp_server.VtsTcpServer()
- _, port = callback_server.Start(self._host_callback_port)
- if port != self._host_callback_port:
- raise errors.ComponentLoadingError(
- "Couldn't start a callback TcpServer at port %s" %
- self._host_callback_port)
client.Connect(command_port=self._host_command_port,
callback_port=self._host_callback_port)
if not handler_name:
@@ -236,16 +255,16 @@
driver_type = {
"hal_conventional": ASysCtrlMsg.VTS_DRIVER_TYPE_HAL_CONVENTIONAL,
"hal_legacy": ASysCtrlMsg.VTS_DRIVER_TYPE_HAL_LEGACY,
- "hal_hidl": ASysCtrlMsg.VTS_DRIVER_TYPE_HAL_HIDL}.get(target_class)
+ "hal_hidl": ASysCtrlMsg.VTS_DRIVER_TYPE_HAL_HIDL
+ }.get(target_class)
- launched = client.LaunchDriverService(
- driver_type=driver_type,
- service_name=service_name,
- bits=bits,
- file_path=target_filename,
- target_class=target_class_id,
- target_type=target_type_id,
- target_version=target_version)
+ launched = client.LaunchDriverService(driver_type=driver_type,
+ service_name=service_name,
+ bits=bits,
+ file_path=target_filename,
+ target_class=target_class_id,
+ target_type=target_type_id,
+ target_version=target_version)
if not launched:
raise errors.ComponentLoadingError(
diff --git a/utils/python/mirror/lib_mirror.py b/utils/python/mirror/lib_mirror.py
index a79a724..3448016 100644
--- a/utils/python/mirror/lib_mirror.py
+++ b/utils/python/mirror/lib_mirror.py
@@ -23,7 +23,6 @@
from vts.proto import AndroidSystemControlMessage_pb2 as ASysCtrlMsg
from vts.proto import InterfaceSpecificationMessage_pb2 as IfaceSpecMsg
from vts.runners.host.tcp_client import vts_tcp_client
-from vts.runners.host.tcp_server import vts_tcp_server
from vts.utils.python.mirror import hal_mirror
from vts.utils.python.mirror import mirror_object
diff --git a/utils/python/mirror/mirror_object.py b/utils/python/mirror/mirror_object.py
index c100dd8..0fc5696 100644
--- a/utils/python/mirror/mirror_object.py
+++ b/utils/python/mirror/mirror_object.py
@@ -222,8 +222,8 @@
setattr(arg.scalar_value, value.scalar_type,
getattr(value.scalar_value, value.scalar_type))
elif value.type == IfaceSpecMsg.TYPE_STRING:
- arg.string_value.message = value.string_value.length
- arg.string_value.length = value.string_value.message
+ arg.string_value.message = value.string_value.message
+ arg.string_value.length = value.string_value.length
elif value.type == IfaceSpecMsg.TYPE_STRUCT:
# TODO: assign recursively
logging.error("TYPE_STRUCT unsupported")