Android C++系列:JNI常见问题

1. 背景

本文整理了JNI开发中常见的问题和解决方案。

2. 编译时指定SDK版本问题

智能语音交互SDK工程模块编译时指定的ANDROID_PLATFORM统一是23:-DANDROID_PLATFORM=23,ndk使用的是版本是17,在手上现有设备跑的都没问题,但是在一个新采购的temi移动机器人上跑不起来,定位到问题是信号处理库报了下面问题:

java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aeabi_memclr4" referenced by "/data/app/com.xxx.xxxx.robot-2/lib/arm/libkeos_signal_processing.so"...

最开始以为是信号处理库中用到了什么不兼容方法,把库的实现都改为空实现后仍报该错误,网上查询到是target version和目标设备不对应会报该错,机器人的系统版本是6.0,信号处理库编译时Application.mk中设置的APP_PLATFORM := android-26,修改完后就果然解决。

https://github.com/android/ndk/issues/126

https://github.com/android/ndk/issues/1188

官网中对该问题有介绍:

当尝试加载原生库时,这些错误会显示在日志中。此符号可以是 __aeabi_* 中的任意一个;其中 __aeabi_memcpy__aeabi_memclr 可能是最常见的。此问题已记录在问题 126 中

2. Using _FILE_OFFSET_BITS=64 with older API levels

与上一个类似,也是API版本问题。

在统一头文件之前,NDK 并不支持 _FILE_OFFSET_BITS=64。如果在构建应用时定义了该选项,系统会静默地忽略它。现在,_FILE_OFFSET_BITS=64 选项受统一头文件的支持,但在旧版本的 Android 中,很少有 off_t API 可用作 off64_t 变体。因此,如果将该功能与旧版 API 级别搭配使用,会导致可用函数减少。

r16 博文和 bionic 文档对该问题作了详细解释。

问题: build 请求获得的 minSdkVersion 中不存在的 API。

解决方案:停用 _FILE_OFFSET_BITS=64 或提高 minSdkVersion

3. jni local reference table overflow (max=512)

正常情况我们在方法里面申请的local reference会在方法执行完后自动释放,所以一直没有太在意local reference的释放,结果在一个线程的looper方法中有两个jstring使用完一直没释放,导致交互多轮后泄露崩溃。

4. FindClass 找不到类

常见问题类型:

  1. 确保类名称字符串的格式正确无误,JNI 类名称以软件包名称开头,并用斜线分隔,例如 java/lang/String。如果要查找某个数组类,则需要以适当数量的英文方括号开头,并且还必须用“L”和“;”将该类包裹起来,因此 String 的一维数组将是 [Ljava/lang/String;。如果要查找内部类,使用“$”而不是“.”,可以在 .class 文件上使用 javap 是查找类的内部名称。
  2. 如果启用代码混淆,请确保查找的类名未被混淆。
  3. 如果类名称形式正确,可能是遇到了类加载器问题。FindClass 需要在与代码关联的类加载器的启动类搜索。它会检查调用堆栈,如下所示:
    Foo.myfunc(Native Method)Foo.main(Foo.java:10)

最顶层的方法是 Foo.myfuncFindClass 会查找与 Foo 类关联的 ClassLoader 对象并使用它。

采用这种方法一般情况可以满足我们的需求。但是如果在native线程(比如通过调用 pthread_create,然后使用 AttachCurrentThread 进行附加),可能会有问题。因为在这个线程中没有堆栈帧,如果从此线程调用 FindClass,JavaVM 会在“系统”类加载器(而不是与应用关联的类加载器)中启动,因此尝试查找特定于应用的类将失败。

可以通过以下几种方法来解决此问题:

  • JNI_OnLoad 中执行一次 FindClass 查找,然后缓存类引用以供日后使用。在执行 JNI_OnLoad 过程中发出的任何 FindClass 调用都会使用与调用 System.loadLibrary 的函数关联的类加载器(这是一条特殊规则,用于更方便地进行库初始化)。如果我们的应用代码要加载库,FindClass 会使用正确的类加载器。
  • 通过声明原生方法来获取 Class 参数,然后传入 Foo.class,从而将类的实例传递给需要它的函数。
  • 在某个便捷位置缓存 ClassLoader 对象的引用,然后直接发出 loadClass 调用,这个比较麻烦一些,而且缓存classloader可能也会存在一些问题。
  • 使用java/lang/ClassLoadergetClassLoader,然后调用findClass:
static jobject gClassLoader;
static jmethodID gFindClassMethod;JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {gJvm = pjvm;  // cache the JavaVM pointerauto env = getEnv();//replace with one of your classes in the line belowauto randomClass = env->FindClass("com/example/RandomClass");jclass classClass = env->GetObjectClass(randomClass);auto classLoaderClass = env->FindClass("java/lang/ClassLoader");auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader","()Ljava/lang/ClassLoader;");gClassLoader = env->CallObjectMethod(randomClass, getClassLoaderMethod);gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass","(Ljava/lang/String;)Ljava/lang/Class;");return JNI_VERSION_1_6;
}jclass findClass(const char* name) {return static_cast<jclass>(getEnv()->CallObjectMethod(gClassLoader, gFindClassMethod, getEnv()->NewStrin

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

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

相关文章

(2024)docker-compose实战 (6)部署前端项目(react, vue)

前言 本次仅使用nginx搭建单一的前端项目, 前端项目可以是html, react, vue.项目目录中需要携带nginx的配置文件(conf/default.conf).前端文件直接拷贝到项目目录中即可.如果不确定镜像的配置文件目录, 可以通过 docker inspect 镜像名 来查看具体的配置信息.使用docker-compos…

D - Intersecting Intervals(abc355)

题意&#xff1a;有n个区间&#xff0c;找出俩俩区间相交的个数 分析&#xff1a; 设初始俩俩相交&#xff0c;找出不相交的&#xff08;不同区间l>r)&#xff0c;减去即可 #include<bits/stdc.h> using namespace std; typedef long long ll; int main(){ ios:…

【前端CSS3】一篇搞懂各类常用选择器(黑马程序员)

文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、正文&#xff1a;2.1 基础选择器2.1.1 标签选择器2.1.2 类选择器2.1.3 id选择器2.1.4 通配符选择题2.1.5 类选择器与id选择器区别☀️☀️☀️2.1.6 基础选择器总结&#x1f680; 2.2 复合类选择器2.2.1 后代选择…

Linux系统编程:信号

目录 1.信号概念 2.信号产生 2.1 终端 2.2 系统调用 2.3 硬件异常 2.4 软件条件 2.5 小结 3. 进程退出时的核心转储问题 4. 信号捕捉初识 5. 阻塞信号 5.1 相关概念 5.2 在内核中的表示 6. 信号捕捉 6.1 知识铺垫 6.2 信号捕捉流程 6.3 sigset_t 6.4 信号集操…

CTFHUB-SSRF-上传文件

通过file协议访问flag.php文件内容 ?urlfile:///var/www/html/flag.php 右键查看页面源代码&#xff0c;发现需要从内部上传一个文件这样才能正常获取到flag ?urlhttp://127.0.0.1/flag.php 发现无提交按钮&#xff0c;构造一个 <input type"submit" name&qu…

RabbitMQ 之 延迟队列

目录 ​编辑一、延迟队列概念 二、延迟队列使用场景 三、整合 SpringBoot 1、创建项目 2、添加依赖 3、修改配置文件 4、添加 Swagger 配置类 四、队列 TTL 1、代码架构图 2、配置文件代码类 3、生产者 4、消费者 5、结果展示 五、延时队列优化 1、代码架构图 …

白骑士的Python教学高级篇 3.4 Web开发

系列目录 上一篇&#xff1a;白骑士的Python教学高级篇 3.3 数据库编程 在现代软件开发中&#xff0c;Web开发占据了重要的一席之地。通过Web开发&#xff0c;我们可以创建从简单的个人博客到复杂的电子商务网站等各种应用。在Python的生态系统中&#xff0c;Flask和Django是两…

Python番外篇之责任转移:有关于虚拟机编程语言的往事

编程之痛 如果&#xff0c;你像笔者一样&#xff0c;有过学习或者使用汇编语言与C、C等语言的经历&#xff0c;一定对下面所说的痛苦感同身受。 汇编语言 将以二进制表示的一条条CPU的机器指令&#xff0c;以人类可读的方式进行表示。虽然&#xff0c;人类可读了&#xff0c…

Java后端开发的最佳工程实践与规范

Java后端开发的最佳工程实践与规范 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨Java后端开发中的最佳工程实践与规范&#xff0c;这些实践可以…

使用deep修改前端框架中的样式

目录 1.deep的作用 2.使用方式 3.特别说明 scoped 的实现原理&#xff1a; !important 1.deep的作用 /deep/、::v-deep 和 :deep 都是用于穿透组件作用域的选择器。它们的主要目的是允许开发者在父组件中直接选择并样式化子组件内部的元素&#xff0c;即使这些元素被封装在…

拓扑学习系列(1)拓扑球与拓扑环面与同胚

拓扑球与拓扑环面 在拓扑学中&#xff0c;"Topological Sphere" 和 "Topological Torus" 是两种不同的拓扑空间&#xff0c;它们具有特定的拓扑性质和几何特征。 Topological Sphere&#xff08;拓扑球&#xff09;&#xff1a; 拓扑球是一个二维曲面&…

JVM原理(九):JVM虚拟机工具之可视化故障处理工具

1. JHSDB:基于服务性代理的调试工具 JHSDB是一款基于服务性代理实现的进程外调试工具。 服务性代理是HotSpot虚拟机中一组用于映射Java虚拟机运行信息的、主要基于Java语言实现的API集合。 2. JConsole:Java监视与管理控制台 JConsole是一款基于JMX的可视化监视、管理工具。…

电脑有线网卡和无线网卡的MAC地址

电脑上的无线网卡和有线网卡是两种不同类型的网络接口卡&#xff0c;它们各自有不同的功能和连接方式。 无线网卡&#xff1a; 功能&#xff1a;无线网卡允许计算机通过无线信号连接到网络&#xff0c;通常是Wi-Fi网络。连接方式&#xff1a;无需物理电缆&#xff0c;通过无线…

编程与教学的奇妙交织:探索未来的教育模式

编程与教学的奇妙交织&#xff1a;探索未来的教育模式 在当今快速发展的科技时代&#xff0c;编程与教学之间的融合已经不再是遥不可及的梦想&#xff0c;而是逐渐成为教育领域的一股新浪潮。本文将从四个方面、五个方面、六个方面和七个方面深入探讨编程与教学的奇妙交织&…

Mac批量替换文件夹下所有文件内容

今天接了一个小需求&#xff0c;将文件夹下字段为% XXDM %替换成#{XXDM} 在苹果系统&#xff08;macOS&#xff09;下&#xff0c;可以使用命令行工具find结合sed来实现对A文件夹下所有文件内容的批量替换。具体操作步骤如下&#xff1a; 1、打开终端&#xff08;Terminal&am…

千益畅行,旅游卡,如何赚钱?

​ 赚钱这件事情&#xff0c;只有自己努力执行才会有结果。生活中没有幸运二字&#xff0c;每个光鲜亮丽的背后&#xff0c;都是不为人知的付出&#xff01; #旅游卡服务#

springboot拦截器,ThreadLocal(每个线程的公共区域)

拦截器 配置信息&#xff08;拦截所有请求&#xff09; 其实这种可以作为springAOP作日志记录

Spring 框架中都用到了哪些设计模式:单例模式、策略模式、代理模式

Spring 框架是一个功能强大的企业级应用开发框架&#xff0c;它使用了多种设计模式来提高代码的可维护性、可扩展性和可重用性。以下是 Spring 框架中常见的几个设计模式&#xff0c;并简要说明它们的应用场景&#xff1a; 1. 单例模式&#xff08;Singleton Pattern&#xff…

SpringCloud_Eureka注册中心

概述 Eureka是SpringCloud的注册中心。 是一款基于REST的服务治理框架&#xff0c;用于实现微服务架构中的服务发现和负载均衡。 在Eureka体系中&#xff0c;有两种角色: 服务提供者和服务消费者。 服务提供者将自己注册到Eureka服务器&#xff0c;服务消费者从Eureka服务器中…

白骑士的Python教学实战项目篇 4.1 数据分析与可视化

系列目录 上一篇&#xff1a;白骑士的Python教学高级篇 3.4 Web开发​​​​​​​ 在本篇内容中&#xff0c;我们将介绍如何使用Python进行数据分析与可视化。数据分析与可视化是数据科学的重要组成部分&#xff0c;能够帮助我们从数据中提取有价值的信息和洞察。我们将使用P…