1#
2# Copyright (C) 2016 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17import logging
18
19from google.protobuf import text_format
20
21from vts.runners.host import errors
22from vts.proto import AndroidSystemControlMessage_pb2 as ASysCtrlMsg
23from vts.proto import ComponentSpecificationMessage_pb2 as CompSpecMsg
24from vts.runners.host.tcp_client import vts_tcp_client
25from vts.runners.host.tcp_server import callback_server
26from vts.utils.python.mirror import mirror_object
27
28COMPONENT_CLASS_DICT = {"hal_conventional": 1,
29                        "hal_conventional_submodule": 2,
30                        "hal_legacy": 3,
31                        "hal_hidl": 4,
32                        "hal_hidl_wrapped_conventional": 5,
33                        "lib_shared": 11}
34
35COMPONENT_TYPE_DICT = {"audio": 1,
36                       "camera": 2,
37                       "gps": 3,
38                       "light": 4,
39                       "wifi": 5,
40                       "mobile": 6,
41                       "bluetooth": 7,
42                       "nfc": 8,
43                       "vibrator": 12,
44                       "thermal": 13,
45                       "tv_input": 14,
46                       "tv_cec": 15,
47                       "sensors": 16,
48                       "vehicle": 17,
49                       "vr": 18,
50                       "graphics_allocator": 19,
51                       "graphics_mapper": 20,
52                       "radio": 21,
53                       "contexthub": 22,
54                       "graphics_composer": 23,
55                       "media_omx": 24,
56                       "bionic_libm": 1001,
57                       "bionic_libc": 1002,
58                       "vndk_libcutils": 1101}
59
60VTS_CALLBACK_SERVER_TARGET_SIDE_PORT = 5010
61
62_DEFAULT_TARGET_BASE_PATHS = ["/system/lib64/hw"]
63_DEFAULT_HWBINDER_SERVICE = "default"
64
65class HalMirror(object):
66    """The class that acts as the mirror to an Android device's HAL layer.
67
68    This class holds and manages the life cycle of multiple mirror objects that
69    map to different HAL components.
70
71    One can use this class to create and destroy a HAL mirror object.
72
73    Attributes:
74        _hal_level_mirrors: dict, key is HAL handler name, value is HAL
75                            mirror object.
76        _callback_server: VtsTcpServer, the server that receives and handles
77                          callback messages from target side.
78        _host_command_port: int, the host-side port for command-response
79                            sessions.
80        _host_callback_port: int, the host-side port for callback sessions.
81        _client: VtsTcpClient, the client instance that can be used to send
82                 commands to the target-side's agent.
83    """
84
85    def __init__(self, host_command_port, host_callback_port):
86        self._hal_level_mirrors = {}
87        self._host_command_port = host_command_port
88        self._host_callback_port = host_callback_port
89        self._callback_server = None
90
91    def __del__(self):
92        self.CleanUp()
93
94    def CleanUp(self):
95        """Shutdown services and release resources held by the HalMirror.
96        """
97        for hal_mirror_name in self._hal_level_mirrors.values():
98            hal_mirror_name.CleanUp()
99        self._hal_level_mirrors = {}
100        if self._callback_server:
101            self._callback_server.Stop()
102            self._callback_server = None
103
104    def InitConventionalHal(self,
105                            target_type,
106                            target_version,
107                            target_package="",
108                            target_basepaths=_DEFAULT_TARGET_BASE_PATHS,
109                            handler_name=None,
110                            bits=64):
111        """Initiates a handler for a particular conventional HAL.
112
113        This will initiate a driver service for a HAL on the target side, create
114        the top level mirror object for a HAL, and register it in the manager.
115
116        Args:
117            target_type: string, the target type name (e.g., light, camera).
118            target_version: float, the target component version (e.g., 1.0).
119            target_basepaths: list of strings, the paths to look for target
120                             files in. Default is _DEFAULT_TARGET_BASE_PATHS.
121            target_package: . separated string (e.g., a.b.c) to denote the
122                            package name of target component.
123            handler_name: string, the name of the handler. target_type is used
124                          by default.
125            bits: integer, processor architecture indicator: 32 or 64.
126        """
127        self._CreateMirrorObject("hal_conventional",
128                                 target_type,
129                                 target_version,
130                                 target_package=target_package,
131                                 target_basepaths=target_basepaths,
132                                 handler_name=handler_name,
133                                 bits=bits)
134
135    def InitLegacyHal(self,
136                      target_type,
137                      target_version,
138                      target_basepaths=_DEFAULT_TARGET_BASE_PATHS,
139                      handler_name=None,
140                      bits=64):
141        """Initiates a handler for a particular legacy HAL.
142
143        This will initiate a driver service for a HAL on the target side, create
144        the top level mirror object for a HAL, and register it in the manager.
145
146        Args:
147            target_type: string, the target type name (e.g., light, camera).
148            target_version: float, the target component version (e.g., 1.0).
149            target_basepaths: list of strings, the paths to look for target
150                             files in. Default is _DEFAULT_TARGET_BASE_PATHS.
151            handler_name: string, the name of the handler. target_type is used
152                          by default.
153            bits: integer, processor architecture indicator: 32 or 64.
154        """
155        self._CreateMirrorObject("hal_legacy",
156                                 target_type,
157                                 target_version,
158                                 target_basepaths=target_basepaths,
159                                 handler_name=handler_name,
160                                 bits=bits)
161
162    def InitHidlHal(self,
163                    target_type,
164                    target_version,
165                    target_package=None,
166                    target_component_name=None,
167                    target_basepaths=_DEFAULT_TARGET_BASE_PATHS,
168                    handler_name=None,
169                    hw_binder_service_name=_DEFAULT_HWBINDER_SERVICE,
170                    bits=64):
171        """Initiates a handler for a particular HIDL HAL.
172
173        This will initiate a driver service for a HAL on the target side, create
174        the top level mirror object for a HAL, and register it in the manager.
175
176        Args:
177            target_type: string, the target type name (e.g., light, camera).
178            target_version: float, the target component version (e.g., 1.0).
179            target_package: string, the package name of a target HIDL HAL.
180            target_basepaths: list of strings, the paths to look for target
181                              files in. Default is _DEFAULT_TARGET_BASE_PATHS.
182            handler_name: string, the name of the handler. target_type is used
183                          by default.
184            hw_binder_service_name: string, the name of a HW binder service.
185            bits: integer, processor architecture indicator: 32 or 64.
186        """
187        self._CreateMirrorObject("hal_hidl",
188                                 target_type,
189                                 target_version,
190                                 target_package=target_package,
191                                 target_component_name=target_component_name,
192                                 target_basepaths=target_basepaths,
193                                 handler_name=handler_name,
194                                 hw_binder_service_name=hw_binder_service_name,
195                                 bits=bits)
196
197    def RemoveHal(self, handler_name):
198        self._hal_level_mirrors[handler_name].CleanUp()
199        self._hal_level_mirrors.pop(handler_name)
200
201    def _StartCallbackServer(self):
202        """Starts the callback server.
203
204        Raises:
205            errors.ComponentLoadingError is raised if the callback server fails
206            to start.
207        """
208        self._callback_server = callback_server.CallbackServer()
209        _, port = self._callback_server.Start(self._host_callback_port)
210        if port != self._host_callback_port:
211            raise errors.ComponentLoadingError(
212                "Failed to start a callback TcpServer at port %s" %
213                self._host_callback_port)
214
215    def _CreateMirrorObject(self,
216                            target_class,
217                            target_type,
218                            target_version,
219                            target_package=None,
220                            target_component_name=None,
221                            target_basepaths=_DEFAULT_TARGET_BASE_PATHS,
222                            handler_name=None,
223                            hw_binder_service_name=None,
224                            bits=64):
225        """Initiates the driver for a HAL on the target device and creates a top
226        level MirroObject for it.
227
228        Also starts the callback server to listen for callback invocations.
229
230        Args:
231            target_class: string, the target class name (e.g., hal).
232            target_type: string, the target type name (e.g., light, camera).
233            target_version: float, the target component version (e.g., 1.0).
234            target_package: string, the package name of a HIDL HAL.
235            target_component_name: string, the name of a target component.
236            target_basepaths: list of strings, the paths to look for target
237                             files in. Default is _DEFAULT_TARGET_BASE_PATHS.
238            handler_name: string, the name of the handler. target_type is used
239                          by default.
240            hw_binder_service_name: string, the name of a HW binder service.
241            bits: integer, processor architecture indicator: 32 or 64.
242
243        Raises:
244            errors.ComponentLoadingError is raised when error occurs trying to
245            create a MirrorObject.
246        """
247        if bits not in [32, 64]:
248            raise error.ComponentLoadingError("Invalid value for bits: %s" %
249                                              bits)
250        self._StartCallbackServer()
251        self._client = vts_tcp_client.VtsTcpClient()
252        self._client.Connect(command_port=self._host_command_port,
253                             callback_port=self._host_callback_port)
254        if not handler_name:
255            handler_name = target_type
256        service_name = "vts_driver_%s" % handler_name
257
258        target_filename = None
259        if target_class == "hal_conventional" or target_class == "hal_legacy":
260            # Get all the HALs available on the target.
261            hal_list = self._client.ListHals(target_basepaths)
262            if not hal_list:
263                raise errors.ComponentLoadingError(
264                    "Could not find any HAL under path %s" % target_basepaths)
265            logging.debug(hal_list)
266
267            # Find the corresponding filename for HAL target type.
268            for name in hal_list:
269                if target_type in name:
270                    # TODO: check more exactly (e.g., multiple hits).
271                    target_filename = name
272            if not target_filename:
273                raise errors.ComponentLoadingError(
274                    "No file found for HAL target type %s." % target_type)
275
276            # Check whether the requested binder service is already running.
277            # if client.CheckDriverService(service_name=service_name):
278            #     raise errors.ComponentLoadingError("A driver for %s already exists" %
279            #                                        service_name)
280        elif target_class == "hal_hidl":
281            # TODO: either user the default hw-binder service or start a new
282            # service (e.g., if an instrumented binary is used).
283            pass
284
285        # Launch the corresponding driver of the requested HAL on the target.
286        logging.info("Init the driver service for %s", target_type)
287        target_class_id = COMPONENT_CLASS_DICT[target_class.lower()]
288        target_type_id = COMPONENT_TYPE_DICT[target_type.lower()]
289        driver_type = {
290            "hal_conventional": ASysCtrlMsg.VTS_DRIVER_TYPE_HAL_CONVENTIONAL,
291            "hal_legacy": ASysCtrlMsg.VTS_DRIVER_TYPE_HAL_LEGACY,
292            "hal_hidl": ASysCtrlMsg.VTS_DRIVER_TYPE_HAL_HIDL
293        }.get(target_class)
294
295        launched = self._client.LaunchDriverService(
296            driver_type=driver_type,
297            service_name=service_name,
298            bits=bits,
299            file_path=target_filename,
300            target_class=target_class_id,
301            target_type=target_type_id,
302            target_version=target_version,
303            target_package=target_package,
304            target_component_name=target_component_name,
305            hw_binder_service_name=hw_binder_service_name)
306
307        if not launched:
308            raise errors.ComponentLoadingError(
309                "Failed to launch driver service %s from file path %s" %
310                (target_type, target_filename))
311
312        # Create API spec message.
313        found_api_spec = self._client.ListApis()
314        if not found_api_spec:
315            raise errors.ComponentLoadingError("No API found for %s" %
316                                               service_name)
317        logging.debug("Found %d APIs for %s:\n%s", len(found_api_spec),
318                      service_name, found_api_spec)
319        if_spec_msg = CompSpecMsg.ComponentSpecificationMessage()
320        text_format.Merge(found_api_spec, if_spec_msg)
321
322        # Instantiate a MirrorObject and return it.
323        hal_mirror = mirror_object.MirrorObject(self._client, if_spec_msg,
324                                                self._callback_server)
325        self._hal_level_mirrors[handler_name] = hal_mirror
326
327    def __getattr__(self, name):
328        return self._hal_level_mirrors[name]
329
330    def Ping(self):
331      """Returns true iff pinging the agent is successful, False otherwise."""
332      return self._client.Ping()
333