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")