# # Copyright (C) 2017 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import collections import json import logging import os import re import zipfile try: from importlib import resources except ImportError: resources = None # The tags in VNDK list: # Low-level NDK libraries that can be used by framework and vendor modules. LL_NDK = "LLNDK" # Same-process HAL implementation in vendor partition. SP_HAL = "SP-HAL" # Framework libraries that can be used by vendor modules except same-process HAL # and its dependencies in vendor partition. VNDK = "VNDK-core" # VNDK dependencies that vendor modules cannot directly access. VNDK_PRIVATE = "VNDK-core-private" # Same-process HAL dependencies in framework. VNDK_SP = "VNDK-SP" # VNDK-SP dependencies that vendor modules cannot directly access. VNDK_SP_PRIVATE = "VNDK-SP-private" # The tuples of (ABI name, bitness, arch name). 64-bit comes before 32-bit in # order to sequentially search for longest prefix. _ABI_LIST = ( ("arm64", 64, "arm64_armv8-a"), ("arm64", 32, "arm_armv8-a"), ("arm", 32, "arm_armv7-a-neon"), ("x86_64", 64, "x86_x86_64"), ("x86_64", 32, "x86_64"), ("x86", 32, "x86"), ) # The data directory. _GOLDEN_DIR = os.path.join("vts", "testcases", "vndk", "golden") # The data package. _RESOURCE_PACKAGE = "vts.testcases.vndk"; # The name of the zip file containing ABI dumps. _ABI_DUMP_ZIP_NAME = "abi_dump.zip" # Regular expression prefix for library name patterns. _REGEX_PREFIX = "[regex]" def LoadDefaultVndkVersion(data_file_path): """Loads the name of the data directory for devices with no VNDK version. Args: data_file_path: The path to VTS data directory. Returns: A string, the directory name. None if fails to load the name. """ try: with open(os.path.join(data_file_path, _GOLDEN_DIR, "platform_vndk_version.txt"), "r") as f: return f.read().strip() except IOError: logging.error("Cannot load default VNDK version.") return None def GetAbiDumpDirectory(data_file_path, version, binder_bitness, abi_name, abi_bitness): """Returns the VNDK dump directory on host. Args: data_file_path: The path to VTS data directory. version: A string, the VNDK version. binder_bitness: A string or an integer, 32 or 64. abi_name: A string, the ABI of the library dump. abi_bitness: A string or an integer, 32 or 64. Returns: A string, the path to the dump directory. None if there is no directory for the version and ABI. """ try: abi_dir = next(x[0] for x in _ABI_LIST if abi_name.startswith(x[0])) except StopIteration: logging.warning("Unknown ABI %s.", abi_name) return None version_dir = (version if version else LoadDefaultVndkVersion(data_file_path)) if not version_dir: return None dump_dir = os.path.join( data_file_path, _GOLDEN_DIR, version_dir, "binder64" if str(binder_bitness) == "64" else "binder32", abi_dir, "lib64" if str(abi_bitness) == "64" else "lib") if not os.path.isdir(dump_dir): logging.warning("%s is not a directory.", dump_dir) return None return dump_dir class AbiDumpResource: """The class for loading ABI dumps from the zip in resources.""" def __init__(self): self._resource = None self.zip_file = None def __enter__(self): self._resource = resources.open_binary(_RESOURCE_PACKAGE, _ABI_DUMP_ZIP_NAME) self.zip_file = zipfile.ZipFile(self._resource, "r") return self def __exit__(self, exc_type, exc_val, traceback): if self._resource: self._resource.close() if self.zip_file: self.zip_file.close() def GetAbiDumpPathsFromResources(version, binder_bitness, abi_name, abi_bitness): """Returns the VNDK dump paths in resources. Args: version: A string, the VNDK version. binder_bitness: A string or an integer, 32 or 64. abi_name: A string, the ABI of the library dump. abi_bitness: A string or an integer, 32 or 64. Returns: A dict of {library name: dump resource path}. For example, {"libbase.so": "R/64/arm64_armv8-a/source-based/libbase.so.lsdump"}. If there is no dump for the version and ABI, this function returns an empty dict. """ if not resources: logging.error("Could not import resources module.") return dict() abi_bitness = int(abi_bitness) try: arch_name = next(x[2] for x in _ABI_LIST if abi_name.startswith(x[0]) and x[1] == abi_bitness) except StopIteration: logging.warning("Unknown %d-bit ABI %s.", abi_bitness, abi_name) return dict() # The separator in zipped path is always "/". dump_dir = "/".join((version, str(binder_bitness), arch_name, "source-based")) + "/" dump_paths = dict() with AbiDumpResource() as dump_resource: for path in dump_resource.zip_file.namelist(): if path.startswith(dump_dir) and path.endswith(".lsdump"): lib_name = path[len(dump_dir):-len(".lsdump")] dump_paths[lib_name] = path return dump_paths def _LoadVndkLibraryListsFile(vndk_lists, tags, vndk_lib_list_file): """Load VNDK libraries from the file to the specified tuple. Args: vndk_lists: The output tuple of lists containing library names. tags: Strings, the tags of the libraries to find. vndk_lib_list_file: The file object containing the VNDK library list. """ lib_sets = collections.defaultdict(set) # Load VNDK tags from the list. for line in vndk_lib_list_file: # Ignore comments. if line.startswith('#'): continue # Split columns. cells = line.split(': ', 1) if len(cells) < 2: continue tag = cells[0] lib_name = cells[1].strip() lib_sets[tag].add(lib_name) # Compute VNDK-core-private and VNDK-SP-private. private = lib_sets.get('VNDK-private', set()) lib_sets[VNDK_PRIVATE].update(lib_sets[VNDK] & private) lib_sets[VNDK_SP_PRIVATE].update(lib_sets[VNDK_SP] & private) lib_sets[LL_NDK].difference_update(private) lib_sets[VNDK].difference_update(private) lib_sets[VNDK_SP].difference_update(private) # Update the output entries. for index, tag in enumerate(tags): for lib_name in lib_sets.get(tag, tuple()): if lib_name.startswith(_REGEX_PREFIX): lib_name = lib_name[len(_REGEX_PREFIX):] vndk_lists[index].append(lib_name) def LoadVndkLibraryLists(data_file_path, version, *tags): """Find the VNDK libraries with specific tags. Args: data_file_path: The path to VTS data directory. version: A string, the VNDK version. *tags: Strings, the tags of the libraries to find. Returns: A tuple of lists containing library names. Each list corresponds to one tag in the argument. For SP-HAL, the returned names are regular expressions. None if the spreadsheet for the version is not found. """ version_dir = (version if version else LoadDefaultVndkVersion(data_file_path)) if not version_dir: return None vndk_lib_list_path = os.path.join( data_file_path, _GOLDEN_DIR, version_dir, "vndk-lib-list.txt") if not os.path.isfile(vndk_lib_list_path): logging.warning("Cannot load %s.", vndk_lib_list_path) return None vndk_lib_extra_list_path = os.path.join( data_file_path, _GOLDEN_DIR, version_dir, "vndk-lib-extra-list.txt") if not os.path.isfile(vndk_lib_extra_list_path): logging.warning("Cannot load %s.", vndk_lib_extra_list_path) return None vndk_lists = tuple([] for x in tags) with open(vndk_lib_list_path, "r") as f: _LoadVndkLibraryListsFile(vndk_lists, tags, f) with open(vndk_lib_extra_list_path, "r") as f: _LoadVndkLibraryListsFile(vndk_lists, tags, f) return vndk_lists def LoadVndkLibraryListsFromResources(version, *tags): """Find the VNDK libraries with specific tags in resources. Args: version: A string, the VNDK version. *tags: Strings, the tags of the libraries to find. Returns: A tuple of lists containing library names. Each list corresponds to one tag in the argument. For SP-HAL, the returned names are regular expressions. None if the VNDK list for the version is not found. """ if not resources: logging.error("Could not import resources module.") return None version_str = (version if version and re.match("\\d+", version) else "current") vndk_lib_list_name = version_str + ".txt" vndk_lib_extra_list_name = "vndk-lib-extra-list-" + version_str + ".txt" if not resources.is_resource(_RESOURCE_PACKAGE, vndk_lib_list_name): logging.warning("Cannot load %s.", vndk_lib_list_name) return None if not resources.is_resource(_RESOURCE_PACKAGE, vndk_lib_extra_list_name): logging.warning("Cannot load %s.", vndk_lib_extra_list_name) return None vndk_lists = tuple([] for x in tags) with resources.open_text(_RESOURCE_PACKAGE, vndk_lib_list_name) as f: _LoadVndkLibraryListsFile(vndk_lists, tags, f) with resources.open_text(_RESOURCE_PACKAGE, vndk_lib_extra_list_name) as f: _LoadVndkLibraryListsFile(vndk_lists, tags, f) return vndk_lists