blob: 22d181fd5884bf4f6d83c4a8334f720908b1f10a [file] [log] [blame]
#
# 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