美文网首页
Android Framework源码中JNI方法注册流程

Android Framework源码中JNI方法注册流程

作者: professorHe | 来源:发表于2017-08-15 15:02 被阅读0次

    Android Zygote进程启动(一) 文章中提到在AndroidRuntime.cpp 中提到 AndroidRuntime::start() 函数主要做的三件事:1.启动java虚拟机、2.注册jni方法 3.调用zygote的main方法。今天就来AndroidFramework中是如何注册JNI方法的。

    /*
     * Register android native functions with the VM.
     */
    /*static*/ int AndroidRuntime::startReg(JNIEnv* env)
    {
        ATRACE_NAME("RegisterAndroidNatives");
        /*
         * This hook causes all future threads created in this process to be
         * attached to the JavaVM.  (This needs to go away in favor of JNI
         * Attach calls.)
         */
        androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
    
        ALOGV("--- registering native functions ---\n");
    
        /*
         * Every "register" function calls one or more things that return
         * a local reference (e.g. FindClass).  Because we haven't really
         * started the VM yet, they're all getting stored in the base frame
         * and never released.  Use Push/Pop to manage the storage.
         */
        env->PushLocalFrame(200);
    
        if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
            env->PopLocalFrame(NULL);
            return -1;
        }
        env->PopLocalFrame(NULL);
    
        //createJavaThread("fubar", quickTest, (void*) "hello");
    
        return 0;
    }
    

    方法中首先设置了线程创建方法为javaCreateThreadEtc ,然后通过register_jni_procs注册了jni的方法。

    register_jni_procs 函数参数RegJNIRec是预先定义的一个宏:

    #ifdef NDEBUG
        #define REG_JNI(name)      { name }
        struct RegJNIRec {
            int (*mProc)(JNIEnv*);
        };
    #else
        #define REG_JNI(name)      { name, #name }
        struct RegJNIRec {
            int (*mProc)(JNIEnv*);
            const char* mName;
        };
    #endif
    

    从代码上看可以看出来RegJNIRec 是一个结构体,里面包含了一个名字叫mProc接收参数为JNIEnv指针返回值为int的函数指针。

    static const RegJNIRec gRegJNI[] = {
        REG_JNI(register_com_android_internal_os_RuntimeInit),
        REG_JNI(register_android_os_SystemClock),
        REG_JNI(register_android_util_EventLog),
        ····
    }
    

    register_jni_procs 函数循环调用RegJNIRec数组中的mProc方法进行jni方法的注册。

    static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
    {
        for (size_t i = 0; i < count; i++) {
            if (array[i].mProc(env) < 0) {
    #ifndef NDEBUG
                ALOGD("----------!!! %s failed to load\n", array[i].mName);
    #endif
                return -1;
            }
        }
        return 0;
    }
    

    这里用register_android_content_AssetManager 这个方法的注册来分析注册过程。首先register_android_content_AssetManager方法的声明的之处位于命名空间android之下,代码如下:

    namespace android {
    
    /*
     * JNI-based registration functions.  Note these are properly contained in
     * namespace android.
     */
    extern int register_android_app_admin_SecurityLog(JNIEnv* env);
    extern int register_android_content_AssetManager(JNIEnv* env);
    
    

    而相应的实现操作写在android_util_AssetManager.cpp 文件中

    int register_android_content_AssetManager(JNIEnv* env)
    {
           ......
           return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
                                    NELEM(gAssetManagerMethods));
    }
    

    gAssetManagerMethods是一个当前需要注册的jni的方法列表:

    static const JNINativeMethod gAssetManagerMethods[] = {
        /* name, signature, funcPtr */
    
        // Basic asset stuff.
        { "openAsset",      "(Ljava/lang/String;I)J",
            (void*) android_content_AssetManager_openAsset },
        { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
            (void*) android_content_AssetManager_openAssetFd },
        { "openNonAssetNative", "(ILjava/lang/String;I)J",
            (void*) android_content_AssetManager_openNonAssetNative },
        { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
            (void*) android_content_AssetManager_openNonAssetFdNative },
        { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
            (void*) android_content_AssetManager_list },
        { "destroyAsset",   "(J)V",
            (void*) android_content_AssetManager_destroyAsset },
        { "readAssetChar",  "(J)I",
            (void*) android_content_AssetManager_readAssetChar },
        { "readAsset",      "(J[BII)I",
            (void*) android_content_AssetManager_readAsset },
        { "seekAsset",      "(JJI)J",
            (void*) android_content_AssetManager_seekAsset },
        { "getAssetLength", "!(J)J",
            (void*) android_content_AssetManager_getAssetLength },
        { "getAssetRemainingLength", "!(J)J",
            (void*) android_content_AssetManager_getAssetRemainingLength },
        { "addAssetPathNative", "(Ljava/lang/String;Z)I",
            (void*) android_content_AssetManager_addAssetPath },
        { "addOverlayPathNative",   "(Ljava/lang/String;)I",
            (void*) android_content_AssetManager_addOverlayPath },
        { "isUpToDate",     "()Z",
            (void*) android_content_AssetManager_isUpToDate },
    
        // Resources.
        { "getLocales",      "()[Ljava/lang/String;",
            (void*) android_content_AssetManager_getLocales },
        { "getNonSystemLocales", "()[Ljava/lang/String;",
            (void*) android_content_AssetManager_getNonSystemLocales },
        { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
            (void*) android_content_AssetManager_getSizeConfigurations },
        { "setConfiguration", "!(IILjava/lang/String;IIIIIIIIIIIIII)V",
            (void*) android_content_AssetManager_setConfiguration },
        { "getResourceIdentifier","!(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
            (void*) android_content_AssetManager_getResourceIdentifier },
        { "getResourceName","!(I)Ljava/lang/String;",
            (void*) android_content_AssetManager_getResourceName },
        { "getResourcePackageName","!(I)Ljava/lang/String;",
            (void*) android_content_AssetManager_getResourcePackageName },
        { "getResourceTypeName","!(I)Ljava/lang/String;",
            (void*) android_content_AssetManager_getResourceTypeName },
        { "getResourceEntryName","!(I)Ljava/lang/String;",
            (void*) android_content_AssetManager_getResourceEntryName },
        { "loadResourceValue","!(ISLandroid/util/TypedValue;Z)I",
            (void*) android_content_AssetManager_loadResourceValue },
        { "loadResourceBagValue","!(IILandroid/util/TypedValue;Z)I",
            (void*) android_content_AssetManager_loadResourceBagValue },
        { "getStringBlockCount","!()I",
            (void*) android_content_AssetManager_getStringBlockCount },
        { "getNativeStringBlock","!(I)J",
            (void*) android_content_AssetManager_getNativeStringBlock },
        { "getCookieName","(I)Ljava/lang/String;",
            (void*) android_content_AssetManager_getCookieName },
        { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
            (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
    
        // Themes.
        { "newTheme", "()J",
            (void*) android_content_AssetManager_newTheme },
        { "deleteTheme", "(J)V",
            (void*) android_content_AssetManager_deleteTheme },
        { "applyThemeStyle", "(JIZ)V",
            (void*) android_content_AssetManager_applyThemeStyle },
        { "copyTheme", "(JJ)V",
            (void*) android_content_AssetManager_copyTheme },
        { "clearTheme", "(J)V",
            (void*) android_content_AssetManager_clearTheme },
        { "loadThemeAttributeValue", "!(JILandroid/util/TypedValue;Z)I",
            (void*) android_content_AssetManager_loadThemeAttributeValue },
        { "getThemeChangingConfigurations", "!(J)I",
            (void*) android_content_AssetManager_getThemeChangingConfigurations },
        { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
            (void*) android_content_AssetManager_dumpTheme },
        { "applyStyle","!(JIIJ[I[I[I)Z",
            (void*) android_content_AssetManager_applyStyle },
        { "resolveAttrs","!(JII[I[I[I[I)Z",
            (void*) android_content_AssetManager_resolveAttrs },
        { "retrieveAttributes","!(J[I[I[I)Z",
            (void*) android_content_AssetManager_retrieveAttributes },
        { "getArraySize","!(I)I",
            (void*) android_content_AssetManager_getArraySize },
        { "retrieveArray","!(I[I)I",
            (void*) android_content_AssetManager_retrieveArray },
    
        // XML files.
        { "openXmlAssetNative", "(ILjava/lang/String;)J",
            (void*) android_content_AssetManager_openXmlAssetNative },
    
        // Arrays.
        { "getArrayStringResource","(I)[Ljava/lang/String;",
            (void*) android_content_AssetManager_getArrayStringResource },
        { "getArrayStringInfo","!(I)[I",
            (void*) android_content_AssetManager_getArrayStringInfo },
        { "getArrayIntResource","!(I)[I",
            (void*) android_content_AssetManager_getArrayIntResource },
        { "getStyleAttributes","!(I)[I",
            (void*) android_content_AssetManager_getStyleAttributes },
    
        // Bookkeeping.
        { "init",           "(Z)V",
            (void*) android_content_AssetManager_init },
        { "destroy",        "()V",
            (void*) android_content_AssetManager_destroy },
        { "getGlobalAssetCount", "()I",
            (void*) android_content_AssetManager_getGlobalAssetCount },
        { "getAssetAllocations", "()Ljava/lang/String;",
            (void*) android_content_AssetManager_getAssetAllocations },
        { "getGlobalAssetManagerCount", "()I",
            (void*) android_content_AssetManager_getGlobalAssetManagerCount },
    };
    

    这里Andoird 中使用了一种不同传统JNI的方式来定义其native的函数。其中很重要的区别是Andorid使用了一种 Java和 C 函数的映射表数组,并在其中描述了函数的参数和返回值。这个数组的类型是JNINativeMethod,定义在jni.h的头文件中如下:

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

    第一个变量name是Java中函数的名字。
    第二个变量signature,用字符串是描述了函数的参数和返回值
    第三个变量fnPtr是函数指针,指向C函数。
    其中比较难以理解的是第二个参数,例如
    "()V"
    "(II)V"
    "(Ljava/lang/String;Ljava/lang/String;)V"
    实际上这些字符是与函数的参数类型一一对应的。
    "()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();
    "(II)V" 表示 void Func(int, int);
    具体的每一个字符的对应关系如下
    字符 Java类型 C类型
    V void void
    Z jboolean boolean
    I jint int
    J jlong long
    D jdouble double
    F jfloat float
    B jbyte byte
    C jchar char
    S jshort short
    数组则以"["开始,用两个字符表示
    [I jintArray int[]
    [F jfloatArray float[]
    [B jbyteArray byte[]
    [C jcharArray char[]
    [S jshortArray short[]
    [D jdoubleArray double[]
    [J jlongArray long[]
    [Z jbooleanArray boolean[]
    上面的都是基本类型。如果Java函数的参数是class,则以"L"开头,以";"结尾中间是用"/" 隔开的包及类名。而其对应的C函数名的参数则为jobject. 一个例外是String类,其对应的类为jstring
    Ljava/lang/String; String jstring
    Ljava/net/Socket; Socket jobject
    如果JAVA函数位于一个嵌入类,则用$作为类名间的分隔符。

    RegisterMethodsOrDie方法的实现:

    static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className,
                                           const JNINativeMethod* gMethods, int numMethods) {
        int res = AndroidRuntime::registerNativeMethods(env, className, gMethods, numMethods);
        LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
        return res;
    }
    

    可以看出,最终是将所有jni的native进行注册。
    至此Android Framework 中JNI注册方法的流程就彻底完成了。

    相关文章

      网友评论

          本文标题:Android Framework源码中JNI方法注册流程

          本文链接:https://www.haomeiwen.com/subject/mexurxtx.html