| # |
| # Copyright (C) 2017 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| import logging |
| |
| from vts.proto import AndroidSystemControlMessage_pb2 as ASysCtrlMsg |
| from vts.runners.host import errors |
| from vts.runners.host.tcp_client import vts_tcp_client |
| from vts.runners.host.tcp_server import callback_server |
| from vts.utils.python.mirror import hal_mirror |
| from vts.utils.python.mirror import lib_mirror |
| from vts.utils.python.mirror import shell_mirror |
| |
| _DEFAULT_TARGET_BASE_PATHS = ["/system/lib64/hw"] |
| _DEFAULT_HWBINDER_SERVICE = "default" |
| _DEFAULT_SHELL_NAME = "_default" |
| |
| |
| class MirrorTracker(object): |
| """The class tracks all mirror objects on the host side. |
| |
| Attributes: |
| _host_command_port: int, the host-side port for command-response |
| sessions. |
| _host_callback_port: int, the host-side port for callback sessions. |
| _adb: An AdbProxy object used for interacting with the device via adb. |
| _registered_mirrors: dict, key is mirror handler name, value is the |
| mirror object. |
| _callback_server: VtsTcpServer, the server that receives and handles |
| callback messages from target side. |
| """ |
| |
| def __init__(self, |
| host_command_port, |
| host_callback_port=None, |
| start_callback_server=False, |
| adb = None): |
| self._host_command_port = host_command_port |
| self._host_callback_port = host_callback_port |
| self._adb = adb |
| self._registered_mirrors = {} |
| self._callback_server = None |
| if start_callback_server: |
| self._StartCallbackServer() |
| |
| def __del__(self): |
| self.CleanUp() |
| |
| def CleanUp(self): |
| """Shutdown services and release resources held by the registered mirrors. |
| """ |
| for mirror in self._registered_mirrors.values(): |
| mirror.CleanUp() |
| self._registered_mirrors = {} |
| if self._callback_server: |
| self._callback_server.Stop() |
| self._callback_server = None |
| |
| def RemoveMirror(self, mirror_name): |
| self._registered_mirrors[mirror_name].CleanUp() |
| self._registered_mirrors.pop(mirror_name) |
| |
| def _StartCallbackServer(self): |
| """Starts the callback server. |
| |
| Raises: |
| errors.ComponentLoadingError is raised if the callback server fails |
| to start. |
| """ |
| self._callback_server = callback_server.CallbackServer() |
| _, 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 InitHidlHal(self, |
| target_type, |
| target_version, |
| target_package=None, |
| target_component_name=None, |
| target_basepaths=_DEFAULT_TARGET_BASE_PATHS, |
| handler_name=None, |
| hw_binder_service_name=_DEFAULT_HWBINDER_SERVICE, |
| bits=64): |
| """Initiates a handler for a particular HIDL HAL. |
| |
| This will initiate a driver service for a HAL on the target side, create |
| a mirror object for a HAL, and register it in the tracker. |
| |
| Args: |
| target_type: string, the target type name (e.g., light, camera). |
| target_version: float, the target component version (e.g., 1.0). |
| target_package: string, the package name of a target HIDL HAL. |
| target_basepaths: list of strings, the paths to look for target |
| files in. Default is _DEFAULT_TARGET_BASE_PATHS. |
| handler_name: string, the name of the handler. target_type is used |
| by default. |
| hw_binder_service_name: string, the name of a HW binder service. |
| bits: integer, processor architecture indicator: 32 or 64. |
| """ |
| |
| if not handler_name: |
| handler_name = target_type |
| client = vts_tcp_client.VtsTcpClient() |
| client.Connect( |
| command_port=self._host_command_port, |
| callback_port=self._host_callback_port) |
| mirror = hal_mirror.HalMirror(client, self._callback_server) |
| mirror.InitHalDriver(target_type, target_version, target_package, |
| target_component_name, hw_binder_service_name, |
| handler_name, bits) |
| self._registered_mirrors[target_type] = mirror |
| |
| def InitSharedLib(self, |
| target_type, |
| target_version, |
| target_basepaths=_DEFAULT_TARGET_BASE_PATHS, |
| target_package="", |
| target_filename=None, |
| handler_name=None, |
| bits=64): |
| """Initiates a handler for a particular lib. |
| |
| This will initiate a driver service for a lib on the target side, create |
| a mirror object for a lib, and register it in the tracker. |
| |
| Args: |
| target_type: string, the target type name (e.g., light, camera). |
| target_version: float, the target component version (e.g., 1.0). |
| target_basepaths: list of strings, the paths to look for target |
| files in. Default is _DEFAULT_TARGET_BASE_PATHS. |
| target_package: . separated string (e.g., a.b.c) to denote the |
| package name of target component. |
| target_filename: string, the target file name (e.g., libm.so). |
| handler_name: string, the name of the handler. target_type is used |
| by default. |
| bits: integer, processor architecture indicator: 32 or 64. |
| """ |
| if not handler_name: |
| handler_name = target_type |
| client = vts_tcp_client.VtsTcpClient() |
| client.Connect(command_port=self._host_command_port) |
| mirror = lib_mirror.LibMirror(client) |
| mirror.InitLibDriver(target_type, target_version, target_package, |
| target_filename, target_basepaths, handler_name, |
| bits) |
| self._registered_mirrors[handler_name] = mirror |
| |
| def InvokeTerminal(self, instance_name, bits=32): |
| """Initiates a handler for a particular shell terminal. |
| |
| This will initiate a driver service for a shell on the target side, |
| create a mirror object for the shell, and register it in the tracker. |
| |
| Args: |
| instance_name: string, the shell terminal instance name. |
| bits: integer, processor architecture indicator: 32 or 64. |
| """ |
| if not instance_name: |
| raise error.ComponentLoadingError("instance_name is None") |
| if bits not in [32, 64]: |
| raise error.ComponentLoadingError("Invalid value for bits: %s" % |
| bits) |
| |
| client = vts_tcp_client.VtsTcpClient() |
| client.Connect(command_port=self._host_command_port) |
| |
| logging.info("Init the driver service for shell, %s", instance_name) |
| launched = client.LaunchDriverService( |
| driver_type=ASysCtrlMsg.VTS_DRIVER_TYPE_SHELL, |
| service_name="shell_" + instance_name, |
| bits=bits) |
| |
| if not launched: |
| raise errors.ComponentLoadingError( |
| "Failed to launch shell driver service %s" % instance_name) |
| |
| mirror = shell_mirror.ShellMirror(client, self._adb) |
| self._registered_mirrors[instance_name] = mirror |
| |
| def DisableShell(self): |
| """Disables all registered shell mirrors.""" |
| for mirror in self._registered_mirrors.values(): |
| if not isinstance(mirror, shell_mirror.ShellMirror): |
| logging.error("mirror object is not a shell mirror") |
| continue |
| mirror.enabled = False |
| |
| def Execute(self, command, no_except=False): |
| """Execute a shell command with default shell terminal.""" |
| if _DEFAULT_SHELL_NAME not in self._registered_mirrors: |
| self.InvokeTerminal(_DEFAULT_SHELL_NAME) |
| return getattr(self, _DEFAULT_SHELL_NAME).Execute(command, no_except) |
| |
| def SetConnTimeout(self, timeout): |
| """Set remove shell connection timeout for default shell terminal. |
| |
| Args: |
| timeout: int, TCP connection timeout in seconds. |
| """ |
| if _DEFAULT_SHELL_NAME not in self._registered_mirrors: |
| self.InvokeTerminal(_DEFAULT_SHELL_NAME) |
| getattr(self, _DEFAULT_SHELL_NAME).SetConnTimeout(timeout) |
| |
| def __getattr__(self, name): |
| if name in self._registered_mirrors: |
| return self._registered_mirrors[name] |
| else: |
| logging.error("No mirror found with name: %s", name) |
| return None |