zoukankan      html  css  js  c++  java
  • 深入理解Android(5)——从MediaScanner分析Android中的JNI

    前面几篇介绍了Android中的JNI和基本用法,这一篇我们通过分析Android源代码中的JNI实例,来对JNI部分做一个总结。

    一、通向两个不同世界的桥梁

    在前面我们说过,JNI就像一个桥梁,将Java和Native世界紧密的联系在了一起,在Android平台上如果没有Native层的支持我们的系统寸步难行,甚至Java中的虚拟机也是通过Native实现的。


    二、MediaScanner类的简单介绍

    MediaScannerr完成android中的多媒体文件的扫描工作。例如,mediascanner扫描系统内存和SD卡文件之后,会将扫描的结果加载在数据库中,在Music这个应用程序中看到的显示在activity 的list列表上歌曲专辑名,流派,歌曲时长等信息,都是扫描后的结果放在数据库中,最后读到的数据库中的信息。

    MediaScanner这项功能使用到的三种android的基本组件:

    1、MediaScannerService(从Service中派生),完成扫描任务,并将扫描结果放入到媒体数据库中。

    2、MediaProvider(ContentProvider派生),针对媒体库进行相关操作请求,一般情况就是写,删,查,更操作。

    3、MediaScannerReceiver接收外界的扫描请求。


    三、MediaScanner注册分析

    打开MediaScnner.java可以看到

        static {
            System.loadLibrary("media_jni");
            native_init();
        }
    在这里加载了动态链接库,再调用了native_init()方法

    private static native final void native_init();
    打开android_media_MediaScanner.cpp可以看到native_init()的实现

    // This function gets a field ID, which in turn causes class initialization.
    // It is called from a static block in MediaScanner, which won't run until the
    // first time an instance of this class is used.
    static void
    android_media_MediaScanner_native_init(JNIEnv *env)
    {
        LOGV("native_init");
        jclass clazz = env->FindClass(kClassMediaScanner);
        if (clazz == NULL) {
            return;
        }
    
        fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
        if (fields.context == NULL) {
            return;
        }
    }
    上面的这种注册方式是静态注册,其实还有一种动态的注册方式

    Java native函数和JNI函数是一一对应的,所以在JNI中,是通过JNINativeMethoid结构来记录这种关系的。下面就是android_media_MediaScanner.cpp中的动态注册表。

    static 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
        },
    
        {
            "setLocale",
            "(Ljava/lang/String;)V",
            (void *)android_media_MediaScanner_setLocale
        },
    
        {
            "extractAlbumArt",
            "(Ljava/io/FileDescriptor;)[B",
            (void *)android_media_MediaScanner_extractAlbumArt
        },
    
        {
            "native_init",
            "()V",
            (void *)android_media_MediaScanner_native_init
        },
    
        {
            "native_setup",
            "()V",
            (void *)android_media_MediaScanner_native_setup
        },
    
        {
            "native_finalize",
            "()V",
            (void *)android_media_MediaScanner_native_finalize
        },
    };
    JNINativeMethod结构体如下:

    type struct{
        const char* name;
        const char* signature;
        void* fnPtr;
    }JNINativeMethod;
    第一个属性是Java中native函数的名字

    第二个属性是参数和返回类型的签名

    第三个属性是Native对应函数名字

    AndroidRunTime类提供了一个registerNativeMethods函数来完成注册工作,实现如下:

    /*
     * Register native methods using JNI.
     */
    /*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,
        const char* className, const JNINativeMethod* gMethods, int numMethods)
    {
        return jniRegisterNativeMethods(env, className, gMethods, numMethods);
    }
    jniRegisterNativeMethods是Android平台提供的一个帮助函数。

    在实际的应用中只用两个函数就可以完成动态注册工作。

    jclass clazz = (*env)->FindClass(env, className);
    (*env)->RegisterNatives(env, clazz, gMethods, numMethods);
    当Java层通过System.loadLibrary加装玩JNI动态库后,紧接着会查找该库中一个叫JNI_OnLoad的函数。如果有,就调用它,而动态注册工作就是在这里完成的。

    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("ERROR: GetEnv failed
    ");
            goto bail;
        }
        assert(env != NULL);
    
        if (register_android_media_MediaPlayer(env) < 0) {
            LOGE("ERROR: MediaPlayer native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_MediaRecorder(env) < 0) {
            LOGE("ERROR: MediaRecorder native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_MediaScanner(env) < 0) {
            LOGE("ERROR: MediaScanner native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_MediaMetadataRetriever(env) < 0) {
            LOGE("ERROR: MediaMetadataRetriever native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_AmrInputStream(env) < 0) {
            LOGE("ERROR: AmrInputStream native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_ResampleInputStream(env) < 0) {
            LOGE("ERROR: ResampleInputStream native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_MediaProfiles(env) < 0) {
            LOGE("ERROR: MediaProfiles native registration failed");
            goto bail;
        }
    
        if (register_android_mtp_MtpDatabase(env) < 0) {
            LOGE("ERROR: MtpDatabase native registration failed");
            goto bail;
        }
    
        if (register_android_mtp_MtpDevice(env) < 0) {
            LOGE("ERROR: MtpDevice native registration failed");
            goto bail;
        }
    
        if (register_android_mtp_MtpServer(env) < 0) {
            LOGE("ERROR: MtpServer native registration failed");
            goto bail;
        }
    
        /* success -- return valid version number */
        result = JNI_VERSION_1_4;
    
    bail:
        return result;
    }

  • 相关阅读:
    小师妹学JVM之:JIT中的PrintCompilation
    八张图彻底了解JDK8 GC调优秘籍-附PDF下载
    区块链系列教程之:比特币中的网络和区块链
    从印度兵力分布聊聊Mybatis中#和$的区别
    区块链系列教程之:比特币的钱包与交易
    小师妹学JVM之:JIT中的LogCompilation
    从发布-订阅模式谈谈 Flask 的 Signals
    基于 Ajax 请求的 Flask-Login 认证
    解决 openpyxl 垂直分页符和水平分页符同时添加的问题
    用 python 抓取知乎指定回答下的视频
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6468557.html
Copyright © 2011-2022 走看看