Android找不到so,实际上apk中有的

解决apk中有.so,实际运行时找不到的问题

排查方向:

  • ①、.so安装位置是否实际存在文件(context.getApplicationInfo().nativeLibraryDir
  • ②、当前ARM架构适配配置或者匹配(armeabi-v7a, arm64-v8a, x86_64, ...
  • ③、加载方式是否正确[System.loadLibrary("so_name_but_no_'lib'_prefix")/System.load("so_absolute_path")]
  • ④、Android版本(Android 31+),AGP版本(AGP 4.2.0+)参加下方配置 ↓↓↓
  • ⑤、android:extractNativeLibs=true是否配置(或者DSL选项useLegacyPackaging=true
  • ⑥、库文件没有访问权限
  1. Android .so存储位置
    可以通过如下方式获取so文件的加载位置
String so_path = context.getApplicationInfo().nativeLibraryDir; //查看加载 .so 的位置

举个栗子
系统应用:/system/lib/xxx[/vendor/lib (三方OEM厂商)] 或者 system/app/xxx/lib

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三方应用: data/app/[package-name]/lib
注意:package-name可能会是一串随机数字,可以通过如下adb命令行根据包名查看app的安装位置:

adb shell
pm list package -f |grep com.axxxx

在这里插入图片描述
您可以通过如下代码查找.so文件所在的目录,参考自:

https://blog.csdn.net/wangbaochu/article/details/47805921

    /*** The function use to find so path for compatible android system* Android OS >= 2.3*/public static String findLibrary1(Context context, String libName) {String result = null;ClassLoader classLoader = (context.getClassLoader());if (classLoader != null) {try {Method findLibraryMethod = classLoader.getClass().getMethod("findLibrary", new Class<?>[] { String.class });   if (findLibraryMethod != null) {Object objPath = findLibraryMethod.invoke(classLoader, new Object[] { libName });if (objPath != null && objPath instanceof String) {result = (String) objPath;}}} catch (NoSuchMethodException e) {Log.e("findLibrary1", e.toString());} catch (IllegalAccessException e) {Log.e("findLibrary1", e.toString());} catch (IllegalArgumentException e) {Log.e("findLibrary1", e.toString());} catch (InvocationTargetException e) {Log.e("findLibrary1", e.toString());} catch (Exception e) {Log.e("findLibrary1", e.toString());}}return result;}/*** The function use to find so path for compatible android system* Android OS <= 2.2*/public static String findLibrary2(Context context, String libName) {String result = null;ClassLoader classLoader = (context.getClassLoader());if (classLoader != null) {try {Method findLibraryMethod = classLoader.getClass().getDeclaredMethod("findLibrary", new Class<?>[] { String.class });if (findLibraryMethod != null) {if (!findLibraryMethod.isAccessible()) {findLibraryMethod.setAccessible(true);}Object objPath = findLibraryMethod.invoke(classLoader, new Object[] { libName });if (objPath != null && objPath instanceof String) {result = (String) objPath;}}} catch (NoSuchMethodException e) {Log.e("findLibrary2", e.toString());} catch (IllegalAccessException e) {Log.e("findLibrary2", e.toString());} catch (IllegalArgumentException e) {Log.e("findLibrary2", e.toString());} catch (InvocationTargetException e) {Log.e("findLibrary2", e.toString());} catch (Exception e) {Log.e("findLibrary2", e.toString());}}return result;}
  1. 查看Android打包配置是否指定了对应ARM架构
android {// ... defaultConfig {// ...ndk {// 目前Android支持的ABIsabiFilters 'mips', 'mips64', 'x86', 'x86–64', 'arm64-v8a', 'armeabi', 'armeabi-v7a'}}
}

您可以通过如下代码获取当前设备支持的ABIs:

	/*** An ordered list of ABIs supported by this device** @return ABI*/public String[] getABIs() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {return Build.SUPPORTED_ABIS;} else {return new String[]{Build.CPU_ABI, Build.CPU_ABI2};}}

或者如下adb命令获取:
在这里插入图片描述
关于ABI架构引用如下文章:

https://www.jianshu.com/p/68b52659a5f6

1.在android4.4以下版本的安装过程中的,是先把所有so库全部寻找出来,然后优先列出cpu类型(通过ro.product.cpu.abi属性获得)目录下的so库,如果有其他的cpu类型下有跟手机cpu类型名称不一致的so库,则会将兼容cpu架构(通过ro.product.cpu.abi2属性获得)的另外的库也列出来。将列出来so库全部拷贝的系统指定目录,以供运行时加载。 即在android4.4以下版本,一个so库只要在 ro.product.cpu.abiro.product.cpu.abi2属性目录下至少存在一个就可以了。在android4.4以下的arm架构的设备 ro.product.cpu.abi的属性通常是armeabi-v7a, ro.product.cpu.abi2的属性值是armeabi,并且armeabi-v7a设备一定兼容armeabi。但不排除某些设备的ro.product.cpu.abi的属性为armeabi。

2.在android5.0及以上,由于增加了arm64的支持,app安装时的so库拷贝代码也修改了。修改成只拷贝一个最合适的目录下的so库到系统指定目录。 在arm架构下,64位cpu的优先级是arm64-v8a > armeabi-v7a > armeabi,32位cpu的优先级是armeabi-v7a > armeabi ,优先级可通过ro.product.cpu.abilist属性查看。由于android5.0是拷贝整体目录,所以在每一个目录下的,都必须要有完整的so,即所有app需要so库都要有。例如64位的cpu的设备上,
如果app目录里存在arm64-v8a子目录,则只拷贝该目录下的so库,其他目录的so,即使名称不一样,也不拷贝,如果arm64-v8a子目录的so库不全,则会报错。

  1. so加载方式不对
    目前有两种加载方式(以某个普通app下有个libtest.so文件为例):
    System.loadLibrary("so_name_but_no_'lib'_prefix") :会优先查找apk中的so目录,再查找系统目录,系统目录包括:/vendor/lib(64),/system/lib(64)
    System.load("so_absolute_path"): 直接加载制定路径下的so
System.loadLibrary("test");// libtest.so
String soRoot = context.getApplicationInfo().nativeLibraryDir;
System.load(soRoot + "/libtest.so");// libtest.so
  1. Google官方更新进行的调整和修改

https://developer.android.google.cn/guide/topics/manifest/application-element?hl=zh-cn

针对AGP >= 3.6.0需要在AndroidMainfest.xml清单文件中添加如下配置

<applicationandroid:extractNativeLibs="true"... >
</application>    

针对AGP >= 4.2.0需要在DSL中添加如下配置(上面配置过时)

android {packagingOptions {jniLibs {useLegacyPackaging true}}
}
  1. 库文件没有访问权限
    .so文件有权限限制(文件读写权限/系统访问权限限制),不允许访问,可通过如下命令查看对应文件的访问权限:

在这里插入图片描述
关于权限说明参考如下:

https://www.jianshu.com/p/ba0d31fc078a

drwxr-xr-x:应该分解为四部分
d rwx r-x r-x第一部分:d表示目录文件,-表示普通文件,l表示链接文件,p表示管道。
第二部分:root用户拥有的权限
第三部分:用户组拥有的权限
第四部分:其他用户拥有的权限r表示可读,w表示可写,x表示可执行,r-x表示可读可执行不可写查看文件权限方法:
ls -lO (大写的o) + 所在文件夹路径

举个栗子:
app需要引用系统的so库,当install形式的时候安装时,打开app需要使用/system/lib64目录下的so库时,提示不能访问。
原因分析:放到system/app下的app是可以找到的,但是普通的安装形式的app是没有权限访问的,所以需要需要声明公有so库才能使用

library "/system/lib64/libserialport.so" ("/system/lib64/libhqbindcs.so") needed or
dlopened by"/system/lib64/libhqbindcs.so" is not accessible for the namespace
"classloader-namespace"

解决方法:
修改system/core/rootdir/etc/public.libraries.txt
添加你要使用的的so到此问题件中。

cat public.libraries.txt 
....
libz.so
libhqbindcs.so

也可以直接不编译在板子上修改,对应目录/system/etc

https://wkingdom.github.io/2020/04/04/JNI%E6%97%A0%E6%B3%95%E8%AE%BF%E9%97%AEso%E6%8F%90%E7%A4%BAnot%20accessible/
https://www.jianshu.com/p/4be3d1dafbec

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/355919.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

拒绝零散碎片, 一文理清MySQL的各种锁

系列文章目录 学习MySQL先有全局观&#xff0c;细说其发展历程及特点 Mysql常用操作&#xff0c;谈谈排序与分页 拒绝零散碎片&#xff0c; 一文理清MySQL的各种锁&#xff08;收藏向&#xff09; 系列文章目录一、MySQL的锁指什么二、排他与共享三、全局锁&#xff08;Global…

Java网络爬虫入门

文章目录 1、导入依赖2、CrawlerFirst 1、导入依赖 <dependencies><!-- HttpClient --><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.3</version></…

【ARMv8/ARMv9 硬件加速系列 3.3 -- SVE LD2D 和 ST2D 使用介绍】

文章目录 SVE 多向量操作LD2D(加载)LD2D 操作说明LD2D 使用举例ST2D(存储)ST2D 使用举例ST2D 存储示例代码ld2d 和 st2d 小结SVE 多向量操作 在ARMv8/9的SVE (Scalable Vector Extension) 指令集中,st2d和ld2d指令用于向量化的存储和加载操作,具体地,它们允许同时对两个…

英文字母表

目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 namespace 英文字母表 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){foreach (var item in panel1.Controls){if (item ! null)…

代理网络基础设施 101:增强安全性、速度和可扩展性

编辑代理网络在现代网络架构中发挥着重要作用&#xff0c;充当管理和重新路由数据流的中介。它们处理的数据可以是各种类型&#xff0c;包括搜索查询和潜在的敏感客户信息&#xff0c;这凸显了它们在数据安全方面的作用。 然而&#xff0c;代理的好处不仅限于安全性。它们为用…

java:Multiple Bounds--类型变量(TypeVariable)定义的高级用法--<A extends ClassAIfAIfB >

做Java开发工作好多年了。今天偶然翻到 java.lang.TypeVariable的源码&#xff0c;好奇为什么 TypeVariable.getBounds()返回类型是个数组。 一般不都是<T extends Number> 这样用码&#xff1f;T难道还能extends多个类型&#xff1f; 同问&#xff1a;不应该是extend,为…

Java基础 - 练习(五)根据今天日期获取一周内的日期(基姆拉尔森公式)

基姆拉尔森计算公式用于计算一周内的日期。比如给你年月日&#xff0c;从而计算今天是星期几。 基姆拉尔森公式 Week (d2*m3*(m1)/5yy/4-y/100y/4001) mod 7&#xff0c; 3<m<14Week的取值范围是0 ~ 6&#xff0c;其中0代表星期日&#xff0c;1 ~ 6分别代表星期一到星期…

如何使用Windows备份轻松将数据转移到新电脑?这里有详细步骤

序言 我们都知道那种买了一台新电脑,就想直接上手的感觉。我记得在过去的日子里,要花几个小时传输我的文件,并试图复制我的设置。在当今传输数据的众多方法中,Windows备份提供了一个简单可靠的解决方案。 登录到你的Microsoft帐户 Microsoft在传输过程中使用其云存储来保…

C# WPF入门学习主线篇(二十三)—— 控件模板(ControlTemplate)和数据模板(DataTemplate)

C# WPF入门学习主线篇&#xff08;二十三&#xff09;—— 控件模板&#xff08;ControlTemplate&#xff09;和数据模板&#xff08;DataTemplate&#xff09; 在WPF开发中&#xff0c;控件模板&#xff08;ControlTemplate&#xff09;和数据模板&#xff08;DataTemplate&am…

设置浏览器互不干扰

目录 一、查看浏览器文件路径 二、 其他盘新建文件夹Cache 三、以管理员运行CMD 四、执行命令 一、查看浏览器文件路径 chrome://version/ 二、 其他盘新建文件夹Cache D:\chrome\Cache 三、以管理员运行CMD 四、执行命令 Mklink /d "C:\Users\Lenovo\AppData\Loca…

社区项目-项目介绍环境搭建

文章目录 1.技术选型2.原型设计1.安装AxureRP2.进行汉化3.载入元件库4.基本设计 3.元数建模1.安装元数建模软件2.新建项目3.新增一个刷题模块主题域4.新增数据表 subject_category5.新增关系图&#xff0c;将表拖过来6.新增题目标签表7.新增题目信息表8.新增单选表、多选表、判…

【linux】dup文件描述符复制函数和管道详解

目录 一、文件描述符复制 1、dup函数&#xff08;复制文件描述符&#xff09; ​编辑 2、dup2函数&#xff08;复制文件描述符&#xff09; ​编辑 二、无名管道pipe 1、概述 2、无名管道的创建 3、无名管道读写的特点 4、无名管道ps -A | grep bash实现 三、有名管道FI…

深度学习Week17——优化器对比实验

文章目录 深度学习Week17——优化器对比实验 一、前言 二、我的环境 三、前期工作 1、配置环境 2、导入数据 2.1 加载数据 2.2 检查数据 2.3 配置数据集 2.4 数据可视化 四、构建模型 五、训练模型 1、将其嵌入model中 2、在Dataset数据集中进行数据增强 六、模型评估 1、Accur…

让我来告诉初学者到底什么叫嵌入式系统?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「嵌入式的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;我们在刚刚开始学习电子学…

噪声-降噪引脚如何提高系统性能

由于LDO是电子器件&#xff0c;因此它们会自行产生一定量的噪声。选择低噪声LDO并采取措施来降低内部噪声对于生成不会影响系统性能的清洁电源轨而言不可或缺。 识别噪声 理想的 LDO 会生成没有交流元件的电压轨。遗憾的是&#xff0c;LDO 会像其他电子器件一样自行产生噪声。…

Java数据类型与运算符

1. 变量和类型 变量指的是程序运行时可变的量&#xff0c;相当于开辟一块空间来保存一些数据。 类型则是对变量的种类进行了划分&#xff0c;不同类型的变量具有不同的特性。 1.1 整型变量&#xff08;重点&#xff09; 基本语法格式&#xff1a; int 变量名 初始值;代码示…

大语言模型-Transformer

目录 1.概述 2.作用 3.诞生背景 4.历史版本 5.优缺点 5.1.优点 5.2.缺点 6.如何使用 7.应用场景 7.1.十大应用场景 7.2.聊天机器人 8.Python示例 9.总结 1.概述 大语言模型-Transformer是一种基于自注意力机制&#xff08;self-attention&#xff09;的深度学习…

开发中遇到的错误 - @SpringBootTest 注解爆红

我在使用 SpringBootTest 注解的时候爆红了&#xff0c;ait 回车也导不了包&#xff0c;后面发现是因为没有加依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId>…

云计算技术高速发展,优势凸显

云计算是一种分布式计算技术&#xff0c;其特点是通过网络“云”将巨大的数据计算处理程序分解成无数个小程序&#xff0c;并通过多部服务器组成的系统进行处理和分析这些小程序&#xff0c;最后将结果返回给用户。它融合了分布式计算、效用计算、负载均衡、并行计算、网络存储…

MEME使用-motif分析(生物信息学工具-24)

01 背景 Motif分析是一种在生物信息学和计算生物学中广泛应用的技术&#xff0c;用于识别DNA、RNA或蛋白质序列中具有生物学功能的短保守序列模式&#xff08;motif&#xff09;。这些motif通常与特定的生物学功能相关&#xff0c;如DNA中的转录因子结合位点、RNA中的剪接位点…