AOSP的libc++.so和NDK的libc++_shared.so一样吗?

Is AOSP's libc++.so the same as NDK's libc++_shared.so?

我在一个 Android 应用程序中工作,其中一个共享库(我在 Android Studio 中构建,我们称之为 libA.so)动态加载另一个共享库提供程序由供应商提供(我们称之为 libB.so)。我知道我不应该在我的应用程序 (https://developer.android.com/ndk/guides/cpp-support.html#important_considerations) 中使用多个 C++ 运行time 库,所以我们决定在两个库中使用 c++_shared。

libB.so(厂商提供的)在AOSP构建时编译linked(厂商非要这样建库,没办法) . libB.so 的 makefile 将 STL 标志设置为 c++_shared 与此:

LOCAL_NDK_STL_VARIANT := c++_shared

当我查看 libB.so 库中的 NEEDED 标签时,我可以看到对 libc++.so

的依赖
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc++.so] <----
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so]
 0x000000000000000e (SONAME)             Library soname: [libB.so]

当我 运行 readelf -d libc++.so 检查 AOSP 的 libc++.so 的内容时,我得到了这个

Dynamic section at offset 0xe4b40 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000003 (PLTGOT)             0xe6310
 0x0000000000000002 (PLTRELSZ)           22128 (bytes)
 0x0000000000000017 (JMPREL)             0x39ff8
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000007 (RELA)               0x2ce58
 0x0000000000000008 (RELASZ)             53664 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffff9 (RELACOUNT)          380
 0x0000000000000006 (SYMTAB)             0x238
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000005 (STRTAB)             0xdeb8
 0x000000000000000a (STRSZ)              102917 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x270c0
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so]
 0x000000000000000e (SONAME)             Library soname: [libc++.so]
 0x000000000000001a (FINI_ARRAY)         0xe08e0
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x0000000000000019 (INIT_ARRAY)         0xe5b38
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001e (FLAGS)              BIND_NOW
 0x000000006ffffffb (FLAGS_1)            Flags: NOW
 0x000000006ffffff0 (VERSYM)             0x2bb7c
 0x000000006ffffffc (VERDEF)             0x2cddc
 0x000000006ffffffd (VERDEFNUM)          1
 0x000000006ffffffe (VERNEED)            0x2cdf8
 0x000000006fffffff (VERNEEDNUM)         2
 0x0000000000000000 (NULL)               0x0

我知道 NDK 也提供 libc++.so,但是当我 运行 在 Android NDK 分发的库中执行相同的命令时,我得到一个错误

readelf: Error: libc++.so: Failed to read file header

如果我没记错的话,那是因为在 NDK 中,libc++.so 实际上是一个 linker 脚本。

libA.so(我用我的应用程序构建并加载 libB.so 的那个)最终依赖于 libc++_shared.so

Dynamic section at offset 0x4bca50 contains 28 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so]
 0x0000000000000001 (NEEDED)             Shared library: [liblog.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc++_shared.so] <---
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
 0x000000000000000e (SONAME)             Library soname: [libA.so]

我认为我不能(或不应该)在我的应用程序中捆绑 libc++.solibc++_shared.so

那么,AOSP的libc++.so和NDK的libc++_shared.so一样吗?

有人知道为什么即使使用 LOCAL_NDK_STL_VARIANT := c++_shared AOSP 也会为 libc++.so 添加动态依赖而不是 libc++_shared.so 吗?我应该让我的提供者 link 而不是 libc++_shared.so 吗?也许有人有更好的建议来解决这个依赖不匹配问题。

首先,可以在一个应用中混合使用不同的 C++ 运行时,只要它们不交互。这意味着 C++ 对象(包括异常)不应跨越其共享库的边界。因此,如果你的 libB.so 提供了一个 extern "C" public API,你可以安全地使用为 any C++ 运行时编译的组件中的这些函数,甚至 stlport_static.

如果供应商库不导出纯 C API,则违反了架构规定(参见 https://source.android.com/devices/architecture/images/vndk_design_android_o.pdf,第 27 页)。在这种情况下,您可能还需要构建依赖的 libA.so 作为 AOSP 的一部分。如果您选择将您的库更紧密地耦合到 libB.so,例如扩展它的一些 类,跨 libA/libB 边界抛出异常,等等

请注意,由于 Android N,系统链接器 protects platform libraries (those in /system/lib and /vendor/lib) from being dlopened from user code. You should consider adding libB, or libA, or both, to the whitelist

不,它们不等价。 AOSP 中的 libc++.so 是针对最新的(技术上是 futureAPI 级别)API 级别构建的,没有 libandroid_support。它是用一组不同的标志构建的,并且可能是一个不同的 ABI。它使用一组体系结构标志构建,允许编译器使用并非在所有 Android 设备上可用的指令。它也是与NDK中的不同的修订,但对于不同的NDK版本也是如此,并且在决定它们是否兼容时意义不大。

如果供应商向您提供 libB.so 以包含在您的应用中,则他们构建的应用不正确。正如您所注意到的,它是针对平台 libc++.so 的 linking,应用程序无法访问该平台。你这边没有解决办法;供应商需要提供合适的 NDK 库。如果他们想继续使用 AOSP 构建系统,他们需要设置 LOCAL_SDK_VERSION 这样 LOCAL_NDK_STL_VARIANT 就不会被忽略。

如果供应商提供的设备在系统映像中安装了此库(即 /system/lib64/libB.so, 包含在您的应用程序中),则指南在@alex-cohn 的回答中适用。这就是 libandroid.so 等官方 NDK 库的构建方式。他们 link 针对系统的 libc++.so,但只向应用程序公开 C ABI。只要供应商遵循这些准则,就可以了。

正如 Alex 所提到的,您引用的文件比实际情况略有限制。 可以在同一个程序中使用多个 STL(否则 NDK 应用程序根本无法工作,因为平台和应用程序使用不同的 STL),但这确实需要非常小心的管理您的 ABI 表面积,并且要格外小心以避免违反 ODR。