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:
@@ -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()
|
||||
|
||||
211
vndk/tools/definition-tool/tests/test_vndk_lib_dir.py
Executable file
211
vndk/tools/definition-tool/tests/test_vndk_lib_dir.py
Executable 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()
|
||||
@@ -0,0 +1 @@
|
||||
ro.vndk.version=29
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user