1# 2# Copyright (C) 2017 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 collections 18import json 19import logging 20import os 21import re 22import zipfile 23 24try: 25 from importlib import resources 26except ImportError: 27 resources = None 28 29# The tags in VNDK list: 30# Low-level NDK libraries that can be used by framework and vendor modules. 31LL_NDK = "LLNDK" 32 33# Same-process HAL implementation in vendor partition. 34SP_HAL = "SP-HAL" 35 36# Framework libraries that can be used by vendor modules except same-process HAL 37# and its dependencies in vendor partition. 38VNDK = "VNDK-core" 39 40# VNDK dependencies that vendor modules cannot directly access. 41VNDK_PRIVATE = "VNDK-core-private" 42 43# Same-process HAL dependencies in framework. 44VNDK_SP = "VNDK-SP" 45 46# VNDK-SP dependencies that vendor modules cannot directly access. 47VNDK_SP_PRIVATE = "VNDK-SP-private" 48 49# The tuples of (ABI name, bitness, arch name). 64-bit comes before 32-bit in 50# order to sequentially search for longest prefix. 51_ABI_LIST = ( 52 ("arm64", 64, "arm64_armv8-a"), 53 ("arm64", 32, "arm_armv8-a"), 54 ("arm", 32, "arm_armv7-a-neon"), 55 ("x86_64", 64, "x86_x86_64"), 56 ("x86_64", 32, "x86_64"), 57 ("x86", 32, "x86"), 58) 59 60# The data directory. 61_GOLDEN_DIR = os.path.join("vts", "testcases", "vndk", "golden") 62 63# The data package. 64_RESOURCE_PACKAGE = "vts.testcases.vndk"; 65 66# The name of the zip file containing ABI dumps. 67_ABI_DUMP_ZIP_NAME = "abi_dump.zip" 68 69# Regular expression prefix for library name patterns. 70_REGEX_PREFIX = "[regex]" 71 72def LoadDefaultVndkVersion(data_file_path): 73 """Loads the name of the data directory for devices with no VNDK version. 74 75 Args: 76 data_file_path: The path to VTS data directory. 77 78 Returns: 79 A string, the directory name. 80 None if fails to load the name. 81 """ 82 try: 83 with open(os.path.join(data_file_path, _GOLDEN_DIR, 84 "platform_vndk_version.txt"), "r") as f: 85 return f.read().strip() 86 except IOError: 87 logging.error("Cannot load default VNDK version.") 88 return None 89 90 91def GetAbiDumpDirectory(data_file_path, version, binder_bitness, abi_name, 92 abi_bitness): 93 """Returns the VNDK dump directory on host. 94 95 Args: 96 data_file_path: The path to VTS data directory. 97 version: A string, the VNDK version. 98 binder_bitness: A string or an integer, 32 or 64. 99 abi_name: A string, the ABI of the library dump. 100 abi_bitness: A string or an integer, 32 or 64. 101 102 Returns: 103 A string, the path to the dump directory. 104 None if there is no directory for the version and ABI. 105 """ 106 try: 107 abi_dir = next(x[0] for x in _ABI_LIST if abi_name.startswith(x[0])) 108 except StopIteration: 109 logging.warning("Unknown ABI %s.", abi_name) 110 return None 111 112 version_dir = (version if version else 113 LoadDefaultVndkVersion(data_file_path)) 114 if not version_dir: 115 return None 116 117 dump_dir = os.path.join( 118 data_file_path, _GOLDEN_DIR, version_dir, 119 "binder64" if str(binder_bitness) == "64" else "binder32", 120 abi_dir, "lib64" if str(abi_bitness) == "64" else "lib") 121 122 if not os.path.isdir(dump_dir): 123 logging.warning("%s is not a directory.", dump_dir) 124 return None 125 126 return dump_dir 127 128 129class AbiDumpResource: 130 """The class for loading ABI dumps from the zip in resources.""" 131 132 def __init__(self): 133 self._resource = None 134 self.zip_file = None 135 136 def __enter__(self): 137 self._resource = resources.open_binary(_RESOURCE_PACKAGE, 138 _ABI_DUMP_ZIP_NAME) 139 self.zip_file = zipfile.ZipFile(self._resource, "r") 140 return self 141 142 def __exit__(self, exc_type, exc_val, traceback): 143 if self._resource: 144 self._resource.close() 145 if self.zip_file: 146 self.zip_file.close() 147 148 149def GetAbiDumpPathsFromResources(version, binder_bitness, abi_name, abi_bitness): 150 """Returns the VNDK dump paths in resources. 151 152 Args: 153 version: A string, the VNDK version. 154 binder_bitness: A string or an integer, 32 or 64. 155 abi_name: A string, the ABI of the library dump. 156 abi_bitness: A string or an integer, 32 or 64. 157 158 Returns: 159 A dict of {library name: dump resource path}. For example, 160 {"libbase.so": "R/64/arm64_armv8-a/source-based/libbase.so.lsdump"}. 161 If there is no dump for the version and ABI, this function returns an 162 empty dict. 163 """ 164 if not resources: 165 logging.error("Could not import resources module.") 166 return dict() 167 168 abi_bitness = int(abi_bitness) 169 try: 170 arch_name = next(x[2] for x in _ABI_LIST if 171 abi_name.startswith(x[0]) and x[1] == abi_bitness) 172 except StopIteration: 173 logging.warning("Unknown %d-bit ABI %s.", abi_bitness, abi_name) 174 return dict() 175 176 # The separator in zipped path is always "/". 177 dump_dir = "/".join((version, str(binder_bitness), arch_name, 178 "source-based")) + "/" 179 180 dump_paths = dict() 181 182 with AbiDumpResource() as dump_resource: 183 for path in dump_resource.zip_file.namelist(): 184 if path.startswith(dump_dir) and path.endswith(".lsdump"): 185 lib_name = path[len(dump_dir):-len(".lsdump")] 186 dump_paths[lib_name] = path 187 188 return dump_paths 189 190 191def _LoadVndkLibraryListsFile(vndk_lists, tags, vndk_lib_list_file): 192 """Load VNDK libraries from the file to the specified tuple. 193 194 Args: 195 vndk_lists: The output tuple of lists containing library names. 196 tags: Strings, the tags of the libraries to find. 197 vndk_lib_list_file: The file object containing the VNDK library list. 198 """ 199 200 lib_sets = collections.defaultdict(set) 201 202 # Load VNDK tags from the list. 203 for line in vndk_lib_list_file: 204 # Ignore comments. 205 if line.startswith('#'): 206 continue 207 208 # Split columns. 209 cells = line.split(': ', 1) 210 if len(cells) < 2: 211 continue 212 tag = cells[0] 213 lib_name = cells[1].strip() 214 215 lib_sets[tag].add(lib_name) 216 217 # Compute VNDK-core-private and VNDK-SP-private. 218 private = lib_sets.get('VNDK-private', set()) 219 220 lib_sets[VNDK_PRIVATE].update(lib_sets[VNDK] & private) 221 lib_sets[VNDK_SP_PRIVATE].update(lib_sets[VNDK_SP] & private) 222 223 lib_sets[LL_NDK].difference_update(private) 224 lib_sets[VNDK].difference_update(private) 225 lib_sets[VNDK_SP].difference_update(private) 226 227 # Update the output entries. 228 for index, tag in enumerate(tags): 229 for lib_name in lib_sets.get(tag, tuple()): 230 if lib_name.startswith(_REGEX_PREFIX): 231 lib_name = lib_name[len(_REGEX_PREFIX):] 232 vndk_lists[index].append(lib_name) 233 234 235def LoadVndkLibraryLists(data_file_path, version, *tags): 236 """Find the VNDK libraries with specific tags. 237 238 Args: 239 data_file_path: The path to VTS data directory. 240 version: A string, the VNDK version. 241 *tags: Strings, the tags of the libraries to find. 242 243 Returns: 244 A tuple of lists containing library names. Each list corresponds to 245 one tag in the argument. For SP-HAL, the returned names are regular 246 expressions. 247 None if the spreadsheet for the version is not found. 248 """ 249 version_dir = (version if version else 250 LoadDefaultVndkVersion(data_file_path)) 251 if not version_dir: 252 return None 253 254 vndk_lib_list_path = os.path.join( 255 data_file_path, _GOLDEN_DIR, version_dir, "vndk-lib-list.txt") 256 if not os.path.isfile(vndk_lib_list_path): 257 logging.warning("Cannot load %s.", vndk_lib_list_path) 258 return None 259 260 vndk_lib_extra_list_path = os.path.join( 261 data_file_path, _GOLDEN_DIR, version_dir, "vndk-lib-extra-list.txt") 262 if not os.path.isfile(vndk_lib_extra_list_path): 263 logging.warning("Cannot load %s.", vndk_lib_extra_list_path) 264 return None 265 266 vndk_lists = tuple([] for x in tags) 267 268 with open(vndk_lib_list_path, "r") as f: 269 _LoadVndkLibraryListsFile(vndk_lists, tags, f) 270 with open(vndk_lib_extra_list_path, "r") as f: 271 _LoadVndkLibraryListsFile(vndk_lists, tags, f) 272 return vndk_lists 273 274 275def LoadVndkLibraryListsFromResources(version, *tags): 276 """Find the VNDK libraries with specific tags in resources. 277 278 Args: 279 version: A string, the VNDK version. 280 *tags: Strings, the tags of the libraries to find. 281 282 Returns: 283 A tuple of lists containing library names. Each list corresponds to 284 one tag in the argument. For SP-HAL, the returned names are regular 285 expressions. 286 None if the VNDK list for the version is not found. 287 """ 288 if not resources: 289 logging.error("Could not import resources module.") 290 return None 291 292 version_str = (version if version and re.match("\\d+", version) else 293 "current") 294 vndk_lib_list_name = version_str + ".txt" 295 vndk_lib_extra_list_name = "vndk-lib-extra-list-" + version_str + ".txt" 296 297 if not resources.is_resource(_RESOURCE_PACKAGE, vndk_lib_list_name): 298 logging.warning("Cannot load %s.", vndk_lib_list_name) 299 return None 300 301 if not resources.is_resource(_RESOURCE_PACKAGE, vndk_lib_extra_list_name): 302 logging.warning("Cannot load %s.", vndk_lib_extra_list_name) 303 return None 304 305 vndk_lists = tuple([] for x in tags) 306 307 with resources.open_text(_RESOURCE_PACKAGE, vndk_lib_list_name) as f: 308 _LoadVndkLibraryListsFile(vndk_lists, tags, f) 309 with resources.open_text(_RESOURCE_PACKAGE, vndk_lib_extra_list_name) as f: 310 _LoadVndkLibraryListsFile(vndk_lists, tags, f) 311 return vndk_lists 312