注册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类有对应关系。
这种关系是习惯上的写法,而不是强制的。
在Android源码根目录/frameworks/base/services/jni/目录下有一个onload.cpp文件,加入 jni函数申明和jni函数注册方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#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文件
1
2
3
int register_android_server_HelloService ( JNIEnv * env ) {
return jniRegisterNativeMethods ( env , "com/android/server/HelloService" , method_table , NELEM ( method_table ));
}
其中jniRegisterNativeMethods为注册JNI方法函数,
此函数的第二个参数为对应着java类即HelloService.java的文件名,第三个参数为注册的方法表
1
2
3
4
5
static const JNINativeMethod method_table [] = {
{ "init_native" , "()Z" , ( void * ) hello_init },
{ "setVal_native" , "(I)V" , ( void * ) hello_setVal },
{ "getVal_native" , "()I" , ( void * ) hello_getVal },
};
1
2
3
4
5
6
7
8
9
10
11
12
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 ;
}
完整代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 ));
}
}