注册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));
}
}
本文欢迎转载,转载请注明出处与作者
出处:http://blog.sina.com.cn/staratsky
作者:流星
- 【转】深入了解android平台的jni---注册native函数
原文网址:http://my.oschina.net/u/157503/blog/169041 注册native函数有两种方法:静态注册和动态注册. 1.静态注册方法 根据函数名找到对应的JNI函数: ...
- 深入了解android平台的jni(二)
Android.mk是Android提供的一种makefile文件,用来指定诸如编译生成so库名.引用的头文件目录.需要编译的.c/.cpp文件和.a静态库文件等.要掌握jni,就必须熟练掌握Andr ...
- 深入了解android平台的jni(一)
android中很多Java类都具有native接口,这些接口由本地实现,然后注册到系统中. 主要的JNI代码放在以下的路径中:frameworks/base/core/jni/,这个路径中的 ...
- Android平台Native开发与JNI机制详解
源文链接: http://mysuperbaby.iteye.com/blog/915425 一个Native Method就是一个Java调用非Java代码的接口.一个Native Method是这 ...
- 【转】 Android 开发 之 JNI入门 - NDK从入门到精通
原文网址:http://blog.csdn.net/shulianghan/article/details/18964835 NDK项目源码地址 : -- 第一个JNI示例程序下载 : GitHub ...
- 【Android 应用开发】Android 开发 之 JNI入门 - NDK从入门到精通
NDK项目源码地址 : -- 第一个JNI示例程序下载 : GitHub - https://github.com/han1202012/NDKHelloworld.git -- Java传递参数给C ...
- Android 开发 之 JNI入门 - NDK从入门到精通
NDK项目源码地址 : -- 第一个JNI示例程序下载 : GitHub - https://github.com/han1202012/NDKHelloworld.git -- Java传递参数给C ...
- 深入理解Android(5)——从MediaScanner分析Android中的JNI
前面几篇介绍了Android中的JNI和基本用法,这一篇我们通过分析Android源代码中的JNI实例,来对JNI部分做一个总结. 一.通向两个不同世界的桥梁 在前面我们说过,JNI就像一个桥梁,将J ...
- Android平台dalvik模式下java Hook框架ddi的分析(1)
本文博客地址:http://blog.csdn.net/qq1084283172/article/details/75710411 一.前 言 在前面的博客中已经学习了作者crmulliner编写的, ...
随机推荐
- 【LeetCode】9 & 234 & 206 - Palindrome Number & Palindrome Linked List & Reverse Linked List
9 - Palindrome Number Determine whether an integer is a palindrome. Do this without extra space. Som ...
- Select模型及tcp select模型
参考:http://m.blog.csdn.net/article/details?id=51420015 一.套接字模式 套接字模式简单的决定了操作套接字时,Winsock函数是如何运转的.Wins ...
- [转] 请别再拿“String s = new String("xyz");创建了多少个String实例”来面试了吧
这帖是用来回复高级语言虚拟机圈子里的一个问题,一道Java笔试题的. 本来因为见得太多已经吐槽无力,但这次实在忍不住了就又爆发了一把.写得太长干脆单独开了一帖. 顺带广告:对JVM感兴趣的同学们同志们 ...
- 使用Maven将Hadoop2.2.0源码编译成Eclipse项目
编译环境: OS:RHEL 6.3 x64 Maven:3.2.1 Eclipse:Juno SR2 Linux x64 libprotoc:2.5.0 JDK:1.7.0_51 x64 步骤: 1. ...
- Python 读取文件下所有内容、获取文件名、截取字符、写回文件
# coding=gbk import os import os.path #读取目录下的所有文件,包括嵌套的文件夹 def GetFileList(dir, fileList): newDir ...
- 第三百二十二天 how can I 坚持
昨晚好像一直在做梦,模模糊糊的,其实很难受. 真不知道该怎么办了,是没有勇气,还是怕什么,总之, 不知道该咋办了. 搞不懂. 回来第二天了,节奏又一点的开始了,一年又会很快过去. 刘松说要来北京,整天 ...
- gdb之watch命令
[gdb之watch命令] 什么是watchpoint? watchpoint,顾名思义,其一般用来观察某个变量/内存地址的状态(也可以是表达式),如可以监控该变量/内存值是否被程序读/写情况. 在g ...
- C++11之sizeof
[C++11之sizeof] 在标准C++,sizeof可以作用在对象以及类别上.但是不能够做以下的事: 这会传回OtherType的大小.C++03并不允许这样做,所以会引发编译错误.C++11将会 ...
- Python基础 条件、循环
1.条件语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. if if语句执行有个特点,它是从上往下判断,如果在某个判断上是True,把该判断对应的 ...
- Python基础 列表
---***---传送门---***--- 文档解释 def append(self, p_object): """ L.append(object) -> Non ...