Android 源码中jni项目 加载so目录小结
文章目录
一、前言
如何实现把so放到Android设备目录system/lib64下面,系统应用apk就能自动获取里面的so?
如果实现了这个功能,后续修改了jni具体功能实现,
就不用修改这个apk的代码,只要替换这个so就可以完成不同的实现了。
其实这个功能不难,只要是系统源码编译的应用就可以;
具体如何编译可以看本文最后的介绍。
本文主要介绍一下,系统源码应用编译后,load so的顺序:
顺序就是优先apk目录下的 lib/arm64/,然后 system/lib64/,有的还会加载 vendor/lib64/
具体实现是cpp底层的,这里不做具体分析。
二、so目录验证测试
jni加载so代码:
static {
System.loadLibrary("native-lib");
}
这里是没有写so路径的,so的固定命名规则是前面加 lib 后面加.so,所以正确的搜命名是:libnative-lib.so
这里拿一个其他错误的libnative-lib.so和一个正确的libnative-lib.so验证测试。
目录分别测试:apk下面的lib/arm64/,system/lib, system/lib64, vendor/lib64,vendor/lib
应用运行后保存主要有两种,一个是找不到so,一个是so找不到jni的方法。
1、jni so文件错误报错
(1)报错1 - 未找到so文件:
2024-09-04 16:10:42.987 1593-1593/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.demo.jnicallback, PID: 1593
java.lang.UnsatisfiedLinkError: dlopen failed: library "libnative-lib.so" not found
at java.lang.Runtime.loadLibrary0(Runtime.java:1077)
at java.lang.Runtime.loadLibrary0(Runtime.java:998)
at java.lang.System.loadLibrary(System.java:1661)
at com.liwenzhi.jnidemo.JniClass.<clinit>(JniClass.java:16)
at com.demo.jnicallback.MainActivity.onCreate(MainActivity.java:27)
上面那几个目录下都没有so文件就会报这个错误。
(2)报错2 - so文件中未找到native方法:
--------- beginning of crash
2024-09-04 15:32:04.294 1600-1600/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.demo.jnicallback, PID: 1600
java.lang.UnsatisfiedLinkError: No implementation found for java.lang.String com.liwenzhi.jnidemo.JniClass.stringFromJNI() (tried Java_com_liwenzhi_jnidemo_JniClass_stringFromJNI and Java_com_liwenzhi_jnidemo_JniClass_stringFromJNI__)
at com.liwenzhi.jnidemo.JniClass.stringFromJNI(Native Method)
at com.demo.jnicallback.MainActivity.onCreate(MainActivity.java:28)
有so但是so里面的实现方法,包名不正常或者不存在这个 native方法就会报上面这个错误。
2、验证的几种情况
(1)apk下面的 lib/arm64/ 放置正确的so文件
其他目录不管放置错误的so文件还是不放置so文件都是不会报错的;
(2)apk下面的 lib/arm64/ 放置错误的so文件
其他目录不管放置正确的so文件还是不放置so文件都是会报错native方法不一致;
所以上面两个测试,验证了 lib/arm64/ 目录才是首先选择的目录。
(3)apk下面的 lib/arm64/ 不放置so文件
① system/lib 、vendor/lib64 、vendor/lib放置正确的so文件
运行后都是报错未找到so文件错误
测试验证了,system/lib 、vendor/lib64 、vendor/lib 系统不会读取里面的so。
其实这个情况不是绝对的,后面简单说一下,这个和应用的32位、64位有关,但是现在应用基本都是64位的了。
② system/lib64 放置正确的so文件
应用不会报错;
③system/lib64 放置错误的so文件
应用会报错native方法不一致;
测试验证了,系统应用会读取 system/lib64/ 下面的so。
上面几个测试,就验证了 so加载的顺序优先apk目录下的 lib/arm64/,然后 system/lib64/。
其实知道就行了,没啥太大必要进行验证测试。
三、其他
1、系统源码中加载so的具体实现
安卓so加载流程源码分析
https://oacia.dev/android-load-so/
android so的加载流程(Android 13~14)
https://blog.csdn.net/qq_61253776/article/details/141675312
在系统中确实看到有应用是加载到了 vendor/lib64 下面的so,
但是不知道为啥我编的系统应用无法加载到这个目录下面的so,这个有待研究!
2、Android JNI SO库和对应的CPU架构详解
armeabi:第五代、第六代ARM处理器,使用软件浮点运算,很古老的手机是这架构, 出现在2000年左右 。(32位)
armeabi-v7a:第七代ARM处理器,使用硬件浮点运算,2018年以前手机主流架构, 2007年开始出现 。(32位)
arm64-v8a:第八代64位处理器,当前主流架构, 2014年左右出现。(64位)
x86/x86-64:Intel处理器,Android模拟器用得比较多。
X86_64与X64都是讲的同一个东西(64位) 。x86(32位)
每一种CPU架构对应一个ABI,ABI定义了二进制文件(比如SO)如何运行在相应的系统平台。
详细介绍:
https://blog.csdn.net/wenzhi20102321/article/details/137064391
看看so和cpu框架,看看时间,大概就知道为啥现在应用都是64位框架的了,不可能再用十几年前的应用了吧。
如果真的使用32位的cpu框架,
apk下面的so目录是: lib/armeabi-v7a
system下面的so目录是 :system/lib
有的系统会在system/lib 和 system/lib64 都放so,防止运行的是32位的cpu框架的应用报错。
3、Android 系统源码项目加载预编好的so库
本来以为只是介绍一下编译使用的Android.mk或者Android.bp就可以了,
但是事实有点出乎意料,总结下来发现收获了一些知识点;
普通应用开发不一定用到这个知识,但是系统编译开发会用到这个知识,并且有的相关文件还不好解决。
https://blog.csdn.net/wenzhi20102321/article/details/141968262