vndk-def: Implement degenerated VNDK for o-release
This commit implements the degenerated directory layout for o-release.
This commit also simplifies the output significantly.
Test: Run vndk_definition_tool.py against o-release images.
Change-Id: I5aad29fa4ff7e819778d26d2e2011af1be61bb58
diff --git a/vndk/tools/definition-tool/datasets/minimum_dlopen_deps.txt b/vndk/tools/definition-tool/datasets/minimum_dlopen_deps.txt
new file mode 100644
index 0000000..b1f057c
--- /dev/null
+++ b/vndk/tools/definition-tool/datasets/minimum_dlopen_deps.txt
@@ -0,0 +1,12 @@
+/system/lib/libEGL.so:/system/lib/libEGL.so
+/system/lib/libEGL.so:/system/lib/libGLESv1_CM.so
+/system/lib/libEGL.so:/system/lib/libGLESv2.so
+/system/lib/libc.so:/system/lib/libc_malloc_debug.so
+/system/lib/libc.so:/system/lib/libicuuc.so
+/system/lib/libc.so:/system/lib/libnetd_client.so
+/system/lib64/libEGL.so:/system/lib64/libEGL.so
+/system/lib64/libEGL.so:/system/lib64/libGLESv1_CM.so
+/system/lib64/libEGL.so:/system/lib64/libGLESv2.so
+/system/lib64/libc.so:/system/lib64/libc_malloc_debug.so
+/system/lib64/libc.so:/system/lib64/libicuuc.so
+/system/lib64/libc.so:/system/lib64/libnetd_client.so
diff --git a/vndk/tools/definition-tool/tests/test_elf_linker.py b/vndk/tools/definition-tool/tests/test_elf_linker.py
index 402646c..68109f2 100755
--- a/vndk/tools/definition-tool/tests/test_elf_linker.py
+++ b/vndk/tools/definition-tool/tests/test_elf_linker.py
@@ -132,17 +132,13 @@
self.assertEqual(['/system/lib64/libdl.so'],
self._get_paths_from_nodes(nodes))
- def test_elf_class(self):
+ def test_elf_class_and_partitions(self):
gb = self._create_normal_graph()
graph = gb.graph
- self.assertEqual(6, len(graph.lib32))
- self.assertEqual(6, len(graph.lib64))
-
- def test_partitions(self):
- gb = self._create_normal_graph()
- graph = gb.graph
- self.assertEqual(10, len(gb.graph.lib_pt[PT_SYSTEM]))
- self.assertEqual(2, len(gb.graph.lib_pt[PT_VENDOR]))
+ self.assertEqual(5, len(graph.lib_pt[PT_SYSTEM].lib32))
+ self.assertEqual(5, len(graph.lib_pt[PT_SYSTEM].lib64))
+ self.assertEqual(1, len(graph.lib_pt[PT_VENDOR].lib32))
+ self.assertEqual(1, len(graph.lib_pt[PT_VENDOR].lib64))
def test_deps(self):
gb = self._create_normal_graph()
@@ -169,7 +165,7 @@
graph = gb.graph
# Check the unresolved symbols.
- for lib_set in (graph.lib32, graph.lib64):
+ for lib_set in graph.lib_pt:
for lib in lib_set.values():
self.assertEqual(set(), lib.unresolved_symbols)
@@ -237,6 +233,27 @@
node = graph.get_lib('/vendor/lib64/libEGL.so')
self.assertEqual([], self._get_paths_from_nodes(node.users))
+ def test_compute_predefined_fwk_only_rs(self):
+ lib_names = (
+ 'libft2',
+ 'libmediandk',
+ )
+
+ # Add VNDK-SP libraries.
+ gb = GraphBuilder()
+ for name in lib_names:
+ gb.add_multilib(PT_SYSTEM, name)
+ gb.resolve()
+
+ # Compute FWK-ONLY-RS and check the result.
+ fwk_only_rs = gb.graph.compute_predefined_fwk_only_rs()
+ fwk_only_rs = set(lib.path for lib in fwk_only_rs)
+
+ for lib_dir_name in ('lib', 'lib64'):
+ lib_dir = '/system/' + lib_dir_name
+ for name in lib_names:
+ self.assertIn(os.path.join(lib_dir, name + '.so'), fwk_only_rs)
+
def test_compute_predefined_vndk_sp(self):
lib_names = (
'android.hardware.graphics.allocator@2.0',
@@ -288,7 +305,6 @@
lib_names = (
'libbacktrace',
'libblas',
- 'libft2',
'liblzma',
'libpng',
'libunwind',
@@ -505,58 +521,6 @@
self.assertNotIn(libc_path, sp_ndk_indirect)
- def test_find_existing_vndk(self):
- gb = GraphBuilder()
-
- libpng32_core, libpng64_core = \
- gb.add_multilib(PT_SYSTEM, 'libpng', extra_dir='vndk-26')
- libpng32_fwk, libpng64_fwk = \
- gb.add_multilib(PT_SYSTEM, 'libpng', extra_dir='vndk-26-ext')
-
- libjpeg32_core, libjpeg64_core = \
- gb.add_multilib(PT_SYSTEM, 'libjpeg', extra_dir='vndk-26')
- libjpeg32_vnd, libjpeg64_vnd = \
- gb.add_multilib(PT_VENDOR, 'libjpeg', extra_dir='vndk-26-ext')
-
- gb.resolve()
-
- vndk_core, vndk_fwk_ext, vndk_vnd_ext = gb.graph.find_existing_vndk()
-
- expected_vndk_core = {
- libpng32_core, libpng64_core, libjpeg32_core, libjpeg64_core}
- expected_vndk_fwk_ext = {libpng32_fwk, libpng64_fwk}
- expected_vndk_vnd_ext = {libjpeg32_vnd, libjpeg64_vnd}
-
- self.assertSetEqual(expected_vndk_core, vndk_core)
- self.assertSetEqual(expected_vndk_fwk_ext, vndk_fwk_ext)
- self.assertSetEqual(expected_vndk_vnd_ext, vndk_vnd_ext)
-
- def test_find_existing_vndk_without_version(self):
- gb = GraphBuilder()
-
- libpng32_core, libpng64_core = \
- gb.add_multilib(PT_SYSTEM, 'libpng', extra_dir='vndk')
- libpng32_fwk, libpng64_fwk = \
- gb.add_multilib(PT_SYSTEM, 'libpng', extra_dir='vndk-ext')
-
- libjpeg32_core, libjpeg64_core = \
- gb.add_multilib(PT_SYSTEM, 'libjpeg', extra_dir='vndk')
- libjpeg32_vnd, libjpeg64_vnd = \
- gb.add_multilib(PT_VENDOR, 'libjpeg', extra_dir='vndk-ext')
-
- gb.resolve()
-
- vndk_core, vndk_fwk_ext, vndk_vnd_ext = gb.graph.find_existing_vndk()
-
- expected_vndk_core = {
- libpng32_core, libpng64_core, libjpeg32_core, libjpeg64_core}
- expected_vndk_fwk_ext = {libpng32_fwk, libpng64_fwk}
- expected_vndk_vnd_ext = {libjpeg32_vnd, libjpeg64_vnd}
-
- self.assertSetEqual(expected_vndk_core, vndk_core)
- self.assertSetEqual(expected_vndk_fwk_ext, vndk_fwk_ext)
- self.assertSetEqual(expected_vndk_vnd_ext, vndk_vnd_ext)
-
def test_compute_vndk_cap(self):
gb = GraphBuilder()
diff --git a/vndk/tools/definition-tool/tests/test_generic_refs.py b/vndk/tools/definition-tool/tests/test_generic_refs.py
index eb20c96..c887d19 100755
--- a/vndk/tools/definition-tool/tests/test_generic_refs.py
+++ b/vndk/tools/definition-tool/tests/test_generic_refs.py
@@ -87,6 +87,12 @@
self.assertTrue(self.ref.is_equivalent_lib(libc_eq))
+ def test_has_same_name_lib(self):
+ self.assertTrue(self.ref.has_same_name_lib(
+ MockLib('/vendor/lib/libc.so', {})))
+ self.assertFalse(self.ref.has_same_name_lib(
+ MockLib('/vendor/lib/lib_does_not_exist.so', {})))
+
if __name__ == '__main__':
unittest.main()
diff --git a/vndk/tools/definition-tool/tests/test_vndk.py b/vndk/tools/definition-tool/tests/test_vndk.py
deleted file mode 100755
index 773ac12..0000000
--- a/vndk/tools/definition-tool/tests/test_vndk.py
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/usr/bin/env python3
-
-from __future__ import print_function
-
-import os
-import sys
-sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-import unittest
-
-from compat import StringIO
-from vndk_definition_tool import (ELF, ELFLinker, PT_SYSTEM, PT_VENDOR,
- GenericRefs, SPLibResult)
-
-SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-TESTDATA_DIR = os.path.join(SCRIPT_DIR ,'testdata', 'test_vndk')
-
-class MockBannedLibs(object):
- def is_banned(self, name):
- return False
-
-class ELFLinkerVNDKTest(unittest.TestCase):
- def _get_paths_from_nodes(self, nodes):
- return sorted([node.path for node in nodes])
-
- def _create_graph_gr(self, input_dir, generic_refs_dir):
- if not generic_refs_dir:
- generic_refs = None
- else:
- generic_refs_dir = os.path.join(TESTDATA_DIR, generic_refs_dir)
- generic_refs = GenericRefs.create_from_sym_dir(generic_refs_dir)
-
- input_dir = os.path.join(TESTDATA_DIR, input_dir)
-
- graph = ELFLinker.create_from_dump(
- system_dirs=[os.path.join(input_dir, 'system')],
- vendor_dirs=[os.path.join(input_dir, 'vendor')],
- generic_refs=generic_refs)
-
- return (graph, generic_refs)
-
- def _create_graph_vndk(self, input_dir, generic_refs_dir):
- graph, generic_refs = self._create_graph_gr(input_dir, generic_refs_dir)
-
- vndk = graph._compute_vndk(
- sp_lib=SPLibResult(set(), set(), set(), set(), set(), set()),
- vndk_customized_for_system=set(),
- vndk_customized_for_vendor=set(),
- generic_refs=generic_refs,
- banned_libs=MockBannedLibs())
-
- return (graph, vndk)
-
- def test_compute_vndk(self):
- graph, vndk = self._create_graph_vndk('pre_treble', None)
-
- self.assertEqual(['/system/lib/vndk/libcutils.so',
- '/system/lib64/vndk/libcutils.so'],
- self._get_paths_from_nodes(vndk.vndk_core))
- self.assertEqual([], self._get_paths_from_nodes(vndk.vndk_fwk_ext))
- self.assertEqual([], self._get_paths_from_nodes(vndk.vndk_vnd_ext))
-
- def test_compute_vndk_indirect_no_gr(self):
- graph, vndk = self._create_graph_vndk('vndk_indirect', None)
-
- self.assertEqual(['/system/lib/vndk/libcutils.so',
- '/system/lib64/vndk/libcutils.so'],
- self._get_paths_from_nodes(vndk.vndk_core))
- self.assertEqual(['/system/lib/vndk/libcutils_dep.so',
- '/system/lib64/vndk/libcutils_dep.so'],
- self._get_paths_from_nodes(vndk.vndk_indirect))
-
- def test_compute_vndk_fwk_ext(self):
- graph, vndk = self._create_graph_vndk('vndk_fwk_ext', 'vndk_gr')
-
- self.assertEqual(['/system/lib/vndk/libRS.so',
- '/system/lib/vndk/libcutils.so',
- '/system/lib64/vndk/libRS.so',
- '/system/lib64/vndk/libcutils.so'],
- self._get_paths_from_nodes(vndk.vndk_core))
- self.assertEqual(['/system/lib/vndk-ext/libRS.so',
- '/system/lib64/vndk-ext/libRS.so'],
- self._get_paths_from_nodes(vndk.vndk_fwk_ext))
- self.assertEqual([], self._get_paths_from_nodes(vndk.vndk_vnd_ext))
-
- def test_compute_vndk_vnd_ext(self):
- graph, vndk = self._create_graph_vndk('vndk_vnd_ext', 'vndk_gr')
-
- self.assertEqual(['/system/lib/vndk/libRS.so',
- '/system/lib/vndk/libcutils.so',
- '/system/lib64/vndk/libRS.so',
- '/system/lib64/vndk/libcutils.so'],
- self._get_paths_from_nodes(vndk.vndk_core))
- self.assertEqual([], self._get_paths_from_nodes(vndk.vndk_fwk_ext))
- self.assertEqual(['/vendor/lib/vndk-ext/libRS.so',
- '/vendor/lib64/vndk-ext/libRS.so'],
- self._get_paths_from_nodes(vndk.vndk_vnd_ext))
-
- def test_compute_vndk_inward_customization(self):
- graph, generic_refs = self._create_graph_gr(
- 'vndk_inward_customization', 'vndk_gr')
-
- # Make sure libjpeg.so was loaded from the input dir.
- libjpeg_32 = graph.get_lib('/system/lib/libjpeg.so')
- self.assertIsNotNone(libjpeg_32)
- libjpeg_64 = graph.get_lib('/system/lib64/libjpeg.so')
- self.assertIsNotNone(libjpeg_64)
-
- # Compute vndk sets and move libraries to the correct directories.
- vndk = graph._compute_vndk(
- sp_lib=SPLibResult(set(), set(), set(), set(), set(), set()),
- vndk_customized_for_system=set(),
- vndk_customized_for_vendor=set(),
- generic_refs=generic_refs,
- banned_libs=MockBannedLibs())
-
- # Check vndk-core libraries.
- self.assertEqual(['/system/lib/vndk/libRS.so',
- '/system/lib/vndk/libcutils.so',
- '/system/lib64/vndk/libRS.so',
- '/system/lib64/vndk/libcutils.so'],
- self._get_paths_from_nodes(vndk.vndk_core))
-
- # Check vndk-indirect libraries.
- self.assertEqual(['/system/lib/vndk/libjpeg.so',
- '/system/lib64/vndk/libjpeg.so'],
- self._get_paths_from_nodes(vndk.vndk_indirect))
-
- # Check libjpeg.so (inward-customization) has been renamed.
- self.assertIsNone(graph.get_lib('/system/lib/libjpeg.so'))
- self.assertIsNone(graph.get_lib('/system/lib64/libjpeg.so'))
- self.assertIs(libjpeg_32,
- graph.get_lib('/system/lib/vndk/libjpeg.so'))
- self.assertIs(libjpeg_64,
- graph.get_lib('/system/lib64/vndk/libjpeg.so'))
-
- # Check the absence of vndk-ext libraries.
- self.assertEqual([], self._get_paths_from_nodes(vndk.vndk_fwk_ext))
- self.assertEqual([], self._get_paths_from_nodes(vndk.vndk_vnd_ext))
-
- def test_compute_vndk_indirect_ext(self):
- # This test case reveals a corner case that will break vndk-indirect
- # computation. To reproduce the case, the following condition must be
- # satisfied:
- #
- # 1. libA depends on libB.
- # 2. libA is a vndk-fwk-ext.
- # 3. libB is an outward-customized vndk which depends on non-AOSP libC.
- #
- # Both AOSP libA and libB will be added to vndk-core. But,
- # unfortunately, libA will be resolved to libB in vndk-fwk-ext and this
- # will break the vndk-indirect computation because libC is not in
- # generic references.
-
- graph, vndk = self._create_graph_vndk('vndk_indirect_ext',
- 'vndk_indirect_ext_gr')
-
- self.assertEqual(['/system/lib/vndk/libRS.so',
- '/system/lib/vndk/libcutils.so',
- '/system/lib64/vndk/libRS.so',
- '/system/lib64/vndk/libcutils.so'],
- self._get_paths_from_nodes(vndk.vndk_core))
-
- self.assertEqual(['/system/lib/vndk/libRS_internal.so',
- '/system/lib64/vndk/libRS_internal.so'],
- self._get_paths_from_nodes(vndk.vndk_indirect))
-
- self.assertEqual(['/system/lib/vndk-ext/libRS_internal.so',
- '/system/lib64/vndk-ext/libRS_internal.so'],
- self._get_paths_from_nodes(vndk.vndk_fwk_ext))
-
- def test_compute_vndk_ext_deps(self):
- # This test case reveals a bug in the vndk-core dependencies assertion.
- # This will happen when libA and libB are added to both vndk-fwk-ext and
- # vndk-vnd-ext in the first round, libA depends libC, libC depends
- # libB.
-
- graph, vndk = self._create_graph_vndk('vndk_ext_dep', 'vndk_ext_dep_gr')
-
- self.assertEqual(['/system/lib/vndk/libA.so',
- '/system/lib/vndk/libB.so',
- '/system/lib/vndk/libC.so'],
- self._get_paths_from_nodes(vndk.vndk_core))
-
- self.assertEqual(['/system/lib/vndk-ext/libA.so',
- '/system/lib/vndk-ext/libB.so',
- '/system/lib/vndk-ext/libC.so'],
- self._get_paths_from_nodes(vndk.vndk_fwk_ext))
-
- self.assertEqual(['/vendor/lib/vndk-ext/libA.so',
- '/vendor/lib/vndk-ext/libB.so',
- '/vendor/lib/vndk-ext/libC.so'],
- self._get_paths_from_nodes(vndk.vndk_vnd_ext))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/vndk/tools/definition-tool/vndk_definition_tool.py b/vndk/tools/definition-tool/vndk_definition_tool.py
index d4bd06b..46c587f 100755
--- a/vndk/tools/definition-tool/vndk_definition_tool.py
+++ b/vndk/tools/definition-tool/vndk_definition_tool.py
@@ -4,6 +4,7 @@
import argparse
import collections
+import copy
import csv
import itertools
import json
@@ -52,6 +53,58 @@
#------------------------------------------------------------------------------
+# Collections
+#------------------------------------------------------------------------------
+
+def defaultnamedtuple(typename, field_names, default):
+ """Create a namedtuple type with default values.
+
+ This function creates a namedtuple type which will fill in default value
+ when actual arguments to the constructor were omitted.
+
+ >>> Point = defaultnamedtuple('Point', ['x', 'y'], 0)
+ >>> Point()
+ Point(x=0, y=0)
+ >>> Point(1)
+ Point(x=1, y=0)
+ >>> Point(1, 2)
+ Point(x=1, y=2)
+ >>> Point(x=1, y=2)
+ Point(x=1, y=2)
+ >>> Point(y=2, x=1)
+ Point(x=1, y=2)
+
+ >>> PermSet = defaultnamedtuple('PermSet', 'allowed disallowed', set())
+ >>> s = PermSet()
+ >>> s
+ PermSet(allowed=set(), disallowed=set())
+ >>> s.allowed is not s.disallowed
+ True
+ >>> PermSet({1})
+ PermSet(allowed={1}, disallowed=set())
+ >>> PermSet({1}, {2})
+ PermSet(allowed={1}, disallowed={2})
+ """
+
+ if isinstance(field_names, str):
+ field_names = field_names.replace(',', ' ').split()
+ field_names = list(map(str, field_names))
+ num_fields = len(field_names)
+
+ base_cls = collections.namedtuple(typename, field_names)
+ def __new__(cls, *args, **kwargs):
+ args = list(args)
+ for i in range(len(args), num_fields):
+ arg = kwargs.get(field_names[i])
+ if arg:
+ args.append(arg)
+ else:
+ args.append(copy.copy(default))
+ return base_cls.__new__(cls, *args)
+ return type(typename, (base_cls,), {'__new__': __new__})
+
+
+#------------------------------------------------------------------------------
# ELF Parser
#------------------------------------------------------------------------------
@@ -621,31 +674,6 @@
NUM_PARTITIONS = 2
-VNDKResult = collections.namedtuple(
- 'VNDKResult',
- 'sp_hal sp_hal_dep vndk_sp_hal sp_ndk sp_ndk_indirect '
- 'vndk_sp_both '
- 'extra_vendor_lib vndk_core vndk_indirect vndk_fwk_ext vndk_vnd_ext')
-
-def print_vndk_lib(vndk_lib, file=sys.stdout):
- # SP-NDK and SP-HAL
- print_sp_lib(vndk_lib, file=file)
-
- # VNDK (framework)
- for lib in sorted_lib_path_list(vndk_lib.vndk_core):
- print('vndk-core:', lib, file=file)
- for lib in sorted_lib_path_list(vndk_lib.vndk_indirect):
- print('vndk-indirect:', lib, file=file)
- for lib in sorted_lib_path_list(vndk_lib.vndk_fwk_ext):
- print('vndk-fwk-ext:', lib, file=file)
-
- # VNDK (vendor)
- for lib in sorted_lib_path_list(vndk_lib.vndk_vnd_ext):
- print('vndk-vnd-ext:', lib, file=file)
- for lib in sorted_lib_path_list(vndk_lib.extra_vendor_lib):
- print('extra-vendor-lib:', lib, file=file)
-
-
SPLibResult = collections.namedtuple(
'SPLibResult',
'sp_hal sp_hal_dep vndk_sp_hal sp_ndk sp_ndk_indirect '
@@ -807,44 +835,53 @@
libs.sort()
return libs
+_VNDK_RESULT_FIELD_NAMES = (
+ 'll_ndk', 'll_ndk_indirect', 'sp_ndk', 'sp_ndk_indirect',
+ 'vndk_sp', 'vndk_sp_unused', 'vndk_sp_indirect',
+ 'vndk_sp_indirect_unused', 'vndk_sp_indirect_private', 'vndk',
+ 'vndk_indirect', 'fwk_only', 'fwk_only_rs', 'sp_hal', 'sp_hal_dep',
+ 'vnd_only', 'vndk_ext', 'vndk_sp_ext', 'vndk_sp_indirect_ext',
+ 'extra_vndk_sp_indirect')
+
+VNDKResult = defaultnamedtuple('VNDKResult', _VNDK_RESULT_FIELD_NAMES, set())
+
+
+class ELFLibDict(defaultnamedtuple('ELFLibDict', ('lib32', 'lib64'), {})):
+ def get_lib_dict(self, elf_class):
+ return self[elf_class - 1]
+
+ def add(self, path, lib):
+ self.get_lib_dict(lib.elf.ei_class)[path] = lib
+
+ def remove(self, lib):
+ del self.get_lib_dict(lib.elf.ei_class)[lib.path]
+
+ def get(self, path, default=None):
+ for lib_set in self:
+ res = lib_set.get(path, None)
+ if res:
+ return res
+ return default
+
+ def keys(self):
+ return itertools.chain(self.lib32.keys(), self.lib64.keys())
+
+ def values(self):
+ return itertools.chain(self.lib32.values(), self.lib64.values())
+
+ def items(self):
+ return itertools.chain(self.lib32.items(), self.lib64.items())
+
class ELFLinker(object):
- LIB32_SEARCH_PATH = (
- '/system/lib',
- '/system/lib/vndk',
- '/system/lib/vndk-ext',
- '/vendor/lib',
- )
-
- LIB64_SEARCH_PATH = (
- '/system/lib64',
- '/system/lib64/vndk',
- '/system/lib64/vndk-ext',
- '/vendor/lib64',
- )
-
-
def __init__(self):
- self.lib32 = dict()
- self.lib64 = dict()
- self.lib_pt = [dict() for i in range(NUM_PARTITIONS)]
-
- self.lib32_resolver = ELFResolver(self.lib32, self.LIB32_SEARCH_PATH)
- self.lib64_resolver = ELFResolver(self.lib64, self.LIB64_SEARCH_PATH)
+ self.lib_pt = [ELFLibDict() for i in range(NUM_PARTITIONS)]
def _add_lib_to_lookup_dict(self, lib):
- if lib.elf.is_32bit:
- self.lib32[lib.path] = lib
- else:
- self.lib64[lib.path] = lib
- self.lib_pt[lib.partition][lib.path] = lib
+ self.lib_pt[lib.partition].add(lib.path, lib)
def _remove_lib_from_lookup_dict(self, lib):
- if lib.elf.is_32bit:
- del self.lib32[lib.path]
- else:
- del self.lib64[lib.path]
- del self.lib_pt[lib.partition][lib.path]
+ self.lib_pt[lib.partition].remove(lib)
def add_lib(self, partition, path, elf):
lib = ELFLinkData(partition, path, elf)
@@ -858,32 +895,52 @@
self._add_lib_to_lookup_dict(lib)
def add_dep(self, src_path, dst_path, ty):
- for lib_set in (self.lib32, self.lib64):
- src = lib_set.get(src_path)
- dst = lib_set.get(dst_path)
+ for elf_class in (ELF.ELFCLASS32, ELF.ELFCLASS64):
+ src = self.get_lib_in_elf_class(elf_class, src_path)
+ dst = self.get_lib_in_elf_class(elf_class, dst_path)
if src and dst:
src.add_dep(dst, ty)
return
print('error: cannot add dependency from {} to {}.'
.format(src_path, dst_path), file=sys.stderr)
+ def get_lib_in_elf_class(self, elf_class, path, default=None):
+ for partition in range(NUM_PARTITIONS):
+ res = self.lib_pt[partition].get_lib_dict(elf_class).get(path)
+ if res:
+ return res
+ return default
+
def get_lib(self, path):
- for lib_set in (self.lib32, self.lib64):
+ for lib_set in self.lib_pt:
lib = lib_set.get(path)
if lib:
return lib
return None
- def get_libs(self, paths, report_error):
+ def get_libs(self, paths, report_error=None):
result = set()
for path in paths:
lib = self.get_lib(path)
if not lib:
+ if report_error is None:
+ raise ValueError('path not found ' + path)
report_error(path)
continue
result.add(lib)
return result
+ def all_libs(self):
+ for lib_set in self.lib_pt:
+ for lib in lib_set.values():
+ yield lib
+
+ def _compute_lib_dict(self, elf_class):
+ res = dict()
+ for lib_pt in self.lib_pt:
+ res.update(lib_pt.get_lib_dict(elf_class))
+ return res
+
@staticmethod
def _compile_path_matcher(root, subdirs):
dirs = [os.path.normpath(os.path.join(root, i)) for i in subdirs]
@@ -965,27 +1022,84 @@
self._resolve_lib_imported_symbols(lib, imported_libs, generic_refs)
def _resolve_lib_set_deps(self, lib_set, resolver, generic_refs):
- for lib in lib_set.values():
+ for lib in lib_set:
self._resolve_lib_deps(lib, resolver, generic_refs)
- def resolve_deps(self, generic_refs=None):
- self._resolve_lib_set_deps(
- self.lib32, self.lib32_resolver, generic_refs)
- self._resolve_lib_set_deps(
- self.lib64, self.lib64_resolver, generic_refs)
+ SYSTEM_SEARCH_PATH = (
+ '/system/${LIB}',
+ '/vendor/${LIB}',
+ )
- def all_lib(self):
- for lib_set in self.lib_pt:
- for lib in lib_set.values():
- yield lib
+ VENDOR_SEARCH_PATH = (
+ '/vendor/${LIB}',
+ '/vendor/${LIB}/vndk-sp',
+ '/system/${LIB}/vndk-sp',
+ '/system/${LIB}', # For degenerated VNDK libs.
+ )
+
+ VNDK_SP_SEARCH_PATH = (
+ '/vendor/${LIB}/vndk-sp',
+ '/system/${LIB}/vndk-sp',
+ '/vendor/${LIB}', # To discover missing vndk-sp dependencies.
+ '/system/${LIB}', # To discover missing vndk-sp dependencies.
+ )
+
+ @staticmethod
+ def _subst_search_path(search_path, elf_class):
+ lib_dir_name = 'lib' if elf_class == ELF.ELFCLASS32 else 'lib64'
+ return [path.replace('${LIB}', lib_dir_name) for path in search_path]
+
+ @staticmethod
+ def _is_in_vndk_sp_dir(path):
+ return os.path.basename(os.path.dirname(path)).startswith('vndk-sp')
+
+ def _resolve_elf_class_deps(self, elf_class, generic_refs):
+ system_lib_dict = self.lib_pt[PT_SYSTEM].get_lib_dict(elf_class)
+ vendor_lib_dict = self.lib_pt[PT_VENDOR].get_lib_dict(elf_class)
+ lib_dict = self._compute_lib_dict(elf_class)
+
+ # Resolve system libs.
+ system_libs = [lib for lib in system_lib_dict.values()
+ if not self._is_in_vndk_sp_dir(lib.path)]
+ search_path = self._subst_search_path(
+ self.SYSTEM_SEARCH_PATH, elf_class)
+ resolver = ELFResolver(lib_dict, search_path)
+ self._resolve_lib_set_deps(system_libs, resolver, generic_refs)
+
+ # Resolve vendor libs.
+ vendor_libs = [lib for lib in vendor_lib_dict.values()
+ if not self._is_in_vndk_sp_dir(lib.path)]
+ search_path = self._subst_search_path(
+ self.VENDOR_SEARCH_PATH, elf_class)
+ resolver = ELFResolver(lib_dict, search_path)
+ self._resolve_lib_set_deps(vendor_libs, resolver, generic_refs)
+
+ # Resolve vndk-sp libs
+ vndk_sp = [lib for lib in lib_dict.values()
+ if self._is_in_vndk_sp_dir(lib.path)]
+ search_path = self._subst_search_path(
+ self.VNDK_SP_SEARCH_PATH, elf_class)
+ resolver = ELFResolver(lib_dict, search_path)
+ self._resolve_lib_set_deps(vndk_sp, resolver, generic_refs)
+
+ def resolve_deps(self, generic_refs=None):
+ self._resolve_elf_class_deps(ELF.ELFCLASS32, generic_refs)
+ self._resolve_elf_class_deps(ELF.ELFCLASS64, generic_refs)
def compute_path_matched_lib(self, path_patterns):
patt = re.compile('|'.join('(?:' + p + ')' for p in path_patterns))
- return set(lib for lib in self.all_lib() if patt.match(lib.path))
+ return set(lib for lib in self.all_libs() if patt.match(lib.path))
+
+ def compute_predefined_fwk_only_rs(self):
+ """Find all fwk-only-rs libraries."""
+ path_patterns = (
+ '^/system/lib(?:64)?/libft2\\.so$',
+ '^/system/lib(?:64)?/libmediandk\\.so',
+ )
+ return self.compute_path_matched_lib(path_patterns)
def compute_predefined_vndk_sp(self):
"""Find all vndk-sp libraries."""
-
path_patterns = (
# Visible to SP-HALs
'^.*/android\\.hardware\\.graphics\\.allocator@2\\.0\\.so$',
@@ -1012,14 +1126,12 @@
)
return self.compute_path_matched_lib(path_patterns)
-
def compute_predefined_vndk_sp_indirect(self):
"""Find all vndk-sp-indirect libraries."""
path_patterns = (
# Invisible to SP-HALs
'^.*/libbacktrace\\.so$',
'^.*/libblas\\.so$',
- '^.*/libft2\\.so$',
'^.*/liblzma\\.so$',
'^.*/libpng\\.so$',
'^.*/libunwind\\.so$',
@@ -1049,7 +1161,7 @@
def compute_sp_ndk(self):
"""Find all SP-NDK libraries."""
- return set(lib for lib in self.all_lib() if lib.is_sp_ndk)
+ return set(lib for lib in self.all_libs() if lib.is_sp_ndk)
def compute_sp_lib(self, generic_refs):
def is_ndk(lib):
@@ -1103,9 +1215,8 @@
return self._po_sorted(lib_set, lambda x: x.users)
def normalize_partition_tags(self, sp_hals, generic_refs):
- system_libs_po = self._deps_po_sorted(self.lib_pt[PT_SYSTEM].values())
- system_libs = self.lib_pt[PT_SYSTEM]
- vendor_libs = self.lib_pt[PT_VENDOR]
+ system_libs = set(self.lib_pt[PT_SYSTEM].values())
+ system_libs_po = self._deps_po_sorted(system_libs)
def is_system_lib_or_sp_hal(lib):
return lib.is_system_lib() or lib in sp_hals
@@ -1142,346 +1253,187 @@
'vendor partition.'
.format(lib.path, dep.path, lib.path),
file=sys.stderr)
- lib.partition = PT_VENDOR
- vendor_libs[lib.path] = lib
- del system_libs[lib.path]
+ new_path = lib.path.replace('/system/', '/vendor/')
+ self.rename_lib(lib, PT_VENDOR, new_path)
- def find_existing_vndk(self):
- def collect_libs_with_path_pattern(pattern):
- result = set()
- pattern = re.compile(pattern)
- for lib_set in (self.lib32.values(), self.lib64.values()):
- for lib in lib_set:
- if pattern.match(lib.path):
- result.add(lib)
- return result
+ def compute_degenerated_vndk(self, sp_lib, generic_refs,
+ tagged_paths=None,
+ action_ineligible_vndk_sp='follow,warn',
+ action_ineligible_vndk='follow,warn'):
+ # Find LL-NDK and SP-NDK libs.
+ ll_ndk = set(lib for lib in self.all_libs() if lib.is_ll_ndk)
- vndk_core = collect_libs_with_path_pattern(
- '^/system/lib(?:64)?/vndk(?:-\\d+)?/')
- vndk_fwk_ext = collect_libs_with_path_pattern(
- '^/system/lib(?:64)?/vndk(?:-\\d+)?-ext?/')
- vndk_vnd_ext = collect_libs_with_path_pattern(
- '^/vendor/lib(?:64)?/vndk(?:-\\d+)?-ext?/')
+ def is_not_ll_ndk_indirect(lib):
+ return lib.is_ll_ndk
- return (vndk_core, vndk_fwk_ext, vndk_vnd_ext)
+ ll_ndk_indirect = self.compute_closure(ll_ndk, is_not_ll_ndk_indirect)
+ ll_ndk_indirect -= ll_ndk
- def compute_vndk(self, vndk_customized_for_system,
- vndk_customized_for_vendor, generic_refs, banned_libs):
- return self._compute_vndk(
- self.compute_sp_lib(generic_refs), vndk_customized_for_system,
- vndk_customized_for_vendor, generic_refs, banned_libs)
+ sp_ndk = set(lib for lib in self.all_libs() if lib.is_sp_ndk)
- def _compute_vndk(self, sp_lib, vndk_customized_for_system,
- vndk_customized_for_vendor, generic_refs, banned_libs):
- # Compute sp-hal and vndk-sp.
- vndk_sp = sp_lib.vndk_sp_hal | sp_lib.sp_ndk_indirect | \
- sp_lib.vndk_sp_both
- sp_hal_closure = sp_lib.sp_hal | sp_lib.sp_hal_dep
+ def is_not_sp_ndk_indirect(lib):
+ return lib.is_ll_ndk or lib.is_sp_ndk or lib in ll_ndk_indirect
+
+ sp_ndk_indirect = self.compute_closure(sp_ndk, is_not_sp_ndk_indirect)
+ sp_ndk_indirect -= sp_ndk
+
+ # Find SP-HAL libs.
+ sp_hal = self.compute_predefined_sp_hal()
# Normalize partition tags. We expect many violations from the
# pre-Treble world. Guess a resolution for the incorrect partition
# tag.
- self.normalize_partition_tags(sp_lib.sp_hal, generic_refs)
+ self.normalize_partition_tags(sp_hal, generic_refs)
- # ELF resolvers.
- VNDK_CORE_SEARCH_PATH32 = (
- '/system/lib/vndk',
- '/system/lib',
- )
+ # Find SP-HAL-Dep libs.
+ def is_not_sp_hal_dep(lib):
+ if lib.is_ll_ndk or lib.is_sp_ndk or lib in sp_hal:
+ return True
+ if not generic_refs:
+ # Use simple heuristic when generic reference is not available.
+ return lib.partition == PT_SYSTEM
+ return generic_refs.has_same_name_lib(lib)
- VNDK_CORE_SEARCH_PATH64 = (
- '/system/lib64/vndk',
- '/system/lib64',
- )
+ sp_hal_dep = self.compute_closure(sp_hal, is_not_sp_hal_dep)
+ sp_hal_dep -= sp_hal
- VENDOR_SEARCH_PATH32 = (
- '/system/lib/vndk',
- '/vendor/lib',
+ # Find FWK-ONLY-RS libs.
+ fwk_only_rs = self.compute_predefined_fwk_only_rs()
- # FIXME: Remove following line after we fixed vndk-sp resolution.
- '/system/lib',
- )
+ # Find VNDK-SP libs.
+ def is_not_vndk_sp(lib):
+ return lib.is_ll_ndk or lib.is_sp_ndk or lib in sp_hal or \
+ lib in sp_hal_dep
- VENDOR_SEARCH_PATH64 = (
- '/system/lib64/vndk',
- '/vendor/lib64',
-
- # FIXME: Remove following line after we fixed vndk-sp resolution.
- '/system/lib64',
- )
-
- vndk_core_resolver32 = ELFResolver(self.lib32, VNDK_CORE_SEARCH_PATH32)
- vndk_core_resolver64 = ELFResolver(self.lib64, VNDK_CORE_SEARCH_PATH64)
- vendor_resolver32 = ELFResolver(self.lib32, VENDOR_SEARCH_PATH32)
- vendor_resolver64 = ELFResolver(self.lib64, VENDOR_SEARCH_PATH64)
-
- # Collect existing VNDK libraries.
- vndk_core, vndk_fwk_ext, vndk_vnd_ext = self.find_existing_vndk()
-
- # Collect VNDK candidates.
- def is_not_vndk(lib):
- return (lib.is_ndk or banned_libs.is_banned(lib.path) or
- (lib in sp_hal_closure) or (lib in vndk_sp))
-
- def collect_libs_with_partition_user(lib_set, partition):
- result = set()
- for lib in lib_set:
- if is_not_vndk(lib):
+ action_ineligible_vndk_sp = set(action_ineligible_vndk_sp.split(','))
+ predefined_vndk_sp = self.compute_predefined_vndk_sp()
+ vndk_sp = set()
+ for lib in itertools.chain(sp_hal, sp_hal_dep):
+ for dep in lib.deps:
+ if is_not_vndk_sp(dep):
continue
- if any(user.partition == partition for user in lib.users):
- result.add(lib)
- return result
+ if dep in predefined_vndk_sp:
+ vndk_sp.add(dep)
+ continue
+ if 'warn' in action_ineligible_vndk_sp:
+ print('error: SP-HAL {} depends on non vndk-sp '
+ 'library {}.'.format(lib.path, dep.path),
+ file=sys.stderr)
+ if 'follow' in action_ineligible_vndk_sp:
+ vndk_sp.add(dep)
- vndk_candidates = collect_libs_with_partition_user(
- self.lib_pt[PT_SYSTEM].values(), PT_VENDOR)
+ # Add other predefined VNDK-SP even if they are not actually used by
+ # SP-HAL libs.
+ vndk_sp_unused = set(lib for lib in predefined_vndk_sp
+ if self._is_in_vndk_sp_dir(lib.path)) - vndk_sp
- vndk_visited = set(vndk_candidates)
+ # Find VNDK-SP-Indirect libs.
+ def is_not_vndk_sp_indirect(lib):
+ return lib.is_ll_ndk or lib.is_sp_ndk or lib in vndk_sp or \
+ lib in fwk_only_rs
- # Sets for missing libraries.
- extra_vendor_lib = set()
+ vndk_sp_indirect = self.compute_closure(
+ vndk_sp, is_not_vndk_sp_indirect)
+ vndk_sp_indirect -= vndk_sp
- def get_vndk_core_lib_name(lib):
- lib_name = os.path.basename(lib.path)
- lib_dir_name = 'lib' if lib.elf.is_32bit else 'lib64'
- return os.path.join('/system', lib_dir_name, 'vndk', lib_name)
+ def is_not_vndk_sp_indirect_unused(lib):
+ return is_not_vndk_sp_indirect(lib) or lib in vndk_sp_indirect
+ vndk_sp_indirect_unused = self.compute_closure(
+ vndk_sp_unused, is_not_vndk_sp_indirect_unused)
+ vndk_sp_indirect_unused -= vndk_sp_unused
- def get_vndk_fwk_ext_lib_name(lib):
- lib_name = os.path.basename(lib.path)
- lib_dir_name = 'lib' if lib.elf.is_32bit else 'lib64'
- return os.path.join('/system', lib_dir_name, 'vndk-ext', lib_name)
+ # TODO: Compute VNDK-SP-Indirect-Private.
+ vndk_sp_indirect_private = set()
- def get_vndk_vnd_ext_lib_name(lib):
- lib_name = os.path.basename(lib.path)
- lib_dir_name = 'lib' if lib.elf.is_32bit else 'lib64'
- return os.path.join('/vendor', lib_dir_name, 'vndk-ext', lib_name)
+ predefined_vndk_sp_indirect = self.compute_predefined_vndk_sp_indirect()
- def is_valid_vndk_core_dep(path):
- d = os.path.dirname(path)
- return (d == '/system/lib' or d == '/system/lib64' or
- d == '/system/lib/vndk' or d == '/system/lib64/vndk')
+ # TODO: Compute VNDK-SP-Ext and VNDK-SP-Indirect-Ext.
+ vndk_sp_ext = set()
- def add_generic_lib_to_vndk_core(lib):
- """Add a library to vndk-core."""
- elf = generic_refs.refs[lib.path]
+ def is_not_vndk_sp_indirect_ext(lib):
+ return lib.is_ll_ndk or lib.is_sp_ndk or lib in vndk_sp_ext or \
+ lib in predefined_vndk_sp or \
+ lib in predefined_vndk_sp_indirect
- # Create new vndk-core lib from generic reference.
- vndk_core_lib_path = get_vndk_core_lib_name(lib)
- vndk_core_lib = self.add_lib(PT_SYSTEM, vndk_core_lib_path, elf)
+ vndk_sp_indirect_ext = self.compute_closure(
+ vndk_sp_ext, is_not_vndk_sp_indirect_ext)
+ vndk_sp_indirect_ext -= vndk_sp_ext
- # Resovle the library dependencies.
- resolver = vndk_core_resolver32 if lib.elf.is_32bit else \
- vndk_core_resolver64
- self._resolve_lib_deps(vndk_core_lib, resolver, generic_refs)
+ extra_vndk_sp_indirect = vndk_sp - predefined_vndk_sp - \
+ predefined_vndk_sp_indirect
- assert all(is_valid_vndk_core_dep(dep.path)
- for dep in vndk_core_lib.deps)
+ # Find VNDK libs (a.k.a. system shared libs directly used by vendor
+ # partition.)
+ def is_not_vndk(lib):
+ if lib.is_ll_ndk or lib.is_sp_ndk or lib in vndk_sp:
+ return True
+ if lib.partition != PT_SYSTEM:
+ return True
+ if not generic_refs:
+ # If generic reference is not available, we assume all system
+ # libs are eligible vndk.
+ return False
+ return not generic_refs.has_same_name_lib(lib)
- # Add vndk-core to the set.
- vndk_core.add(vndk_core_lib)
- return vndk_core_lib
-
- def add_to_vndk_core(lib):
- self.rename_lib(lib, PT_SYSTEM, get_vndk_core_lib_name(lib))
- vndk_core.add(lib)
-
- # Compute vndk-core, vndk-fwk-ext and vndk-vnd-ext.
- if not generic_refs:
- for lib in vndk_candidates:
- add_to_vndk_core(lib)
- else:
- while vndk_candidates:
- if __debug__:
- # Loop invariant: These set should be pairwise independent.
- # Each VNDK libraries should have their ELFLinkData
- # instance.
- assert not (vndk_core & vndk_fwk_ext)
- assert not (vndk_core & vndk_vnd_ext)
- assert not (vndk_fwk_ext & vndk_vnd_ext)
-
- # Loop invariant: The library names in vndk_fwk_ext and
- # vndk_vnd_ext must exist in vndk_core as well.
- vndk_core_lib_names = \
- set(os.path.basename(x.path) for x in vndk_core)
- vndk_fwk_ext_lib_names = \
- set(os.path.basename(x.path) for x in vndk_fwk_ext)
- vndk_vnd_ext_lib_names = \
- set(os.path.basename(x.path) for x in vndk_vnd_ext)
- assert vndk_fwk_ext_lib_names <= vndk_core_lib_names
- assert vndk_vnd_ext_lib_names <= vndk_core_lib_names
-
- prev_vndk_candidates = vndk_candidates
- vndk_candidates = set()
-
- def replace_linked_lib(user, old_lib, new_lib, dep_type):
- user.remove_dep(old_lib, dep_type)
- user.add_dep(new_lib, dep_type)
- for symbol, imported_lib in user.linked_symbols.items():
- if imported_lib == old_lib:
- user.linked_symbols[symbol] = new_lib
-
- def replace_generic_lib_usages(lib, generic_lib):
- for user, dep_type in list(lib.users_with_type):
- if lib not in user.imported_ext_symbols:
- replace_linked_lib(user, lib, generic_lib, dep_type)
-
- def add_to_vndk_fwk_ext(lib, generic_lib):
- self.rename_lib(lib, PT_SYSTEM,
- get_vndk_fwk_ext_lib_name(lib))
- vndk_fwk_ext.add(lib)
- replace_generic_lib_usages(lib, generic_lib)
-
- def add_to_vndk_vnd_ext(lib, generic_lib):
- """Add a library to vndk-vnd-ext."""
-
- replace_generic_lib_usages(lib, generic_lib)
-
- # Create a new vndk-vnd-ext library.
- vndk_vnd_ext_lib = self.add_lib(
- PT_VENDOR, get_vndk_vnd_ext_lib_name(lib), lib.elf)
-
- # Vendor libraries should link to vndk_vnd_ext_lib instead.
- for user, dep_type in list(lib.users_with_type):
- if not user.is_system_lib():
- replace_linked_lib(user, lib, vndk_vnd_ext_lib,
- dep_type)
-
- # Resolve the dependencies. In order to find more
- # dependencies from vendor partition to system partition,
- # continue to resolve dependencies with the global
- # ELFResolver.
- resolver = self.lib32_resolver if lib.elf.is_32bit else \
- self.lib64_resolver
- self._resolve_lib_deps(vndk_vnd_ext_lib, resolver,
- generic_refs)
-
- add_deps_to_vndk_candidate(vndk_vnd_ext_lib)
-
- vndk_vnd_ext.add(vndk_vnd_ext_lib)
-
- def add_to_vndk_candidate(lib):
- if is_not_vndk(lib):
- return
- if lib not in vndk_visited:
- vndk_candidates.add(lib)
- vndk_visited.add(lib)
-
- def add_deps_to_vndk_candidate(lib):
- for dep in lib.deps:
- if dep.is_system_lib():
- add_to_vndk_candidate(dep)
-
- # Remove non-AOSP libraries.
- vndk_extended_candidates = set()
- vndk_customized_candidates = set()
- for lib in prev_vndk_candidates:
- category = generic_refs.classify_lib(lib)
- if category == GenericRefs.NEW_LIB:
- extra_vendor_lib.add(lib)
- add_deps_to_vndk_candidate(lib)
- elif category == GenericRefs.EXPORT_EQUAL:
- vndk_customized_candidates.add(lib)
- elif category == GenericRefs.EXPORT_SUPER_SET:
- vndk_extended_candidates.add(lib)
- else:
- print('error: {}: vndk library must not be modified.'
- .format(lib.path), file=sys.stderr)
-
- # Classify VNDK customized candidates.
- for lib in vndk_customized_candidates:
- if not lib.imported_ext_symbols:
- # Inward-customized VNDK-core libraries.
- add_to_vndk_core(lib)
- else:
- # Outward-customized VNDK libraries.
- generic_lib = add_generic_lib_to_vndk_core(lib)
- if lib in vndk_customized_for_system:
- add_to_vndk_fwk_ext(lib, generic_lib)
- if lib in vndk_customized_for_vendor:
- add_to_vndk_vnd_ext(lib, generic_lib)
-
- # Compute VNDK extension candidates.
- for lib in self._users_po_sorted(vndk_extended_candidates):
- # Check the users of the extended exported symbols.
- has_system_users = False
- has_vendor_users = False
- for user in lib.users:
- if lib in user.imported_ext_symbols:
- if user.is_system_lib():
- has_system_users = True
- else:
- has_vendor_users = True
- if has_system_users and has_vendor_users:
- break
-
- generic_lib = add_generic_lib_to_vndk_core(lib)
- if has_system_users:
- add_to_vndk_fwk_ext(lib, generic_lib)
- if has_vendor_users:
- add_to_vndk_vnd_ext(lib, generic_lib)
-
- # Compute the closure of the VNDK libs.
- visited_libs = set(vndk_core)
- processed_paths = set(lib.path for lib in vndk_core)
- stack = []
-
- def add_vndk_core_deps_to_stack(lib):
+ action_ineligible_vndk = set(action_ineligible_vndk.split(','))
+ vndk = set()
+ for lib in self.lib_pt[PT_VENDOR].values():
for dep in lib.deps:
if is_not_vndk(dep):
continue
- if dep not in visited_libs:
- stack.append(dep)
- visited_libs.add(dep)
+ if not tagged_paths or \
+ tagged_paths.is_path_visible(lib.path, dep.path):
+ vndk.add(dep)
+ continue
+ if 'warn' in action_ineligible_vndk:
+ print('warning: vendor lib/exe {} depends on ineligible '
+ 'framework shared lib {}.'
+ .format(lib.path, dep.path), file=sys.stderr)
+ if 'follow' in action_ineligible_vndk:
+ vndk.add(dep)
- for lib in vndk_core:
- add_vndk_core_deps_to_stack(lib)
+ vndk_indirect = self.compute_closure(vndk, is_not_vndk)
+ vndk_indirect -= vndk_indirect
- while stack:
- lib = stack.pop()
+ # Compute the extended usages from vendor partition.
+ # FIXME: DAUX libraries won't be found by the following algorithm.
+ vndk_ext = set()
- vndk_lib_path = get_vndk_core_lib_name(lib)
- if vndk_lib_path in processed_paths:
- continue
+ def collect_vndk_ext(libs):
+ result = set()
+ for lib in libs:
+ for dep in lib.imported_ext_symbols:
+ if dep in vndk and dep not in vndk_ext:
+ result.add(dep)
+ return result
- processed_paths.add(vndk_lib_path)
+ candidates = collect_vndk_ext(self.lib_pt[PT_VENDOR].values())
- if lib.imported_ext_symbols or \
- (generic_refs and not generic_refs.is_equivalent_lib(lib)):
- generic_lib = add_generic_lib_to_vndk_core(lib)
- add_vndk_core_deps_to_stack(generic_lib)
- add_to_vndk_fwk_ext(lib, generic_lib)
- else:
- add_to_vndk_core(lib)
- add_vndk_core_deps_to_stack(lib)
-
- # Truncate all vendor libs and resolve it again.
- for lib in self.lib_pt[PT_VENDOR].values():
- lib._deps = (set(), set())
- lib._users = (set(), set())
- lib.imported_ext_symbols = collections.defaultdict(set)
- lib.unresolved_symbols = set()
- lib.linked_symbols = dict()
-
- for lib in self.lib_pt[PT_VENDOR].values():
- resolver = vendor_resolver32 if lib.elf.is_32bit else \
- vendor_resolver64
- self._resolve_lib_deps(lib, resolver, generic_refs)
-
- # Separate vndk-core and vndk-indirect.
- vndk_core_indirect = vndk_core
- vndk_core = set()
- vndk_indirect = set()
- for lib in vndk_core_indirect:
- if any(not user.is_system_lib() for user in lib.users):
- vndk_core.add(lib)
- else:
- vndk_indirect.add(lib)
+ while candidates:
+ vndk_ext |= candidates
+ candidates = collect_vndk_ext(candidates)
return VNDKResult(
- sp_lib.sp_hal, sp_lib.sp_hal_dep, sp_lib.vndk_sp_hal,
- sp_lib.sp_ndk, sp_lib.sp_ndk_indirect,
- sp_lib.vndk_sp_both,
- extra_vendor_lib, vndk_core, vndk_indirect,
- vndk_fwk_ext, vndk_vnd_ext)
+ ll_ndk=ll_ndk,
+ ll_ndk_indirect=ll_ndk_indirect,
+ sp_ndk=sp_ndk,
+ sp_ndk_indirect=sp_ndk_indirect,
+ vndk_sp=vndk_sp,
+ vndk_sp_indirect=vndk_sp_indirect,
+ # vndk_sp_indirect_private=vndk_sp_indirect_private,
+ vndk_sp_unused=vndk_sp_unused,
+ vndk_sp_indirect_unused=vndk_sp_indirect_unused,
+ vndk=vndk,
+ vndk_indirect=vndk_indirect,
+ # fwk_only=fwk_only,
+ fwk_only_rs=fwk_only_rs,
+ sp_hal=sp_hal,
+ sp_hal_dep=sp_hal_dep,
+ # vnd_only=vnd_only,
+ vndk_ext=vndk_ext,
+ # vndk_sp_ext=vndk_sp_ext,
+ # vndk_sp_indirect_ext=vndk_sp_indirect_ext,
+ extra_vndk_sp_indirect=extra_vndk_sp_indirect)
def compute_vndk_cap(self, banned_libs):
# ELF files on vendor partitions are banned unconditionally. ELF files
@@ -1588,9 +1540,11 @@
def __init__(self):
self.refs = dict()
+ self._lib_names = set()
- def add(self, name, elf):
- self.refs[name] = elf
+ def add(self, path, elf):
+ self.refs[path] = elf
+ self._lib_names.add(os.path.basename(path))
def _load_from_sym_dir(self, root):
root = os.path.abspath(root)
@@ -1600,9 +1554,9 @@
if not filename.endswith('.sym'):
continue
path = os.path.join(base, filename)
- lib_name = '/' + path[prefix_len:-4]
+ lib_path = '/' + path[prefix_len:-4]
with open(path, 'r') as f:
- self.add(lib_name, ELF.load_dump(path))
+ self.add(lib_path, ELF.load_dump(path))
@staticmethod
def create_from_sym_dir(root):
@@ -1636,6 +1590,9 @@
def is_equivalent_lib(self, lib):
return self.classify_lib(lib) == GenericRefs.EXPORT_EQUAL
+ def has_same_name_lib(self, lib):
+ return os.path.basename(lib.path) in self._lib_names
+
#------------------------------------------------------------------------------
# Commands
@@ -1740,21 +1697,8 @@
def add_argparser_options(self, parser):
super(VNDKCommandBase, self).add_argparser_options(parser)
- parser.add_argument(
- '--ban-vendor-lib-dep', action='append',
- help='library that must not be used by vendor binaries')
-
- parser.add_argument(
- '--outward-customization-default-partition', default='system',
- help='default partition for outward customized vndk libs')
-
- parser.add_argument(
- '--outward-customization-for-system', action='append',
- help='outward customized vndk for system partition')
-
- parser.add_argument(
- '--outward-customization-for-vendor', action='append',
- help='outward customized vndk for vendor partition')
+ parser.add_argument('--no-default-dlopen-deps', action='store_true',
+ help='do not add default dlopen dependencies')
def _check_arg_dir_exists(self, arg_name, dirs):
for path in dirs:
@@ -1771,55 +1715,25 @@
self._check_arg_dir_exists('--system', args.system)
self._check_arg_dir_exists('--vendor', args.vendor)
- def _get_banned_libs_from_args(self, args):
- if not args.ban_vendor_lib_dep:
- return BannedLibDict.create_default()
-
- banned_libs = BannedLibDict()
- for name in args.ban_vendor_lib_dep:
- banned_libs.add(name, 'user-banned', BA_WARN)
- return banned_libs
-
- def _get_outward_customized_sets_from_args(self, args, graph):
- vndk_customized_for_system = set()
- vndk_customized_for_vendor = set()
- system_libs = graph.lib_pt[PT_SYSTEM].values()
-
- if args.outward_customization_default_partition in {'system', 'both'}:
- vndk_customized_for_system.update(system_libs)
-
- if args.outward_customization_default_partition in {'vendor', 'both'}:
- vndk_customized_for_vendor.update(system_libs)
-
- if args.outward_customization_for_system:
- vndk_customized_for_system.update(
- graph.get_libs(
- args.outward_customization_for_system, lambda x: None))
-
- if args.outward_customization_for_vendor:
- vndk_customized_for_vendor.update(
- graph.get_libs(
- args.outward_customization_for_vendor, lambda x: None))
- return (vndk_customized_for_system, vndk_customized_for_vendor)
-
def create_from_args(self, args):
"""Create all essential data structures for VNDK computation."""
self.check_dirs_from_args(args)
generic_refs = self.get_generic_refs_from_args(args)
- banned_libs = self._get_banned_libs_from_args(args)
graph = ELFLinker.create(args.system, args.system_dir_as_vendor,
args.vendor, args.vendor_dir_as_system,
args.load_extra_deps,
generic_refs=generic_refs)
- vndk_customized_for_system, vndk_customized_for_vendor = \
- self._get_outward_customized_sets_from_args(args, graph)
+ if not args.no_default_dlopen_deps:
+ script_dir = os.path.dirname(os.path.abspath(__file__))
+ minimum_dlopen_deps = os.path.join(script_dir, 'datasets',
+ 'minimum_dlopen_deps.txt')
+ graph.load_extra_deps(minimum_dlopen_deps)
- return (generic_refs, banned_libs, graph, vndk_customized_for_system,
- vndk_customized_for_vendor)
+ return (generic_refs, graph)
class VNDKCommand(VNDKCommandBase):
@@ -1834,6 +1748,20 @@
'--warn-incorrect-partition', action='store_true',
help='warn about libraries only have cross partition linkages')
+ parser.add_argument(
+ '--full', action='store_true',
+ help='print all classification')
+
+ parser.add_argument('--tag-file', help='lib tag file')
+
+ parser.add_argument(
+ '--action-ineligible-vndk-sp', default='warn,follow',
+ help='action when a sp-hal uses non-vndk-sp libs')
+
+ parser.add_argument(
+ '--action-ineligible-vndk', default='warn,follow',
+ help='action when a vendor lib/exe uses fwk-only libs')
+
def _warn_incorrect_partition_lib_set(self, lib_set, partition, error_msg):
for lib in lib_set.values():
if not lib.num_users:
@@ -1853,15 +1781,14 @@
'usages.')
def _check_ndk_extensions(self, graph, generic_refs):
- for lib_set in (graph.lib32, graph.lib64):
+ for lib_set in graph.lib_pt:
for lib in lib_set.values():
if lib.is_ndk and not generic_refs.is_equivalent_lib(lib):
print('warning: {}: NDK library should not be extended.'
.format(lib.path), file=sys.stderr)
def main(self, args):
- generic_refs, banned_libs, graph, vndk_customized_for_system, \
- vndk_customized_for_vendor = self.create_from_args(args)
+ generic_refs, graph = self.create_from_args(args)
# Check the API extensions to NDK libraries.
if generic_refs:
@@ -1870,13 +1797,25 @@
if args.warn_incorrect_partition:
self._warn_incorrect_partition(graph)
+ if args.tag_file:
+ tagged_paths = TaggedPathDict.create_from_csv_path(args.tag_file)
+ else:
+ tagged_paths = None
+
# Compute vndk heuristics.
- vndk_lib = graph.compute_vndk(vndk_customized_for_system,
- vndk_customized_for_vendor, generic_refs,
- banned_libs)
+ sp_lib = graph.compute_sp_lib(generic_refs)
+ vndk_lib = graph.compute_degenerated_vndk(
+ sp_lib, generic_refs, tagged_paths,
+ args.action_ineligible_vndk_sp, args.action_ineligible_vndk)
# Print results.
- print_vndk_lib(vndk_lib)
+ field_names = ['extra_vndk_sp_indirect', 'vndk_ext']
+ if args.full:
+ field_names = _VNDK_RESULT_FIELD_NAMES
+ for field_name in field_names:
+ tag = field_name + ':'
+ for lib in sorted_lib_path_list(getattr(vndk_lib, field_name)):
+ print(tag, lib)
return 0
@@ -1892,19 +1831,17 @@
'--output', '-o', help='output directory')
def main(self, args):
- generic_refs, banned_libs, graph, vndk_customized_for_system, \
- vndk_customized_for_vendor = self.create_from_args(args)
+ generic_refs, graph = self.create_from_args(args)
# Compute vndk heuristics.
- vndk_lib = graph.compute_vndk(vndk_customized_for_system,
- vndk_customized_for_vendor, generic_refs,
- banned_libs)
+ sp_lib = graph.compute_sp_lib(generic_refs)
+ vndk_lib = graph.compute_degenerated_vndk(sp_lib, generic_refs)
# Serialize data.
strs = []
strs_dict = dict()
- libs = list(graph.lib32.values()) + list(graph.lib64.values())
+ libs = list(graph.all_libs())
libs.sort(key=lambda lib: lib.path)
libs_dict = {lib: i for i, lib in enumerate(libs)}
@@ -1945,35 +1882,9 @@
def collect_tags(lib):
tags = []
- if lib.is_ll_ndk:
- tags.append(get_str_idx('ll-ndk'))
- if lib.is_sp_ndk:
- tags.append(get_str_idx('sp-ndk'))
- if lib.is_hl_ndk:
- tags.append(get_str_idx('hl-ndk'))
-
- if lib in vndk_lib.sp_hal:
- tags.append(get_str_idx('sp-hal'))
- if lib in vndk_lib.sp_hal_dep:
- tags.append(get_str_idx('sp-hal-dep'))
- if lib in vndk_lib.vndk_sp_hal:
- tags.append(get_str_idx('vndk-sp-hal'))
-
- if lib in vndk_lib.sp_ndk_indirect:
- tags.append(get_str_idx('sp-ndk-indirect'))
- if lib in vndk_lib.vndk_sp_both:
- tags.append(get_str_idx('vndk-sp-both'))
-
- if lib in vndk_lib.vndk_core:
- tags.append(get_str_idx('vndk-core'))
- if lib in vndk_lib.vndk_indirect:
- tags.append(get_str_idx('vndk-indirect'))
- if lib in vndk_lib.vndk_fwk_ext:
- tags.append(get_str_idx('vndk-fwk-ext'))
- if lib in vndk_lib.vndk_vnd_ext:
- tags.append(get_str_idx('vndk-vnd-ext'))
- if lib in vndk_lib.extra_vendor_lib:
- tags.append(get_str_idx('extra-vendor-lib'))
+ for field_name in _VNDK_RESULT_FIELD_NAMES:
+ if lib in getattr(vndk_lib, field_name):
+ tags.append(get_str_idx(field_name))
return tags
mods = []