• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, legacy name ...). The legacy
50# name is for VNDK 32 and older versions. 64-bit comes before 32-bit in order
51# to sequentially search for longest prefix.
52_ABI_LIST = (
53    ("arm64", 64, "arm64", "arm64_armv8-a"),
54    ("arm64", 32, "arm_arm64", "arm_armv8-a"),
55    ("arm", 32, "arm", "arm_armv7-a-neon"),
56    ("x86_64", 64, "x86_64"),
57    ("x86_64", 32, "x86_x86_64"),
58    ("x86", 32, "x86"),
59)
60
61# The data directory.
62_GOLDEN_DIR = os.path.join("vts", "testcases", "vndk", "golden")
63
64# The data package.
65_RESOURCE_PACKAGE = "vts.testcases.vndk"
66
67# The name of the zip file containing ABI dumps.
68_ABI_DUMP_ZIP_NAME = "abi_dump.zip"
69
70# Regular expression prefix for library name patterns.
71_REGEX_PREFIX = "[regex]"
72
73
74class AbiDumpResource:
75    """The class for loading ABI dumps from the zip in resources."""
76
77    def __init__(self):
78        self._resource = None
79        self.zip_file = None
80
81    def __enter__(self):
82        self._resource = resources.open_binary(_RESOURCE_PACKAGE,
83                                               _ABI_DUMP_ZIP_NAME)
84        self.zip_file = zipfile.ZipFile(self._resource, "r")
85        return self
86
87    def __exit__(self, exc_type, exc_val, traceback):
88        if self._resource:
89            self._resource.close()
90        if self.zip_file:
91            self.zip_file.close()
92
93
94def GetAbiDumpPathsFromResources(version, binder_bitness, abi_name, abi_bitness):
95    """Returns the VNDK dump paths in resources.
96
97    Args:
98        version: A string, the VNDK version.
99        binder_bitness: A string or an integer, 32 or 64.
100        abi_name: A string, the ABI of the library dump.
101        abi_bitness: A string or an integer, 32 or 64.
102
103    Returns:
104        A dict of {library name: dump resource path}. For example,
105        {"libbase.so": "R/64/arm64_armv8-a/source-based/libbase.so.lsdump"}.
106        If there is no dump for the version and ABI, this function returns an
107        empty dict.
108    """
109    if not resources:
110        logging.error("Could not import resources module.")
111        return dict()
112
113    abi_bitness = int(abi_bitness)
114    try:
115        arch_names = next(x[2:] for x in _ABI_LIST if
116                          abi_name.startswith(x[0]) and x[1] == abi_bitness)
117    except StopIteration:
118        logging.warning("Unknown %d-bit ABI %s.", abi_bitness, abi_name)
119        return dict()
120
121    # The separator in zipped path is always "/".
122    dump_dirs = ["/".join((version, str(binder_bitness), arch_name,
123                           "source-based")) + "/"
124                 for arch_name in arch_names]
125    ext = ".lsdump"
126
127    dump_paths = dict()
128
129    with AbiDumpResource() as dump_resource:
130        for path in dump_resource.zip_file.namelist():
131            for dump_dir in dump_dirs:
132                if path.startswith(dump_dir) and path.endswith(ext):
133                    lib_name = path[len(dump_dir):-len(ext)]
134                    dump_paths[lib_name] = path
135                    break
136
137    return dump_paths
138
139
140def _LoadVndkLibraryListsFile(vndk_lists, tags, vndk_lib_list_file):
141    """Load VNDK libraries from the file to the specified tuple.
142
143    Args:
144        vndk_lists: The output tuple of lists containing library names.
145        tags: Strings, the tags of the libraries to find.
146        vndk_lib_list_file: The file object containing the VNDK library list.
147    """
148
149    lib_sets = collections.defaultdict(set)
150
151    # Load VNDK tags from the list.
152    for line in vndk_lib_list_file:
153        # Ignore comments.
154        if line.startswith('#'):
155            continue
156
157        # Split columns.
158        cells = line.split(': ', 1)
159        if len(cells) < 2:
160            continue
161        tag = cells[0]
162        lib_name = cells[1].strip()
163
164        lib_sets[tag].add(lib_name)
165
166    # Compute VNDK-core-private and VNDK-SP-private.
167    private = lib_sets.get('VNDK-private', set())
168
169    lib_sets[VNDK_PRIVATE].update(lib_sets[VNDK] & private)
170    lib_sets[VNDK_SP_PRIVATE].update(lib_sets[VNDK_SP] & private)
171
172    lib_sets[LL_NDK].difference_update(private)
173    lib_sets[VNDK].difference_update(private)
174    lib_sets[VNDK_SP].difference_update(private)
175
176    # Update the output entries.
177    for index, tag in enumerate(tags):
178        for lib_name in lib_sets.get(tag, tuple()):
179            if lib_name.startswith(_REGEX_PREFIX):
180                lib_name = lib_name[len(_REGEX_PREFIX):]
181            vndk_lists[index].append(lib_name)
182
183
184def LoadVndkLibraryListsFromResources(version, *tags):
185    """Find the VNDK libraries with specific tags in resources.
186
187    Args:
188        version: A string, the VNDK version.
189        *tags: Strings, the tags of the libraries to find.
190
191    Returns:
192        A tuple of lists containing library names. Each list corresponds to
193        one tag in the argument. For SP-HAL, the returned names are regular
194        expressions.
195        None if the VNDK list for the version is not found.
196    """
197    if not resources:
198        logging.error("Could not import resources module.")
199        return None
200
201    version_str = (version if version and re.match("\\d+", version) else
202                   "current")
203    vndk_lib_list_name = version_str + ".txt"
204    vndk_lib_extra_list_name = "vndk-lib-extra-list-" + version_str + ".txt"
205
206    if not resources.is_resource(_RESOURCE_PACKAGE, vndk_lib_list_name):
207        logging.warning("Cannot load %s.", vndk_lib_list_name)
208        return None
209
210    if not resources.is_resource(_RESOURCE_PACKAGE, vndk_lib_extra_list_name):
211        logging.warning("Cannot load %s.", vndk_lib_extra_list_name)
212        return None
213
214    vndk_lists = tuple([] for x in tags)
215
216    with resources.open_text(_RESOURCE_PACKAGE, vndk_lib_list_name) as f:
217        _LoadVndkLibraryListsFile(vndk_lists, tags, f)
218    with resources.open_text(_RESOURCE_PACKAGE, vndk_lib_extra_list_name) as f:
219        _LoadVndkLibraryListsFile(vndk_lists, tags, f)
220    return vndk_lists
221