• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 copy
18import logging
19import random
20import sys
21
22from vts.utils.python.fuzzer import FuzzerUtils
23from vts.utils.python.mirror import mirror_object_for_types
24from vts.proto import ComponentSpecificationMessage_pb2 as CompSpecMsg
25from google.protobuf import text_format
26
27# a dict containing the IDs of the registered function pointers.
28_function_pointer_id_dict = {}
29
30INTERFACE = "interface"
31API = "api"
32
33class MirrorObjectError(Exception):
34    """Raised when there is a general error in manipulating a mirror object."""
35    pass
36
37
38class MirrorObject(object):
39    """The class that mirrors objects on the native side.
40
41    This class exists on the host and can be used to communicate to a
42    particular HAL in the HAL agent on the target side.
43
44    Attributes:
45        _client: the TCP client instance.
46        _if_spec_msg: the interface specification message of a host object to
47                      mirror.
48        _callback_server: the instance of a callback server.
49        _parent_path: the name of a sub struct this object mirrors.
50        _last_raw_code_coverage_data: NativeCodeCoverageRawDataMessage,
51                                      last seen raw code coverage data.
52        __caller_uid: string, the caller's UID if not None.
53    """
54
55    def __init__(self, client, msg, callback_server, parent_path=None):
56        self._client = client
57        self._if_spec_msg = msg
58        self._callback_server = callback_server
59        self._parent_path = parent_path
60        self._last_raw_code_coverage_data = None
61        self.__caller_uid = None
62
63    def GetFunctionPointerID(self, function_pointer):
64        """Returns the function pointer ID for the given one."""
65        max_num = 0
66        for key in _function_pointer_id_dict:
67            if _function_pointer_id_dict[key] == function_pointer:
68                return str(key)
69            if not max_num or key > max_num:
70                max_num = key
71        _function_pointer_id_dict[max_num + 1] = function_pointer
72        id = str(max_num + 1)
73        if self._callback_server:
74            self._callback_server.RegisterCallback(id, function_pointer)
75        return id
76
77    def OpenConventionalHal(self, module_name=None):
78        """Opens the target conventional HAL component.
79
80        This is only needed for conventional HAL.
81
82        Args:
83            module_name: string, the name of a module to load.
84        """
85        func_msg = CompSpecMsg.FunctionSpecificationMessage()
86        func_msg.name = "#Open"
87        logging.debug("remote call %s", func_msg.name)
88        if module_name:
89            arg = func_msg.arg.add()
90            arg.type = CompSpecMsg.TYPE_STRING
91            arg.string_value.message = module_name
92
93            func_msg.return_type.type == CompSpecMsg.TYPE_SCALAR
94            func_msg.return_type.scalar_type = "int32_t"
95        logging.debug("final msg %s", func_msg)
96
97        result = self._client.CallApi(text_format.MessageToString(func_msg),
98                                      self.__caller_uid)
99        logging.debug(result)
100        return result
101
102    def SetCallerUid(self, uid):
103        """Sets target-side caller's UID.
104
105        Args:
106            uid: string, the caller's UID.
107        """
108        self.__caller_uid = uid
109
110    def GetAttributeValue(self, attribute_name):
111        """Retrieves the value of an attribute from a target.
112
113        Args:
114            attribute_name: string, the name of an attribute.
115
116        Returns:
117            FunctionSpecificationMessage which contains the value.
118        """
119        def RemoteCallToGetAttribute(*args, **kwargs):
120            """Makes a remote call and retrieves an attribute."""
121            func_msg = self.GetAttribute(attribute_name)
122            if not func_msg:
123                raise MirrorObjectError("attribute %s unknown", func_msg)
124
125            logging.debug("remote call %s.%s", self._parent_path, attribute_name)
126            logging.info("remote call %s%s", attribute_name, args)
127            if self._parent_path:
128                func_msg.parent_path = self._parent_path
129            try:
130                if isinstance(self._if_spec_msg,
131                              CompSpecMsg.ComponentSpecificationMessage):
132                    logging.info("component_class %s",
133                                 self._if_spec_msg.component_class)
134                    if (self._if_spec_msg.component_class
135                        == CompSpecMsg.HAL_CONVENTIONAL_SUBMODULE):
136                        submodule_name = self._if_spec_msg.original_data_structure_name
137                        if submodule_name.endswith("*"):
138                            submodule_name = submodule_name[:-1]
139                        func_msg.submodule_name = submodule_name
140                elif isinstance(self._if_spec_msg,
141                                CompSpecMsg.StructSpecificationMessage):
142                    pass
143                else:
144                    logging.error("unknown type %s", type(self._if_spec_msg))
145                    sys.exit(1)
146            except AttributeError as e:
147                logging.exception("%s" % e)
148                pass
149            result = self._client.GetAttribute(
150                text_format.MessageToString(func_msg))
151            logging.debug(result)
152            return result
153
154        var_msg = self.GetAttribute(attribute_name)
155        if var_msg:
156            logging.debug("attribute: %s", var_msg)
157            return RemoteCallToGetAttribute()
158        raise MirrorObjectError("unknown attribute name %s" % attribute_name)
159
160    def GetHidlCallbackInterface(self, interface_name, **kwargs):
161        var_msg = CompSpecMsg.VariableSpecificationMessage()
162        var_msg.name = interface_name
163        var_msg.type = CompSpecMsg.TYPE_FUNCTION_POINTER
164        var_msg.is_callback = True
165
166        msg = self._if_spec_msg
167        specification = self._client.ReadSpecification(
168            interface_name,
169            msg.component_class,
170            msg.component_type,
171            msg.component_type_version,
172            msg.package)
173        logging.info("specification: %s", specification)
174        interface = getattr(specification, INTERFACE, None)
175        apis = getattr(interface, API, [])
176        for api in apis:
177            function_pointer = None
178            if api.name in kwargs:
179                function_pointer = kwargs[api.name]
180            else:
181                def dummy(*args):
182                    """Dummy implementation for any callback function."""
183                    logging.info("Entering dummy implementation"
184                                 " for callback function: %s", api.name)
185                    for arg_index in range(len(args)):
186                        logging.info("arg%s: %s", arg_index, args[arg_index])
187                function_pointer = dummy
188            func_pt_msg = var_msg.function_pointer.add()
189            func_pt_msg.function_name = api.name
190            func_pt_msg.id = self.GetFunctionPointerID(function_pointer)
191
192        return var_msg
193
194    def GetHidlTypeInterface(self, interface_name,
195                             target_class=None, target_type=None,
196                             version=None, package=None):
197        """Gets HIDL type interface's host-side mirror.
198
199        Args:
200            interface_name: string, the name of a target interface to read.
201            target_class: integer, optional used to override the loaded HAL's
202                          component_class.
203            target_type: integer, optional used to override the loaded HAL's
204                         component_type.
205            version: integer, optional used to override the loaded HAL's
206                     component_type_version.
207            package: integer, optional used to override the loaded HAL's
208                              package.
209
210        Returns:
211            a host-side mirror of a HIDL interface
212        """
213        msg = self._if_spec_msg
214        result = self._client.ReadSpecification(
215            interface_name,
216            msg.component_class if target_class is None else target_class,
217            msg.component_type if target_type is None else target_type,
218            msg.component_type_version if version is None else version,
219            msg.package if package is None else package,
220            recursive=True)
221
222        logging.info("result %s", result)
223        return mirror_object_for_types.MirrorObjectForTypes(result)
224
225    def CleanUp(self):
226        self._client.Disconnect()
227
228    def GetApi(self, api_name):
229        """Returns the Function Specification Message.
230
231        Args:
232            api_name: string, the name of the target function API.
233
234        Returns:
235            FunctionSpecificationMessage or StructSpecificationMessage if found,
236            None otherwise
237        """
238        logging.debug("GetAPI %s for %s", api_name, self._if_spec_msg)
239        # handle reserved methods first.
240        if api_name == "notifySyspropsChanged":
241            func_msg = CompSpecMsg.FunctionSpecificationMessage()
242            func_msg.name =  api_name
243            return func_msg
244        if isinstance(self._if_spec_msg, CompSpecMsg.ComponentSpecificationMessage):
245            if len(self._if_spec_msg.interface.api) > 0:
246                for api in self._if_spec_msg.interface.api:
247                    if api.name == api_name:
248                        return copy.copy(api)
249        elif isinstance(self._if_spec_msg, CompSpecMsg.StructSpecificationMessage):
250            if len(self._if_spec_msg.api) > 0:
251                for api in self._if_spec_msg.api:
252                    logging.info("api %s", api)
253                    if api.name == api_name:
254                        return copy.copy(api)
255            if len(self._if_spec_msg.sub_struct) > 0:
256                for sub_struct in self._if_spec_msg.sub_struct:
257                    if len(sub_struct.api) > 0:
258                        for api in sub_struct.api:
259                            logging.info("api %s", api)
260                            if api.name == api_name:
261                                return copy.copy(api)
262        else:
263            logging.error("unknown spec type %s", type(self._if_spec_msg))
264            sys.exit(1)
265        return None
266
267    def GetAttribute(self, attribute_name):
268        """Returns the Message.
269        """
270        logging.debug("GetAttribute %s for %s",
271                      attribute_name, self._if_spec_msg)
272        if self._if_spec_msg.attribute:
273            for attribute in self._if_spec_msg.attribute:
274                if attribute.name == attribute_name:
275                    func_msg = CompSpecMsg.FunctionSpecificationMessage()
276                    func_msg.name = attribute.name
277                    func_msg.return_type.type = attribute.type
278                    if func_msg.return_type.type == CompSpecMsg.TYPE_SCALAR:
279                        func_msg.return_type.scalar_type = attribute.scalar_type
280                    else:
281                        func_msg.return_type.predefined_type = attribute.predefined_type
282                    logging.info("GetAttribute attribute: %s", attribute)
283                    logging.info("GetAttribute request: %s", func_msg)
284                    return copy.copy(func_msg)
285        if (self._if_spec_msg.interface and
286            self._if_spec_msg.interface.attribute):
287            for attribute in self._if_spec_msg.interface.attribute:
288                if attribute.name == attribute_name:
289                    func_msg = CompSpecMsg.FunctionSpecificationMessage()
290                    func_msg.name = attribute.name
291                    func_msg.return_type.type = attribute.type
292                    if func_msg.return_type.type == CompSpecMsg.TYPE_SCALAR:
293                        func_msg.return_type.scalar_type = attribute.scalar_type
294                    else:
295                        func_msg.return_type.predefined_type = attribute.predefined_type
296                    logging.info("GetAttribute attribute: %s", attribute)
297                    logging.info("GetAttribute request: %s", func_msg)
298                    return copy.copy(func_msg)
299        return None
300
301    def GetSubStruct(self, sub_struct_name):
302        """Returns the Struct Specification Message.
303
304        Args:
305            sub_struct_name: string, the name of the target sub struct attribute.
306
307        Returns:
308            StructSpecificationMessage if found, None otherwise
309        """
310        if isinstance(self._if_spec_msg, CompSpecMsg.ComponentSpecificationMessage):
311            if (self._if_spec_msg.interface and
312                self._if_spec_msg.interface.sub_struct):
313                for sub_struct in self._if_spec_msg.interface.sub_struct:
314                    if sub_struct.name == sub_struct_name:
315                        return copy.copy(sub_struct)
316        elif isinstance(self._if_spec_msg, CompSpecMsg.StructSpecificationMessage):
317            if len(self._if_spec_msg.sub_struct) > 0:
318                for sub_struct in self._if_spec_msg.sub_struct:
319                    if sub_struct.name == sub_struct_name:
320                        return copy.copy(sub_struct)
321        return None
322
323    def GetCustomAggregateType(self, type_name):
324        """Returns the Argument Specification Message.
325
326        Args:
327            type_name: string, the name of the target data type.
328
329        Returns:
330            VariableSpecificationMessage if found, None otherwise
331        """
332        try:
333            if self._if_spec_msg.attribute:
334                for attribute in self._if_spec_msg.attribute:
335                    if not attribute.is_const and attribute.name == type_name:
336                        return copy.copy(attribute)
337            if (self._if_spec_msg.interface and
338                self._if_spec_msg.interface.attribute):
339                for attribute in self._if_spec_msg.interface.attribute:
340                    if not attribute.is_const and attribute.name == type_name:
341                        return copy.copy(attribute)
342            return None
343        except AttributeError as e:
344            # TODO: check in advance whether self._if_spec_msg Interface
345            # SpecificationMessage.
346            return None
347
348    def GetConstType(self, type_name):
349        """Returns the Argument Specification Message.
350
351        Args:
352            type_name: string, the name of the target const data variable.
353
354        Returns:
355            VariableSpecificationMessage if found, None otherwise
356        """
357        try:
358            if self._if_spec_msg.attribute:
359                for attribute in self._if_spec_msg.attribute:
360                    if attribute.is_const and attribute.name == type_name:
361                        return copy.copy(attribute)
362                    elif attribute.type == CompSpecMsg.TYPE_ENUM:
363                      for enumerator in attribute.enum_value.enumerator:
364                            if enumerator == type_name:
365                                return copy.copy(attribute)
366            if self._if_spec_msg.interface and self._if_spec_msg.interface.attribute:
367                for attribute in self._if_spec_msg.interface.attribute:
368                    if attribute.is_const and attribute.name == type_name:
369                        return copy.copy(attribute)
370                    elif attribute.type == CompSpecMsg.TYPE_ENUM:
371                        for enumerator in attribute.enum_value.enumerator:
372                            if enumerator == type_name:
373                                return copy.copy(attribute)
374            return None
375        except AttributeError as e:
376            # TODO: check in advance whether self._if_spec_msg Interface
377            # SpecificationMessage.
378            return None
379
380    def ArgToPb(self, arg_msg, value_msg):
381        """Converts args to a ProtoBuf message.
382
383        Args:
384            arg_msg: the ProtoBuf message where the result will be stored in.
385            value_msg: value given as an argument. it can be either Python
386                       data structure, a ProtoBuf message, or both.
387
388        Raises:
389            AttributeError: when unexpected type is seen.
390        """
391        if isinstance(value_msg, CompSpecMsg.VariableSpecificationMessage):
392            arg_msg.CopyFrom(value_msg)
393        elif isinstance(value_msg, int):
394            arg_msg.type = CompSpecMsg.TYPE_SCALAR
395            if not arg_msg.scalar_type:
396                arg_msg.scalar_type = "int32_t"
397            setattr(arg_msg.scalar_value, arg_msg.scalar_type, value_msg)
398        elif isinstance(value_msg, float):
399            arg_msg.type = CompSpecMsg.TYPE_SCALAR
400            arg_msg.scalar_value.float_t = value_msg
401            arg_msg.scalar_type = "float_t"
402        elif isinstance(value_msg, str):
403            if ((arg_msg.type == CompSpecMsg.TYPE_SCALAR and
404                 (arg_msg.scalar_type == "char_pointer" or
405                  arg_msg.scalar_type == "uchar_pointer")) or
406                arg_msg.type == CompSpecMsg.TYPE_STRING):
407                arg_msg.string_value.message = value_msg
408                arg_msg.string_value.length = len(value_msg)
409            else:
410                raise MirrorObjectError(
411                    "unsupported type %s for str" % arg_msg)
412        elif isinstance(value_msg, list):
413            if (arg_msg.type == CompSpecMsg.TYPE_VECTOR or
414                arg_msg.type == CompSpecMsg.TYPE_ARRAY):
415                first = True
416                for list_element in value_msg:
417                    if first:
418                        self.ArgToPb(arg_msg.vector_value[0], list_element)
419                        first = False
420                    else:
421                        self.ArgToPb(arg_msg.vector_value.add(), list_element)
422                arg_msg.vector_size = len(value_msg)
423            else:
424                raise MirrorObjectError(
425                    "unsupported arg_msg type %s for list" % arg_msg.type)
426        else:
427            raise MirrorObjectError(
428                "unsupported value type %s" % type(value_msg))
429
430    # TODO: Guard against calls to this function after self.CleanUp is called.
431    def __getattr__(self, api_name, *args, **kwargs):
432        """Calls a target component's API.
433
434        Args:
435            api_name: string, the name of an API function to call.
436            *args: a list of arguments
437            **kwargs: a dict for the arg name and value pairs
438        """
439        def RemoteCall(*args, **kwargs):
440            """Dynamically calls a remote API."""
441            func_msg = self.GetApi(api_name)
442            if not func_msg:
443                raise MirrorObjectError("api %s unknown", func_msg)
444
445            logging.debug("remote call %s.%s", self._parent_path, api_name)
446            logging.info("remote call %s%s", api_name, args)
447            if args:
448                for arg_msg, value_msg in zip(func_msg.arg, args):
449                    logging.debug("arg msg %s", arg_msg)
450                    logging.debug("value %s", value_msg)
451                    if value_msg is not None:
452                        self.ArgToPb(arg_msg, value_msg)
453
454                logging.debug("final msg %s", func_msg)
455            else:
456                # TODO: use kwargs
457                for arg in func_msg.arg:
458                    # TODO: handle other
459                    if (arg.type == CompSpecMsg.TYPE_SCALAR
460                        and arg.scalar_type == "pointer"):
461                        arg.scalar_value.pointer = 0
462                logging.debug(func_msg)
463
464            if self._parent_path:
465                func_msg.parent_path = self._parent_path
466
467            if isinstance(self._if_spec_msg, CompSpecMsg.ComponentSpecificationMessage):
468                if self._if_spec_msg.component_class:
469                    logging.info("component_class %s",
470                                 self._if_spec_msg.component_class)
471                    if self._if_spec_msg.component_class == CompSpecMsg.HAL_CONVENTIONAL_SUBMODULE:
472                        submodule_name = self._if_spec_msg.original_data_structure_name
473                        if submodule_name.endswith("*"):
474                            submodule_name = submodule_name[:-1]
475                        func_msg.submodule_name = submodule_name
476            result = self._client.CallApi(text_format.MessageToString(func_msg),
477                                          self.__caller_uid)
478            logging.debug(result)
479            if (isinstance(result, tuple) and len(result) == 2 and
480                isinstance(result[1], dict) and "coverage" in result[1]):
481                self._last_raw_code_coverage_data = result[1]["coverage"]
482                return result[0]
483            return result
484
485        def MessageGenerator(*args, **kwargs):
486            """Dynamically generates a custom message instance."""
487            arg_msg = self.GetCustomAggregateType(api_name)
488            if not arg_msg:
489                raise MirrorObjectError("arg %s unknown" % arg_msg)
490            logging.info("MessageGenerator %s %s", api_name, arg_msg)
491            logging.debug("MESSAGE %s", api_name)
492            if arg_msg.type == CompSpecMsg.TYPE_STRUCT:
493                for struct_value in arg_msg.struct_value:
494                    logging.debug("for %s %s",
495                                  struct_value.name, struct_value.scalar_type)
496                    for given_name, given_value in kwargs.iteritems():
497                        logging.debug("check %s %s", struct_value.name, given_name)
498                        if given_name == struct_value.name:
499                            logging.debug("match type=%s", struct_value.scalar_type)
500                            if struct_value.type == CompSpecMsg.TYPE_SCALAR:
501                                if struct_value.scalar_type == "uint32_t":
502                                    struct_value.scalar_value.uint32_t = given_value
503                                elif struct_value.scalar_type == "int32_t":
504                                    struct_value.scalar_value.int32_t = given_value
505                                else:
506                                    raise MirrorObjectError(
507                                        "support %s" % struct_value.scalar_type)
508                            continue
509            elif arg_msg.type == CompSpecMsg.TYPE_FUNCTION_POINTER:
510                for fp_value in arg_msg.function_pointer:
511                    logging.debug("for %s", fp_value.function_name)
512                    for given_name, given_value in kwargs.iteritems():
513                          logging.debug("check %s %s", fp_value.function_name, given_name)
514                          if given_name == fp_value.function_name:
515                              fp_value.id = self.GetFunctionPointerID(given_value)
516                              break
517
518            if arg_msg.type == CompSpecMsg.TYPE_STRUCT:
519                for struct_value, given_value in zip(arg_msg.struct_value, args):
520                    logging.debug("arg match type=%s", struct_value.scalar_type)
521                    if struct_value.type == CompSpecMsg.TYPE_SCALAR:
522                        if struct_value.scalar_type == "uint32_t":
523                            struct_value.scalar_value.uint32_t = given_value
524                        elif struct_value.scalar_type == "int32_t":
525                            struct_value.scalar_value.int32_t = given_value
526                        else:
527                            raise MirrorObjectError("support %s" % p_type)
528            elif arg_msg.type == CompSpecMsg.TYPE_FUNCTION_POINTER:
529                for fp_value, given_value in zip(arg_msg.function_pointer, args):
530                    logging.debug("for %s", fp_value.function_name)
531                    fp_value.id = self.GetFunctionPointerID(given_value)
532                    logging.debug("fp %s", fp_value)
533            logging.debug("generated %s", arg_msg)
534            return arg_msg
535
536        def MessageFuzzer(arg_msg):
537            """Fuzz a custom message instance."""
538            if not self.GetCustomAggregateType(api_name):
539                raise MirrorObjectError("fuzz arg %s unknown" % arg_msg)
540
541            if arg_msg.type == CompSpecMsg.TYPE_STRUCT:
542                index = random.randint(0, len(arg_msg.struct_value))
543                count = 0
544                for struct_value in arg_msg.struct_value:
545                    if count == index:
546                        if struct_value.scalar_type == "uint32_t":
547                            struct_value.scalar_value.uint32_t ^= FuzzerUtils.mask_uint32_t()
548                        elif struct_value.scalar_type == "int32_t":
549                            mask = FuzzerUtils.mask_int32_t()
550                            if mask == (1 << 31):
551                                struct_value.scalar_value.int32_t *= -1
552                                struct_value.scalar_value.int32_t += 1
553                            else:
554                                struct_value.scalar_value.int32_t ^= mask
555                        else:
556                            raise MirrorObjectError(
557                                "support %s" % struct_value.scalar_type)
558                        break
559                    count += 1
560                logging.debug("fuzzed %s", arg_msg)
561            else:
562                raise MirrorObjectError(
563                    "unsupported fuzz message type %s." % arg_msg.type)
564            return arg_msg
565
566        def ConstGenerator():
567            """Dynamically generates a const variable's value."""
568            arg_msg = self.GetConstType(api_name)
569            if not arg_msg:
570                raise MirrorObjectError("const %s unknown" % arg_msg)
571            logging.debug("check %s", api_name)
572            if arg_msg.type == CompSpecMsg.TYPE_SCALAR:
573                ret_v = getattr(arg_msg.scalar_value, arg_msg.scalar_type, None)
574                if ret_v is None:
575                    raise MirrorObjectError(
576                        "No value found for type %s in %s." %
577                        (arg_msg.scalar_type, api_name))
578                return ret_v
579            elif arg_msg.type == CompSpecMsg.TYPE_STRING:
580                return arg_msg.string_value.message
581            elif arg_msg.type == CompSpecMsg.TYPE_ENUM:
582                for enumerator, scalar_value in zip(
583                        arg_msg.enum_value.enumerator,
584                        arg_msg.enum_value.scalar_value):
585                    if enumerator == api_name:
586                      return getattr(scalar_value,
587                                     arg_msg.enum_value.scalar_type)
588            raise MirrorObjectError("const %s not found" % api_name)
589
590        # handle APIs.
591        func_msg = self.GetApi(api_name)
592        if func_msg:
593            logging.debug("api %s", func_msg)
594            return RemoteCall
595
596        struct_msg = self.GetSubStruct(api_name)
597        if struct_msg:
598            logging.debug("sub_struct %s", struct_msg)
599            if self._parent_path:
600                parent_name = "%s.%s" % (self._parent_path, api_name)
601            else:
602                parent_name = api_name
603            return MirrorObject(self._client, struct_msg,
604                                self._callback_server,
605                                parent_path=parent_name)
606
607        # handle attributes.
608        fuzz = False
609        if api_name.endswith("_fuzz"):
610            fuzz = True
611            api_name = api_name[:-5]
612        arg_msg = self.GetCustomAggregateType(api_name)
613        if arg_msg:
614            logging.debug("arg %s", arg_msg)
615            if not fuzz:
616                return MessageGenerator
617            else:
618                return MessageFuzzer
619
620        arg_msg = self.GetConstType(api_name)
621        if arg_msg:
622            logging.debug("const %s *\n%s", api_name, arg_msg)
623            return ConstGenerator()
624        raise MirrorObjectError("unknown api name %s" % api_name)
625
626    def GetRawCodeCoverage(self):
627        """Returns any measured raw code coverage data."""
628        return self._last_raw_code_coverage_data
629
630    def __str__(self):
631        """Prints all the attributes and methods."""
632        result = ""
633        if self._if_spec_msg:
634            if self._if_spec_msg.attribute:
635                for attribute in self._if_spec_msg.attribute:
636                    result += "attribute %s\n" % attribute.name
637            if self._if_spec_msg.api:
638                for api in self._if_spec_msg.api:
639                    result += "api %s\n" % api.name
640        return result
641