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