浅析Android-JNI

概述

** JNI (Java Native Interface)是帮助Java调用Native库的桥梁**

图解如下


JNI示意图

JNI 是通过C/C++实现的一层桥梁。
那么Native 世界是什么呢?说简单一点就是C/C++底层世界。

为什么需要这一层呢?
以我现在的理解是,在两个不同的世界直接通讯是可行的,但是会很麻烦,因为你每一次通讯都必须讲两个世界的语言翻译一下。如果我们实现一个大家公认的翻译程序,那么到时候只需调用一下这些已经定义好的接口就行了!这就是JNI也叫Java 和 Native 之间的接口。

既然知道他是什么之后,我们要开始了解他是真么运行的!

实例

Jni_MediaScanner.png

注意:名字是media,前面的lib.so是拓展名,如果是在windows 下拓展名是libmeida.dll

MediaScanner.java
目录frameworks/base/media/java/android/meidia/MediaScanner.java

public class MediaScanner { 
  static {
   /**加载对应的JNI库,media_jni是对应JNI库的名字,实际上加载动态库的时候他 会拓展成libmedia_jni.so **/
   System.loadLibrary("media_jni"); native_init(); //调用native_init()函数,他是一个native函数
   }
 ...... 
  //非native函数
  public void scanDirectories(String[] directories, String volumeName) {
      ...... 
      for (int i = 0; i < directories.length; i++) { 
         processDirectory(directories[i], mClient); 
      }
      ...... 
  }
   
  //扫面目录的函数,里面用到了processDirectory这个native函数 
  //native 为java关键字,表示它将由JNI完成
  private native void processFile(String path, String mimeType, MediaScannerClient client); 
  private static native final void native_init(); 
  ......
}

JNI 层的MediaScanner

目录frameworks/base/media/jni/android_media_MediaScanner.cpp

267  static void 
268  android_media_MediaScanner_processFile(
269         JNIEnv *env, jobject thiz, jstring path,
270         jstring mimeType, jobject client)
271 {           
272     ALOGV("processFile");
273             
274     // Lock already hold by processDirectory
275     MediaScanner *mp = getNativeScanner_l(env, thiz);
276     if (mp == NULL) {
277         jniThrowException(env, kRunTimeException, "No scanner available");
278         return;
279     }       
280             
281     if (path == NULL) {
282         jniThrowException(env, kIllegalArgumentException, NULL);
283         return;
284     }       
285             
286     const char *pathStr = env->GetStringUTFChars(path, NULL);
287     if (pathStr == NULL) {  // Out of memory
288         return;
289     }       
290             
291     const char *mimeTypeStr =
292         (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
293     if (mimeType && mimeTypeStr == NULL) {  // Out of memory
294         // ReleaseStringUTFChars can be called with an exception pending.
295         env->ReleaseStringUTFChars(path, pathStr);
296         return;
297     }       
298             
299     MyMediaScannerClient myClient(env, client);
300     MediaScanResult result = mp->processFile(pathStr, mimeTypeStr, myClient);
301     if (result == MEDIA_SCAN_RESULT_ERROR) {
302         ALOGE("An error occurred while scanning file '%s'.", pathStr);
303     }       
304     env->ReleaseStringUTFChars(path, pathStr);
305     if (mimeType) {
306         env->ReleaseStringUTFChars(mimeType, mimeTypeStr);                             
307     }       
308 }
问题:Java申明的函数是如何找到相应的JNI文件的?
  • 静态注册
静态注册流程

效率低用的少

  • 动态注册
    Java Native 函数和JNI函数一一对应,故可以通过JNINativeMethod结构记录这种关系
    基本结构
typedef struct { 
     //java类中native函数的名字,不用携带包名,例如“native_init” 
    const char* name; 
    //java函数的签名信息,用字符串表示,是参数类型和返回值类型的组合 
    const char* signature; 
    //JNI层对应函数的函数指针,它是void* 类型 void* fnPtr;
}JNINativeMethod;

具体实例

static const JNINativeMethod gMethods[] = { 
//
  { 
    "processDirectory", 
    "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V", 
    (void *)android_media_MediaScanner_processDirectory 
  }, 
//
  {
     "processFile", 
     "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
     (void *)android_media_MediaScanner_processFile 
   },
     ....... 
//
  {
     "native_init", "()V",
     (void *)android_media_MediaScanner_native_init 
  }, 
    ......
};

定义完毕以后需要执行注册

int register_android_media_MediaScanner(JNIEnv *env){ 
    return AndroidRuntime::registerNativeMethods(env,
                    kClassMediaScanner, gMethods, NELEM(gMethods));
}
JNI动态注册
问题:什么时候执行注册呢?

在Java层执行System.loadLibrary加载JNI动态库后,紧接着会查找该库中一个JNI_OnLoad的函数,如果有的话,动态注册就在这里完成。然而在MediaScanner对应的android_media_MediaScanner.cpp中并没有发现这个函数。由于多媒体系统中很对地方用到JNI,所以register_android_media_MediaScanner这个注册方法被放在了android_media_MediaPlayer.cppJNI_OnLoad方法中,当然还有其它的多媒体相关的注册函数。

Jint JNI_OnLoad(JavaVm* vm,void* reserved);

传入一个虚拟机对象,用来生产JNIEnv结构体,JNIEnv结构体提供JNI系统操作方法。

参考:

http://www.jianshu.com/p/1e7e6689e5b1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容