Home | History | Annotate | Download | only in build
      1 #!/usr/bin/env python3.4
      2 #
      3 # Copyright (C) 2017 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the 'License');
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 #      http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an 'AS IS' BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 #
     17 
     18 import fnmatch
     19 import os
     20 import shutil
     21 import subprocess
     22 import sys
     23 import tempfile
     24 
     25 ANDROID_BUILD_TOP = os.environ.get('ANDROID_BUILD_TOP')
     26 if not ANDROID_BUILD_TOP:
     27     print 'Run "lunch" command first.'
     28     sys.exit(1)
     29 
     30 # TODO(trong): use proper packaging without referencing modules from source.
     31 TEST_VTS_DIR = os.path.join(ANDROID_BUILD_TOP, 'test', 'vts')
     32 sys.path.append(TEST_VTS_DIR)
     33 from proto import ComponentSpecificationMessage_pb2 as CompSpecMsg
     34 from google.protobuf import text_format
     35 import build_rule_gen_utils as utils
     36 
     37 
     38 class VtsSpecParser(object):
     39     """Provides an API to generate a parse .vts spec files."""
     40     HW_IFACE_DIR = os.path.join(ANDROID_BUILD_TOP, 'hardware', 'interfaces')
     41 
     42     def __init__(self):
     43         """VtsSpecParser constructor.
     44 
     45         For every unique pair of (hal name, hal version) available under
     46         hardware/interfaces, generates .vts files using hidl-gen.
     47 
     48         Args:
     49             tmp_dir: string, temporary directory to which to write .vts files.
     50         """
     51         self._cache = set()
     52         self._tmp_dir = tempfile.mkdtemp()
     53         hal_list = self.HalNamesAndVersions()
     54 
     55     def __del__(self):
     56         """VtsSpecParser destructor.
     57 
     58         Removes all temporary files that were generated.
     59         """
     60         print "Removing temp files."
     61         if os.path.exists(self._tmp_dir):
     62             shutil.rmtree(self._tmp_dir)
     63 
     64     def ImportedPackagesList(self, hal_name, hal_version):
     65         """Returns a list of imported packages.
     66 
     67         Args:
     68           hal_name: string, name of the hal, e.g. 'vibrator'.
     69           hal_version: string, version of the hal, e.g '7.4'
     70 
     71         Returns:
     72           list of strings. For example,
     73               ['android.hardware.vibrator (at] 1.3', 'android.hidl.base (at] 1.7']
     74         """
     75         self.GenerateVtsSpecs(hal_name, hal_version)
     76         vts_spec_protos = self.VtsSpecProtos(hal_name, hal_version)
     77 
     78         imported_packages = set()
     79         for vts_spec in vts_spec_protos:
     80             for package in getattr(vts_spec, 'import', []):
     81                 package = package.split('::')[0]
     82                 imported_packages.add(package)
     83 
     84         this_package = 'android.hardware.%s@%s' % (hal_name, hal_version)
     85         if this_package in imported_packages:
     86             imported_packages.remove(this_package)
     87 
     88         return sorted(imported_packages)
     89 
     90     def GenerateVtsSpecs(self, hal_name, hal_version):
     91         """Generates VTS specs.
     92 
     93         Uses hidl-gen to generate .vts files under a tmp directory.
     94 
     95         Args:
     96           hal_name: string, name of the hal, e.g. 'vibrator'.
     97           hal_version: string, version of the hal, e.g '7.4'
     98           tmp_dir: string, location to which to write tmp files.
     99         """
    100         if (hal_name, hal_version) in self._cache:
    101             return
    102         hidl_gen_cmd = (
    103             'hidl-gen -o {TEMP_DIR} -L vts '
    104             '-r android.hardware:{HW_IFACE_DIR} '
    105             '-r android.hidl:{ANDROID_BUILD_TOP}/system/libhidl/transport '
    106             'android.hardware.{HAL_NAME}@{HAL_VERSION}').format(
    107                 TEMP_DIR=self._tmp_dir,
    108                 HW_IFACE_DIR=self.HW_IFACE_DIR,
    109                 ANDROID_BUILD_TOP=ANDROID_BUILD_TOP,
    110                 HAL_NAME=hal_name,
    111                 HAL_VERSION=hal_version)
    112         subprocess.call(hidl_gen_cmd, shell=True)
    113         self._cache.add((hal_name, hal_version))
    114 
    115     def HalNamesAndVersions(self):
    116         """Returns a list of hals and version present under hardware/interfaces.
    117 
    118         Returns:
    119           List of tuples of strings containing hal names and hal versions.
    120           For example, [('vibrator', '1.3'), ('sensors', '1.7')]
    121         """
    122         result = []
    123         for base, dirs, files in os.walk(self.HW_IFACE_DIR):
    124             pattern = self.HW_IFACE_DIR + '*/[0-9].[0-9]'
    125             if fnmatch.fnmatch(base, pattern) and 'example' not in base:
    126                 hal_dir = os.path.relpath(base, self.HW_IFACE_DIR)
    127                 (hal_name, hal_version) = os.path.split(hal_dir)
    128                 hal_name = hal_name.replace('/', '.')
    129                 result.append((hal_name, hal_version))
    130         return sorted(result)
    131 
    132     def VtsSpecNames(self, hal_name, hal_version):
    133         """Returns list of .vts file names for given hal name and version.
    134 
    135         hal_name: string, name of the hal, e.g. 'vibrator'.
    136         hal_version: string, version of the hal, e.g '7.4'
    137 
    138         Returns:
    139           list of string, .vts files for given hal name and version,
    140               e.g. ['Vibrator.vts', 'types.vts']
    141         """
    142         self.GenerateVtsSpecs(hal_name, hal_version)
    143         vts_spec_dir = os.path.join(self._tmp_dir, 'android', 'hardware',
    144                                     utils.HalNameDir(hal_name), hal_version)
    145         vts_spec_names = filter(lambda x: x.endswith('.vts'),
    146                                 os.listdir(vts_spec_dir))
    147         return sorted(vts_spec_names)
    148 
    149     def VtsSpecProtos(self, hal_name, hal_version):
    150         """Returns list of .vts protos for given hal name and version.
    151 
    152         hal_name: string, name of the hal, e.g. 'vibrator'.
    153         hal_version: string, version of the hal, e.g '7.4'
    154 
    155         Returns:
    156           list of ComponentSpecificationMessages
    157         """
    158         self.GenerateVtsSpecs(hal_name, hal_version)
    159         vts_spec_dir = os.path.join(self._tmp_dir, 'android', 'hardware',
    160                                     utils.HalNameDir(hal_name), hal_version)
    161         vts_spec_protos = []
    162         for vts_spec in self.VtsSpecNames(hal_name, hal_version):
    163             spec_proto = CompSpecMsg.ComponentSpecificationMessage()
    164             vts_spec_path = os.path.join(vts_spec_dir, vts_spec)
    165             with open(vts_spec_path, 'r') as spec_file:
    166                 spec_string = spec_file.read()
    167                 text_format.Merge(spec_string, spec_proto)
    168 
    169             vts_spec_protos.append(spec_proto)
    170         return vts_spec_protos
    171