Merge changes I3073efe9,I3b0f06e3,I4ca80033,I3bc23fd4,I327a085d, ...
* changes: vndk-def: Add GenericRefs.classify_lib(). vndk-def: Link imported symbols. vndk-def: Add vndk-stable finder. vndk-def: Extract sp-hal finder. vndk-def: Return ELFLinkData for unit test. vndk-def: Refactor BannedLibDict and add unittests. vndk-def: Separate SP-NDK from HL-NDK.
This commit is contained in:
42
vndk/tools/definition-tool/tests/test_banned_libs.py
Executable file
42
vndk/tools/definition-tool/tests/test_banned_libs.py
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import unittest
|
||||
|
||||
from vndk_definition_tool import BA_WARN, BannedLibDict
|
||||
|
||||
|
||||
class BannedLibDictTest(unittest.TestCase):
|
||||
def test_add(self):
|
||||
d = BannedLibDict()
|
||||
d.add('libfoo.so', 'test', BA_WARN)
|
||||
x = d.get('libfoo.so')
|
||||
|
||||
self.assertIsNotNone(x)
|
||||
self.assertEqual('libfoo.so', x.name)
|
||||
self.assertEqual('test', x.reason)
|
||||
self.assertEqual(BA_WARN, x.action)
|
||||
|
||||
def test_get(self):
|
||||
d = BannedLibDict.create_default()
|
||||
self.assertIsNotNone(d.get('libbinder.so'))
|
||||
self.assertIsNotNone(d.get('libselinux.so'))
|
||||
self.assertIsNone(d.get('libc.so'))
|
||||
|
||||
def test_is_banned(self):
|
||||
d = BannedLibDict.create_default()
|
||||
self.assertTrue(d.is_banned('/system/lib/libbinder.so'))
|
||||
self.assertTrue(d.is_banned('/system/lib/libselinux.so'))
|
||||
self.assertTrue(d.is_banned('/system/lib64/libbinder.so'))
|
||||
self.assertTrue(d.is_banned('/system/lib64/libselinux.so'))
|
||||
self.assertFalse(d.is_banned('/system/lib64/libc.so'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -26,26 +26,36 @@ class GraphBuilder(object):
|
||||
def __init__(self):
|
||||
self.graph = ELFLinker()
|
||||
|
||||
def add_lib(self, partition, klass, name, dt_needed, exported_symbols,
|
||||
imported_symbols):
|
||||
def add_lib(self, partition, klass, name, dt_needed=[],
|
||||
exported_symbols=set(), imported_symbols=set(),
|
||||
extra_dir=None):
|
||||
"""Create and add a shared library to ELFLinker."""
|
||||
|
||||
lib_dir = os.path.join('/', self._PARTITION_NAMES[partition],
|
||||
self._LIB_DIRS[klass])
|
||||
if extra_dir:
|
||||
lib_dir = os.path.join(lib_dir, extra_dir)
|
||||
|
||||
path = os.path.join(lib_dir, name + '.so')
|
||||
|
||||
elf = ELF(klass, ELF.ELFDATA2LSB, dt_needed=dt_needed,
|
||||
exported_symbols=exported_symbols,
|
||||
imported_symbols=imported_symbols)
|
||||
setattr(self, 'elf' + elf.elf_class_name + '_' + name, elf)
|
||||
|
||||
path = os.path.join('/', self._PARTITION_NAMES[partition],
|
||||
self._LIB_DIRS[klass], name + '.so')
|
||||
self.graph.add(partition, path, elf)
|
||||
node = self.graph.add(partition, path, elf)
|
||||
setattr(self, name + '_' + elf.elf_class_name, node)
|
||||
return node
|
||||
|
||||
def add_multilib(self, partition, name, dt_needed, exported_symbols,
|
||||
imported_symbols):
|
||||
def add_multilib(self, partition, name, dt_needed=[],
|
||||
exported_symbols=set(), imported_symbols=set(),
|
||||
extra_dir=None):
|
||||
"""Add 32-bit / 64-bit shared libraries to ELFLinker."""
|
||||
|
||||
for klass in (ELF.ELFCLASS32, ELF.ELFCLASS64):
|
||||
self.add_lib(partition, klass, name, dt_needed,
|
||||
exported_symbols, imported_symbols)
|
||||
return (
|
||||
self.add_lib(partition, ELF.ELFCLASS32, name, dt_needed,
|
||||
exported_symbols, imported_symbols, extra_dir),
|
||||
self.add_lib(partition, ELF.ELFCLASS64, name, dt_needed,
|
||||
exported_symbols, imported_symbols, extra_dir)
|
||||
)
|
||||
|
||||
def resolve(self):
|
||||
self.graph.resolve_deps()
|
||||
@@ -55,13 +65,10 @@ class ELFLinkerTest(unittest.TestCase):
|
||||
def _create_normal_graph(self):
|
||||
gb = GraphBuilder()
|
||||
|
||||
gb.add_multilib(PT_SYSTEM, 'libdl', dt_needed=[],
|
||||
exported_symbols={'dlclose', 'dlopen', 'dlsym'},
|
||||
imported_symbols={})
|
||||
gb.add_multilib(PT_SYSTEM, 'libdl',
|
||||
exported_symbols={'dlclose', 'dlopen', 'dlsym'})
|
||||
|
||||
gb.add_multilib(PT_SYSTEM, 'libm', dt_needed=[],
|
||||
exported_symbols={'cos', 'sin'},
|
||||
imported_symbols={})
|
||||
gb.add_multilib(PT_SYSTEM, 'libm', exported_symbols={'cos', 'sin'})
|
||||
|
||||
gb.add_multilib(PT_SYSTEM, 'libc', dt_needed=['libdl.so', 'libm.so'],
|
||||
exported_symbols={'fclose', 'fopen', 'fread'},
|
||||
@@ -73,7 +80,6 @@ class ELFLinkerTest(unittest.TestCase):
|
||||
|
||||
gb.add_multilib(PT_SYSTEM, 'libcutils',
|
||||
dt_needed=['libc.so', 'libdl.so'],
|
||||
exported_symbols={},
|
||||
imported_symbols={'dlclose', 'dlopen', 'fclose',
|
||||
'fopen'})
|
||||
|
||||
@@ -93,15 +99,15 @@ class ELFLinkerTest(unittest.TestCase):
|
||||
graph = gb.graph
|
||||
|
||||
node = graph.map_path_to_lib('/system/lib/libc.so')
|
||||
self.assertEqual(gb.elf32_libc, node.elf)
|
||||
self.assertEqual(gb.libc_32, node)
|
||||
self.assertEqual('/system/lib/libc.so', node.path)
|
||||
|
||||
node = graph.map_path_to_lib('/system/lib64/libdl.so')
|
||||
self.assertEqual(gb.elf64_libdl, node.elf)
|
||||
self.assertEqual(gb.libdl_64, node)
|
||||
self.assertEqual('/system/lib64/libdl.so', node.path)
|
||||
|
||||
node = graph.map_path_to_lib('/vendor/lib64/libEGL.so')
|
||||
self.assertEqual(gb.elf64_libEGL, node.elf)
|
||||
self.assertEqual(gb.libEGL_64, node)
|
||||
self.assertEqual('/vendor/lib64/libEGL.so', node.path)
|
||||
|
||||
self.assertEqual(None, graph.map_path_to_lib('/no/such/path.so'))
|
||||
@@ -157,6 +163,56 @@ class ELFLinkerTest(unittest.TestCase):
|
||||
'/system/lib64/libdl.so'],
|
||||
self._get_paths_from_nodes(node.deps))
|
||||
|
||||
def test_linked_symbols(self):
|
||||
gb = self._create_normal_graph()
|
||||
graph = gb.graph
|
||||
|
||||
# Check the unresolved symbols.
|
||||
for lib_set in (graph.lib32, graph.lib64):
|
||||
for lib in lib_set.values():
|
||||
self.assertEqual(set(), lib.unresolved_symbols)
|
||||
|
||||
# Check the linked symbols.
|
||||
for lib in ('lib', 'lib64'):
|
||||
libdl = graph.map_path_to_lib('/system/' + lib + '/libdl.so')
|
||||
libm = graph.map_path_to_lib('/system/' + lib + '/libm.so')
|
||||
libc = graph.map_path_to_lib('/system/' + lib + '/libc.so')
|
||||
libRS = graph.map_path_to_lib('/system/' + lib + '/libRS.so')
|
||||
libcutils = \
|
||||
graph.map_path_to_lib('/system/' + lib + '/libcutils.so')
|
||||
libEGL = graph.map_path_to_lib('/vendor/' + lib + '/libEGL.so')
|
||||
|
||||
# Check the linked symbols for libc.so.
|
||||
self.assertIs(libdl, libc.linked_symbols['dlclose'])
|
||||
self.assertIs(libdl, libc.linked_symbols['dlopen'])
|
||||
self.assertIs(libm, libc.linked_symbols['cos'])
|
||||
self.assertIs(libm, libc.linked_symbols['sin'])
|
||||
|
||||
# Check the linked symbols for libRS.so.
|
||||
self.assertIs(libdl, libRS.linked_symbols['dlclose'])
|
||||
self.assertIs(libdl, libRS.linked_symbols['dlopen'])
|
||||
self.assertIs(libdl, libRS.linked_symbols['dlsym'])
|
||||
|
||||
# Check the linked symbols for libcutils.so.
|
||||
self.assertIs(libdl, libcutils.linked_symbols['dlclose'])
|
||||
self.assertIs(libdl, libcutils.linked_symbols['dlopen'])
|
||||
self.assertIs(libc, libcutils.linked_symbols['fclose'])
|
||||
self.assertIs(libc, libcutils.linked_symbols['fopen'])
|
||||
|
||||
# Check the linked symbols for libEGL.so.
|
||||
self.assertIs(libc, libEGL.linked_symbols['fclose'])
|
||||
self.assertIs(libc, libEGL.linked_symbols['fopen'])
|
||||
|
||||
def test_unresolved_symbols(self):
|
||||
gb = GraphBuilder()
|
||||
gb.add_lib(PT_SYSTEM, ELF.ELFCLASS64, 'libfoo', dt_needed=[],
|
||||
exported_symbols={'foo', 'bar'},
|
||||
imported_symbols={'__does_not_exist'})
|
||||
gb.resolve()
|
||||
|
||||
lib = gb.graph.map_path_to_lib('/system/lib64/libfoo.so')
|
||||
self.assertEqual({'__does_not_exist'}, lib.unresolved_symbols)
|
||||
|
||||
def test_users(self):
|
||||
gb = self._create_normal_graph()
|
||||
graph = gb.graph
|
||||
@@ -185,8 +241,8 @@ class ELFLinkerTest(unittest.TestCase):
|
||||
graph = gb.graph
|
||||
|
||||
class MockBannedLibs(object):
|
||||
def get(self, name):
|
||||
return None
|
||||
def is_banned(self, name):
|
||||
return False
|
||||
|
||||
vndk_core, vndk_indirect, vndk_ext = \
|
||||
graph.compute_vndk_libs(None, MockBannedLibs())
|
||||
@@ -197,6 +253,169 @@ class ELFLinkerTest(unittest.TestCase):
|
||||
self.assertEqual([], self._get_paths_from_nodes(vndk_indirect))
|
||||
self.assertEqual([], self._get_paths_from_nodes(vndk_ext))
|
||||
|
||||
def test_compute_vndk_stable(self):
|
||||
gb = GraphBuilder()
|
||||
|
||||
# HIDL libraries.
|
||||
gb.add_multilib(PT_SYSTEM, 'libhidlbase', extra_dir='vndk-stable')
|
||||
gb.add_multilib(PT_SYSTEM, 'libhidltransport', extra_dir='vndk-stable')
|
||||
gb.add_multilib(PT_SYSTEM, 'libhidlmemory', extra_dir='vndk-stable')
|
||||
gb.add_multilib(PT_SYSTEM, 'libfmp', extra_dir='vndk-stable')
|
||||
gb.add_multilib(PT_SYSTEM, 'libhwbinder', extra_dir='vndk-stable')
|
||||
|
||||
# UI libraries.
|
||||
# TODO: Add libui.so here.
|
||||
|
||||
gb.resolve()
|
||||
|
||||
# Compute VNDK-stable.
|
||||
vndk_stable = set(
|
||||
lib.path for lib in gb.graph.compute_vndk_stable(False))
|
||||
|
||||
for lib in ('lib', 'lib64'):
|
||||
# Check HIDL libraries.
|
||||
self.assertIn('/system/' + lib + '/vndk-stable/libhidlbase.so',
|
||||
vndk_stable)
|
||||
self.assertIn('/system/' + lib + '/vndk-stable/libhidltransport.so',
|
||||
vndk_stable)
|
||||
self.assertIn('/system/' + lib + '/vndk-stable/libhidlmemory.so',
|
||||
vndk_stable)
|
||||
self.assertIn('/system/' + lib + '/vndk-stable/libfmp.so',
|
||||
vndk_stable)
|
||||
self.assertIn('/system/' + lib + '/vndk-stable/libhwbinder.so',
|
||||
vndk_stable)
|
||||
|
||||
# TODO: Check libui.so here.
|
||||
|
||||
def test_compute_vndk_stable_closure(self):
|
||||
gb = GraphBuilder()
|
||||
|
||||
libc = gb.add_lib(PT_SYSTEM, ELF.ELFCLASS64, 'libc')
|
||||
|
||||
libhidlbase = gb.add_lib(PT_SYSTEM, ELF.ELFCLASS64, 'libhidlbase',
|
||||
dt_needed=['libfoo.so'],
|
||||
extra_dir='vndk-stable')
|
||||
|
||||
libfoo = gb.add_lib(PT_SYSTEM, ELF.ELFCLASS64, 'libfoo')
|
||||
|
||||
gb.resolve()
|
||||
|
||||
# Compute VNDK-stable.
|
||||
vndk_stable = gb.graph.compute_vndk_stable(False)
|
||||
vndk_stable_closure = gb.graph.compute_vndk_stable(True)
|
||||
|
||||
self.assertSetEqual({libhidlbase}, vndk_stable)
|
||||
self.assertSetEqual({libhidlbase, libfoo}, vndk_stable_closure)
|
||||
self.assertNotIn(libc, vndk_stable)
|
||||
self.assertNotIn(libc, vndk_stable_closure)
|
||||
|
||||
def test_compute_sp_hal(self):
|
||||
gb = GraphBuilder()
|
||||
|
||||
# HIDL SP-HAL implementation.
|
||||
gb.add_multilib(PT_SYSTEM, 'gralloc.default', extra_dir='hw')
|
||||
gb.add_multilib(PT_SYSTEM, 'gralloc.chipset', extra_dir='hw')
|
||||
gb.add_multilib(PT_SYSTEM, 'android.hardware.graphics.mapper@2.0-impl',
|
||||
extra_dir='hw')
|
||||
|
||||
# NDK loader libraries should not be considered as SP-HALs.
|
||||
gb.add_multilib(PT_SYSTEM, 'libvulkan')
|
||||
gb.add_multilib(PT_SYSTEM, 'libEGL')
|
||||
gb.add_multilib(PT_SYSTEM, 'libGLESv1_CM')
|
||||
gb.add_multilib(PT_SYSTEM, 'libGLESv2')
|
||||
gb.add_multilib(PT_SYSTEM, 'libGLESv3')
|
||||
|
||||
# OpenGL implementation.
|
||||
gb.add_multilib(PT_VENDOR, 'libEGL_chipset', extra_dir='egl')
|
||||
gb.add_multilib(PT_VENDOR, 'libGLESv1_CM_chipset', extra_dir='egl')
|
||||
gb.add_multilib(PT_VENDOR, 'libGLESv2_chipset', extra_dir='egl')
|
||||
gb.add_multilib(PT_VENDOR, 'libGLESv3_chipset', extra_dir='egl')
|
||||
|
||||
# Renderscript implementation.
|
||||
gb.add_multilib(PT_VENDOR, 'libRSDriver_chipset')
|
||||
gb.add_multilib(PT_VENDOR, 'libPVRRS')
|
||||
|
||||
# Vulkan implementation.
|
||||
gb.add_multilib(PT_VENDOR, 'vulkan.chipset', extra_dir='hw')
|
||||
|
||||
# Some un-related libraries.
|
||||
gb.add_multilib(PT_SYSTEM, 'libfoo')
|
||||
gb.add_multilib(PT_VENDOR, 'libfoo')
|
||||
|
||||
gb.resolve()
|
||||
|
||||
# Compute SP-HAL.
|
||||
sp_hals = set(lib.path for lib in gb.graph.compute_sp_hal(set(), False))
|
||||
|
||||
for lib in ('lib', 'lib64'):
|
||||
# Check HIDL SP-HAL implementation.
|
||||
self.assertIn('/system/' + lib + '/hw/gralloc.default.so', sp_hals)
|
||||
self.assertIn('/system/' + lib + '/hw/gralloc.chipset.so', sp_hals)
|
||||
self.assertIn('/system/' + lib + '/hw/'
|
||||
'android.hardware.graphics.mapper@2.0-impl.so',
|
||||
sp_hals)
|
||||
|
||||
|
||||
# Check that NDK loaders are not SP-HALs.
|
||||
self.assertNotIn('/system/' + lib + '/libvulkan.so', sp_hals)
|
||||
self.assertNotIn('/system/' + lib + '/libEGL.so', sp_hals)
|
||||
self.assertNotIn('/system/' + lib + '/libGLESv1_CM.so', sp_hals)
|
||||
self.assertNotIn('/system/' + lib + '/libGLESv2.so', sp_hals)
|
||||
self.assertNotIn('/system/' + lib + '/libGLESv3.so', sp_hals)
|
||||
|
||||
# Check that OpenGL implementations are SP-HALs.
|
||||
self.assertIn('/vendor/' + lib + '/egl/libEGL_chipset.so', sp_hals)
|
||||
self.assertIn('/vendor/' + lib + '/egl/libGLESv1_CM_chipset.so',
|
||||
sp_hals)
|
||||
self.assertIn('/vendor/' + lib + '/egl/libGLESv2_chipset.so',
|
||||
sp_hals)
|
||||
self.assertIn('/vendor/' + lib + '/egl/libGLESv3_chipset.so',
|
||||
sp_hals)
|
||||
|
||||
# Check that Renderscript implementations are SP-HALs.
|
||||
self.assertIn('/vendor/' + lib + '/libRSDriver_chipset.so', sp_hals)
|
||||
self.assertIn('/vendor/' + lib + '/libPVRRS.so', sp_hals)
|
||||
|
||||
# Check that vulkan implementation are SP-HALs.
|
||||
self.assertIn('/vendor/' + lib + '/libPVRRS.so', sp_hals)
|
||||
|
||||
# Check that un-related libraries are not SP-HALs.
|
||||
self.assertNotIn('/system/' + lib + '/libfoo.so', sp_hals)
|
||||
self.assertNotIn('/vendor/' + lib + '/libfoo.so', sp_hals)
|
||||
|
||||
def test_compute_sp_hal_closure(self):
|
||||
gb = GraphBuilder()
|
||||
|
||||
libc = gb.add_lib(PT_SYSTEM, ELF.ELFCLASS64, 'libc')
|
||||
|
||||
libhidlbase = gb.add_lib(PT_SYSTEM, ELF.ELFCLASS64, 'libhidlbase')
|
||||
|
||||
libhidltransport = gb.add_lib(PT_SYSTEM, ELF.ELFCLASS64,
|
||||
'libhidltransport')
|
||||
|
||||
gralloc_mapper = gb.add_lib(
|
||||
PT_VENDOR, ELF.ELFCLASS64,
|
||||
name='android.hardware.graphics.mapper@2.0-impl',
|
||||
dt_needed=['libhidlbase.so', 'libhidltransport.so',
|
||||
'libc.so', 'gralloc_vnd.so'],
|
||||
extra_dir='sameprocess')
|
||||
|
||||
gralloc_vnd = gb.add_lib(PT_VENDOR, ELF.ELFCLASS64, 'gralloc_vnd')
|
||||
|
||||
gb.resolve()
|
||||
|
||||
vndk_stable = {libhidlbase, libhidltransport}
|
||||
|
||||
sp_hal = gb.graph.compute_sp_hal(vndk_stable, closure=False)
|
||||
sp_hal_closure = gb.graph.compute_sp_hal(vndk_stable, closure=True)
|
||||
|
||||
self.assertSetEqual({gralloc_mapper}, sp_hal)
|
||||
|
||||
self.assertSetEqual({gralloc_mapper, gralloc_vnd}, sp_hal_closure)
|
||||
self.assertNotIn(libhidlbase, sp_hal_closure)
|
||||
self.assertNotIn(libhidltransport, sp_hal_closure)
|
||||
self.assertNotIn(libc, sp_hal_closure)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -13,72 +13,91 @@ from compat import TemporaryDirectory, makedirs
|
||||
from vndk_definition_tool import GenericRefs
|
||||
|
||||
|
||||
test_dir = None
|
||||
test_dir_base = None
|
||||
|
||||
|
||||
class MockELF(object):
|
||||
def __init__(self, exported_symbols):
|
||||
self.exported_symbols = exported_symbols
|
||||
|
||||
|
||||
class MockLib(object):
|
||||
def __init__(self, path, exported_symbols):
|
||||
self.path = path
|
||||
self.elf = MockELF(exported_symbols)
|
||||
|
||||
|
||||
class GenericRefsTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
if test_dir:
|
||||
cls.test_dir = test_dir
|
||||
else:
|
||||
cls.tmp_dir = TemporaryDirectory()
|
||||
cls.test_dir = cls.tmp_dir.name
|
||||
|
||||
cls._build_fixtures()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
if not test_dir:
|
||||
cls.tmp_dir.cleanup()
|
||||
|
||||
@classmethod
|
||||
def _build_fixture(cls, path, content):
|
||||
def _build_file_fixture(self, path, content):
|
||||
makedirs(os.path.dirname(path), exist_ok=True)
|
||||
with open(path, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
@classmethod
|
||||
def _build_fixtures(cls):
|
||||
lib32 = os.path.join(cls.test_dir, 'system', 'lib')
|
||||
lib64 = os.path.join(cls.test_dir, 'system', 'lib64')
|
||||
def _build_dir_fixtures(self, test_dir):
|
||||
lib32 = os.path.join(test_dir, 'system', 'lib')
|
||||
lib64 = os.path.join(test_dir, 'system', 'lib64')
|
||||
|
||||
for lib_dir in (lib32, lib64):
|
||||
cls._build_fixture(os.path.join(lib_dir, 'libc.so.sym'),
|
||||
'fclose\nfopen\nfread\nfwrite\n')
|
||||
cls._build_fixture(os.path.join(lib_dir, 'libm.so.sym'),
|
||||
'cos\nsin\ntan\n')
|
||||
self._build_file_fixture(os.path.join(lib_dir, 'libc.so.sym'),
|
||||
'fclose\nfopen\nfread\nfwrite\n')
|
||||
self._build_file_fixture(os.path.join(lib_dir, 'libm.so.sym'),
|
||||
'cos\nsin\ntan\n')
|
||||
|
||||
def _build_fixture(self):
|
||||
res = GenericRefs()
|
||||
res.add('/system/lib/libc.so', {'fclose', 'fopen', 'fread', 'fwrite'})
|
||||
res.add('/system/lib/libm.so', {'cos', 'sin', 'tan'})
|
||||
res.add('/system/lib64/libc.so', {'fclose', 'fopen', 'fread', 'fwrite'})
|
||||
res.add('/system/lib64/libm.so', {'cos', 'sin', 'tan'})
|
||||
return res
|
||||
|
||||
def test_create_from_dir(self):
|
||||
g = GenericRefs.create_from_dir(self.test_dir)
|
||||
self.assertEqual(4, len(g.refs))
|
||||
try:
|
||||
if test_dir_base:
|
||||
test_dir = test_dir_base
|
||||
else:
|
||||
tmp_dir = TemporaryDirectory()
|
||||
test_dir = tmp_dir.name
|
||||
|
||||
self.assertIn('/system/lib/libc.so', g.refs)
|
||||
self.assertIn('/system/lib/libm.so', g.refs)
|
||||
self.assertIn('/system/lib64/libc.so', g.refs)
|
||||
self.assertIn('/system/lib64/libm.so', g.refs)
|
||||
self._build_dir_fixtures(test_dir)
|
||||
g = GenericRefs.create_from_dir(test_dir)
|
||||
self.assertEqual(4, len(g.refs))
|
||||
|
||||
self.assertEqual({'fclose', 'fopen', 'fread', 'fwrite'},
|
||||
g.refs['/system/lib/libc.so'])
|
||||
self.assertEqual({'fclose', 'fopen', 'fread', 'fwrite'},
|
||||
g.refs['/system/lib64/libc.so'])
|
||||
self.assertIn('/system/lib/libc.so', g.refs)
|
||||
self.assertIn('/system/lib/libm.so', g.refs)
|
||||
self.assertIn('/system/lib64/libc.so', g.refs)
|
||||
self.assertIn('/system/lib64/libm.so', g.refs)
|
||||
|
||||
self.assertEqual({'cos', 'sin', 'tan'},
|
||||
g.refs['/system/lib/libm.so'])
|
||||
self.assertEqual({'cos', 'sin', 'tan'},
|
||||
g.refs['/system/lib64/libm.so'])
|
||||
self.assertEqual({'fclose', 'fopen', 'fread', 'fwrite'},
|
||||
g.refs['/system/lib/libc.so'])
|
||||
self.assertEqual({'fclose', 'fopen', 'fread', 'fwrite'},
|
||||
g.refs['/system/lib64/libc.so'])
|
||||
|
||||
self.assertEqual({'cos', 'sin', 'tan'},
|
||||
g.refs['/system/lib/libm.so'])
|
||||
self.assertEqual({'cos', 'sin', 'tan'},
|
||||
g.refs['/system/lib64/libm.so'])
|
||||
finally:
|
||||
if not test_dir_base:
|
||||
tmp_dir.cleanup()
|
||||
|
||||
def test_classify_lib(self):
|
||||
g = self._build_fixture()
|
||||
|
||||
libc_sub = MockLib('/system/lib/libc.so', {'fclose', 'fopen', 'fread'})
|
||||
libc_sup = MockLib('/system/lib/libc.so',
|
||||
{'fclose', 'fopen', 'fread', 'fwrite', 'open'})
|
||||
libc_eq = MockLib('/system/lib/libc.so',
|
||||
{'fclose', 'fopen', 'fread', 'fwrite'})
|
||||
libfoo = MockLib('/system/lib/libfoo.so', {})
|
||||
|
||||
self.assertEqual(GenericRefs.MODIFIED, g.classify_lib(libc_sub))
|
||||
self.assertEqual(GenericRefs.EXPORT_SUPER_SET, g.classify_lib(libc_sup))
|
||||
self.assertEqual(GenericRefs.EXPORT_EQUAL, g.classify_lib(libc_eq))
|
||||
self.assertEqual(GenericRefs.NEW_LIB, g.classify_lib(libfoo))
|
||||
|
||||
def test_is_equivalent_lib(self):
|
||||
g = GenericRefs.create_from_dir(self.test_dir)
|
||||
|
||||
class MockELF(object):
|
||||
def __init__(self, exported_symbols):
|
||||
self.exported_symbols = exported_symbols
|
||||
|
||||
class MockLib(object):
|
||||
def __init__(self, path, exported_symbols):
|
||||
self.path = path
|
||||
self.elf = MockELF(exported_symbols)
|
||||
g = self._build_fixture()
|
||||
|
||||
libc_sub = MockLib('/system/lib/libc.so', {'fclose', 'fopen', 'fread'})
|
||||
libc_sup = MockLib('/system/lib/libc.so',
|
||||
@@ -99,10 +118,10 @@ def main():
|
||||
args, unittest_args = parser.parse_known_args()
|
||||
|
||||
# Convert command line options.
|
||||
global test_dir
|
||||
global test_dir_base
|
||||
|
||||
if args.test_dir:
|
||||
test_dir = args.test_dir
|
||||
test_dir_base = args.test_dir
|
||||
|
||||
# Run unit test.
|
||||
unittest.main(argv=[sys.argv[0]] + unittest_args)
|
||||
|
||||
128
vndk/tools/definition-tool/tests/test_ndk_libs.py
Executable file
128
vndk/tools/definition-tool/tests/test_ndk_libs.py
Executable file
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import unittest
|
||||
|
||||
from vndk_definition_tool import NDK_LIBS
|
||||
|
||||
|
||||
class NDKLibDictTest(unittest.TestCase):
|
||||
def test_is_llndk(self):
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib/libc.so'))
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib/libdl.so'))
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib/liblog.so'))
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib/libm.so'))
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib/libstdc++.so'))
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib/libz.so'))
|
||||
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib64/libc.so'))
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib64/libdl.so'))
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib64/liblog.so'))
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib64/libm.so'))
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib64/libstdc++.so'))
|
||||
self.assertTrue(NDK_LIBS.is_llndk('/system/lib64/libz.so'))
|
||||
|
||||
self.assertFalse(NDK_LIBS.is_llndk('/system/lib/libz'))
|
||||
self.assertFalse(NDK_LIBS.is_llndk('/system/lib/libzz.so'))
|
||||
|
||||
def test_is_spndk(self):
|
||||
self.assertTrue(NDK_LIBS.is_spndk('/system/lib/libEGL.so'))
|
||||
self.assertTrue(NDK_LIBS.is_spndk('/system/lib/libGLESv1_CM.so'))
|
||||
self.assertTrue(NDK_LIBS.is_spndk('/system/lib/libGLESv2.so'))
|
||||
self.assertTrue(NDK_LIBS.is_spndk('/system/lib/libGLESv3.so'))
|
||||
|
||||
self.assertTrue(NDK_LIBS.is_spndk('/system/lib64/libEGL.so'))
|
||||
self.assertTrue(NDK_LIBS.is_spndk('/system/lib64/libGLESv1_CM.so'))
|
||||
self.assertTrue(NDK_LIBS.is_spndk('/system/lib64/libGLESv2.so'))
|
||||
self.assertTrue(NDK_LIBS.is_spndk('/system/lib64/libGLESv3.so'))
|
||||
|
||||
# Vendor libraries with the same name are still not SP-NDK.
|
||||
self.assertFalse(NDK_LIBS.is_spndk('/vendor/lib64/libEGL.so'))
|
||||
self.assertFalse(NDK_LIBS.is_spndk('/vendor/lib64/libGLESv1_CM.so'))
|
||||
self.assertFalse(NDK_LIBS.is_spndk('/vendor/lib64/libGLESv2.so'))
|
||||
self.assertFalse(NDK_LIBS.is_spndk('/vendor/lib64/libGLESv3.so'))
|
||||
|
||||
self.assertFalse(NDK_LIBS.is_spndk('/vendor/lib64/egl/libEGL.so'))
|
||||
self.assertFalse(NDK_LIBS.is_spndk('/vendor/lib64/egl/libGLESv1_CM.so'))
|
||||
self.assertFalse(NDK_LIBS.is_spndk('/vendor/lib64/egl/libGLESv2.so'))
|
||||
self.assertFalse(NDK_LIBS.is_spndk('/vendor/lib64/egl/libGLESv3.so'))
|
||||
|
||||
# LL-NDK is not SP-NDK.
|
||||
self.assertFalse(NDK_LIBS.is_spndk('/system/lib/libc.so'))
|
||||
|
||||
def test_is_hlndk(self):
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib/libOpenMAXAL.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib/libOpenSLES.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib/libandroid.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib/libcamera2ndk.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib/libjnigraphics.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib/libmediandk.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib/libvulkan.so'))
|
||||
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib64/libOpenMAXAL.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib64/libOpenSLES.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib64/libandroid.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib64/libcamera2ndk.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib64/libjnigraphics.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib64/libmediandk.so'))
|
||||
self.assertTrue(NDK_LIBS.is_hlndk('/system/lib64/libvulkan.so'))
|
||||
|
||||
# LL-NDK and SP-NDK are not HL-NDK.
|
||||
self.assertFalse(NDK_LIBS.is_hlndk('/system/lib/libc.so'))
|
||||
self.assertFalse(NDK_LIBS.is_hlndk('/system/lib/libEGL.so'))
|
||||
self.assertFalse(NDK_LIBS.is_hlndk('/system/lib/libGLESv1_CM.so'))
|
||||
self.assertFalse(NDK_LIBS.is_hlndk('/system/lib/libGLESv2.so'))
|
||||
self.assertFalse(NDK_LIBS.is_hlndk('/system/lib/libGLESv3.so'))
|
||||
|
||||
def test_is_ndk(self):
|
||||
# LL-NDK
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libc.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libdl.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/liblog.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libm.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libstdc++.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libz.so'))
|
||||
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libc.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libdl.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/liblog.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libm.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libstdc++.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libz.so'))
|
||||
|
||||
# SP-NDK
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libEGL.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libGLESv1_CM.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libGLESv2.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libGLESv3.so'))
|
||||
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libEGL.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libGLESv1_CM.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libGLESv2.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libGLESv3.so'))
|
||||
|
||||
# HL-NDK
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libOpenMAXAL.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libOpenSLES.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libandroid.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libcamera2ndk.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libjnigraphics.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libmediandk.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib/libvulkan.so'))
|
||||
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libOpenMAXAL.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libOpenSLES.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libandroid.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libcamera2ndk.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libjnigraphics.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libmediandk.so'))
|
||||
self.assertTrue(NDK_LIBS.is_ndk('/system/lib64/libvulkan.so'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -406,26 +406,66 @@ class ELF(object):
|
||||
# NDK and Banned Libraries
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
NDK_LOW_LEVEL = {
|
||||
'libc.so', 'libstdc++.so', 'libdl.so', 'liblog.so', 'libm.so', 'libz.so',
|
||||
}
|
||||
class NDKLibDict(object):
|
||||
LLNDK_LIB_NAMES = (
|
||||
'libc.so',
|
||||
'libdl.so',
|
||||
'liblog.so',
|
||||
'libm.so',
|
||||
'libstdc++.so',
|
||||
'libz.so',
|
||||
)
|
||||
|
||||
SPNDK_LIB_NAMES = (
|
||||
'libEGL.so',
|
||||
'libGLESv1_CM.so',
|
||||
'libGLESv2.so',
|
||||
'libGLESv3.so',
|
||||
)
|
||||
|
||||
NDK_HIGH_LEVEL = {
|
||||
'libandroid.so', 'libcamera2ndk.so', 'libEGL.so', 'libGLESv1_CM.so',
|
||||
'libGLESv2.so', 'libGLESv3.so', 'libjnigraphics.so', 'libmediandk.so',
|
||||
'libOpenMAXAL.so', 'libOpenSLES.so', 'libvulkan.so',
|
||||
}
|
||||
HLNDK_LIB_NAMES = (
|
||||
'libOpenMAXAL.so',
|
||||
'libOpenSLES.so',
|
||||
'libandroid.so',
|
||||
'libcamera2ndk.so',
|
||||
'libjnigraphics.so',
|
||||
'libmediandk.so',
|
||||
'libvulkan.so',
|
||||
)
|
||||
|
||||
def _is_ndk_lib(path):
|
||||
lib_name = os.path.basename(path)
|
||||
return lib_name in NDK_LOW_LEVEL or lib_name in NDK_HIGH_LEVEL
|
||||
@staticmethod
|
||||
def _compile_path_matcher(names):
|
||||
patts = '|'.join('(?:^\\/system\\/lib(?:64)?\\/' + re.escape(i) + '$)'
|
||||
for i in names)
|
||||
return re.compile(patts)
|
||||
|
||||
def __init__(self):
|
||||
self.llndk_patterns = self._compile_path_matcher(self.LLNDK_LIB_NAMES)
|
||||
self.spndk_patterns = self._compile_path_matcher(self.SPNDK_LIB_NAMES)
|
||||
self.hlndk_patterns = self._compile_path_matcher(self.HLNDK_LIB_NAMES)
|
||||
self.ndk_patterns = self._compile_path_matcher(
|
||||
self.LLNDK_LIB_NAMES + self.SPNDK_LIB_NAMES +
|
||||
self.HLNDK_LIB_NAMES)
|
||||
|
||||
def is_ndk(self, path):
|
||||
return self.ndk_patterns.match(path)
|
||||
|
||||
def is_llndk(self, path):
|
||||
return self.llndk_patterns.match(path)
|
||||
|
||||
def is_spndk(self, path):
|
||||
return self.spndk_patterns.match(path)
|
||||
|
||||
def is_hlndk(self, path):
|
||||
return self.hlndk_patterns.match(path)
|
||||
|
||||
NDK_LIBS = NDKLibDict()
|
||||
|
||||
|
||||
BannedLib = collections.namedtuple(
|
||||
'BannedLib', ('name', 'reason', 'action',))
|
||||
|
||||
BA_WARN = 0
|
||||
BA_WARN = 0
|
||||
BA_EXCLUDE = 1
|
||||
|
||||
class BannedLibDict(object):
|
||||
@@ -436,7 +476,10 @@ class BannedLibDict(object):
|
||||
self.banned_libs[name] = BannedLib(name, reason, action)
|
||||
|
||||
def get(self, name):
|
||||
return self.banned_libs.get(name, None)
|
||||
return self.banned_libs.get(name)
|
||||
|
||||
def is_banned(self, path):
|
||||
return self.get(os.path.basename(path))
|
||||
|
||||
@staticmethod
|
||||
def create_default():
|
||||
@@ -502,7 +545,9 @@ class ELFLinkData(object):
|
||||
self.elf = elf
|
||||
self.deps = set()
|
||||
self.users = set()
|
||||
self.is_ndk = _is_ndk_lib(path)
|
||||
self.is_ndk = NDK_LIBS.is_ndk(path)
|
||||
self.unresolved_symbols = set()
|
||||
self.linked_symbols = dict()
|
||||
|
||||
def add_dep(self, dst):
|
||||
self.deps.add(dst)
|
||||
@@ -528,6 +573,7 @@ class ELFLinker(object):
|
||||
else:
|
||||
self.lib64[path] = node
|
||||
self.lib_pt[partition][path] = node
|
||||
return node
|
||||
|
||||
def add_dep(self, src_path, dst_path):
|
||||
for lib_set in (self.lib32, self.lib64):
|
||||
@@ -587,7 +633,24 @@ class ELFLinker(object):
|
||||
if match:
|
||||
self.add_dep(match.group(1), match.group(2))
|
||||
|
||||
def _find_exported_symbol(self, symbol, libs):
|
||||
"""Find the shared library with the exported symbol."""
|
||||
for lib in libs:
|
||||
if symbol in lib.elf.exported_symbols:
|
||||
return lib
|
||||
return None
|
||||
|
||||
def _resolve_lib_imported_symbols(self, lib, imported_libs):
|
||||
"""Resolve the imported symbols in a library."""
|
||||
for symbol in lib.elf.imported_symbols:
|
||||
imported_lib = self._find_exported_symbol(symbol, imported_libs)
|
||||
if imported_lib:
|
||||
lib.linked_symbols[symbol] = imported_lib
|
||||
else:
|
||||
lib.unresolved_symbols.add(symbol)
|
||||
|
||||
def _resolve_lib_dt_needed(self, lib, resolver):
|
||||
imported_libs = []
|
||||
for dt_needed in lib.elf.dt_needed:
|
||||
dep = resolver.resolve(dt_needed, lib.elf.dt_rpath,
|
||||
lib.elf.dt_runpath)
|
||||
@@ -598,9 +661,12 @@ class ELFLinker(object):
|
||||
.format(lib.path, dt_needed, candidates), file=sys.stderr)
|
||||
continue
|
||||
lib.add_dep(dep)
|
||||
imported_libs.append(dep)
|
||||
return imported_libs
|
||||
|
||||
def _resolve_lib_deps(self, lib, resolver):
|
||||
self._resolve_lib_dt_needed(lib, resolver)
|
||||
imported_libs = self._resolve_lib_dt_needed(lib, resolver)
|
||||
self._resolve_lib_imported_symbols(lib, imported_libs)
|
||||
|
||||
def _resolve_lib_set_deps(self, lib_set, resolver):
|
||||
for lib in lib_set.values():
|
||||
@@ -615,6 +681,73 @@ class ELFLinker(object):
|
||||
self.lib64,
|
||||
ELFResolver(self.lib64, ['/system/lib64', '/vendor/lib64']))
|
||||
|
||||
def compute_matched_libs(self, path_patterns, closure=False,
|
||||
is_excluded_libs=None):
|
||||
patt = re.compile('|'.join('(?:' + p + ')' for p in path_patterns))
|
||||
|
||||
# Find libraries with matching paths.
|
||||
libs = set()
|
||||
for lib_set in self.lib_pt:
|
||||
for lib in lib_set.values():
|
||||
if patt.match(lib.path):
|
||||
libs.add(lib)
|
||||
|
||||
if closure:
|
||||
# Compute transitive closure.
|
||||
if not is_excluded_libs:
|
||||
def is_excluded_libs(lib):
|
||||
return False
|
||||
libs = self.compute_closure(libs, is_excluded_libs)
|
||||
|
||||
return libs
|
||||
|
||||
def compute_vndk_stable(self, closure):
|
||||
"""Find all vndk stable libraries."""
|
||||
|
||||
path_patterns = (
|
||||
# HIDL libraries used by android.hardware.graphics.mapper@2.0-impl.
|
||||
'^.*/libhidlbase\\.so$',
|
||||
'^.*/libhidltransport\\.so$',
|
||||
'^.*/libhidlmemory\\.so$',
|
||||
'^.*/libfmp\\.so$',
|
||||
'^.*/libhwbinder\\.so$',
|
||||
|
||||
# UI libraries used by libEGL.
|
||||
#'^.*/libui\\.so$',
|
||||
#'^.*/libnativewindow\\.so$',
|
||||
)
|
||||
|
||||
def is_excluded_libs(lib):
|
||||
return lib.is_ndk
|
||||
|
||||
return self.compute_matched_libs(path_patterns, closure,
|
||||
is_excluded_libs)
|
||||
|
||||
def compute_sp_hal(self, vndk_stable, closure):
|
||||
"""Find all same-process HALs."""
|
||||
|
||||
path_patterns = (
|
||||
# OpenGL-related
|
||||
'^/vendor/.*/libEGL_.*\\.so$',
|
||||
'^/vendor/.*/libGLESv1_CM_.*\\.so$',
|
||||
'^/vendor/.*/libGLESv2_.*\\.so$',
|
||||
'^/vendor/.*/libGLESv3_.*\\.so$',
|
||||
# Vulkan
|
||||
'^/vendor/.*/vulkan.*\\.so$',
|
||||
# libRSDriver
|
||||
'^/vendor/.*/libRSDriver.*\\.so$',
|
||||
'^/vendor/.*/libPVRRS\\.so$',
|
||||
# Gralloc mapper
|
||||
'^.*/gralloc\\..*\\.so$',
|
||||
'^.*/android\\.hardware\\.graphics\\.mapper@\\d+\\.\\d+-impl\\.so$',
|
||||
)
|
||||
|
||||
def is_excluded_libs(lib):
|
||||
return lib.is_ndk or lib in vndk_stable
|
||||
|
||||
return self.compute_matched_libs(path_patterns, closure,
|
||||
is_excluded_libs)
|
||||
|
||||
def compute_vndk_libs(self, generic_refs, banned_libs):
|
||||
vndk_core = set()
|
||||
vndk_ext = set()
|
||||
@@ -636,7 +769,7 @@ class ELFLinker(object):
|
||||
|
||||
# Remove NDK libraries and banned libraries.
|
||||
def is_not_vndk(lib):
|
||||
return lib.is_ndk or banned_libs.get(os.path.basename(lib.path))
|
||||
return lib.is_ndk or banned_libs.is_banned(lib.path)
|
||||
|
||||
def remove_ndk_libs(libs):
|
||||
return set(lib for lib in libs if not is_not_vndk(lib))
|
||||
@@ -731,9 +864,17 @@ class ELFLinker(object):
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
class GenericRefs(object):
|
||||
NEW_LIB = 0
|
||||
EXPORT_EQUAL = 1
|
||||
EXPORT_SUPER_SET = 2
|
||||
MODIFIED = 3
|
||||
|
||||
def __init__(self):
|
||||
self.refs = dict()
|
||||
|
||||
def add(self, name, symbols):
|
||||
self.refs[name] = symbols
|
||||
|
||||
def _load_from_dir(self, root):
|
||||
root = os.path.abspath(root)
|
||||
prefix_len = len(root) + 1
|
||||
@@ -744,7 +885,7 @@ class GenericRefs(object):
|
||||
path = os.path.join(base, filename)
|
||||
lib_name = '/' + path[prefix_len:-4]
|
||||
with open(path, 'r') as f:
|
||||
self.refs[lib_name] = set(line.strip() for line in f)
|
||||
self.add(lib_name, set(line.strip() for line in f))
|
||||
|
||||
@staticmethod
|
||||
def create_from_dir(root):
|
||||
@@ -752,8 +893,19 @@ class GenericRefs(object):
|
||||
result._load_from_dir(root)
|
||||
return result
|
||||
|
||||
def classify_lib(self, lib):
|
||||
ref_lib_symbols = self.refs.get(lib.path)
|
||||
if not ref_lib_symbols:
|
||||
return GenericRefs.NEW_LIB
|
||||
exported_symbols = lib.elf.exported_symbols
|
||||
if exported_symbols == ref_lib_symbols:
|
||||
return GenericRefs.EXPORT_EQUAL
|
||||
if exported_symbols > ref_lib_symbols:
|
||||
return GenericRefs.EXPORT_SUPER_SET
|
||||
return GenericRefs.MODIFIED
|
||||
|
||||
def is_equivalent_lib(self, lib):
|
||||
return self.refs.get(lib.path) == lib.elf.exported_symbols
|
||||
return self.classify_lib(lib) == GenericRefs.EXPORT_EQUAL
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
@@ -893,15 +1045,14 @@ class VNDKCommand(ELFGraphCommand):
|
||||
for lib_set in lib_sets:
|
||||
for lib in lib_set:
|
||||
for dep in lib.deps:
|
||||
dep_name = os.path.basename(dep.path)
|
||||
if dep_name in NDK_HIGH_LEVEL:
|
||||
if NDK_LIBS.is_hlndk(dep.path):
|
||||
print('warning: {}: VNDK is using high-level NDK {}.'
|
||||
.format(lib.path, dep.path), file=sys.stderr)
|
||||
|
||||
def _warn_banned_vendor_lib_deps(self, graph, banned_libs):
|
||||
for lib in graph.lib_pt[PT_VENDOR].values():
|
||||
for dep in lib.deps:
|
||||
banned = banned_libs.get(os.path.basename(dep.path))
|
||||
banned = banned_libs.is_banned(dep.path)
|
||||
if banned:
|
||||
print('warning: {}: Vendor binary depends on banned {} '
|
||||
'(reason: {})'.format(
|
||||
@@ -1039,6 +1190,28 @@ class DepsClosureCommand(ELFGraphCommand):
|
||||
return 0
|
||||
|
||||
|
||||
class VNDKStableCommand(ELFGraphCommand):
|
||||
def __init__(self):
|
||||
super(VNDKStableCommand, self).__init__(
|
||||
'vndk-stable', help='Find transitive closure of VNDK stable')
|
||||
|
||||
def add_argparser_options(self, parser):
|
||||
super(VNDKStableCommand, self).add_argparser_options(parser)
|
||||
|
||||
parser.add_argument('--closure', action='store_true',
|
||||
help='show the closure')
|
||||
|
||||
def main(self, args):
|
||||
graph = ELFLinker.create(args.system, args.system_dir_as_vendor,
|
||||
args.vendor, args.vendor_dir_as_system,
|
||||
args.load_extra_deps)
|
||||
|
||||
vndk_stable = graph.compute_vndk_stable(closure=args.closure)
|
||||
for lib in sorted_lib_path_list(vndk_stable):
|
||||
print(lib)
|
||||
return 0
|
||||
|
||||
|
||||
class SpHalCommand(ELFGraphCommand):
|
||||
def __init__(self):
|
||||
super(SpHalCommand, self).__init__(
|
||||
@@ -1055,39 +1228,8 @@ class SpHalCommand(ELFGraphCommand):
|
||||
args.vendor, args.vendor_dir_as_system,
|
||||
args.load_extra_deps)
|
||||
|
||||
# Find SP HALs.
|
||||
name_patterns = (
|
||||
# OpenGL-related
|
||||
'^/vendor/.*/libEGL_.*\\.so$',
|
||||
'^/vendor/.*/libGLESv1_CM_.*\\.so$',
|
||||
'^/vendor/.*/libGLESv2_.*\\.so$',
|
||||
'^/vendor/.*/libGLESv3_.*\\.so$',
|
||||
# Vulkan
|
||||
'^/vendor/.*/vulkan.*\\.so$',
|
||||
# libRSDriver
|
||||
'^/vendor/.*/libRSDriver.*\\.so$',
|
||||
'^/vendor/.*/libPVRRS\\.so$',
|
||||
# Gralloc mapper
|
||||
'^.*/gralloc\\..*\\.so$',
|
||||
'^.*/android\\.hardware\\.graphics\\.mapper@\\d+\\.\\d+-impl\\.so$',
|
||||
)
|
||||
|
||||
patt = re.compile('|'.join('(?:' + p + ')' for p in name_patterns))
|
||||
|
||||
# Find root/excluded libraries by their paths.
|
||||
sp_hals = set()
|
||||
for lib_set in graph.lib_pt:
|
||||
for lib in lib_set.values():
|
||||
if patt.match(lib.path):
|
||||
sp_hals.add(lib)
|
||||
|
||||
# Compute the closure (if specified).
|
||||
if args.closure:
|
||||
def is_excluded_libs(lib):
|
||||
return lib.is_ndk
|
||||
sp_hals = graph.compute_closure(sp_hals, is_excluded_libs)
|
||||
|
||||
# Print the result.
|
||||
vndk_stable = graph.compute_vndk_stable(closure=True)
|
||||
sp_hals = graph.compute_sp_hal(vndk_stable, closure=args.closure)
|
||||
for lib in sorted_lib_path_list(sp_hals):
|
||||
print(lib)
|
||||
return 0
|
||||
@@ -1109,6 +1251,7 @@ def main():
|
||||
register_subcmd(DepsCommand())
|
||||
register_subcmd(DepsClosureCommand())
|
||||
register_subcmd(SpHalCommand())
|
||||
register_subcmd(VNDKStableCommand())
|
||||
|
||||
args = parser.parse_args()
|
||||
if not args.subcmd:
|
||||
|
||||
Reference in New Issue
Block a user