Android 源码中jni项目 加载so目录小结

2024-09-07 04:28

本文主要是介绍Android 源码中jni项目 加载so目录小结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android 源码中jni项目 加载so目录小结

文章目录

  • Android 源码中jni项目 加载so目录小结
    • 一、前言
    • 二、so目录验证测试
      • 1、jni so文件错误报错
        • (1)报错1 - 未找到so文件:
        • (2)报错2 - so文件中未找到native方法:
      • 2、验证的几种情况
        • (1)apk下面的 lib/arm64/ 放置正确的so文件
        • (2)apk下面的 lib/arm64/ 放置错误的so文件
        • 所以上面两个测试,验证了 lib/arm64/ 目录才是首先选择的目录。
        • (3)apk下面的 lib/arm64/ 不放置so文件
          • ① system/lib 、vendor/lib64 、vendor/lib放置正确的so文件
        • 测试验证了,system/lib 、vendor/lib64 、vendor/lib 系统不会读取里面的so。
          • ② system/lib64 放置正确的so文件
          • ③system/lib64 放置错误的so文件
        • 测试验证了,系统应用会读取 system/lib64/ 下面的so。
    • 三、其他
      • 1、系统源码中加载so的具体实现
      • 2、Android JNI SO库和对应的CPU架构详解
      • 3、Android 系统源码项目加载预编好的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: mainProcess: com.demo.jnicallback, PID: 1593java.lang.UnsatisfiedLinkError: dlopen failed: library "libnative-lib.so" not foundat 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: mainProcess: com.demo.jnicallback, PID: 1600java.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

这篇关于Android 源码中jni项目 加载so目录小结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1144052

相关文章

mybatis映射器配置小结

《mybatis映射器配置小结》本文详解MyBatis映射器配置,重点讲解字段映射的三种解决方案(别名、自动驼峰映射、resultMap),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定... 目录select中字段的映射问题使用SQL语句中的别名功能使用mapUnderscoreToCame

Vue和React受控组件的区别小结

《Vue和React受控组件的区别小结》本文主要介绍了Vue和React受控组件的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录背景React 的实现vue3 的实现写法一:直接修改事件参数写法二:通过ref引用 DOMVu

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可

sky-take-out项目中Redis的使用示例详解

《sky-take-out项目中Redis的使用示例详解》SpringCache是Spring的缓存抽象层,通过注解简化缓存管理,支持Redis等提供者,适用于方法结果缓存、更新和删除操作,但无法实现... 目录Spring Cache主要特性核心注解1.@Cacheable2.@CachePut3.@Ca

Java Stream 并行流简介、使用与注意事项小结

《JavaStream并行流简介、使用与注意事项小结》Java8并行流基于StreamAPI,利用多核CPU提升计算密集型任务效率,但需注意线程安全、顺序不确定及线程池管理,可通过自定义线程池与C... 目录1. 并行流简介​特点:​2. 并行流的简单使用​示例:并行流的基本使用​3. 配合自定义线程池​示

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对

SpringBoot通过main方法启动web项目实践

《SpringBoot通过main方法启动web项目实践》SpringBoot通过SpringApplication.run()启动Web项目,自动推断应用类型,加载初始化器与监听器,配置Spring... 目录1. 启动入口:SpringApplication.run()2. SpringApplicat