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