在运行时选择并加载其中一个备用共享库

时间:2014-10-14 14:18:13

标签: android c++ android-ndk

尝试根据文档中的CPU-ARM-NEON.html向应用程序添加NEON支持。文档提到运行时检查,但事实证明本机库不能同时是普通的v7a和NEON,运行时链接器根本不会在某些设备上加载这样的库。

所以看起来我需要同一个库的两个版本,针对不同的功能进行了优化,以便在运行时手动加载一个。 Reportedly这可以做到,虽然距离ndk-through-eclipse路径还有一步之遥,但我却不知道如何设置。

我想我列出了LOCAL_SHARED_LIBRARIES下的一个版本,以便核心正确链接,但是无论我列出什么,都会添加到核心依赖项中。运行时链接器然后在我加载核心时检查它是否存在,并且即使已经在其位置加载了另一个库,也会抛出它。

此外,未列出的库仍保持未提取状态,并且不会自动添加到包中。我必须从eclipse导出unsigned apk,每次都添加.so,签名,对齐和重新安装,这是可以忍受的但是远非实用。

关于如何在不引入硬编码依赖模块名称的情况下构建核心二进制文件的任何建议?有没有一种文明的方法可以将“未参考”的库与其他东西一起打包?


终于找到了问题 - 有一个带有.neon后缀的霓虹灯和普通代码的混合文件。显然,库可以包含NEON和plain-v7a代码,但是单个文件不能 - d32指令在氖执行路径之外泄漏,运行时链接器执行此操作:

D/dalvikvm(5323): Trying to load lib /data/data/com.my.app/lib/libapp.so 0x410b96e8
A/libc(5323): Fatal signal 4 (SIGILL) at 0x5c21ae92 (code=1)
D/dalvikvm(3908): GC_CONCURRENT freed 222K, 9% free 7010K/7687K, paused 38ms+2ms
I/DEBUG(91): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG(91): Build fingerprint: 'Lenovo/ThinkPadTablet/Indigo:4.0.3/ThinkPadTablet_A400_03/0070_0132_ROW:user/release-keys'
I/DEBUG(91): pid: 5323, tid: 5336  >>> com.my.app <<<
I/DEBUG(91): signal 4 (SIGILL), code 1 (ILL_ILLOPC), fault addr 5c21ae96
I/DEBUG(91):  r0 5c51d250  r1 00000000  r2 00000000  r3 00000000
I/DEBUG(91):  r4 00000000  r5 00000000  r6 00000000  r7 00000000
I/DEBUG(91):  r8 00000000  r9 3f800000  10 3f800000  fp 00000000
I/DEBUG(91):  ip 00000000  sp 5bc1c9d8  lr 5bf7423d  pc 5c21ae96  cpsr 40000070
I/DEBUG(91):  d0  3ef99342e0ee5069  d1  4012d97c7f3321d2
I/DEBUG(91):  d2  3f985a30f4230d02  d3  3fa55553e1053a42
I/DEBUG(91):  d4  543f7d0ef4230d02  d5  41d50fdf43800000
I/DEBUG(91):  d6  0000000000000000  d7  42c8000041f00000
I/DEBUG(91):  d8  0000000000000000  d9  0000000000000000
I/DEBUG(91):  d10 0000000000000000  d11 0000000000000000
I/DEBUG(91):  d12 0000000000000000  d13 0000000000000000
I/DEBUG(91):  d14 0000000000000000  d15 0000000000000000
I/DEBUG(91):  scr 80000012
I/DEBUG(91):          #00  pc 005fde96  /data/data/com.my.app/lib/libapp.so (_ZN4math7Matrix4C2Effffffffffffffff)

  5fde90:   eddd 0b0c   vldr    d16, [sp, #48]  ; 0x30
  5fde94:   eddd 1b0e   vldr    d17, [sp, #56]  ; 0x38
  5fde98:   f8cd 8028   str.w   r8, [sp, #40]   ; 0x28

1 个答案:

答案 0 :(得分:0)

如果您希望能够加载一个库或另一个库而不依赖于模块名称,那么最简单的方法是避免直接链接到该库,只需在运行时加载正确的库并加​​载使用dlsym动态生成符号。如果图书馆只有一些功能/入口点,这不应该太复杂。另一方面,如果库具有非常大的接口(C ++库通常倾向于使用大量入口点,使用dlsym加载更加困难),那就更难了。

从技术上讲,如果这不仅限于android,你可以在不同的目录中有两个不同版本的库,名称相同,并预先加载正确的版本。

但原则上你不一定需要两个不同版本的库。你写道:

  

但事实证明原生库无论如何都不能同时是普通的v7a和NEON,运行时链接器根本不会在某些设备上加载这样的库。

库当然可以包含plain-v7a和NEON代码,并且应该加载到所有armeabi-v7a设备上 - 那里有很多这样的库。您只需要确保公共代码路径不是在启用NEON的情况下构建的,并且只在运行时检查后才使用内部NEON代码路径。这要求库从一开始就考虑到运行时启用的SIMD扩展,但是 - 某些库可能被设计为在编译时决定这些事情。将-mfpu=neon(或将.neon添加到Android.mk中的文件名)添加到通用的非SIMD代码并不能为普通代码添加很多可衡量的性能提升;在最坏的情况下,它偶尔会插入一些指令,这将阻止代码在其他设备上运行,而不会真正帮助提高性能。

NDK中的hello-neon示例是关于如何处理此问题的一个简单示例。实现这一目标的实际真实库是libav和OpenH264,仅举几例。