blob: 5e971aa5a98c9040b4a71e628856fb4901cbe9c6 [file] [log] [blame]
#
# 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