`
tiankong6622
  • 浏览: 53630 次
社区版块
存档分类
最新评论

JNI浅析

阅读更多

 JNI是Java Native Interface的缩写,JNI是一种机制,有了它就可以在java程序中调用其他native代码,或者使native代码调用java层的代码。也就是说,有了JNI我们可以使Android项目中,java层与native层各自发挥所长并相互配合。如下图所示,JNI在Android中所处的位置。

   

                                                                          

                                                                好吧谁不知道JNI应该在JAVA和Native的中间呢?

 

        JNI相对与native层来说是一个接口,java层的程序想访问native层,必须通过JNI,反过来也一样。下面我们来看几个问题。

1,如何告诉VM(虚拟机)java层需要调用native层的哪些libs?

        我们知道java程序是运行在VM上的,而Native层的libs则不然。所以为了让java层能访问native层的libs,必须得告诉VM要使用哪些native层的libs。下面看一段代码

 

[java] view plaincopy
 
  1. public class MediaPlayer    
  2.  {    
  3.      ...    
  4.      
  5.      static {    
  6.          System.loadLibrary("media_jni");    
  7.          native_init();    
  8.      }    
  9.      
  10.       ...    
  11.      
  12.      private native final void native_setup(Object mediaplayer_this);    
  13.           
  14.       ...    
  15.   }  



 

可以看到上面的代码中,在MediaPlayer类中有一段static块包围起来的代码,其中System.loadLibrary("media_jni")就是告诉VM去加载libmedia_jni.so这个动态库,那么这个动态库什么时候被加载呢?因为static语句块的原因,所以在MediaPlayer第一次实例化的时候就会被加载了。这段代码中,我们还看到了一个函数native_init(),该函数被申明为native型,就是告诉VM该函数由native层来实现。

 

 

2,如何做到java层到native层的映射。

        事实上我想表达的意思是,如何完成java层的代码到native层代码的映射,例如上面的代码中有一个native函数native_init(),那么如何使这个函数映射到一个由C/C++(或者其他语言)实现的具体函数呢?PS:本菜鸟,表达能力欠缺,不知道大家有没有看明白。

             当VM执行到System.loadLibrary()的时候就会去执行native libs中的JNI_OnLoad(JavaVM* vm, void* reserved)函数,因为JNI_OnLoad函数是从java层进入native层第一个调用的方法,所以可以在JNI_OnLoad函数中完成一些native层组件的初始化工作,同时更加重要的是,通常在JNI_jint JNI_OnLoad(JavaVM* vm, void* reserved)函数中会注册java层的native方法。下面看一段代码:

[java] view plaincopy
 
  1. jint JNI_OnLoad(JavaVM* vm, void* reserved)  
  2. {  
  3.     JNIEnv* env = NULL;  
  4.     jint result = -1;  
  5.     //判断一下JNI的版本   
  6.     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
  7.         LOGE("ERROR: GetEnv failed\n");  
  8.         goto bail;  
  9.     }  
  10.     assert(env != NULL);  
  11.   
  12.     if (register_android_media_MediaPlayer(env) < 0) {  
  13.         LOGE("ERROR: MediaPlayer native registration failed\n");  
  14.         goto bail;  
  15.     }  
  16.   
  17.     if (register_android_media_MediaRecorder(env) < 0) {  
  18.         LOGE("ERROR: MediaRecorder native registration failed\n");  
  19.         goto bail;  
  20.     }  
  21.   
  22.     if (register<span style="font-size:16px;">_android_media_MediaScanner(env) < 0) {  
  23.         LOGE("ERROR: MediaScanner native registration failed\n");  
  24.         goto bail;  
  25.     }</span>  
  26.   
  27.     if (register_android_media_MediaMetadataRetriever(env) < 0) {  
  28.         LOGE("ERROR: MediaMetadataRetriever native registration failed\n");  
  29.         goto bail;  
  30.     }  
  31.   
  32.     if (register_android_media_AmrInputStream(env) < 0) {  
  33.         LOGE("ERROR: AmrInputStream native registration failed\n");  
  34.         goto bail;  
  35.     }  
  36.   
  37.     if (register_android_media_ResampleInputStream(env) < 0) {  
  38.         LOGE("ERROR: ResampleInputStream native registration failed\n");  
  39.         goto bail;  
  40.     }  
  41.   
  42.     if (register_android_media_MediaProfiles(env) < 0) {  
  43.         LOGE("ERROR: MediaProfiles native registration failed");  
  44.         goto bail;  
  45.     }  
  46.   
  47.     /* success -- return valid version number */  
  48.     result = JNI_VERSION_1_4;  
  49.   
  50. bail:  
  51.     return result;  
  52. }  

上面这段代码的JNI_OnLoad(JavaVM* vm, void* reserved)函数实现与libmedia_jni.so库中。上面的代码中调用了一些形如register_android_media_MediaPlayer(env)的函数,这些函数的作用是注册native method。我们来看看函数register_android_media_MediaPlayer(env)的实现。

 

 

[java] view plaincopy
 
  1. // This function only registers the native methods  
  2. static int register_android_media_MediaPlayer(JNIEnv *env)  
  3. {  
  4.     return AndroidRuntime::registerNativeMethods(env,  
  5.                 "android/media/MediaPlayer", gMethods, NELEM(gMethods));  
[java] view plaincopy
 
  1. /* 
  2.  * Register native methods using JNI. 
  3.  */  
  4. /*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,  
  5.     const char* className, const JNINativeMethod* gMethods, int numMethods)  
  6. {  
  7.     return jniRegisterNativeMethods(env, className, gMethods, numMethods);  
  8. }  

最终jniRegisterNativeMethods函数完成java标准的native函数的映射工作。下面我们来具体的看看上面这个函数中各个参数的意义。

 

a,JNIEnv* env,关于JNIEnv我在google上找到了这些信息:

JNI defines two key data structures, "JavaVM" and "JNIEnv". Both of these are essentiallypointers to pointers to function tables. (In the C++ version, they're classes with apointer to a function table and a member function for each JNI function that indirects throughthe table.) The JavaVM provides the "invocation interface" functions,which allow you to create and destroy a JavaVM. In theory you can have multiple JavaVMs per process,but Android only allows one.

The JNIEnv provides most of the JNI functions. Your native functions all receive a JNIEnv asthe first argument.

The JNIEnv is used for thread-local storage. For this reason, you cannot share a JNIEnv between threads.If a piece of code has no other way to get its JNIEnv, you should sharethe JavaVM, and useGetEnv to discover the thread's JNIEnv. (Assuming it has one; see AttachCurrentThread below.)

这里需要注意一点的是,JNIEnv是一个线程的局部变量,这以为这JNIEnv是存在与多线程环境下的,因为 VM 通常是多执行绪(Multi-threading)的执行环境。每一个执行绪在呼叫JNI_OnLoad()时,所传递进来的 JNIEnv 指标值都是不同的。为了配合这种多执行绪的环境,C/C++组件开发者在撰写本地函数时,可藉由 JNIEnv 指标值之不同而避免执行绪的资料冲突问题,才能确保所写的本地函数能安全地在 Android 的多执行绪 VM 里安全地执行。基于这个理由,当在
呼叫 C/C++ 组件的函数时,都会将 JNIEnv 指标值传递给它。

b,char* className,这个没什么好说的,java空间中类名,其中包含了包名。

c,JNINativeMethod* gMethods,传递进去的是一个JNINativeMethod类型的指针gMethodsgMethods指向一个JNINativeMethod数组,我们先看看JNINativeMethod这个结构体。

 

[java] view plaincopy
 
  1. typedef struct {  
  2.  const char* name; /*Java 中函数的名字*/  
  3.  const char* signature; /*描述了函数的参数和返回值*/  
  4.  void* fnPtr; /*函数指针,指向 C 函数*/  
  5.  } JNINativeMethod;  

再来看看gMethods数组

 

 

[java] view plaincopy
 
  1. static JNINativeMethod gMethods[] = {  
  2.     {"setDataSource",       "(Ljava/lang/String;)V",            (void *)android_media_MediaPlayer_setDataSource},  
  3.     。。。  
  4.     {"setAuxEffectSendLevel""(F)V",                           (void *)android_media_MediaPlayer_setAuxEffectSendLevel},  
  5.     {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer_attachAuxEffect},  
  6.     {"getOrganDBIndex",     "(II)I",                            (void *)android_media_MediaPlayer_getOrganDBIndex},  
  7. };  

d,int numMethods,不解释。

 

 

这样一来就完成了java native函数到到JNI层函数的映射。当然具体功能实现还是由JNI层函数来调用C/C++相应的功能函数

 

原文出处:http://blog.csdn.net/mci2004/article/details/7211678

分享到:
评论

相关推荐

    Android JNI 浅析

    文中较为详细的介绍了Android JNI的工作原理,Android的JAVA层如何通过JNI与Native层交互的方法。新手入门必看!

    浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制

    浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制

    浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power

    浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power

    浅析Android.mk

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

    Android代码-各种实例库

    博客:NDK-JNI实战教程(三) 从比Hello World稍复杂点儿的NDK例子说说模板 博客文章链接---------实例代码工程 博客:facebook Fresco框架库源使用基础 博客文章链接---------实例代码工程 博客:浅谈MVP实现...

    Android博客来源:博客演示存储

    我的博客实例库( ##示例索引###博客:NDK-JNI实战教程(三)从比Hello World稍复杂点儿的NDK例子说说模板---------###博客:facebook Fresco框架库源使用基础---------###博客:浅谈MVP实现Android应用层开发------...

    2010年谢彦的android笔记

    4.6 浅析dalvik虚拟机JIT技术的实现 133 4.7 应用程序的签名(Signature) 135 4.8 应用的权限 138 4.9 屏幕密度Density 140 4.10 Prelink实现的源码分析 142 4.11 适配硬件平台 145 4.12 其他介绍 147 4.12.1 手机...

    android笔记.rar

    4.6 浅析dalvik虚拟机JIT技术的实现... ...133 4.7 应用程序的签名(Signature) ... ...135 4.8 应用的权限... ..138 4.9 屏幕密度Density ... ..140 3 4.10 Prelink实现的源码分析 ... ...142 4.11 适配...

    Android 4游戏编程入门经典

     7.12.6 减少opengl es/jni方法的调用  7.12.7 绑定顶点的概念  7.12.8 写在结束之前  7.13 小结 第8章 2d游戏编程技巧  8.1 写在开始  8.2 向量  8.2.1 使用向量  8.2.2 一点三角学的知识  8.2.3 实现一个...

    android游戏编程入门

     7.12.6 减少OpenGL ES/JNI方法的  调用 278  7.12.7 绑定顶点的概念 279  7.12.8 写在结束之前 282  7.13 小结 283  第8章 2D游戏编程技巧 285  8.1 写在开始 285  8.2 向量 286  8.2.1 使用向量 286  ...

Global site tag (gtag.js) - Google Analytics