如何理解android平台的jni—注册native函数
创始人
2024-12-25 21:43:05
0次

注册native函数有两种方法:静态注册和动态注册。

1、静态注册方法根据函数名找到对应的JNI函数:Java层调用函数时,会从对应的JNI中寻找该函数,如果没有就会报错,如果存在则会建立一个关联联系,以后在调用时会直接使用这个函数,这部分的操作由虚拟机完成。 静态方法就是根据函数名来遍历java和jni函数之间的关联,而且要求jni层函数的名字必须遵循 特定的格式,其缺点在于:

 1)javah生成的jni层函数特别长;

 2)初次调用native函数时要根据名字搜索对应的jni层函数来建立关联联系,这样影响效率。

2、动态注册方法JNI 允许你提供一个函数映射表,注册给Jave虚拟机,这样Jvm就可以用函数映射表来调用相应的函数, 就可以不必通过函数名来查找需要调用的函数了。 Java与JNI通过JNINativeMethod的结构来建立联系,它在jni.h中被定义,其结构内容如下: typedef struct { const char* name; const char* signature; void* fnPtr; } JNINativeMethod; 第一个变量name是Java中函数的名字。 第二个变量signature,用字符串是描述了函数的参数和返回值 第三个变量fnPtr是函数指针,指向C函数。 当java通过System.loadLibrary加载完JNI动态库后,紧接着会查找一个JNI_OnLoad的函数,如果有,就调用它, 而动态注册的工作就是在这里完成的。 1)JNI_OnLoad()函数 JNI_OnLoad()函数在VM执行System.loadLibrary(xxx)函数时被调用,它有两个重要的作用: 指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),如果要使用新版本的JNI, 例如JNI 1.4版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_4(该常量定义在jni.h中) 来告知VM。 初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_OnLoad()方法,因此在该方法中进行各种资源的初始化操作最为恰当, 2)RegisterNatives RegisterNatives在AndroidRunTime里定义 syntax: jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods)

3、在android中加入自定义的native函数JNI在Android层次结构中的作用

在Android中,主要的JNI代码在以下的路径中: Android源码根目录/frameworks/base/core/jni/ 这个路径中的内容将被编译成库libandroid_runtime.so,这就是一个普通的动态库,被放置在目标系统的/system/lib目录中.除此之外,Android还包含其他的JNI库,例如,媒体部分的JNI目录frameworks/base/media/jni/中,被编译成库libmedia_jni.so. JNI中的各个文件实际上就是C++的普通文件,其命名一般和支持的Java类有对应关系。 这种关系是习惯上的写法,而不是强制的。 1)注册JNI方法 在Android源码根目录/frameworks/base/services/jni/目录下有一个onload.cpp文件,加入 jni函数申明和jni函数注册方法 #include "JNIHelp.h"  

#include "jni.h"  

#include "utils/Log.h"  

#include "utils/misc.h"  

namespace android {  

int register_android_server_AlarmManagerService(JNIEnv* env);  

int register_android_server_BatteryService(JNIEnv* env);  

int register_android_server_InputApplicationHandle(JNIEnv* env);  

int register_android_server_InputWindowHandle(JNIEnv* env);  

int register_android_server_InputManager(JNIEnv* env);  

int register_android_server_LightsService(JNIEnv* env);  

int register_android_server_PowerManagerService(JNIEnv* env);  

int register_android_server_UsbDeviceManager(JNIEnv* env);  

int register_android_server_UsbHostManager(JNIEnv* env);  

int register_android_server_VibratorService(JNIEnv* env);  

int register_android_server_SystemServer(JNIEnv* env);  

int register_android_server_location_GpsLocationProvider(JNIEnv* env);  

int register_android_server_connectivity_Vpn(JNIEnv* env);  

int register_android_server_HelloService(JNIEnv *env);  

//此处加入自定义jni函数申明};  

using namespace android;  

extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)  

{  

 JNIEnv* env = NULL;  

 jint result = -1;  

 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  

 LOGE("GetEnv failed!");  

 return result;  

 }  

 LOG_ASSERT(env, "Could not retrieve the env!");  

 register_android_server_PowerManagerService(env);  

 register_android_server_InputApplicationHandle(env);  

 register_android_server_InputWindowHandle(env);  

 register_android_server_InputManager(env);  

 register_android_server_LightsService(env);  

 register_android_server_AlarmManagerService(env);  

 register_android_server_BatteryService(env);  

 register_android_server_UsbDeviceManager(env);  

 register_android_server_UsbHostManager(env);  

 register_android_server_VibratorService(env);  

 register_android_server_SystemServer(env);  

 register_android_server_location_GpsLocationProvider(env);  

 register_android_server_connectivity_Vpn(env);  

 register_android_server_HelloService(env); //jni方法注册 

 return JNI_VERSION_1_4;  

}  

onload.cpp文件上部分为注册函数的声明,下部分为调用各种注册函数,而这些注册函数就是JNI方法的注册函数! 正是通过这些注册函数,上层才能调用注册的JNI方法. 以register_android_server_HelloService为例,来看一个注册函数的具体实现过程是如何的。 打开com_android_service_HelloService.cpp文件 2)加入注册函数的实现代码,如下: int register_android_server_HelloService(JNIEnv *env) {  

 return jniRegisterNativeMethods

(env, "com/android/server/HelloService", method_table, NELEM(method_table));  

}  

#其中jniRegisterNativeMethods

为注册JNI方法函数,#此函数的第二个参数为对应着java类即HelloService.java的文件名,第三个参数为注册的方法表 3)加入jni方法表  

static const JNINativeMethod method_table[] = {  

 {"init_native", "()Z", (void*)hello_init},  

 {"setVal_native", "(I)V", (void*)hello_setVal},  

 {"getVal_native", "()I", (void*)hello_getVal},  

};  

4)方法表内各个接口的实现代码 static void hello_setVal(JNIEnv* env, jobject clazz, jint value) {  

val = value;  

 LOGI("Hello JNI: set value %d to device.", val);  

}  

static jint hello_getVal(JNIEnv* env, jobject clazz) {  

 LOGI("Hello JNI: get value %d from device.", val);  

 return val;  

 } 

static jboolean hello_init(JNIEnv* env, jclass clazz) {  

 LOGI("Hello JNI: initializing......");  

 return -1;  

 } 

完整代码如下: namespace android {  

 int val; 

 static void hello_setVal(JNIEnv* env, jobject clazz, jint value) {  

val = value;  

 LOGI("Hello JNI: set value %d to device.", val);  

 }  

 static jint hello_getVal(JNIEnv* env, jobject clazz) {  

 LOGI("Hello JNI: get value %d from device.", val);  

 return val;  

 } 

static jboolean hello_init(JNIEnv* env, jclass clazz) {  

 LOGI("Hello JNI: initializing......");  

 return -1;  

 } 

 static const JNINativeMethod method_table[] = {  

 {"init_native", "()Z", (void*)hello_init},  

 {"setVal_native", "(I)V", (void*)hello_setVal},  

 {"getVal_native", "()I", (void*)hello_getVal},  

}; 

int register_android_server_HelloService(JNIEnv *env) {  

 return jniRegisterNativeMethods

(env, "com/android/server/HelloService", method_table, NELEM(method_table));  

}  

}

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...