JNI杂谈

JNI,Java Native Interface,用来使Java代码通过Java VM与本地代码交互。那么这个交互过程是怎样实现的呢?

 

我目前遇到的跨语言交互一般都是通过函数指针(函数地址)。语言之间通过调用规定的API注册函数指针,由OS、VM或其它实例维护一个表格。JNI也不例外。

 

Java类调用一个native函数首先需要在Java类中声明它(不用实现),关键字native用来告诉javac编译时关于此函数的调用生成特殊的二进制码,再由VM去执行调用native函数。

 

一般在调用native的函数Java类中有个static块来加载对应的库,如下:

static
{
    System.loadLibrary("xxx");
}


Java是跨平台的,它的VM当然知道如何处理类似Windows dll和Linux so之间的问题。

 

那么Java VM调用native函数都做了哪些工作呢?它在System.loadLibrary()时会调用lib(dll、so等)中的JNI_OnLoad(),lib应该在其中设置好前面说的VM维护的一张表格。下面是表格中的项的定义:

typedef struct {
       const char* name;
       const char* signature;
       void* fnPtr;
} JNINativeMethod;


name为函数名,signature为函数原型的描述,fnPtr为函数指针。

 

设置表格需要先声明一个static的JNINativeMethod数组:

static JNINativeMethod gMethods[] = {
    // 见JNINativeMethod的定义
}


然后调用AndroidRuntime::registerNativeMethods(这是Android中VM的规范,Java VM也应该有类似的API):

AndroidRuntime::registerNativeMethods(env, "com/media/ffmpeg/FFMpeg", gMethods, sizeof(gMethods) / sizeof(gMethods[0]);


其中“com/media/ffmpeg/FFMpeg”说明了这是注册com.media.ffmpeg包下的FFMpeg Java类中的native函数,可以说是作用域吧,Java VM应该会根据这个来查第一层表。

 

但一般并没有在JNI_OnLoad()中直接调用上面的API注册native函数,因为不同Java类可能会有它自己的native函数的调用,因此一般都是做了一层封装,如JNI_OnLoad()中:

if(register_android_media_FFMpeg(env) != JNI_OK) {
    	__android_log_print(ANDROID_LOG_ERROR, TAG, "can't load android_media_FFMpeg");
        goto end;
	}


register_android_media_FFMpegAVFormatContext其实是对上面AndroidRuntime::registerNativeMethods封装,但它很好的分离的不同的Java类各自的native函数注册。

 

参考资料:

http://jinguo.iteye.com/blog/696185

http://www.douban.com/note/101269287/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值