vndk-def: Support versioned VNDK directory paths

This commit add versioned VNDK directories (e.g. /system/lib/vndk-sp-28
or /system/lib/vndk-28) to the ELF linker search paths.

Bug: 70243016
Test: ./tests/run.py
Test: Run vndk_definition_tool.py and only reasonable changes
Change-Id: I95b8c142043943157892059842953da127e239fa
This commit is contained in:
Logan Chien
2017-12-07 17:59:29 +08:00
parent 13848207f0
commit 49f0e6482f
37 changed files with 619 additions and 91 deletions

View File

@@ -9,7 +9,11 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from compat import StringIO, patch
from utils import GraphBuilder
from vndk_definition_tool import (ELF, GenericRefs, PT_SYSTEM, PT_VENDOR)
from vndk_definition_tool import (
ELF, ELFLinker, GenericRefs, PT_SYSTEM, PT_VENDOR, VNDKLibDir)
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
class ELFLinkerTest(unittest.TestCase):
@@ -377,6 +381,86 @@ class ELFLinkerTest(unittest.TestCase):
self.assertNotIn(libc_path, sp_ndk_indirect)
def test_link_vndk_ver_dirs(self):
gb = GraphBuilder()
libc_32, libc_64 = gb.add_multilib(PT_SYSTEM, 'libc')
libvndk_a_32, libvndk_a_64 = gb.add_multilib(
PT_SYSTEM, 'libvndk_a', extra_dir='vndk-28',
dt_needed=['libc.so', 'libvndk_b.so', 'libvndk_sp_b.so'])
libvndk_b_32, libvndk_b_64 = gb.add_multilib(
PT_SYSTEM, 'libvndk_b', extra_dir='vndk-28',
dt_needed=['libc.so', 'libvndk_sp_b.so'])
libvndk_c_32, libvndk_c_64 = gb.add_multilib(
PT_VENDOR, 'libvndk_c', extra_dir='vndk-28',
dt_needed=['libc.so', 'libvndk_d.so', 'libvndk_sp_d.so'])
libvndk_d_32, libvndk_d_64 = gb.add_multilib(
PT_VENDOR, 'libvndk_d', extra_dir='vndk-28',
dt_needed=['libc.so', 'libvndk_sp_d.so'])
libvndk_sp_a_32, libvndk_sp_a_64 = gb.add_multilib(
PT_SYSTEM, 'libvndk_sp_a', extra_dir='vndk-sp-28',
dt_needed=['libc.so', 'libvndk_sp_b.so'])
libvndk_sp_b_32, libvndk_sp_b_64 = gb.add_multilib(
PT_SYSTEM, 'libvndk_sp_b', extra_dir='vndk-sp-28',
dt_needed=['libc.so'])
libvndk_sp_c_32, libvndk_sp_c_64 = gb.add_multilib(
PT_VENDOR, 'libvndk_sp_c', extra_dir='vndk-sp-28',
dt_needed=['libc.so', 'libvndk_sp_d.so'])
libvndk_sp_d_32, libvndk_sp_d_64 = gb.add_multilib(
PT_VENDOR, 'libvndk_sp_d', extra_dir='vndk-sp-28',
dt_needed=['libc.so'])
gb.resolve(VNDKLibDir.create_from_version('28'), '28')
# 32-bit shared libraries
self.assertIn(libc_32, libvndk_a_32.deps_all)
self.assertIn(libc_32, libvndk_b_32.deps_all)
self.assertIn(libc_32, libvndk_c_32.deps_all)
self.assertIn(libc_32, libvndk_d_32.deps_all)
self.assertIn(libc_32, libvndk_sp_a_32.deps_all)
self.assertIn(libc_32, libvndk_sp_b_32.deps_all)
self.assertIn(libc_32, libvndk_sp_c_32.deps_all)
self.assertIn(libc_32, libvndk_sp_d_32.deps_all)
self.assertIn(libvndk_b_32, libvndk_a_32.deps_all)
self.assertIn(libvndk_sp_b_32, libvndk_a_32.deps_all)
self.assertIn(libvndk_sp_b_32, libvndk_b_32.deps_all)
self.assertIn(libvndk_sp_b_32, libvndk_sp_a_32.deps_all)
self.assertIn(libvndk_d_32, libvndk_c_32.deps_all)
self.assertIn(libvndk_sp_d_32, libvndk_c_32.deps_all)
self.assertIn(libvndk_sp_d_32, libvndk_d_32.deps_all)
self.assertIn(libvndk_sp_d_32, libvndk_sp_c_32.deps_all)
# 64-bit shared libraries
self.assertIn(libc_64, libvndk_a_64.deps_all)
self.assertIn(libc_64, libvndk_b_64.deps_all)
self.assertIn(libc_64, libvndk_c_64.deps_all)
self.assertIn(libc_64, libvndk_d_64.deps_all)
self.assertIn(libc_64, libvndk_sp_a_64.deps_all)
self.assertIn(libc_64, libvndk_sp_b_64.deps_all)
self.assertIn(libc_64, libvndk_sp_c_64.deps_all)
self.assertIn(libc_64, libvndk_sp_d_64.deps_all)
self.assertIn(libvndk_b_64, libvndk_a_64.deps_all)
self.assertIn(libvndk_sp_b_64, libvndk_a_64.deps_all)
self.assertIn(libvndk_sp_b_64, libvndk_b_64.deps_all)
self.assertIn(libvndk_sp_b_64, libvndk_sp_a_64.deps_all)
self.assertIn(libvndk_d_64, libvndk_c_64.deps_all)
self.assertIn(libvndk_sp_d_64, libvndk_c_64.deps_all)
self.assertIn(libvndk_sp_d_64, libvndk_d_64.deps_all)
self.assertIn(libvndk_sp_d_64, libvndk_sp_c_64.deps_all)
class ELFLinkerDlopenDepsTest(unittest.TestCase):
def test_add_dlopen_deps(self):
gb = GraphBuilder()

View File

@@ -0,0 +1,211 @@
#!/usr/bin/env python3
import os
import posixpath
import sys
import unittest
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from compat import StringIO
from vndk_definition_tool import ELF, VNDKLibDir
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
class VNDKLibDirTest(unittest.TestCase):
def test_create_vndk_sp_dir_name(self):
self.assertEqual(
'vndk-sp', VNDKLibDir.create_vndk_sp_dir_name('current'))
self.assertEqual(
'vndk-sp-28', VNDKLibDir.create_vndk_sp_dir_name('28'))
def test_create_vndk_dir_name(self):
self.assertEqual(
'vndk', VNDKLibDir.create_vndk_dir_name('current'))
self.assertEqual(
'vndk-28', VNDKLibDir.create_vndk_dir_name('28'))
def test_extract_vndk_version_from_name(self):
self.assertEqual(
'current', VNDKLibDir.extract_version_from_name('vndk'))
self.assertEqual(
'current', VNDKLibDir.extract_version_from_name('vndk-sp'))
self.assertEqual(
'28', VNDKLibDir.extract_version_from_name('vndk-28'))
self.assertEqual(
'28', VNDKLibDir.extract_version_from_name('vndk-sp-28'))
self.assertEqual(
'p', VNDKLibDir.extract_version_from_name('vndk-p'))
self.assertEqual(
'p', VNDKLibDir.extract_version_from_name('vndk-sp-p'))
def test_extract_vndk_version_from_path(self):
ans = VNDKLibDir.extract_version_from_path(
'/system/lib64/vndk/libexample.so')
self.assertEqual('current', ans)
ans = VNDKLibDir.extract_version_from_path(
'/system/lib64/vndk-sp/libexample.so')
self.assertEqual('current', ans)
ans = VNDKLibDir.extract_version_from_path(
'/system/lib64/vndk-28/libexample.so')
self.assertEqual('28', ans)
ans = VNDKLibDir.extract_version_from_path(
'/system/lib64/vndk-sp-28/libexample.so')
self.assertEqual('28', ans)
ans = VNDKLibDir.extract_version_from_path(
'/system/lib64/vndk-p/libexample.so')
self.assertEqual('p', ans)
ans = VNDKLibDir.extract_version_from_path(
'/system/lib64/vndk-sp-p/libexample.so')
self.assertEqual('p', ans)
ans = VNDKLibDir.extract_version_from_path(
'/system/lib64/vndk-sp-p/hw/libexample.so')
self.assertEqual('p', ans)
ans = VNDKLibDir.extract_version_from_path(
'/system/lib64/libexample.so')
self.assertEqual(None, ans)
def test_is_in_vndk_sp_dir(self):
self.assertFalse(VNDKLibDir.is_in_vndk_sp_dir('/system/lib/liba.so'))
self.assertFalse(
VNDKLibDir.is_in_vndk_sp_dir('/system/lib/vndk/liba.so'))
self.assertFalse(
VNDKLibDir.is_in_vndk_sp_dir('/system/lib/vndk-28/liba.so'))
self.assertFalse(
VNDKLibDir.is_in_vndk_sp_dir('/system/lib/vndk-spec/liba.so'))
self.assertTrue(
VNDKLibDir.is_in_vndk_sp_dir('/system/lib/vndk-sp/liba.so'))
self.assertTrue(
VNDKLibDir.is_in_vndk_sp_dir('/system/lib/vndk-sp-28/liba.so'))
def test_is_in_vndk_dir(self):
self.assertFalse(VNDKLibDir.is_in_vndk_dir('/system/lib/liba.so'))
self.assertTrue(VNDKLibDir.is_in_vndk_dir('/system/lib/vndk/liba.so'))
self.assertTrue(
VNDKLibDir.is_in_vndk_dir('/system/lib/vndk-28/liba.so'))
self.assertTrue(
VNDKLibDir.is_in_vndk_dir('/system/lib/vndk-spec/liba.so'))
self.assertFalse(
VNDKLibDir.is_in_vndk_dir('/system/lib/vndk-sp/liba.so'))
self.assertFalse(
VNDKLibDir.is_in_vndk_dir('/system/lib/vndk-sp-28/liba.so'))
def test_create_vndk_search_paths(self):
for version in ('current', '28'):
for lib_dir in ('lib', 'lib64'):
vndk_sp_name = VNDKLibDir.create_vndk_sp_dir_name(version)
vndk_name = VNDKLibDir.create_vndk_dir_name(version)
expected_vndk_sp = [
posixpath.join('/vendor', lib_dir, vndk_sp_name),
posixpath.join('/system', lib_dir, vndk_sp_name),
]
expected_vndk = [
posixpath.join('/vendor', lib_dir, vndk_name),
posixpath.join('/system', lib_dir, vndk_name),
]
vndk_sp_dirs, vndk_dirs = \
VNDKLibDir.create_vndk_search_paths(lib_dir, version)
self.assertEqual(expected_vndk_sp, vndk_sp_dirs)
self.assertEqual(expected_vndk, vndk_dirs)
def test_add_version_current(self):
vndk_lib_dirs = VNDKLibDir()
vndk_lib_dirs.append('current')
self.assertIn('current', vndk_lib_dirs)
def test_create_from_dirs_unversioned(self):
input_dir = os.path.join(
SCRIPT_DIR, 'testdata', 'test_vndk_lib_dir',
'vndk_unversioned')
vndk_lib_dirs = VNDKLibDir.create_from_dirs(
[os.path.join(input_dir, 'system')],
[os.path.join(input_dir, 'vendor')])
self.assertIn('current', vndk_lib_dirs)
def test_create_from_dirs_versioned(self):
input_dir = os.path.join(
SCRIPT_DIR, 'testdata', 'test_vndk_lib_dir', 'vndk_versioned')
vndk_lib_dirs = VNDKLibDir.create_from_dirs(
[os.path.join(input_dir, 'system')],
[os.path.join(input_dir, 'vendor')])
self.assertIn('28', vndk_lib_dirs)
def test_create_from_dirs_versioned_multiple(self):
input_dir = os.path.join(
SCRIPT_DIR, 'testdata', 'test_vndk_lib_dir',
'vndk_versioned_multiple')
vndk_lib_dirs = VNDKLibDir.create_from_dirs(
[os.path.join(input_dir, 'system')],
[os.path.join(input_dir, 'vendor')])
self.assertIn('28', vndk_lib_dirs)
self.assertIn('29', vndk_lib_dirs)
def test_get_property(self):
property_file = StringIO('ro.vndk.version=example\n')
ans = VNDKLibDir._get_property(property_file, 'ro.vndk.version')
self.assertEqual('example', ans)
property_file = StringIO('# comments\n')
ans = VNDKLibDir._get_property(property_file, 'ro.vndk.version')
self.assertEqual(None, ans)
def test_get_ro_vndk_version(self):
input_dir = os.path.join(
SCRIPT_DIR, 'testdata', 'test_vndk_lib_dir',
'vndk_versioned_multiple')
vendor_dirs = [os.path.join(input_dir, 'vendor')]
self.assertEqual('29', VNDKLibDir.get_ro_vndk_version(vendor_dirs))
def test_sorted_versions(self):
self.assertEqual(
['20', '10', '2', '1'],
VNDKLibDir.sorted_version(['1', '2', '10', '20']))
self.assertEqual(
['b', 'a', '20', '10', '2', '1'],
VNDKLibDir.sorted_version(['1', '2', '10', '20', 'a', 'b']))
self.assertEqual(
['a', '10b', '10', '2', '1'],
VNDKLibDir.sorted_version(['1', '2', '10', 'a', '10b']))
self.assertEqual(
['current', 'd', 'a', '10', '1'],
VNDKLibDir.sorted_version(['1', '10', 'a', 'd', 'current']))
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1 @@
ro.vndk.version=29

View File

@@ -6,7 +6,8 @@ import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from compat import StringIO
from vndk_definition_tool import (ELF, ELFLinker, PT_SYSTEM, PT_VENDOR)
from vndk_definition_tool import (
ELF, ELFLinker, PT_SYSTEM, PT_VENDOR, VNDKLibDir)
class GraphBuilder(object):
@@ -66,5 +67,9 @@ class GraphBuilder(object):
exported_symbols, imported_symbols, extra_dir)
)
def resolve(self):
def resolve(self, vndk_lib_dirs=None, ro_vndk_version=None):
if vndk_lib_dirs is not None:
self.graph.vndk_lib_dirs = vndk_lib_dirs
if ro_vndk_version is not None:
self.graph.ro_vndk_version = ro_vndk_version
self.graph.resolve_deps()

View File

@@ -9,6 +9,7 @@ import csv
import itertools
import json
import os
import posixpath
import re
import shutil
import stat
@@ -901,6 +902,234 @@ SPLibResult = collections.namedtuple(
'vndk_sp_both')
VNDKLibTuple = defaultnamedtuple('VNDKLibTuple', 'vndk_sp vndk', [])
class VNDKLibDir(list):
"""VNDKLibDir is a dict which maps version to VNDK-SP and VNDK directory
paths."""
@classmethod
def create_vndk_sp_dir_name(cls, version):
"""Create VNDK-SP directory name from a given version."""
return 'vndk-sp' if version == 'current' else 'vndk-sp-' + version
@classmethod
def create_vndk_dir_name(cls, version):
"""Create VNDK directory name from a given version."""
return 'vndk' if version == 'current' else 'vndk-' + version
@classmethod
def extract_version_from_name(cls, name):
"""Extract VNDK version from a name."""
if name in {'vndk', 'vndk-sp'}:
return 'current'
elif name.startswith('vndk-sp-'):
return name[len('vndk-sp-'):]
elif name.startswith('vndk-'):
return name[len('vndk-'):]
else:
return None
@classmethod
def extract_path_component(cls, path, index):
"""Extract n-th path component from a posix path."""
start = 0
for i in range(index):
pos = path.find('/', start)
if pos == -1:
return None
start = pos + 1
end = path.find('/', start)
if end == -1:
return None
return path[start:end]
@classmethod
def extract_version_from_path(cls, path):
"""Extract VNDK version from the third path component."""
component = cls.extract_path_component(path, 3)
if not component:
return None
return cls.extract_version_from_name(component)
@classmethod
def is_in_vndk_dir(cls, path):
"""Determine whether a path is under a VNDK directory."""
component = cls.extract_path_component(path, 3)
if not component:
return False
return (component == 'vndk' or
(component.startswith('vndk-') and
not component == 'vndk-sp' and
not component.startswith('vndk-sp-')))
@classmethod
def is_in_vndk_sp_dir(cls, path):
"""Determine whether a path is under a VNDK-SP directory."""
component = cls.extract_path_component(path, 3)
if not component:
return False
return component == 'vndk-sp' or component.startswith('vndk-sp-')
@classmethod
def create_vndk_search_paths(cls, lib_dir, version):
"""Create VNDK/VNDK-SP search paths from lib_dir and version."""
vndk_sp_name = cls.create_vndk_sp_dir_name(version)
vndk_name = cls.create_vndk_dir_name(version)
return VNDKLibTuple(
[posixpath.join('/vendor', lib_dir, vndk_sp_name),
posixpath.join('/system', lib_dir, vndk_sp_name)],
[posixpath.join('/vendor', lib_dir, vndk_name),
posixpath.join('/system', lib_dir, vndk_name)])
@classmethod
def create_default(cls):
"""Create default VNDK-SP and VNDK paths without versions."""
vndk_lib_dirs = VNDKLibDir()
vndk_lib_dirs.append('current')
return vndk_lib_dirs
@classmethod
def create_from_version(cls, version):
"""Create default VNDK-SP and VNDK paths with the specified version."""
vndk_lib_dirs = VNDKLibDir()
vndk_lib_dirs.append(version)
return vndk_lib_dirs
@classmethod
def create_from_dirs(cls, system_dirs, vendor_dirs):
"""Scan system_dirs and vendor_dirs and collect all VNDK-SP and VNDK
directory paths."""
def collect_versions(base_dirs):
versions = set()
for base_dir in base_dirs:
for lib_dir in ('lib', 'lib64'):
lib_dir_path = os.path.join(base_dir, lib_dir)
for name in os.listdir(lib_dir_path):
version = cls.extract_version_from_name(name)
if version:
versions.add(version)
return versions
versions = set()
if system_dirs:
versions.update(collect_versions(system_dirs))
if vendor_dirs:
versions.update(collect_versions(vendor_dirs))
# Sanity check: Versions must not be 'sp' or start with 'sp-'.
bad_versions = [version for version in versions
if version == 'sp' or version.startswith('sp-')]
if bad_versions:
raise ValueError('bad vndk version: ' + repr(bad_versions))
return VNDKLibDir(cls.sorted_version(versions))
def classify_vndk_libs(self, libs):
"""Classify VNDK/VNDK-SP shared libraries."""
vndk_sp_libs = collections.defaultdict(set)
vndk_libs = collections.defaultdict(set)
other_libs = set()
for lib in libs:
component = self.extract_path_component(lib.path, 3)
if component is None:
other_libs.add(lib)
continue
version = self.extract_version_from_name(component)
if version is None:
other_libs.add(lib)
continue
if component.startswith('vndk-sp'):
vndk_sp_libs[version].add(lib)
else:
vndk_libs[version].add(lib)
return (vndk_sp_libs, vndk_libs, other_libs)
@classmethod
def _get_property(cls, property_file, name):
"""Read a property from a property file."""
for line in property_file:
if line.startswith(name + '='):
return line[len(name) + 1:].strip()
return None
@classmethod
def get_ro_vndk_version(cls, vendor_dirs):
"""Read ro.vendor.version property from vendor partitions."""
for vendor_dir in vendor_dirs:
path = os.path.join(vendor_dir, 'default.prop')
with open(path, 'r') as property_file:
result = cls._get_property(property_file, 'ro.vndk.version')
if result is not None:
return result
return None
@classmethod
def sorted_version(cls, versions):
"""Sort versions in the following rule:
1. 'current' is the first.
2. The versions that cannot be converted to int are sorted
lexicographically in descendant order.
3. The versions that can be converted to int are sorted as integers in
descendant order.
"""
current = []
alpha = []
numeric = []
for version in versions:
if version == 'current':
current.append(version)
continue
try:
numeric.append(int(version))
except ValueError:
alpha.append(version)
alpha.sort(reverse=True)
numeric.sort(reverse=True)
return current + alpha + [str(x) for x in numeric]
def find_vendor_vndk_version(self, vendor_dirs):
"""Find the best-fitting VNDK version."""
ro_vndk_version = self.get_ro_vndk_version(vendor_dirs)
if ro_vndk_version is not None:
return ro_vndk_version
if not self:
return 'current'
return self.sorted_version(self)[0]
class ELFResolver(object):
def __init__(self, lib_set, default_search_path):
self.lib_set = lib_set
@@ -1120,16 +1349,25 @@ class ELFLibDict(defaultnamedtuple('ELFLibDict', ('lib32', 'lib64'), {})):
class ELFLinker(object):
def __init__(self, tagged_paths=None):
def __init__(self, tagged_paths=None, vndk_lib_dirs=None,
ro_vndk_version='current'):
self.lib_pt = [ELFLibDict() for i in range(NUM_PARTITIONS)]
if tagged_paths is None:
script_dir = os.path.dirname(os.path.abspath(__file__))
dataset_path = os.path.join(
script_dir, 'datasets', 'minimum_tag_file.csv')
tagged_paths = TaggedPathDict.create_from_csv_path(dataset_path)
self.tagged_paths = \
TaggedPathDict.create_from_csv_path(dataset_path)
else:
self.tagged_paths = tagged_paths
self.tagged_paths = tagged_paths
if vndk_lib_dirs is None:
self.vndk_lib_dirs = VNDKLibDir.create_default()
else:
self.vndk_lib_dirs = vndk_lib_dirs
self.ro_vndk_version = ro_vndk_version
def _add_lib_to_lookup_dict(self, lib):
self.lib_pt[lib.partition].add(lib.path, lib)
@@ -1300,110 +1538,96 @@ class ELFLinker(object):
for lib in lib_set:
self._resolve_lib_deps(lib, resolver, generic_refs)
SYSTEM_SEARCH_PATH = (
'/system/${LIB}',
'/vendor/${LIB}',
)
VENDOR_SEARCH_PATH = (
'/vendor/${LIB}/hw',
'/vendor/${LIB}/egl',
'/vendor/${LIB}',
'/vendor/${LIB}/vndk-sp',
'/system/${LIB}/vndk-sp',
'/vendor/${LIB}/vndk',
'/system/${LIB}/vndk',
'/system/${LIB}', # For degenerated VNDK libs.
)
def _get_system_search_paths(self, lib_dir):
return [
'/system/' + lib_dir,
# To find violating dependencies to vendor partitions.
'/vendor/' + lib_dir,
]
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 or LL-NDK.
)
VNDK_SEARCH_PATH = (
'/vendor/${LIB}/vndk-sp',
'/system/${LIB}/vndk-sp',
'/vendor/${LIB}/vndk',
'/system/${LIB}/vndk',
'/system/${LIB}', # To discover missing VNDK dependencies or LL-NDK.
)
def _get_vendor_search_paths(self, lib_dir, vndk_sp_dirs, vndk_dirs):
vendor_lib_dirs = [
'/vendor/' + lib_dir + '/hw',
'/vendor/' + lib_dir + '/egl',
'/vendor/' + lib_dir,
]
system_lib_dirs = [
# For degenerated VNDK libs.
'/system/' + lib_dir,
]
return vendor_lib_dirs + vndk_sp_dirs + vndk_dirs + system_lib_dirs
@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]
def _get_vndk_sp_search_paths(self, lib_dir, vndk_sp_dirs):
fallback_lib_dirs = [
# To find missing VNDK-SP dependencies.
'/vendor/' + lib_dir,
# To find missing VNDK-SP dependencies or LL-NDK.
'/system/' + lib_dir,
]
return vndk_sp_dirs + fallback_lib_dirs
@classmethod
def _get_dirname(cls, path):
return os.path.basename(os.path.dirname(path))
@classmethod
def _is_in_vndk_dir(cls, path):
return cls._get_dirname(path) == 'vndk'
def _get_vndk_search_paths(self, lib_dir, vndk_sp_dirs, vndk_dirs):
fallback_lib_dirs = [
# To find missing VNDK dependencies or LL-NDK.
'/system/' + lib_dir,
]
return vndk_sp_dirs + vndk_dirs + fallback_lib_dirs
@classmethod
def _is_in_vndk_sp_dir(cls, path):
return cls._get_dirname(path) == 'vndk-sp'
@classmethod
def _classify_vndk_libs(cls, libs):
vndk_libs = set()
vndk_sp_libs = set()
other_libs = set()
for lib in libs:
dirname = cls._get_dirname(lib.path)
if dirname == 'vndk':
vndk_libs.add(lib)
elif dirname == 'vndk-sp':
vndk_sp_libs.add(lib)
else:
other_libs.add(lib)
return (vndk_libs, vndk_sp_libs, other_libs)
def _resolve_elf_class_deps(self, elf_class, generic_refs):
def _resolve_elf_class_deps(self, lib_dir, elf_class, generic_refs):
# Classify libs.
vndk_lib_dirs = self.vndk_lib_dirs
lib_dict = self._compute_lib_dict(elf_class)
system_lib_dict = self.lib_pt[PT_SYSTEM].get_lib_dict(elf_class)
system_vndk_libs, system_vndk_sp_libs, system_libs = \
self._classify_vndk_libs(system_lib_dict.values())
system_vndk_sp_libs, system_vndk_libs, system_libs = \
vndk_lib_dirs.classify_vndk_libs(system_lib_dict.values())
vendor_lib_dict = self.lib_pt[PT_VENDOR].get_lib_dict(elf_class)
vendor_vndk_libs, vendor_vndk_sp_libs, vendor_libs = \
self._classify_vndk_libs(vendor_lib_dict.values())
vndk_libs = system_vndk_libs | vendor_vndk_libs
vndk_sp_libs = system_vndk_sp_libs | vendor_vndk_sp_libs
vendor_vndk_sp_libs, vendor_vndk_libs, vendor_libs = \
vndk_lib_dirs.classify_vndk_libs(vendor_lib_dict.values())
# Resolve system libs.
search_path = self._subst_search_path(
self.SYSTEM_SEARCH_PATH, elf_class)
resolver = ELFResolver(lib_dict, search_path)
search_paths = self._get_system_search_paths(lib_dir)
resolver = ELFResolver(lib_dict, search_paths)
self._resolve_lib_set_deps(system_libs, resolver, generic_refs)
# Resolve vndk-sp libs
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_libs, resolver, generic_refs)
for version in vndk_lib_dirs:
vndk_sp_dirs, vndk_dirs = \
vndk_lib_dirs.create_vndk_search_paths(lib_dir, version)
vndk_sp_libs = system_vndk_sp_libs[version] | \
vendor_vndk_sp_libs[version]
search_paths = self._get_vndk_sp_search_paths(lib_dir, vndk_sp_dirs)
resolver = ELFResolver(lib_dict, search_paths)
self._resolve_lib_set_deps(vndk_sp_libs, resolver, generic_refs)
# Resolve vndk libs
search_path = self._subst_search_path(self.VNDK_SEARCH_PATH, elf_class)
resolver = ELFResolver(lib_dict, search_path)
self._resolve_lib_set_deps(vndk_libs, resolver, generic_refs)
for version in vndk_lib_dirs:
vndk_sp_dirs, vndk_dirs = \
vndk_lib_dirs.create_vndk_search_paths(lib_dir, version)
vndk_libs = system_vndk_libs[version] | vendor_vndk_libs[version]
search_paths = self._get_vndk_search_paths(
lib_dir, vndk_sp_dirs, vndk_dirs)
resolver = ELFResolver(lib_dict, search_paths)
self._resolve_lib_set_deps(vndk_libs, resolver, generic_refs)
# Resolve vendor libs.
search_path = self._subst_search_path(
self.VENDOR_SEARCH_PATH, elf_class)
resolver = ELFResolver(lib_dict, search_path)
vndk_sp_dirs, vndk_dirs = vndk_lib_dirs.create_vndk_search_paths(
lib_dir, self.ro_vndk_version)
search_paths = self._get_vendor_search_paths(
lib_dir, vndk_sp_dirs, vndk_dirs)
resolver = ELFResolver(lib_dict, search_paths)
self._resolve_lib_set_deps(vendor_libs, 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)
self._resolve_elf_class_deps('lib', ELF.ELFCLASS32, generic_refs)
self._resolve_elf_class_deps('lib64', ELF.ELFCLASS64, generic_refs)
def compute_predefined_sp_hal(self):
"""Find all same-process HALs."""
@@ -1562,7 +1786,7 @@ class ELFLinker(object):
# Find unused predefined VNDK-SP libs.
vndk_sp_unused = set(lib for lib in predefined_vndk_sp
if self._is_in_vndk_sp_dir(lib.path))
if VNDKLibDir.is_in_vndk_sp_dir(lib.path))
vndk_sp_unused -= vndk_sp
vndk_sp_unused -= vndk_sp_indirect
@@ -1574,7 +1798,7 @@ class ELFLinker(object):
vndk_sp_unused_deps -= vndk_sp_unused
vndk_sp_indirect_unused = set(lib for lib in predefined_vndk_sp_indirect
if self._is_in_vndk_sp_dir(lib.path))
if VNDKLibDir.is_in_vndk_sp_dir(lib.path))
vndk_sp_indirect_unused -= vndk_sp_indirect
vndk_sp_indirect_unused -= vndk_sp_unused
vndk_sp_indirect_unused |= vndk_sp_unused_deps
@@ -1809,7 +2033,9 @@ class ELFLinker(object):
system_dirs_ignored, vendor_dirs,
vendor_dirs_as_system, vendor_dirs_ignored,
extra_deps, generic_refs, tagged_paths):
graph = ELFLinker(tagged_paths)
vndk_lib_dirs = VNDKLibDir.create_from_dirs(system_dirs, vendor_dirs)
ro_vndk_version = vndk_lib_dirs.find_vendor_vndk_version(vendor_dirs)
graph = ELFLinker(tagged_paths, vndk_lib_dirs, ro_vndk_version)
if system_dirs:
for path in system_dirs:
@@ -1845,12 +2071,13 @@ class ELFLinker(object):
@staticmethod
def create_from_dump(system_dirs=None, system_dirs_as_vendor=None,
vendor_dirs=None, vendor_dirs_as_system=None,
system_dirs_ignored=None, vendor_dirs=None,
vendor_dirs_as_system=None, vendor_dirs_ignored=None,
extra_deps=None, generic_refs=None, tagged_paths=None):
return ELFLinker._create_internal(
scan_elf_dump_files, system_dirs, system_dirs_as_vendor,
vendor_dirs, vendor_dirs_as_system, extra_deps, generic_refs,
tagged_paths)
system_dirs_ignored, vendor_dirs, vendor_dirs_as_system,
vendor_dirs_ignored, extra_deps, generic_refs, tagged_paths)
#------------------------------------------------------------------------------