[Android JNI] --- JNI基础

news2024/11/19 9:35:55

1 JNI概念

什么是JNI
JNI 全称 Java Native Interface,Java 本地化接口,可以通过 JNI 调用系统提供的 API。操作系统,无论是 Linux,Windows 还是 Mac OS,或者一些汇编语言写的底层硬件驱动都是 C/C++ 写的。Java和C/C++不同 ,它不会直接编译成平台机器码,而是编译成虚拟机可以运行的Java字节码的.class文件,通过JIT技术即时编译成本地机器码,所以有效率就比不上C/C++代码,JNI技术就解决了这一痛点,JNI 可以说是 C 语言和 Java 语言交流的适配器、中间件。
JNI调用示意图:
在这里插入图片描述

什么是NDK?
NDK 全名Native Develop Kit,官方说法:Android NDK 是一套允许您使用 C 和 C++ 等语言,以原生代码实现部分应用的工具集。在开发某些类型的应用时,这有助于您重复使用以这些语言编写的代码库。

JNI与NDK区别
JNI:JNI是一套编程接口,用来实现Java代码与本地的C/C++代码进行交互;
NDK: NDK是Google开发的一套开发和编译工具集,可以生成动态链接库,主要用于Android的JNI开发;

JNI与NDK中都有jni.h文件
jdk中jni.h路径
C:\Program Files\Java\jdk-1.8\include\jni.h路径
ndk中jni.h路径
C:\Users\Administrator\AppData\Local\Android\Sdk\ndk\25.1.8937393\toolchains\llvm\prebuilt\windows-x86_64\sysroot\usr\include
ndk对jdk的jni.h进行了封装,native c/c++使用的是ndk中的jni.h

JNI在Android中作用
JNI可以调用本地代码库(即C/C++代码),并通过 Dalvik 虚拟机与应用层和应用框架层进行交互,Android中JNI代码主要位于应用层和应用框架层;

  • 应用层: 该层是由JNI开发,主要使用标准JNI编程模型;
  • 应用框架层: 使用的是Android中自定义的一套JNI编程模型,该自定义的JNI编程模型弥补了标准JNI编程模型的不足;

2 JNI数据类型映射

在 JNI 开发中,Java 的数据类型并不是直接在 JNI 里使用的

2.1 基本数据类型

Java基本数据类型和本地类型的映射关系,这些基本数据类型都是可以直接在 Native 层直接使用的

Java数据类型JNI本地类型C/C++数据类型数据类型描述
booleanjbooleanunsigned charC/C++无符号8为整数
bytejbytesigned charC/C++有符号8位整数
charjcharunsigned shortC/C++无符号16位整数
shortjshortsigned shortC/C++有符号16位整数
intjintsigned intC/C++有符号32位整数
longjlongsigned longC/C++有符号64位整数
floatjfloatfloatC/C++32位浮点数
doublejdoubledoubleC/C++64位浮点数

2.2 引用数据类型

引用数据类型和本地类型的映射关系:

Java数据类型JNI本地类型数据类型描述
java.lang.Objectjobject可以表示任何Java的对象,或者没有JNI对应类型的Java对象(实例方法的强制参数)
java.lang.StringjstringJava的String字符串类型的对象
java.lang.ClassjclassJava的Class类型对象(静态方法的强制参数)
Object[]jobjectArrayJava任何对象的数组表示形式
boolean[]jbooleanArrayJava基本类型boolean的数组表示形式
byte[]jbyteArrayJava基本类型byte的数组表示形式
char[]jcharArrayJava基本类型char的数组表示形式
short[]jshortArrayJava基本类型short的数组表示形式
int[]jintArrayJava基本类型int的数组表示形式
long[]jlongArrayJava基本类型long的数组表示形式
float[]jfloatArrayJava基本类型float的数组表示形式
double[]jdoubleArrayJava基本类型double的数组表示形式
java.lang.ThrowablejthrowableJava的Throwable类型,表示异常的所有类型和子类
voidvoidN/A

需要注意的是:
1)引用类型不能直接在 Native 层使用,需要根据 JNI 函数进行类型的转化后,才能使用;
2)多维数组(含二维数组)都是引用类型,需要使用 jobjectArray 类型存取其值;

2.3 方法和变量ID

同样不能直接在 Native 层使用。当 Native 层需要调用 Java 的某个方法时,需要通过 JNI 函数获取它的 ID,根据 ID 调用 JNI 函数获取该方法;变量的获取也是类似。ID 的结构体如下:

struct _jfieldID;                       /* opaque structure */
typedef struct _jfieldID* jfieldID;     /* field IDs */

struct _jmethodID;                      /* opaque structure */
typedef struct _jmethodID* jmethodID;   /* method IDs */```

3 JNI描述符

3.1 域描述符

基本类型描述符

在这里插入图片描述
Tips:
除了 boolean 和 long 类型分别是 Z 和 J 外,其他的描述符对应的类型名的大写首字母

引用类型描述符

一般引用类型描述符的规则如下,注意不要丢掉“;”

L + 类描述符 + ;

如,String 类型的域描述符为:

Ljava/lang/String;

数组的域描述符特殊一点,如下,其中有多少级数组就有多少个“[”,数组的类型为类时,则有分号,为基本类型时没有分号

[ + 其类型的域描述符

例如:

int[]    描述符为 [I
double[] 描述符为 [D
String[] 描述符为 [Ljava/lang/String;
Object[] 描述符为 [Ljava/lang/Object;
int[][]  描述符为 [[I
double[][] 描述符为 [[D

对应在 jni.h 获取 Java 的字段的 native 函数如下,name为 Java 的字段名字,sig 为域描述符

//C
jfieldID    (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);
jobject     (*GetObjectField)(JNIEnv*, jobject, jfieldID);
//C++
jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)
    { return functions->GetFieldID(this, clazz, name, sig); }
jobject GetObjectField(jobject obj, jfieldID fieldID)
    { return functions->GetObjectField(this, obj, fieldID); }

3.2 类描述符

类描述符是类的完整名称:包名+类名,java 中包名用 . 分割,jni 中改为用 / 分割
如,Java 中 java.lang.String 类的描述符为 java/lang/String
native 层获取 Java 的类对象,需要通过 FindClass() 函数获取, jni.h 的函数定义如下:

//C
jclass  (*FindClass)(JNIEnv*, const char*);
//C++
jclass FindClass(const char* name)
    { return functions->FindClass(this, name); }

字符串参数就是类的引用类型描述符,如 Java 对象 cn.cfanr.jni.JniTest,对应字符串为Lcn/cfanr/jni/JniTest; 如下:

jclass jclazz = env->FindClass("Lcn/cfanr/jni/JniTest;");

3.3 方法描述符

方法描述符需要将所有参数类型的域描述符按照声明顺序放入括号,然后再加上返回值类型的域描述符,其中没有参数时,不需要括号,如下规则:

(参数……)返回类型

例如:

  Java 层方法   ——>  JNI 函数签名
String getString()  ——>  Ljava/lang/String;
int sum(int a, int b)  ——>  (II)Ivoid main(String[] args) ——> ([Ljava/lang/String;)V

另外,对应在 jni.h 获取 Java 方法的 native 函数如下,其中 jclass 是获取到的类对象,name 是 Java 对应的方法名字,sig 就是上面说的方法描述符

//C
jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
//C++
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
    { return functions->GetMethodID(this, clazz, name, sig); }

不需要记住,可以使用下面方法查看签名

java -s -p xxx.class

4 静态注册和动态注册

当执行一个 Java 的 native 方法时,虚拟机是怎么知道该调用 so 中的哪个方法呢?这就需要用到注册的概念了,通过注册,将指定的 native 方法和 so 中对应的方法绑定起来(函数映射表),这样就能够找到相应的方法了。
注册分为 静态注册 和 动态注册两种。

4.1 静态注册

定义
通过 JNIEXPORT 和 JNICALL 两个宏定义声明,在虚拟机加载 so 时发现上面两个宏定义的函数时就会链接到对应的 native 方法。

规则
java_完整包名_类名_方法名
特殊规则:

  • 包名或类名或方法名中含下划线 _ 要用 _1 连接;
  • 重载的本地方法命名要用双下划线 __ 连接;
  • 参数签名的斜杠 “/” 改为下划线 “_” 连接,分号 “;” 改为 “_2” 连接,左方括号 “[” 改为 “_3” 连接;
    另外,对于 Java 的 native 方法,static 和非 static 方法的区别在于第二个参数,static 的为 jclass,非 static 的 为 jobject;JNI 函数中是没有修饰符的。

示例

包名:com.android.javac,类名:NativeAccessJava

// java method
public native void setJavaString();

// jni method
JNIEXPORT void JNICALL
Java_com_android_javac_NativeAccessJava_setJavaString(JNIEnv *env, jobject thiz) 

4.2 动态注册

动态注册原理
动态注册 JNI 的原理:直接告诉 native 方法其在JNI 中对应函数的指针。通过使用 JNINativeMethod 结构来保存 Java native 方法和 JNI 函数关联关系,步骤:
1> 先编写 Java 的 native 方法;
2> 编写 JNI 函数的实现(函数名可以随便命名);
3> 利用结构体 JNINativeMethod 保存Java native方法和 JNI函数的对应关系;
4> 利用registerNatives(JNIEnv* env)注册类的所有本地方法;
5> 在 JNI_OnLoad 方法中调用注册方法;
6> 在Java中通过System.loadLibrary加载完JNI动态库之后,会自动调用JNI_OnLoad函数,完成动态注册;

不再使用 JNIEXPORT 和 JNICALL 两个宏定义声明指定的方法,也不用依照固定的命名规则命名方法(不过通常 jni 里的方法名还是保持和 native 方法的方法名一致,见名思义),而是通过了一个 RegisterNatives 方法完成了动态注册。

函数映射表
JNINativeMethod这其实是一个结构体,在jni.h头文件中定义,通过这个结构体从而使Java与jni建立联系

typedef struct {
const char* name; //Java中函数的名字
const char* signature;//符号签名,描述了函数的参数和返回值
void* fnPtr;//函数指针,指向一个被调用的函数
} JNINativeMethod;

示例

// java method
    public native String stringFromJNI();
    public static native int add(int a, int b);
// jni register
jint DyReg::RegisterNatives(JNIEnv *env) {
    LOGE("RegisterNatives");
    jclass clazz = env->FindClass("com/android/javac/DynamicReg");
    if (clazz == NULL) {
        LOGE("could't find class: com/android/javac/DynamicReg");
        return JNI_ERR;
    }
    JNINativeMethod methods_MainActivity[] = {
            {"stringFromJNI", "()Ljava/lang/String;", (void *) stringFromJNI},
            {"add",           "(II)I",                (void *) add}
    };
    // int len = sizeof(methods_MainActivity) / sizeof(methods_MainActivity[0]);
    return env->RegisterNatives(clazz, methods_MainActivity,
                                sizeof(methods_MainActivity) / sizeof(methods_MainActivity[0]));
}

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

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

相关文章

一款批量漏洞挖掘工具

介绍 QingScan一个批量漏洞挖掘工具,黏合各种好用的扫描器。 是一款聚合扫描器,本身不生产安全扫描功能,但会作为一个安全扫描工具的搬运工;当添加一个目标后,QingScan会自动调用各种扫描器对目标进行扫描&#xff0c…

一文读懂智能汽车滑板底盘

摘要: 所谓滑板式底盘,即将电池、电动传动系统、悬架、刹车等部件提前整合在底盘上,实现车身和底盘的分离,设计解耦。基于这类平台,车企可以大幅降低前期研发和测试成本,同时快速响应市场需求打造不同的车型。尤其是无…

系统架构设计师-软件工程(2)

一、需求工程 1、需求工程阶段划分 软件需求是指用户对系统在功能、行为、性能、设计约束等方面的期望。 【需求工程主要活动的阶段划分】 2、需求获取 3、需求分析 (1)数据流图(DFD) 简称DFD,它从…

LabVIEW开发矿用泵液压头测试系

LabVIEW开发矿用泵液压头测试系 在矿井中,矿用泵是用于排放矿井水的关键设备。如果不正常运行,矿山的生产必然受到严重影响,工人的生命也受到严重威胁。确保矿用泵能够正常运行非常重要。由于其运行条件非常恶劣,矿用泵的故障率高…

网络故障排除之Traceroute命令详解

概要 遇到网络故障的时候,你一般会最先使用哪条命令进行排障? 除了Ping,还有Traceroute、Show、Telnet又或是Clear、Debug等等。 今天安排的,是Traceroute排障命令详解,给你分享3个经典排障案例哈。 一. Traceroute…

ChatGPT 最佳实践指南之:写出清晰的指示

Write clear instructions 写出清晰的指示 GPTs can’t read your mind. If outputs are too long, ask for brief replies. If outputs are too simple, ask for expert-level writing. If you dislike the format, demonstrate the format you’d like to see. The less GPTs…

如何使网站快速拥有登录注册功能

如何使网站快速拥有登录注册功能 一、产品介绍二、开始使用1、如何判断用户是否登录?2、如何让用户登录?举个例子: 3、登录成功后如何拿到用户数据?4、如何维护用户的登录态? 二、注意点 前端必备工具(免费图床、API、chatAI等)推荐网站LuckyCola: h…

机器学习——支持向量机(数学基础推导篇【未完】)

在一个周日下午,夏天的雨稀里哗啦地下着 我躺在床上,捧着ipad看支持向量机 睡了好几个觉…支持向量机太好睡了 拉格朗日乘数法太好睡了 几何函数太好睡了 在我看来,支持向量机是目前学下来,最难以理解的内容 希望日后不要太难…脑…

[计算机入门] Windows对话框

2.4 对话框 在图形用户界面中,对话框是一种特殊的窗口, 用来在用户界面中向用户显示信息,或者在需要的时候获得用户的输入响应。之所以称之为对话框是因为它们使计算机和用户之间构成了一个对话——或者是通知用户一些信息,或者是请求用户的…

C. Russian Roulette(构造)

传送门 题意 俄罗斯转盘,长度为n的环,有k个子弹,然后挨着对着脑袋打。 你是第一个人,你希望你死的概率最小,问你怎么去设置这个子弹的位置。 第二个人会一开始随机砖圈,使得每一个位置开始都是可能的。…

电脑技巧:怎么轻松地搞定Win11系统备份任务

目录 1、选择免费备份软件来自动备份系统 2、如何逐步配置定时系统备份任务? “我是一个电脑小白,不是很懂电脑的一些操作。我刚买了一台新电脑,它装的是Win11系统,我害怕它出现什么问题,听朋友说可以通过备份的方…

Kotlin~责任链模式

概念 允许多个对象按顺序处理请求或任务。 角色介绍 Handler: 处理器接口,提供设置后继者&#xff08;可选&#xff09;ConcreteHandler&#xff1a;具体处理器&#xff0c;处理请求 UML 代码实现 比如ATM机吐钱就可以使用责任链实现。 class PartialFunction<in P1, o…

【环境配置】Conda ERROR:Failed building wheel for lap

问题 note: This error originates from a subprocess, and is likely not a problem with pip.ERROR: Failed building wheel for lapRunning setup.py clean for lap Failed to build lap ERROR: Could not build wheels for lap, which is required to install pyproject.to…

JDK8安装

在官网进行下载Java Downloads | Oracle 点击进行安装即可。 之后是配置环境变量 点击我的电脑 – 属性 – 高级系统设置 – 环境变量 添加JAVA_8_HOME环境变量&#xff0c;指向jdk的安装目录。 之后编辑path环境变量&#xff0c;增加%JAVA_8_HOME%\bin win R 输入javac 测…

在线支付安全-业务安全测试实操(35)

目前网络在线消费和支付,已遍布人们生活的衣食住行等冬个方面,比如网上商城在线购物、水电燃气在线缴费、手机话费在线充值等。由于在线消费和支付过程中涉及真金白银,一旦存在漏洞,将会带来重大的经济损失。 某快餐连锁店官网订单金额篡改 篡改订单金额的流程如图 所示 步…

Spark(14):SparkSQL之概述

目录 0. 相关文章链接 1. SparkSQL是什么 2. Hive and SparkSQL 3. SparkSQL 特点 3.1. 易整合 3.2. 统一的数据访问 3.3. 兼容Hive 3.4. 标准数据连接 4. DataFrame 是什么 5. DataSet 是什么 6. SparkSQL的运行环境 0. 相关文章链接 Spark文章汇总 1. SparkSQL是…

java pdf加水印

本文将Base64编码形式的pdf文件加水印&#xff0c;并输出完成后的pdf的Base64编码&#xff0c;也可以根据情况自行改动&#xff0c;输出其他形式的内容。 首先引入两个包 <!-- PDF文件依赖包 --><dependency><groupId>com.itextpdf</groupId><arti…

计算机体系结构基础知识介绍之缓存性能的十大进阶优化之编译器优化和硬件预取(六)

优化七&#xff1a;编译器优化&#xff0c;降低miss率 处理器和主内存之间不断扩大的性能差距促使编译器编写者仔细检查内存层次结构&#xff0c;看看编译时优化是否可以提高性能。再次&#xff0c;研究分为指令缺失的改进和数据缺失的改进。接下来介绍的优化可以在许多现代编…

步入JAVA——环境搭建与项目通览

前言 在这篇文章中&#xff0c;荔枝会介绍如何配置Java后端开发环境并借助一个Java web项目简单介绍一下Java的后端开发逻辑。与python的后端开发逻辑是类似的&#xff0c;Java的后端开发其实也是通过一个个类来实现的。对于像荔枝这种小白白来说&#xff0c;入门的第一个练手J…

java项目之高校四六级报名管理系统(ssm+jsp+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的高校四六级报名管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1a;风歌…