缘起
最近分析一个Android平台上的so,发现JNI函数命名如下:
函数名字和自己平时写代码不一样,故重新学习JNI方法的签名规则。
规则
工具使用
可以使用javah自动生成JNI函数签名,来探索函数命名规则。
javah -jni 包名.类名
一般类的普通函数
package com.example;
public class Sample{
public static native int GetSample(int n, String s,int [] arr);
}
执行命令 "javah -jni com.example.Sample" 后生成的c++文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_Sample */
#ifndef _Included_com_example_Sample
#define _Included_com_example_Sample
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_Sample
* Method: GetSample
* Signature: (ILjava/lang/String;[I)I
*/
JNIEXPORT jint JNICALL Java_com_example_Sample_GetSample
(JNIEnv *, jclass, jint, jstring, jintArray);
#ifdef __cplusplus
}
#endif
#endif
内部类的函数和重载函数
package com.example;
public class Native{
public static native int GetSample();
public static native int GetSample(int n, String s,int [] arr);
public static class Stub{
public static native int GetSample();
}
}
执行命令 "javah -jni com.example.Native" 后生成的c++文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_Native */
#ifndef _Included_com_example_Native
#define _Included_com_example_Native
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_Native
* Method: GetSample
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_example_Native_GetSample__
(JNIEnv *, jclass);
/*
* Class: com_example_Native
* Method: GetSample
* Signature: (ILjava/lang/String;[I)I
*/
JNIEXPORT jint JNICALL Java_com_example_Native_GetSample__ILjava_lang_String_2_3I
(JNIEnv *, jclass, jint, jstring, jintArray);
#ifdef __cplusplus
}
#endif
#endif
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_Native_Stub */
#ifndef _Included_com_example_Native_Stub
#define _Included_com_example_Native_Stub
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_Native_Stub
* Method: GetSample
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_example_Native_00024Stub_GetSample
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
函数签名
一般函数的JNI接口函数命名:Java_包名_类名_方法名。 比如包com.example下的类Sample中的GetSample函数对应的JNI函数名 : “Java_com_example_Sample_GetSample” 。
重载函数的JNI接口函数命名:Java_包名_类名_方法名__参数签名。 比如包名com.example下的类Native中的GetSample函数对应的JNI函数名: “Java_com_example_Native_GetSample__ILjava_lang_String_2_3I” 。
内部类Stub的JNI函数名: “Java_com_example_Native_00024Stub_GetSample” 。
类型签名
类型签名 | Java类型 |
---|---|
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
Lfully-qulitied-class; | 全限定类 |
[type | type[] 数组 |
(argtypes)rettype | 方法类型 |
转义字符
JNI在函数命名时采用名字扰乱方案,以保证所有的Unicode字符都能转换为有效的C函数名,所有的“/”,无论是包名中的还是全限定类名中的,均使用“_”代替,用_0,…,_9来代替转义字符。
转义字符序列 | 表示 |
---|---|
_0XXXX | Unicode字符XXXX |
_1 | 字符“_” |
_2 | 签名中的字符“;” |
_3 | 签名中的字符“[” |
比如 "IdsSupplier_00024Stub" 中的"_00024" 表示字符"$" 。
Comments