1. 如何使用第三方so库如何使用第三方so库?
在app的build.gradle中加入
android { sourceSets { main { jniLibs.srcDirs = ['libs'] } } //如下语句用于指定apk只生成指定cpu架构的so文件夹 ndk { abiFilters "armeabi", "armeabi-v7a", "x86", "mips" } }复制代码
2. android6.0以上报错UnsatisfiedLinkError: dlopen failed . text relocations
在使用libserial_port 库时,在android5.1上运行正常,但当移植到7.0上时出现 UnsatisfiedLinkError: dlopen failed . text relocations
- 这个问题出现在loadLibrary()的过程中.
- 在Android 6.0之前, text reloactions问题, 会在编译的过程中, 作为warning报出来, log大致如下:
ActivityManager: WARNING: linker: libdvm.so has text relocations. This is wasting memory and is a security risk. Please fix.复制代码
在Android 6.0中, 原来的warning被升级为error了. 因此, 同样的库文件, 在Android 6.0前的 环境运行, 不报错, 6.0下就会crash掉.
- text reloactions又被称为TEXTREL, 它与PIC相关, 先说PIC:
PIC: Position Independent Code, 指一段代码, 在加载到内存后, 其物理地址与代码本身是无关的.
为什么要使用PIC:
1. 效率相关: 使用PIC后, 代码可以被加载到内存的任意位置, 即不存在某段代码始终对应特定物理地址的情况, 这样的方式, 适用于共享对象的加载.
换个说法, 使用PIC的共享对象, 在内存中是真正"共享"的; 而未使用PIC的共享对象, 在被不同进程加载的过程中, 会产生多个copy, 从而引入效率问题.
2. 安全相关: 使用PIC后, 特定代码被加载的内存地址不确定, 这样可以避免某些内存地址敏感的攻击. RedHat有一篇相关的文章: ,回到TEXTREL, 它实际上是源码中存在"特定代码映射特定地址". 加载代码时, 必须将其加载到特定物理地址, 导致调用这些代码时, 必需增加一个relocation的过程.
解决方案:
方案一 :
把targetSdkVersion设为小于23,这样是可以回避掉上述问题,但只是治标不治本。
方案二 (简单但会影响程序效率):
在使用NDK编译so时配置Android.mk,增添PIC相关的配置项,这样编译出来的so文件将不再有text relocations的问题。具体配置如下:
LOCAL_LDFLAGS += -fPIC复制代码
PIC参数用于编译位置无关代码,生成可用于共享库的位置独立代码。若不添加-fPIC,则加载so文件的代码段时,代码段引用的数据对象需要重定位,重定位会修改代码段内容,这样就导致没使用这个so文件,代码段的进程在内核中就会生成这个文件的拷贝。
参考文章: