diff --git a/vndk/tools/definition-tool/tests/test_elf_linker.py b/vndk/tools/definition-tool/tests/test_elf_linker.py index d2dbe2409..490546647 100755 --- a/vndk/tools/definition-tool/tests/test_elf_linker.py +++ b/vndk/tools/definition-tool/tests/test_elf_linker.py @@ -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() diff --git a/vndk/tools/definition-tool/tests/test_vndk_lib_dir.py b/vndk/tools/definition-tool/tests/test_vndk_lib_dir.py new file mode 100755 index 000000000..73e2307d3 --- /dev/null +++ b/vndk/tools/definition-tool/tests/test_vndk_lib_dir.py @@ -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() diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/system/lib/vndk-sp/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/system/lib/vndk-sp/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/system/lib/vndk/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/system/lib/vndk/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/system/lib64/vndk-sp/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/system/lib64/vndk-sp/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/system/lib64/vndk/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/system/lib64/vndk/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/vendor/lib/vndk-sp/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/vendor/lib/vndk-sp/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/vendor/lib/vndk/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/vendor/lib/vndk/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/vendor/lib64/vndk-sp/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/vendor/lib64/vndk-sp/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/vendor/lib64/vndk/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_unversioned/vendor/lib64/vndk/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/system/lib/vndk-28/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/system/lib/vndk-28/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/system/lib/vndk-sp-28/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/system/lib/vndk-sp-28/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/system/lib64/vndk-28/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/system/lib64/vndk-28/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/system/lib64/vndk-sp-28/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/system/lib64/vndk-sp-28/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/vendor/lib/vndk-28/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/vendor/lib/vndk-28/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/vendor/lib/vndk-sp-28/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/vendor/lib/vndk-sp-28/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/vendor/lib64/vndk-28/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/vendor/lib64/vndk-28/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/vendor/lib64/vndk-sp-28/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned/vendor/lib64/vndk-sp-28/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib/vndk-28/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib/vndk-28/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib/vndk-29/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib/vndk-29/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib/vndk-sp-28/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib/vndk-sp-28/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib/vndk-sp-29/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib/vndk-sp-29/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib64/vndk-28/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib64/vndk-28/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib64/vndk-29/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib64/vndk-29/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib64/vndk-sp-28/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib64/vndk-sp-28/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib64/vndk-sp-29/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/system/lib64/vndk-sp-29/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/default.prop b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/default.prop new file mode 100644 index 000000000..abed6a832 --- /dev/null +++ b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/default.prop @@ -0,0 +1 @@ +ro.vndk.version=29 diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib/vndk-28/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib/vndk-28/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib/vndk-29/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib/vndk-29/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib/vndk-sp-28/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib/vndk-sp-28/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib/vndk-sp-29/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib/vndk-sp-29/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib64/vndk-28/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib64/vndk-28/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib64/vndk-29/libvndk.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib64/vndk-29/libvndk.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib64/vndk-sp-28/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib64/vndk-sp-28/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib64/vndk-sp-29/libvndk_sp.so b/vndk/tools/definition-tool/tests/testdata/test_vndk_lib_dir/vndk_versioned_multiple/vendor/lib64/vndk-sp-29/libvndk_sp.so new file mode 100644 index 000000000..e69de29bb diff --git a/vndk/tools/definition-tool/tests/utils.py b/vndk/tools/definition-tool/tests/utils.py index e3de28533..6c61a3467 100644 --- a/vndk/tools/definition-tool/tests/utils.py +++ b/vndk/tools/definition-tool/tests/utils.py @@ -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() diff --git a/vndk/tools/definition-tool/vndk_definition_tool.py b/vndk/tools/definition-tool/vndk_definition_tool.py index 9841c6957..9ac5e1b9e 100755 --- a/vndk/tools/definition-tool/vndk_definition_tool.py +++ b/vndk/tools/definition-tool/vndk_definition_tool.py @@ -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) #------------------------------------------------------------------------------