summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHsin-Yi Chen <hsinyichen@google.com>2019-11-27 20:02:48 -0800
committerandroid-build-merger <android-build-merger@google.com>2019-11-27 20:02:48 -0800
commit92a4343173b9267c778f84692e50fbcefc061422 (patch)
treee37feed0174741b41e88671326399dc9a7f8f719
parent6fc25f21ba0a9df321e6179f0f9ac62104e0af46 (diff)
parent4ac58572556870023bbd9908cffd33d992595b45 (diff)
downloadvndk-92a4343173b9267c778f84692e50fbcefc061422.tar.gz
Search runpaths for ELF dependencies am: 7b2cdca6e7
am: 4ac5857255 Change-Id: I538d140c38d98f91d6dc26ea784db4610fb0bda1
-rw-r--r--dependency/VtsVndkDependencyTest.py255
1 files changed, 119 insertions, 136 deletions
diff --git a/dependency/VtsVndkDependencyTest.py b/dependency/VtsVndkDependencyTest.py
index 0ad79e7..49ac575 100644
--- a/dependency/VtsVndkDependencyTest.py
+++ b/dependency/VtsVndkDependencyTest.py
@@ -15,6 +15,7 @@
# limitations under the License.
#
+import collections
import logging
import os
import re
@@ -51,6 +52,7 @@ class VtsVndkDependencyTest(base_test.BaseTestClass):
_SP_HAL_LINK_PATHS: Format strings of same-process HAL's link paths.
_VENDOR_LINK_PATHS: Format strings of vendor processes' link paths.
"""
+ _TARGET_DIR_SEP = "/"
_TARGET_ROOT_DIR = "/"
_TARGET_ODM_DIR = "/odm"
_TARGET_VENDOR_DIR = "/vendor"
@@ -76,14 +78,24 @@ class VtsVndkDependencyTest(base_test.BaseTestClass):
target_dir: String. The directory containing the ELF file on target.
bitness: Integer. Bitness of the ELF.
deps: List of strings. The names of the depended libraries.
+ runpaths: List of strings. The library search paths.
"""
- def __init__(self, target_path, bitness, deps):
+ def __init__(self, target_path, bitness, deps, runpaths):
self.target_path = target_path
self.name = path_utils.TargetBaseName(target_path)
self.target_dir = path_utils.TargetDirName(target_path)
self.bitness = bitness
self.deps = deps
+ # Format runpaths
+ self.runpaths = []
+ lib_dir_name = "lib64" if bitness == 64 else "lib"
+ for runpath in runpaths:
+ path = runpath.replace("${LIB}", lib_dir_name)
+ path = path.replace("$LIB", lib_dir_name)
+ path = path.replace("${ORIGIN}", self.target_dir)
+ path = path.replace("$ORIGIN", self.target_dir)
+ self.runpaths.append(path)
def setUpClass(self):
"""Initializes device, temporary directory, and VNDK lists."""
@@ -229,7 +241,7 @@ class VtsVndkDependencyTest(base_test.BaseTestClass):
logging.info("%s is not built for Android", target_path)
continue
- deps = elf.ListDependencies()
+ deps, runpaths = elf.ListDependencies()
except elf_parser.ElfError as e:
elf_error_handler(target_path, e)
continue
@@ -237,147 +249,85 @@ class VtsVndkDependencyTest(base_test.BaseTestClass):
elf.Close()
logging.info("%s depends on: %s", target_path, ", ".join(deps))
- objs.append(self.ElfObject(target_path, elf.bitness, deps))
+ if runpaths:
+ logging.info("%s has runpaths: %s",
+ target_path, ":".join(runpaths))
+ objs.append(self.ElfObject(target_path, elf.bitness, deps,
+ runpaths))
return objs
- def _DfsDependencies(self, lib, searched, searchable):
+ def _FindLibsInLinkPaths(self, bitness, link_paths, objs):
+ """Finds libraries in link paths.
+
+ Args:
+ bitness: 32 or 64, the bitness of the returned libraries.
+ link_paths: List of strings, the default link paths.
+ objs: List of ElfObject, the libraries/executables to be filtered
+ by bitness and path.
+
+ Returns:
+ A defaultdict, {dir: {name: obj}} where obj is an ElfObject, dir
+ is obj.target_dir, and name is obj.name.
+ """
+ namespace = collections.defaultdict(dict)
+ for obj in objs:
+ if (obj.bitness == bitness and
+ any(obj.target_path.startswith(link_path +
+ self._TARGET_DIR_SEP)
+ for link_path in link_paths)):
+ namespace[obj.target_dir][obj.name] = obj
+ return namespace
+
+ def _DfsDependencies(self, lib, searched, namespace, link_paths):
"""Depth-first-search for library dependencies.
Args:
- lib: ElfObject. The library to search dependencies.
+ lib: ElfObject, the library to search for dependencies.
searched: The set of searched libraries.
- searchable: The dictionary that maps file names to libraries.
+ namespace: Defaultdict, {dir: {name: obj}} containing all
+ searchable libraries.
+ link_paths: List of strings, the default link paths.
"""
if lib in searched:
return
searched.add(lib)
for dep_name in lib.deps:
- if dep_name in searchable:
- self._DfsDependencies(searchable[dep_name], searched,
- searchable)
+ for link_path in lib.runpaths + link_paths:
+ if dep_name in namespace[link_path]:
+ self._DfsDependencies(namespace[link_path][dep_name],
+ searched, namespace, link_paths)
+ break
- def _FindLibsInSpHalNamespace(self, bitness, objs):
- """Finds libraries in SP-HAL link paths.
+ def _FindDisallowedDependencies(self, objs, namespace, link_paths,
+ *vndk_lists):
+ """Tests if libraries/executables have disallowed dependencies.
Args:
- bitness: 32 or 64, the bitness of the returned libraries.
- objs: List of ElfObject, the libraries/executables in odm and
- vendor partitions.
+ objs: Collection of ElfObject, the libraries/executables under
+ test.
+ namespace: Defaultdict, {dir: {name: obj}} containing all libraries
+ in the linker namespace.
+ link_paths: List of strings, the default link paths.
+ vndk_lists: Collections of library names in VNDK, VNDK-SP, etc.
Returns:
- Dict of {string: ElfObject}, the library name and the first library
- in SP-HAL link paths.
- """
- sp_hal_link_paths = [vndk_utils.FormatVndkPath(x, bitness) for
- x in self._SP_HAL_LINK_PATHS]
- vendor_libs = [obj for obj in objs if
- obj.bitness == bitness and
- obj.target_dir in sp_hal_link_paths]
- linkable_libs = dict()
- for obj in vendor_libs:
- if obj.name not in linkable_libs:
- linkable_libs[obj.name] = obj
- else:
- linkable_libs[obj.name] = min(
- linkable_libs[obj.name], obj,
- key=lambda x: sp_hal_link_paths.index(x.target_dir))
- return linkable_libs
-
- def _FilterDisallowedDependencies(self, objs, is_allowed_dependency):
- """Returns libraries with disallowed dependencies.
-
- Args:
- objs: A collection of ElfObject, the libraries/executables.
- is_allowed_dependency: A function that takes the library name as the
- argument and returns whether objs can depend
- on the library.
-
- Returns:
- List of tuples (path, disallowed_dependencies). The library with
- disallowed dependencies and list of the dependencies.
+ List of tuples (path, disallowed_dependencies).
"""
dep_errors = []
for obj in objs:
- disallowed_libs = [
- x for x in obj.deps if not is_allowed_dependency(x)]
+ disallowed_libs = []
+ for dep_name in obj.deps:
+ if any((dep_name in vndk_list) for vndk_list in vndk_lists):
+ continue
+ if any((dep_name in namespace[link_path]) for link_path in
+ obj.runpaths + link_paths):
+ continue
+ disallowed_libs.append(dep_name)
+
if disallowed_libs:
dep_errors.append((obj.target_path, disallowed_libs))
return dep_errors
- def _TestVendorDependency(self, vendor_objs, vendor_libs):
- """Tests if vendor libraries/executables have disallowed dependencies.
-
- A vendor library/executable is allowed to depend on
- - LL-NDK
- - VNDK
- - VNDK-SP
- - Other libraries in vendor link paths.
-
- Args:
- vendor_objs: Collection of ElfObject, the libraries/executables in
- odm and vendor partitions, excluding VNDK-SP extension
- and SP-HAL.
- vendor_libs: Set of ElfObject, the libraries in vendor link paths,
- including SP-HAL.
-
- Returns:
- List of tuples (path, disallowed_dependencies).
- """
- vendor_lib_names = set(x.name for x in vendor_libs)
- is_allowed_dep = lambda x: (x in self._ll_ndk or
- x in self._vndk or
- x in self._vndk_sp or
- x in vendor_lib_names)
- return self._FilterDisallowedDependencies(vendor_objs, is_allowed_dep)
-
- def _TestVndkSpExtDependency(self, vndk_sp_ext_deps, vendor_libs):
- """Tests if VNDK-SP extension libraries have disallowed dependencies.
-
- A VNDK-SP extension library/dependency is allowed to depend on
- - LL-NDK
- - VNDK-SP
- - Libraries in vendor link paths
- - Other VNDK-SP extension libraries, which is a subset of VNDK-SP
-
- However, it is not allowed to indirectly depend on VNDK. i.e., the
- depended vendor libraries must not depend on VNDK.
-
- Args:
- vndk_sp_ext_deps: Collection of ElfObject, the VNDK-SP extension
- libraries and dependencies.
- vendor_libs: Set of ElfObject, the libraries in vendor link paths.
-
- Returns:
- List of tuples (path, disallowed_dependencies).
- """
- vendor_lib_names = set(x.name for x in vendor_libs)
- is_allowed_dep = lambda x: (x in self._ll_ndk or
- x in self._vndk_sp or
- x in vendor_lib_names)
- return self._FilterDisallowedDependencies(
- vndk_sp_ext_deps, is_allowed_dep)
-
- def _TestSpHalDependency(self, sp_hal_libs):
- """Tests if SP-HAL libraries have disallowed dependencies.
-
- A same-process HAL library is allowed to depend on
- - LL-NDK
- - VNDK-SP
- - Other same-process HAL libraries and dependencies
-
- Args:
- sp_hal_libs: Set of ElfObject, the Same-process HAL libraries and
- the dependencies.
-
- Returns:
- List of tuples (path, disallowed_dependencies).
- """
- sp_hal_lib_names = set(x.name for x in sp_hal_libs)
- is_allowed_dep = lambda x: (x in self._ll_ndk or
- x in self._vndk_sp or
- x in sp_hal_lib_names)
- return self._FilterDisallowedDependencies(sp_hal_libs, is_allowed_dep)
-
def _TestElfDependency(self, bitness, objs):
"""Tests vendor libraries/executables and SP-HAL dependencies.
@@ -390,22 +340,31 @@ class VtsVndkDependencyTest(base_test.BaseTestClass):
List of tuples (path, disallowed_dependencies).
"""
vndk_sp_ext_dirs = vndk_utils.GetVndkSpExtDirectories(bitness)
+
vendor_link_paths = [vndk_utils.FormatVndkPath(x, bitness) for
x in self._VENDOR_LINK_PATHS]
+ vendor_namespace = self._FindLibsInLinkPaths(bitness,
+ vendor_link_paths, objs)
+ # Exclude VNDK and VNDK-SP extensions from vendor libraries.
+ for vndk_ext_dir in (vndk_utils.GetVndkExtDirectories(bitness) +
+ vndk_utils.GetVndkSpExtDirectories(bitness)):
+ vendor_namespace.pop(vndk_ext_dir, None)
+ logging.info("%d-bit odm, vendor, and SP-HAL libraries:", bitness)
+ for dir_path, libs in vendor_namespace.iteritems():
+ logging.info("%s: %s", dir_path, ",".join(libs.iterkeys()))
- vendor_libs = set(obj for obj in objs if
- obj.bitness == bitness and
- obj.target_dir in vendor_link_paths)
- logging.info("%d-bit odm and vendor libraries including SP-HAL: %s",
- bitness, ", ".join(x.name for x in vendor_libs))
-
- sp_hal_namespace = self._FindLibsInSpHalNamespace(bitness, objs)
+ sp_hal_link_paths = [vndk_utils.FormatVndkPath(x, bitness) for
+ x in self._SP_HAL_LINK_PATHS]
+ sp_hal_namespace = self._FindLibsInLinkPaths(bitness,
+ sp_hal_link_paths, objs)
# Find same-process HAL and dependencies
sp_hal_libs = set()
- for obj in sp_hal_namespace.itervalues():
- if any(x.match(obj.target_path) for x in self._sp_hal):
- self._DfsDependencies(obj, sp_hal_libs, sp_hal_namespace)
+ for link_path in sp_hal_link_paths:
+ for obj in sp_hal_namespace[link_path].itervalues():
+ if any(x.match(obj.target_path) for x in self._sp_hal):
+ self._DfsDependencies(obj, sp_hal_libs, sp_hal_namespace,
+ sp_hal_link_paths)
logging.info("%d-bit SP-HAL libraries: %s",
bitness, ", ".join(x.name for x in sp_hal_libs))
@@ -415,26 +374,50 @@ class VtsVndkDependencyTest(base_test.BaseTestClass):
obj.target_dir in vndk_sp_ext_dirs)
vndk_sp_ext_deps = set()
for lib in vndk_sp_ext_libs:
- self._DfsDependencies(lib, vndk_sp_ext_deps, sp_hal_namespace)
+ self._DfsDependencies(lib, vndk_sp_ext_deps, sp_hal_namespace,
+ sp_hal_link_paths)
logging.info("%d-bit VNDK-SP extension libraries and dependencies: %s",
bitness, ", ".join(x.name for x in vndk_sp_ext_deps))
+ # A vendor library/executable is allowed to depend on
+ # LL-NDK
+ # VNDK
+ # VNDK-SP
+ # Other libraries in vendor link paths
vendor_objs = {obj for obj in objs if
obj.bitness == bitness and
obj not in sp_hal_libs and
obj not in vndk_sp_ext_deps}
- dep_errors = self._TestVendorDependency(vendor_objs, vendor_libs)
-
+ dep_errors = self._FindDisallowedDependencies(
+ vendor_objs, vendor_namespace, vendor_link_paths,
+ self._ll_ndk, self._vndk, self._vndk_sp)
+
+ # A VNDK-SP extension library/dependency is allowed to depend on
+ # LL-NDK
+ # VNDK-SP
+ # Libraries in vendor link paths
+ # Other VNDK-SP extension libraries, which is a subset of VNDK-SP
+ #
+ # However, it is not allowed to indirectly depend on VNDK. i.e., the
+ # depended vendor libraries must not depend on VNDK.
+ #
# vndk_sp_ext_deps and sp_hal_libs may overlap. Their dependency
# restrictions are the same.
- dep_errors.extend(self._TestVndkSpExtDependency(
- vndk_sp_ext_deps - sp_hal_libs, vendor_libs))
+ dep_errors.extend(self._FindDisallowedDependencies(
+ vndk_sp_ext_deps - sp_hal_libs, vendor_namespace,
+ vendor_link_paths, self._ll_ndk, self._vndk_sp))
if not vndk_utils.IsVndkRuntimeEnforced(self._dut):
logging.warning("Ignore dependency errors: %s", dep_errors)
dep_errors = []
- dep_errors.extend(self._TestSpHalDependency(sp_hal_libs))
+ # A same-process HAL library is allowed to depend on
+ # LL-NDK
+ # VNDK-SP
+ # Other same-process HAL libraries and dependencies
+ dep_errors.extend(self._FindDisallowedDependencies(
+ sp_hal_libs, sp_hal_namespace, sp_hal_link_paths,
+ self._ll_ndk, self._vndk_sp))
return dep_errors
def testElfDependency(self):