原文网址:http://my.oschina.net/u/157503/blog/169041

注册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函数的更多相关文章

  1. 深入了解android平台的jni---注册native函数

    注册native函数有两种方法:静态注册和动态注册. 1.静态注册方法 根据函数名找到对应的JNI函数:Java层调用函数时,会从对应的JNI中寻找该函数,如果没有就会报错,如果存在则会建立一个关联联 ...

  2. 深入了解android平台的jni(二)

    Android.mk是Android提供的一种makefile文件,用来指定诸如编译生成so库名.引用的头文件目录.需要编译的.c/.cpp文件和.a静态库文件等.要掌握jni,就必须熟练掌握Andr ...

  3. 深入了解android平台的jni(一)

    android中很多Java类都具有native接口,这些接口由本地实现,然后注册到系统中.     主要的JNI代码放在以下的路径中:frameworks/base/core/jni/,这个路径中的 ...

  4. Android平台Native开发与JNI机制详解

    源文链接: http://mysuperbaby.iteye.com/blog/915425 一个Native Method就是一个Java调用非Java代码的接口.一个Native Method是这 ...

  5. 【转】 Android 开发 之 JNI入门 - NDK从入门到精通

    原文网址:http://blog.csdn.net/shulianghan/article/details/18964835 NDK项目源码地址 : -- 第一个JNI示例程序下载 : GitHub  ...

  6. 【Android 应用开发】Android 开发 之 JNI入门 - NDK从入门到精通

    NDK项目源码地址 : -- 第一个JNI示例程序下载 : GitHub - https://github.com/han1202012/NDKHelloworld.git -- Java传递参数给C ...

  7. Android 开发 之 JNI入门 - NDK从入门到精通

    NDK项目源码地址 : -- 第一个JNI示例程序下载 : GitHub - https://github.com/han1202012/NDKHelloworld.git -- Java传递参数给C ...

  8. 深入理解Android(5)——从MediaScanner分析Android中的JNI

    前面几篇介绍了Android中的JNI和基本用法,这一篇我们通过分析Android源代码中的JNI实例,来对JNI部分做一个总结. 一.通向两个不同世界的桥梁 在前面我们说过,JNI就像一个桥梁,将J ...

  9. Android平台dalvik模式下java Hook框架ddi的分析(1)

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/75710411 一.前 言 在前面的博客中已经学习了作者crmulliner编写的, ...

随机推荐

  1. android开发之AlertDialog点击按钮之后不消失 分类: android 学习笔记 2015-07-15 18:07 89人阅读 评论(0) 收藏

    最近有这样一个需求,我需要用户在一个弹出框里输入密码来验证,验证成功当然好说,但是如果验证失败则需要把alertdialog的标题改为"密码错误,请重新输入",并且这个alertd ...

  2. 自己写的自动生成动态边框的jquery小插件

    思路就是在元素四周添加<ul>列表,然后周期性地改变它的颜色,实现动态的效果,不支持ie7.ie8 预览链接http://gorey.sinaapp.com/myBorder/border ...

  3. Linux 自动更新时间

    1. 从NTP上把时间同步到本地 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 2. 更新本地时间 ntpdate us.pool.ntp.o ...

  4. XE6 /XE8 & IOS开发之免证书真机调试三步走,生成iPA文件并安装到其它苹果设备上

    XE6 & IOS开发之免证书真机调试(1):颁发属于自己的App签名证书(有图有真相) XE6 & IOS开发之免证书真机调试(2):连接真机并运行App(有图有真相) XE6 &a ...

  5. 【转】 OC基础数据类型-NSSet

    原文 : http://www.cnblogs.com/GISerYang/p/3340937.html 1.集合:集合(NSSet)和数组(NSArray)有相似之处,都是存储不同的对象的地址:不过 ...

  6. 解决ld: warning: directory not found for option警告

    去掉警告的办法如下: 1选择工程, 编译的 (targets) 2选择 Build Settings 菜单 3查找 Library Search Paths 和 Framework Search Pa ...

  7. 十一、C# 泛型

    为了促进代码重用,尤其是算法的重用,C#支持一个名为泛型的特性. 泛型与模块类相似. 泛型使算法和模式只需要实现一交.而不必为每个类型都实现一次.在实例化的时候,传入相应的数据类型便可. 注:可空值类 ...

  8. Sqoop import加载HBase过程中,遇到Permission denied: user=root, access=WRITE, inode="/user":hdfs:supergroup:drwxr-xr-x

    在执行hbase sqoop抽取的时候,遇到了一个错误,如下图: 在执行程序的过程中,遇到权限问题很正常,也容易让人防不胜防,有问题就想办法解决,这个是关键. 解决办法如下: 第一步:su hdfs, ...

  9. I/O多路转接之select

    系统提供select函数来实现多路复⽤用输入/输出模型.select系统调用是用来让我们的程序监视 多个文件句柄的状态变化的.程序会停在select这里等待,直到被监视的文件句柄有一个或 多个发生了状 ...

  10. 344. Reverse String(C++)

    344. Reverse String Write a function that takes a string as input and returns the string reversed. E ...