标准的JNI (Java Native Interface) 加载函数 JNI_OnLoad

1.JNI_OnLoad

在 Android Native 开发中,JNI_OnLoad 是动态注册本地方法的标准入口点。以下是一个标准实现示例及其说明:


JNI_OnLoad 标准实现

#include <jni.h>
#include <string>// 声明本地方法对应的 C/C++ 函数
jint native_add(JNIEnv* env, jobject thiz, jint a, jint b) {return a + b;
}// 定义 JNINativeMethod 结构体数组
static JNINativeMethod gMethods[] = {// Java方法名 | 方法签名 | 本地函数指针{"add", "(II)I", (void*)native_add},
};// 缓存 JavaVM 实例(用于后续获取 JNIEnv)
JavaVM* gJavaVM = nullptr;JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {JNIEnv* env = nullptr;jint result = -1;// 1. 获取 JNIEnvif (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) {return JNI_ERR;}// 2. 缓存 JavaVM 实例gJavaVM = vm;// 3. 找到目标 Java 类const char* className = "com/example/MyJniClass";jclass clazz = env->FindClass(className);if (clazz == nullptr) {return JNI_ERR;}// 4. 注册本地方法if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) < 0) {return JNI_ERR;}// 5. 返回使用的 JNI 版本(必须与获取 JNIEnv 时指定的版本一致)return JNI_VERSION_1_6;
}

关键步骤说明

  1. 获取 JNIEnv
    通过 JavaVM::GetEnv 获取 JNIEnv 指针,需指定 JNI 版本(通常为 JNI_VERSION_1_6)。

  2. 缓存 JavaVM
    JavaVM 实例保存到全局变量中,以便在其他线程中通过 AttachCurrentThread 获取 JNIEnv

  3. 查找 Java 类
    使用 FindClass 找到需要注册本地方法的 Java 类(需全限定类名,如 com/example/MyJniClass)。

  4. 注册本地方法
    调用 RegisterNativesJNINativeMethod 数组中的方法动态注册到目标类。每个 JNINativeMethod 包含:

    • Java 方法名:与 Java 代码中的 native 方法名一致。
    • 方法签名:描述方法的参数和返回值类型(可通过 javap -s <ClassName> 生成)。
    • 本地函数指针:C/C++ 实现的函数地址。
  5. 返回 JNI 版本
    需返回与 GetEnv 中指定的版本一致的 JNI 版本号(如 JNI_VERSION_1_6)。


注意事项

  1. 方法签名
    必须与 Java 方法的参数和返回值类型完全匹配。例如:

    • (II)I 表示接收两个 int 参数并返回 int
    • (Ljava/lang/String;)V 表示接收一个 String 参数且无返回值。
  2. 避免名称改编(C++)
    如果使用 C++,需通过 extern "C"#pragma GCC visibility 确保函数名称不被编译器改编:

    extern "C" JNIEXPORT jint JNICALL Java_com_example_MyJniClass_add(JNIEnv*, jobject, jint, jint);
    
  3. 错误处理
    检查 FindClassRegisterNatives 的返回值,避免因注册失败导致崩溃。

  4. 线程安全
    通过缓存的 JavaVM,可在其他线程中安全获取 JNIEnv

    JNIEnv* env;
    gJavaVM->AttachCurrentThread(&env, nullptr);
    

优势(动态注册 vs 静态注册)

  • 更高效:避免运行时通过方法名动态查找本地函数。
  • 更灵活:无需遵循 Java_<Package>_<Class>_<Method> 的命名格式。
  • 可控性:可在 JNI_OnLoad 中集中管理所有注册逻辑。

通过以上实现,可确保本地方法在 JNI 库加载时正确注册,提升代码可维护性和性能。

2.调用JNI_OnLoad

在 Android 开发中,JNI_OnLoad 不是由开发者直接调用的,而是由 Java 虚拟机(JVM)在加载动态库(.so 文件)时自动触发的。以下是它的调用机制和触发方式:


1. JNI_OnLoad 的调用机制

当你在 Java 代码中加载一个 JNI 动态库(.so 文件)时,系统会自动检查该库是否实现了 JNI_OnLoad 函数。如果存在,JVM 会在库加载后立即调用它。

触发 JNI_OnLoad 的方式

// Java 代码(例如 MainActivity.java)
static {System.loadLibrary("myjni"); // 加载 libmyjni.so
}
  • System.loadLibrary("myjni")
    会尝试加载 libmyjni.so(在 Android 中会自动添加 lib 前缀和 .so 后缀)。
  • JVM 检查 JNI_OnLoad
    如果 libmyjni.so 实现了 JNI_OnLoad,JVM 会在加载后立即调用它。

2. JNI_OnLoad 的调用流程

  1. Java 代码调用 System.loadLibrary("myjni")
  2. Android Runtime(ART/Dalvik)加载 libmyjni.so
  3. JVM 检查是否实现了 JNI_OnLoad
    • 如果存在,调用 JNI_OnLoad(JavaVM* vm, void* reserved)
    • 如果不存在,JNI 会使用默认的静态注册方式(基于 JNIEXPORT 函数名匹配)。
  4. JNI_OnLoad 执行动态注册
    • 注册 JNINativeMethod 数组中的本地方法。
    • 返回 JNI 版本(如 JNI_VERSION_1_6)。

3. 如何确保 JNI_OnLoad 被正确调用?

(1)确保 .so 文件正确编译

CMakeLists.txtAndroid.mk 中正确配置:

# CMakeLists.txt
add_library(myjni SHARED native-lib.cpp)

# Android.mk
LOCAL_MODULE := myjni
LOCAL_SRC_FILES := native-lib.cpp

(2)确保 Java 代码正确加载库

// 在静态代码块中加载库(避免重复加载)
static {System.loadLibrary("myjni");
}

(3)检查 JNI_OnLoad 是否被调用

可以在 JNI_OnLoad 中添加日志:

#include <android/log.h>
#define LOG_TAG "JNI_DEBUG"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {LOGD("JNI_OnLoad called!"); // 检查是否执行// ... 其他注册逻辑return JNI_VERSION_1_6;
}

然后在 logcat 中查看日志:

adb logcat | grep "JNI_DEBUG"

4. 常见问题

(1)JNI_OnLoad 没有被调用?

  • 库未正确加载:检查 System.loadLibrary 是否成功执行(无 UnsatisfiedLinkError)。
  • .so 文件未正确编译:确保 JNI_OnLoad 被包含在最终 .so 中(可通过 nm -D libmyjni.so | grep JNI_OnLoad 检查)。
  • JNI 版本不匹配:确保 JNI_OnLoad 返回正确的版本(如 JNI_VERSION_1_6)。

(2)JNI_OnLoad 和静态注册的区别?

特性JNI_OnLoad(动态注册)静态注册(默认方式)
注册方式主动调用 RegisterNatives基于函数名匹配(如 Java_com_example_MyClass_method
性能更快(避免运行时查找)较慢(首次调用需解析)
灵活性可自定义注册逻辑必须遵循固定命名规则
适用场景推荐用于复杂项目简单 JNI 调用

5. 总结

  • JNI_OnLoad 由 JVM 自动调用,开发者只需实现它并在其中注册本地方法。
  • 触发方式:在 Java 中调用 System.loadLibrary("mylib")
  • 核心作用:动态注册 JNI 方法,提升性能并增强灵活性。
  • 调试技巧:通过 __android_log_print 打印日志,确保 JNI_OnLoad 被正确执行。

如果你的 JNI_OnLoad 没有被调用,请检查库加载流程和编译配置!

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

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

相关文章

算法导论思考题

2-1 在归并排序中对小数组采用插入排序 c. 假定修改后的算法的最坏情况运行时间为 Θ \Theta Θ(nknlg(n/k))&#xff0c;要使修改后的算法与标准的归并排序具有相同的运行时间&#xff0c;作为n的一个函数&#xff0c;借助 Θ \Theta Θ记号&#xff0c;k的最大值是什么&#…

JavaScript 性能优化

JavaScript 性能优化是提高 Web 应用性能的关键步骤,特别是在处理大量数据、复杂计算或频繁的 DOM 操作时。以下是一些常见的 JavaScript 性能优化技巧和策略: 文章目录 @[TOC]一、代码层面优化1. **减少全局变量**2. **避免使用 `with` 语句**3. **使用局部变量**4. **减少 …

NLP高频面试题(四十七)——探讨Transformer中的注意力机制:MHA、MQA与GQA

MHA、MQA和GQA基本概念与区别 1. 多头注意力(MHA) 多头注意力(Multi-Head Attention,MHA)通过多个独立的注意力头同时处理信息,每个头有各自的键(Key)、查询(Query)和值(Value)。这种机制允许模型并行关注不同的子空间上下文信息,捕捉复杂的交互关系。然而,MHA…

51单片机的原理图和PCB绘制

51单片机最小系统原理图 加了两个led灯和按键检测电路。 PCB中原件摆放位置 成品 资源链接&#xff1a;https://download.csdn.net/download/qq_61556106/90656365

使用注解方式整合ssm时,启动tomcat扫描不到resource下面的xxxmapper.xml

解决org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.xxx.mapper.方法 在Spring与Mybatis整合时&#xff0c;可能会遇到这样的报错 原因&#xff1a; 其原因为mapper路径的映射错误&#xff0c;表示在尝试执行某个 Mapper 接口的方法时…

提示词设计:动态提示词 标准提示词

提示词设计:动态提示词 标准提示词 研究背景:随着人工智能与司法结合的推进以及裁判文书公开数量增多,司法摘要任务愈发重要。传统司法摘要方法生成质量有待提升,大语言模型虽有优势,但处理裁判文书时存在摘要结构信息缺失、与原文不一致等问题。研究方法 DPCM方法:分为大…

Jenkins 多分支管道

如果您正在寻找一个基于拉取请求或分支的自动化 Jenkins 持续集成和交付 (CI/CD) 流水线&#xff0c;本指南将帮助您全面了解如何使用 Jenkins 多分支流水线实现它。 Jenkins 的多分支流水线是设计 CI/CD 工作流的最佳方式之一&#xff0c;因为它完全基于 git&#xff08;源代…

跨境电商管理转型:日事清通过目标管理、流程自动化助力智优美科技项目管理升级与目标落地复盘

1.客户背景介绍 深圳市智优美科技有限公司是一家专业从事外贸B2C的电子商务公司&#xff0c;公司总部位于深圳市宝安区&#xff0c;旗下拥有三家子公司。目前销售的品类有&#xff1a;家居用品、电子产品、电子配件产品等&#xff0c;在深圳外贸电商行业销售额稳居行业前10名。…

基于Docker+k8s集群的web应用部署与监控

项目架构图 server ip master 192.168.140.130 node1 192.168.140.131 node2 192.168.140.132 ansible 192.168.140.166 jumpserver 192.168.100.133 firewall 192.168.1.86 nfs 192.168.140.157 harbor 192.168.140.159 Promethethus 192.168.140.130 Jen…

量子计算与经典计算融合:开启计算新时代

一、引言 随着科技的飞速发展&#xff0c;计算技术正迎来一场前所未有的变革。量子计算作为前沿技术&#xff0c;以其强大的并行计算能力和对复杂问题的高效处理能力&#xff0c;吸引了全球科技界的关注。然而&#xff0c;量子计算并非要完全取代经典计算&#xff0c;而是与经典…

【HarmonyOS 5】makeObserved接口详解

【HarmonyOS 5】makeObserved接口详解 一、makeObserved接口是什么&#xff1f; makeObserved 接口&#xff08;API version 12 起可用&#xff09;用于将非观察数据转为可观察数据&#xff0c;适用于三方包类、Sendable 装饰的类、JSON.parse 返回的对象、collections.Array…

豆瓣图书数据采集与可视化分析(二)- 豆瓣图书数据清洗与处理

文章目录 前言一、查看数据基本信息二、拆分pub列三、日期列处理四、价格列处理五、出版社列处理六、评价人数列处理七、缺失值处理八、重复数据处理九、异常值处理十、完整代码十一、清洗与处理后的数据集展示 前言 豆瓣作为国内知名的文化社区&#xff0c;拥有庞大且丰富的图…

Wasm -WebAssembly简介

WebAssembly 是什么&#xff1f; WebAssembly/wasm WebAssembly 或者 wasm 是一个可移植、体积小、加载快并且兼容 Web 的全新格式 WebAssembly&#xff08;简称 Wasm&#xff09;是一种二进制指令格式&#xff0c;设计用于在现代 Web 浏览器中高效运行程序。它可以被认为是一…

驱动开发硬核特训 · Day 15:电源管理核心知识与实战解析

在嵌入式系统中&#xff0c;电源管理&#xff08;Power Management&#xff09;并不是“可选项”&#xff0c;而是实际部署中影响系统稳定性、功耗、安全性的重要一环。今天我们将以 Linux 电源管理框架 为基础&#xff0c;从理论结构、内核架构&#xff0c;再到典型驱动实战&a…

【SpringBoot】99、SpringBoot中整合RabbitMQ实现重试功能

最近在做一个项目,需要使用 MQ 实现重试功能,在这里给各位分享一下。 1、整合 RabbitMQ <!-- rabbitmq消息队列 --> <dependency><groupId>org.springframework.boot</groupId><

AI 中的 CoT 是什么?一文详解思维链

文章目录 CoT 的组成CoT 的作用CoT 的推理结构变体CoT 的特点CoT 的适用场景总结 在人工智能领域&#xff0c;尤其是自然语言处理和机器学习中&#xff0c;有一种名为思维链&#xff08;Chain of Thought&#xff0c;CoT&#xff09;的技术&#xff0c;它正逐渐改变着我们对 AI…

Vue3集成Element Plus完整指南:从安装到主题定制上

一、Element Plus简介 Element Plus是一套基于Vue 3.0的桌面端组件库&#xff0c;由饿了么前端团队开源维护。它提供了丰富的UI组件&#xff0c;能够帮助开发者快速构建企业级中后台产品。 1. 安装与卸载 bash 复制 下载 # 安装最新版本 npm install element-plus -S# 卸…

Java29:Spring MVC

一&#xff1a;Springmvc简介 1.简介&#xff1a; Spring Web MVC 是基于Servlet API构建的原始Web框架&#xff0c;从一开始就包含在Spring Framework中。正式名称“Spring Web MVC” 来自其源模块名称&#xff08;spring-webmvc&#xff09;但它通常被称为“Spring Mvc” …

VLC搭建本机的rtsp直播推流和拉流

媒体---流---捕获设备&#xff0c;选择摄像头&#xff0c;点击串流 x下一步 选择rtsp&#xff0c;点击添加 看到了端口&#xff0c;并设置路径&#xff1a; 选择Video -H 264 mp3(TS) 点击下一个&#xff0c; 点击流&#xff0c;就开始推流了 拉流&#xff0c;观看端&#x…

云点数据读写

一、常见点云数据格式 LAS/LAZ格式 LAS是点云数据的行业标准格式 LAZ是LAS的压缩版本 支持地理参考信息、颜色、强度等属性 PCD格式(Point Cloud Data) PCL(Point Cloud Library)开发的格式 支持ASCII和二进制存储 包含头部信息和数据部分 PLY格式(Polygon File Format…