Home | History | Annotate | Download | only in tests
      1 #!/usr/bin/env python3
      2 
      3 import os
      4 import re
      5 import sys
      6 import tempfile
      7 import unittest
      8 
      9 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
     10 
     11 from compat import StringIO, patch
     12 from utils import GraphBuilder
     13 from vndk_definition_tool import (
     14     ELF, ELFLinker, GenericRefs, PT_SYSTEM, PT_VENDOR, VNDKLibDir)
     15 
     16 
     17 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
     18 
     19 
     20 class ELFLinkerTest(unittest.TestCase):
     21     def _create_normal_graph(self):
     22         gb = GraphBuilder()
     23 
     24         gb.add_multilib(PT_SYSTEM, 'libdl',
     25                         exported_symbols={'dlclose', 'dlopen', 'dlsym'})
     26 
     27         gb.add_multilib(PT_SYSTEM, 'libm', exported_symbols={'cos', 'sin'})
     28 
     29         gb.add_multilib(PT_SYSTEM, 'libc', dt_needed=['libdl.so', 'libm.so'],
     30                         exported_symbols={'fclose', 'fopen', 'fread'},
     31                         imported_symbols={'dlclose', 'dlopen', 'cos', 'sin'})
     32 
     33         gb.add_multilib(PT_SYSTEM, 'libRS', dt_needed=['libdl.so'],
     34                         exported_symbols={'rsContextCreate'},
     35                         imported_symbols={'dlclose', 'dlopen', 'dlsym'})
     36 
     37         gb.add_multilib(PT_SYSTEM, 'libcutils',
     38                         dt_needed=['libc.so', 'libdl.so'],
     39                         imported_symbols={'dlclose', 'dlopen', 'fclose',
     40                                           'fopen'})
     41 
     42         gb.add_multilib(PT_VENDOR, 'libEGL',
     43                         dt_needed=['libc.so', 'libcutils.so', 'libdl.so'],
     44                         exported_symbols={'eglGetDisplay'},
     45                         imported_symbols={'fclose', 'fopen'})
     46 
     47         gb.resolve()
     48         return gb
     49 
     50 
     51     def _get_paths_from_nodes(self, nodes):
     52         return sorted([node.path for node in nodes])
     53 
     54 
     55     def test_get_lib(self):
     56         gb = self._create_normal_graph()
     57         graph = gb.graph
     58 
     59         node = graph.get_lib('/system/lib/libc.so')
     60         self.assertEqual(gb.libc_32, node)
     61         self.assertEqual('/system/lib/libc.so', node.path)
     62 
     63         node = graph.get_lib('/system/lib64/libdl.so')
     64         self.assertEqual(gb.libdl_64, node)
     65         self.assertEqual('/system/lib64/libdl.so', node.path)
     66 
     67         node = graph.get_lib('/vendor/lib64/libEGL.so')
     68         self.assertEqual(gb.libEGL_64, node)
     69         self.assertEqual('/vendor/lib64/libEGL.so', node.path)
     70 
     71         self.assertEqual(None, graph.get_lib('/no/such/path.so'))
     72 
     73 
     74     def test_map_paths_to_libs(self):
     75         gb = self._create_normal_graph()
     76         graph = gb.graph
     77 
     78         bad = []
     79         paths = ['/system/lib/libc.so', '/system/lib/libdl.so']
     80         nodes = graph.get_libs(paths, bad.append)
     81 
     82         self.assertEqual([], bad)
     83         self.assertEqual(2, len(nodes))
     84         self.assertEqual(paths, self._get_paths_from_nodes(nodes))
     85 
     86         bad = []
     87         paths = ['/no/such/path.so', '/system/lib64/libdl.so']
     88         nodes = graph.get_libs(paths, bad.append)
     89         self.assertEqual(['/no/such/path.so'], bad)
     90         self.assertEqual(['/system/lib64/libdl.so'],
     91                          self._get_paths_from_nodes(nodes))
     92 
     93 
     94     def test_elf_class_and_partitions(self):
     95         gb = self._create_normal_graph()
     96         graph = gb.graph
     97         self.assertEqual(5, len(graph.lib_pt[PT_SYSTEM].lib32))
     98         self.assertEqual(5, len(graph.lib_pt[PT_SYSTEM].lib64))
     99         self.assertEqual(1, len(graph.lib_pt[PT_VENDOR].lib32))
    100         self.assertEqual(1, len(graph.lib_pt[PT_VENDOR].lib64))
    101 
    102 
    103     def test_deps(self):
    104         gb = self._create_normal_graph()
    105         graph = gb.graph
    106 
    107         # Check the dependencies of libc.so.
    108         node = gb.graph.get_lib('/system/lib/libc.so')
    109         self.assertEqual(['/system/lib/libdl.so', '/system/lib/libm.so'],
    110                          self._get_paths_from_nodes(node.deps_all))
    111 
    112         # Check the dependencies of libRS.so.
    113         node = gb.graph.get_lib('/system/lib64/libRS.so')
    114         self.assertEqual(['/system/lib64/libdl.so'],
    115                          self._get_paths_from_nodes(node.deps_all))
    116 
    117         # Check the dependencies of libEGL.so.
    118         node = gb.graph.get_lib('/vendor/lib64/libEGL.so')
    119         self.assertEqual(['/system/lib64/libc.so', '/system/lib64/libcutils.so',
    120                           '/system/lib64/libdl.so'],
    121                          self._get_paths_from_nodes(node.deps_all))
    122 
    123 
    124     def test_linked_symbols(self):
    125         gb = self._create_normal_graph()
    126         graph = gb.graph
    127 
    128         # Check the unresolved symbols.
    129         for lib_set in graph.lib_pt:
    130             for lib in lib_set.values():
    131                 self.assertEqual(set(), lib.unresolved_symbols)
    132 
    133         # Check the linked symbols.
    134         for lib in ('lib', 'lib64'):
    135             libdl = graph.get_lib('/system/' + lib + '/libdl.so')
    136             libm = graph.get_lib('/system/' + lib + '/libm.so')
    137             libc = graph.get_lib('/system/' + lib + '/libc.so')
    138             libRS = graph.get_lib('/system/' + lib + '/libRS.so')
    139             libcutils = \
    140                     graph.get_lib('/system/' + lib + '/libcutils.so')
    141             libEGL = graph.get_lib('/vendor/' + lib + '/libEGL.so')
    142 
    143             # Check the linked symbols for libc.so.
    144             self.assertIs(libdl, libc.linked_symbols['dlclose'])
    145             self.assertIs(libdl, libc.linked_symbols['dlopen'])
    146             self.assertIs(libm, libc.linked_symbols['cos'])
    147             self.assertIs(libm, libc.linked_symbols['sin'])
    148 
    149             # Check the linked symbols for libRS.so.
    150             self.assertIs(libdl, libRS.linked_symbols['dlclose'])
    151             self.assertIs(libdl, libRS.linked_symbols['dlopen'])
    152             self.assertIs(libdl, libRS.linked_symbols['dlsym'])
    153 
    154             # Check the linked symbols for libcutils.so.
    155             self.assertIs(libdl, libcutils.linked_symbols['dlclose'])
    156             self.assertIs(libdl, libcutils.linked_symbols['dlopen'])
    157             self.assertIs(libc, libcutils.linked_symbols['fclose'])
    158             self.assertIs(libc, libcutils.linked_symbols['fopen'])
    159 
    160             # Check the linked symbols for libEGL.so.
    161             self.assertIs(libc, libEGL.linked_symbols['fclose'])
    162             self.assertIs(libc, libEGL.linked_symbols['fopen'])
    163 
    164 
    165     def test_unresolved_symbols(self):
    166         gb = GraphBuilder()
    167         gb.add_lib(PT_SYSTEM, ELF.ELFCLASS64, 'libfoo', dt_needed=[],
    168                    exported_symbols={'foo', 'bar'},
    169                    imported_symbols={'__does_not_exist'})
    170         gb.resolve()
    171 
    172         lib = gb.graph.get_lib('/system/lib64/libfoo.so')
    173         self.assertEqual({'__does_not_exist'}, lib.unresolved_symbols)
    174 
    175 
    176     def test_users(self):
    177         gb = self._create_normal_graph()
    178         graph = gb.graph
    179 
    180         # Check the users of libc.so.
    181         node = graph.get_lib('/system/lib/libc.so')
    182         self.assertEqual(['/system/lib/libcutils.so', '/vendor/lib/libEGL.so'],
    183                          self._get_paths_from_nodes(node.users_all))
    184 
    185         # Check the users of libdl.so.
    186         node = graph.get_lib('/system/lib/libdl.so')
    187         self.assertEqual(['/system/lib/libRS.so', '/system/lib/libc.so',
    188                           '/system/lib/libcutils.so', '/vendor/lib/libEGL.so'],
    189                          self._get_paths_from_nodes(node.users_all))
    190 
    191         # Check the users of libRS.so.
    192         node = graph.get_lib('/system/lib64/libRS.so')
    193         self.assertEqual([], self._get_paths_from_nodes(node.users_all))
    194 
    195         # Check the users of libEGL.so.
    196         node = graph.get_lib('/vendor/lib64/libEGL.so')
    197         self.assertEqual([], self._get_paths_from_nodes(node.users_all))
    198 
    199 
    200     def test_compute_predefined_sp_hal(self):
    201         gb = GraphBuilder()
    202 
    203         # HIDL SP-HAL implementation.
    204         gb.add_multilib(PT_SYSTEM, 'gralloc.default', extra_dir='hw')
    205         gb.add_multilib(PT_SYSTEM, 'gralloc.chipset', extra_dir='hw')
    206         gb.add_multilib(PT_SYSTEM, 'android.hardware.graphics.mapper (at] 2.0-impl',
    207                         extra_dir='hw')
    208 
    209         # NDK loader libraries should not be considered as SP-HALs.
    210         gb.add_multilib(PT_SYSTEM, 'libvulkan')
    211         gb.add_multilib(PT_SYSTEM, 'libEGL')
    212         gb.add_multilib(PT_SYSTEM, 'libGLESv1_CM')
    213         gb.add_multilib(PT_SYSTEM, 'libGLESv2')
    214         gb.add_multilib(PT_SYSTEM, 'libGLESv3')
    215 
    216         # OpenGL implementation.
    217         gb.add_multilib(PT_VENDOR, 'libEGL_chipset', extra_dir='egl')
    218         gb.add_multilib(PT_VENDOR, 'libGLES_chipset', extra_dir='egl')
    219         gb.add_multilib(PT_VENDOR, 'libGLESv1_CM_chipset', extra_dir='egl')
    220         gb.add_multilib(PT_VENDOR, 'libGLESv2_chipset', extra_dir='egl')
    221         gb.add_multilib(PT_VENDOR, 'libGLESv3_chipset', extra_dir='egl')
    222 
    223         # Renderscript implementation.
    224         gb.add_multilib(PT_VENDOR, 'libRSDriver_chipset')
    225         gb.add_multilib(PT_VENDOR, 'libPVRRS')
    226 
    227         # Vulkan implementation.
    228         gb.add_multilib(PT_VENDOR, 'vulkan.chipset', extra_dir='hw')
    229 
    230         # Some un-related libraries.
    231         gb.add_multilib(PT_SYSTEM, 'libfoo')
    232         gb.add_multilib(PT_VENDOR, 'libfoo')
    233 
    234         gb.resolve()
    235 
    236         # Compute SP-HAL.
    237         sp_hals = set(lib.path for lib in gb.graph.compute_predefined_sp_hal())
    238 
    239         for lib in ('lib', 'lib64'):
    240             # Check HIDL SP-HAL implementation.
    241             self.assertIn('/system/' + lib + '/hw/gralloc.default.so', sp_hals)
    242             self.assertIn('/system/' + lib + '/hw/gralloc.chipset.so', sp_hals)
    243             self.assertIn('/system/' + lib + '/hw/'
    244                           'android.hardware.graphics.mapper (at] 2.0-impl.so',
    245                           sp_hals)
    246 
    247 
    248             # Check that NDK loaders are not SP-HALs.
    249             self.assertNotIn('/system/' + lib + '/libvulkan.so', sp_hals)
    250             self.assertNotIn('/system/' + lib + '/libEGL.so', sp_hals)
    251             self.assertNotIn('/system/' + lib + '/libGLESv1_CM.so', sp_hals)
    252             self.assertNotIn('/system/' + lib + '/libGLESv2.so', sp_hals)
    253             self.assertNotIn('/system/' + lib + '/libGLESv3.so', sp_hals)
    254 
    255             # Check that OpenGL implementations are SP-HALs.
    256             self.assertIn('/vendor/' + lib + '/egl/libEGL_chipset.so', sp_hals)
    257             self.assertIn('/vendor/' + lib + '/egl/libGLES_chipset.so',
    258                           sp_hals)
    259             self.assertIn('/vendor/' + lib + '/egl/libGLESv1_CM_chipset.so',
    260                           sp_hals)
    261             self.assertIn('/vendor/' + lib + '/egl/libGLESv2_chipset.so',
    262                           sp_hals)
    263             self.assertIn('/vendor/' + lib + '/egl/libGLESv3_chipset.so',
    264                           sp_hals)
    265 
    266             # Check that Renderscript implementations are SP-HALs.
    267             self.assertIn('/vendor/' + lib + '/libRSDriver_chipset.so', sp_hals)
    268             self.assertIn('/vendor/' + lib + '/libPVRRS.so', sp_hals)
    269 
    270             # Check that vulkan implementation are SP-HALs.
    271             self.assertIn('/vendor/' + lib + '/libPVRRS.so', sp_hals)
    272 
    273             # Check that un-related libraries are not SP-HALs.
    274             self.assertNotIn('/system/' + lib + '/libfoo.so', sp_hals)
    275             self.assertNotIn('/vendor/' + lib + '/libfoo.so', sp_hals)
    276 
    277 
    278     def test_compute_sp_lib(self):
    279         # Create graph.
    280         gb = GraphBuilder()
    281 
    282         # LL-NDK (should be excluded from result)
    283         gb.add_multilib(PT_SYSTEM, 'libc')
    284 
    285         libEGL_32, libEGL_64 = \
    286                 gb.add_multilib(PT_SYSTEM, 'libEGL',
    287                                 dt_needed=['libc.so', 'libutils.so'])
    288 
    289         # LL-NDK dependencies
    290         gb.add_multilib(PT_SYSTEM, 'libutils',
    291                         dt_needed=['libc.so', 'libcutils.so'])
    292 
    293         # VNDK-SP used by both LL-NDK and SP-HAL
    294         gb.add_multilib(PT_SYSTEM, 'libsp_both_vs')
    295 
    296         # VNDK-SP used by LL-NDK
    297         gb.add_multilib(PT_SYSTEM, 'libcutils_dep', dt_needed=['libc.so'])
    298         gb.add_multilib(PT_SYSTEM, 'libcutils',
    299                         dt_needed=['libc.so', 'libcutils_dep.so',
    300                                    'libsp_both_vs.so'])
    301 
    302         # VNDK-SP used by SP-HAL
    303         gb.add_multilib(PT_SYSTEM, 'libhidlbase')
    304         gb.add_multilib(PT_SYSTEM, 'libhidlmemory',
    305                         dt_needed=['libhidlbase.so', 'libsp_both_vs.so'])
    306 
    307         # SP-HAL dependencies
    308         gb.add_multilib(PT_VENDOR, 'libllvm_vendor_dep')
    309         gb.add_multilib(PT_VENDOR, 'libllvm_vendor',
    310                         dt_needed=['libc.so', 'libllvm_vendor_dep.so'])
    311 
    312         # SP-HAL
    313         libEGL_chipset_32, libEGL_chipset_64 = \
    314                 gb.add_multilib(PT_VENDOR, 'libEGL_chipset', extra_dir='egl',
    315                                 dt_needed=['libc.so', 'libllvm_vendor.so',
    316                                            'libhidlmemory.so'])
    317 
    318         gb.resolve()
    319 
    320         # Add dlopen() dependencies from libEGL to libEGL_chipset.
    321         libEGL_32.add_dlopen_dep(libEGL_chipset_32)
    322         libEGL_64.add_dlopen_dep(libEGL_chipset_64)
    323 
    324         # Create generic reference.
    325         class MockGenericRefs(object):
    326             def classify_lib(self, lib):
    327                 if 'libllvm_vendor' in lib.path:
    328                     return GenericRefs.NEW_LIB
    329                 return GenericRefs.EXPORT_EQUAL
    330 
    331         sp_lib = gb.graph.compute_sp_lib(MockGenericRefs())
    332 
    333         self.assertEqual(2 * 1, len(sp_lib.sp_hal))
    334         self.assertEqual(2 * 2, len(sp_lib.sp_hal_dep))
    335         self.assertEqual(2 * 2, len(sp_lib.vndk_sp_hal))
    336         self.assertEqual(2 * 2, len(sp_lib.ll_ndk))
    337         self.assertEqual(2 * 3, len(sp_lib.ll_ndk_indirect))
    338         self.assertEqual(2 * 1, len(sp_lib.vndk_sp_both))
    339 
    340         sp_hal = self._get_paths_from_nodes(sp_lib.sp_hal)
    341         sp_hal_dep = self._get_paths_from_nodes(sp_lib.sp_hal_dep)
    342         vndk_sp_hal = self._get_paths_from_nodes(sp_lib.vndk_sp_hal)
    343 
    344         ll_ndk = self._get_paths_from_nodes(sp_lib.ll_ndk)
    345         ll_ndk_indirect = self._get_paths_from_nodes(sp_lib.ll_ndk_indirect)
    346 
    347         vndk_sp_both = self._get_paths_from_nodes(sp_lib.vndk_sp_both)
    348 
    349         for lib_dir in ('lib', 'lib64'):
    350             # VNDK-SP used by both LL-NDK and SP-HAL
    351             self.assertIn('/system/{}/libsp_both_vs.so'.format(lib_dir),
    352                           vndk_sp_both)
    353 
    354             # VNDK-SP used by LL-NDK
    355             self.assertIn('/system/{}/libcutils.so'.format(lib_dir),
    356                           ll_ndk_indirect)
    357             self.assertIn('/system/{}/libcutils_dep.so'.format(lib_dir),
    358                           ll_ndk_indirect)
    359             self.assertIn('/system/{}/libutils.so'.format(lib_dir),
    360                           ll_ndk_indirect)
    361 
    362             # VNDK-SP used by SP-HAL
    363             self.assertIn('/system/{}/libhidlbase.so'.format(lib_dir),
    364                           vndk_sp_hal)
    365             self.assertIn('/system/{}/libhidlmemory.so'.format(lib_dir),
    366                           vndk_sp_hal)
    367 
    368             # SP-HAL dependencies
    369             self.assertIn('/vendor/{}/libllvm_vendor.so'.format(lib_dir),
    370                           sp_hal_dep)
    371             self.assertIn('/vendor/{}/libllvm_vendor_dep.so'.format(lib_dir),
    372                           sp_hal_dep)
    373 
    374             # SP-HAL
    375             self.assertIn('/vendor/{}/egl/libEGL_chipset.so'.format(lib_dir),
    376                           sp_hal)
    377 
    378             # LL-NDK
    379             self.assertIn('/system/{}/libEGL.so'.format(lib_dir), ll_ndk)
    380             self.assertIn('/system/{}/libc.so'.format(lib_dir), ll_ndk)
    381 
    382             # LL-NDK must not in sp_hal, sp_hal_dep, and vndk_sp_hal.
    383             libc_path = '/system/{}/libc.so'.format(lib_dir)
    384             self.assertNotIn(libc_path, sp_hal)
    385             self.assertNotIn(libc_path, sp_hal_dep)
    386             self.assertNotIn(libc_path, vndk_sp_hal)
    387             self.assertNotIn(libc_path, ll_ndk_indirect)
    388 
    389 
    390     def test_link_vndk_ver_dirs(self):
    391         gb = GraphBuilder()
    392 
    393         libc_32, libc_64 = gb.add_multilib(PT_SYSTEM, 'libc')
    394 
    395         libvndk_a_32, libvndk_a_64 = gb.add_multilib(
    396                 PT_SYSTEM, 'libvndk_a', extra_dir='vndk-28',
    397                 dt_needed=['libc.so', 'libvndk_b.so', 'libvndk_sp_b.so'])
    398 
    399         libvndk_b_32, libvndk_b_64 = gb.add_multilib(
    400                 PT_SYSTEM, 'libvndk_b', extra_dir='vndk-28',
    401                 dt_needed=['libc.so', 'libvndk_sp_b.so'])
    402 
    403         libvndk_c_32, libvndk_c_64 = gb.add_multilib(
    404                 PT_VENDOR, 'libvndk_c', extra_dir='vndk-28',
    405                 dt_needed=['libc.so', 'libvndk_d.so', 'libvndk_sp_d.so'])
    406 
    407         libvndk_d_32, libvndk_d_64 = gb.add_multilib(
    408                 PT_VENDOR, 'libvndk_d', extra_dir='vndk-28',
    409                 dt_needed=['libc.so', 'libvndk_sp_d.so'])
    410 
    411         libvndk_sp_a_32, libvndk_sp_a_64 = gb.add_multilib(
    412                 PT_SYSTEM, 'libvndk_sp_a', extra_dir='vndk-sp-28',
    413                 dt_needed=['libc.so', 'libvndk_sp_b.so'])
    414 
    415         libvndk_sp_b_32, libvndk_sp_b_64 = gb.add_multilib(
    416                 PT_SYSTEM, 'libvndk_sp_b', extra_dir='vndk-sp-28',
    417                 dt_needed=['libc.so'])
    418 
    419         libvndk_sp_c_32, libvndk_sp_c_64 = gb.add_multilib(
    420                 PT_VENDOR, 'libvndk_sp_c', extra_dir='vndk-sp-28',
    421                 dt_needed=['libc.so', 'libvndk_sp_d.so'])
    422 
    423         libvndk_sp_d_32, libvndk_sp_d_64 = gb.add_multilib(
    424                 PT_VENDOR, 'libvndk_sp_d', extra_dir='vndk-sp-28',
    425                 dt_needed=['libc.so'])
    426 
    427         gb.resolve(VNDKLibDir.create_from_version('28'), '28')
    428 
    429         # 32-bit shared libraries
    430         self.assertIn(libc_32, libvndk_a_32.deps_all)
    431         self.assertIn(libc_32, libvndk_b_32.deps_all)
    432         self.assertIn(libc_32, libvndk_c_32.deps_all)
    433         self.assertIn(libc_32, libvndk_d_32.deps_all)
    434         self.assertIn(libc_32, libvndk_sp_a_32.deps_all)
    435         self.assertIn(libc_32, libvndk_sp_b_32.deps_all)
    436         self.assertIn(libc_32, libvndk_sp_c_32.deps_all)
    437         self.assertIn(libc_32, libvndk_sp_d_32.deps_all)
    438 
    439         self.assertIn(libvndk_b_32, libvndk_a_32.deps_all)
    440         self.assertIn(libvndk_sp_b_32, libvndk_a_32.deps_all)
    441         self.assertIn(libvndk_sp_b_32, libvndk_b_32.deps_all)
    442         self.assertIn(libvndk_sp_b_32, libvndk_sp_a_32.deps_all)
    443 
    444         self.assertIn(libvndk_d_32, libvndk_c_32.deps_all)
    445         self.assertIn(libvndk_sp_d_32, libvndk_c_32.deps_all)
    446         self.assertIn(libvndk_sp_d_32, libvndk_d_32.deps_all)
    447         self.assertIn(libvndk_sp_d_32, libvndk_sp_c_32.deps_all)
    448 
    449         # 64-bit shared libraries
    450         self.assertIn(libc_64, libvndk_a_64.deps_all)
    451         self.assertIn(libc_64, libvndk_b_64.deps_all)
    452         self.assertIn(libc_64, libvndk_c_64.deps_all)
    453         self.assertIn(libc_64, libvndk_d_64.deps_all)
    454         self.assertIn(libc_64, libvndk_sp_a_64.deps_all)
    455         self.assertIn(libc_64, libvndk_sp_b_64.deps_all)
    456         self.assertIn(libc_64, libvndk_sp_c_64.deps_all)
    457         self.assertIn(libc_64, libvndk_sp_d_64.deps_all)
    458 
    459         self.assertIn(libvndk_b_64, libvndk_a_64.deps_all)
    460         self.assertIn(libvndk_sp_b_64, libvndk_a_64.deps_all)
    461         self.assertIn(libvndk_sp_b_64, libvndk_b_64.deps_all)
    462         self.assertIn(libvndk_sp_b_64, libvndk_sp_a_64.deps_all)
    463 
    464         self.assertIn(libvndk_d_64, libvndk_c_64.deps_all)
    465         self.assertIn(libvndk_sp_d_64, libvndk_c_64.deps_all)
    466         self.assertIn(libvndk_sp_d_64, libvndk_d_64.deps_all)
    467         self.assertIn(libvndk_sp_d_64, libvndk_sp_c_64.deps_all)
    468 
    469 
    470 class ELFLinkerDlopenDepsTest(unittest.TestCase):
    471     def test_add_dlopen_deps(self):
    472         gb = GraphBuilder()
    473         liba = gb.add_lib32(PT_SYSTEM, 'liba')
    474         libb = gb.add_lib32(PT_SYSTEM, 'libb')
    475         gb.resolve()
    476 
    477         with tempfile.NamedTemporaryFile(mode='w') as tmp_file:
    478             tmp_file.write('/system/lib/liba.so: /system/lib/libb.so')
    479             tmp_file.seek(0)
    480             gb.graph.add_dlopen_deps(tmp_file.name)
    481 
    482         self.assertIn(libb, liba.deps_dlopen)
    483         self.assertIn(liba, libb.users_dlopen)
    484 
    485         self.assertNotIn(libb, liba.deps_needed)
    486         self.assertNotIn(liba, libb.users_needed)
    487 
    488 
    489     def test_add_dlopen_deps_lib_subst(self):
    490         gb = GraphBuilder()
    491         liba_32, liba_64 = gb.add_multilib(PT_SYSTEM, 'liba')
    492         libb_32, libb_64 = gb.add_multilib(PT_SYSTEM, 'libb')
    493         gb.resolve()
    494 
    495         with tempfile.NamedTemporaryFile(mode='w') as tmp_file:
    496             tmp_file.write('/system/${LIB}/liba.so: /system/${LIB}/libb.so')
    497             tmp_file.seek(0)
    498             gb.graph.add_dlopen_deps(tmp_file.name)
    499 
    500         self.assertIn(libb_32, liba_32.deps_dlopen)
    501         self.assertIn(liba_32, libb_32.users_dlopen)
    502 
    503         self.assertIn(libb_64, liba_64.deps_dlopen)
    504         self.assertIn(liba_64, libb_64.users_dlopen)
    505 
    506 
    507     def test_add_dlopen_deps_lib_subset_single_bitness(self):
    508         gb = GraphBuilder()
    509         liba_32, liba_64 = gb.add_multilib(PT_SYSTEM, 'liba')
    510         libb_32 = gb.add_lib32(PT_SYSTEM, 'libb')
    511         gb.resolve()
    512 
    513         with tempfile.NamedTemporaryFile(mode='w') as tmp_file:
    514             tmp_file.write('/system/${LIB}/libb.so: /system/${LIB}/liba.so')
    515             tmp_file.seek(0)
    516 
    517             stderr = StringIO()
    518             with patch('sys.stderr', stderr):
    519                 gb.graph.add_dlopen_deps(tmp_file.name)
    520 
    521             self.assertEqual('', stderr.getvalue())
    522 
    523         self.assertIn(liba_32, libb_32.deps_dlopen)
    524         self.assertIn(libb_32, liba_32.users_dlopen)
    525 
    526         self.assertEqual(0, len(liba_64.users_dlopen))
    527 
    528 
    529     def test_add_dlopen_deps_regex(self):
    530         gb = GraphBuilder()
    531         liba = gb.add_lib32(PT_SYSTEM, 'liba')
    532         libb = gb.add_lib32(PT_SYSTEM, 'libb')
    533         gb.resolve()
    534 
    535         with tempfile.NamedTemporaryFile(mode='w') as tmp_file:
    536             tmp_file.write('[regex].*libb\\.so: [regex].*/${LIB}/liba\\.so')
    537             tmp_file.seek(0)
    538 
    539             stderr = StringIO()
    540             with patch('sys.stderr', stderr):
    541                 gb.graph.add_dlopen_deps(tmp_file.name)
    542 
    543             self.assertEqual('', stderr.getvalue())
    544 
    545         self.assertIn(liba, libb.deps_dlopen)
    546         self.assertIn(libb, liba.users_dlopen)
    547 
    548 
    549     def test_add_dlopen_deps_error(self):
    550         gb = GraphBuilder()
    551         liba = gb.add_lib32(PT_SYSTEM, 'liba')
    552         libb = gb.add_lib32(PT_SYSTEM, 'libb')
    553         gb.resolve()
    554 
    555         with tempfile.NamedTemporaryFile(mode='w') as tmp_file:
    556             tmp_file.write('/system/lib/libc.so: /system/lib/libd.so')
    557             tmp_file.seek(0)
    558 
    559             stderr = StringIO()
    560             with patch('sys.stderr', stderr):
    561                 gb.graph.add_dlopen_deps(tmp_file.name)
    562 
    563             self.assertRegexpMatches(
    564                     stderr.getvalue(),
    565                     'error:' + re.escape(tmp_file.name) + ':1: ' +
    566                     'Failed to add dlopen dependency from .* to .*\\.\n')
    567 
    568 
    569 if __name__ == '__main__':
    570     unittest.main()
    571