summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHsin-Yi Chen <hsinyichen@google.com>2019-11-18 11:05:40 +0800
committerHsin-Yi Chen <hsinyichen@google.com>2019-11-21 11:33:04 +0800
commit7b2cdca6e74ff5ec21a159a7af551300bff5548f (patch)
treee37feed0174741b41e88671326399dc9a7f8f719
parent850a88f26440a9af94a2a30a4076c7f25e158691 (diff)
downloadvndk-7b2cdca6e74ff5ec21a159a7af551300bff5548f.tar.gz
Search runpaths for ELF dependencies
This commit extends VtsVndkDependency to load runpaths from ELF. If an ELF object has runpaths under the permitted link paths, the linker searches the runpaths and the default paths for dependencies. Test: vts-tradefed run vts -m VtsVndkDependency -a arm64-v8a Bug: 144316411 Change-Id: Ib25399267e8eb3ee2b3d3c016560ce7554a83182
-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):