zoukankan      html  css  js  c++  java
  • Android JNI 之 JNIEnv 解析

    jni.h文件 : 了解 JNI 需要配合 jni.h 文件, jni.h 是 Google NDK 中的一个文件, 位置是 $/android-ndk-r9d/platforms/android-19/arch-arm/usr/include/jni.h ;

    1. JNIEnv 作用

    JNIEnv 概念 : 是一个线程相关的结构体, 该结构体代表了 Java 在本线程的运行环境 ;

    JNIEnv 与 JavaVM : 注意区分这两个概念;

    -- JavaVM : JavaVM 是 Java虚拟机在 JNI 层的代表, JNI 全局只有一个;

    -- JNIEnv : JavaVM 在线程中的代表, 每个线程都有一个, JNI 中可能有很多个 JNIEnv;

    JNIEnv 作用 :

    -- 调用 Java 函数 : JNIEnv 代表 Java 运行环境, 可以使用 JNIEnv 调用 Java 中的代码;

    -- 操作 Java 对象 : Java 对象传入 JNI 层就是 Jobject 对象, 需要使用 JNIEnv 来操作这个 Java 对象;

    2. JNIEnv 的创建和释放

    JNIEnv 创建 和 释放 : 从 JavaVM 获得 : 下面是 JavaVM 结构体的代码,

    -- C语言 中来源 : JNIInvokeInterface 是 C 语言环境中的 JavaVM 结构体, 调用 (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*) 方法, 可以获取 JNIEnv结构体;

    -- C++ 中来源 : _JavaVM 是 C++ 中的 JavaVM 结构体, 调用 jint AttachCurrentThread(JNIEnv** p_env, void* thr_args) 方法, 可以获取 JNIEnv 结构体;

    -- C语言 中释放 : 调用 JavaVM结构体 (JNIInvokeInterface) 中的 (*DetachCurrentThread)(JavaVM*)方法, 可以释放本线程中的 JNIEnv;

    -- C++ 中释放 : 调用 JavaVM 结构体 (_JavaVM) 中的 jint DetachCurrentThread(){ return functions->DetachCurrentThread(this); } 方法, 即可释放 本线程中的 JNIEnv ;

    /*
     * JNI invocation interface.
     */
    struct JNIInvokeInterface {
        void*       reserved0;
        void*       reserved1;
        void*       reserved2;
     
        jint        (*DestroyJavaVM)(JavaVM*);
            /* 创建 JNIEnv , 每个线程创建一个 */
        jint        (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);
            /* 释放本线程的 JNIEnv */
        jint        (*DetachCurrentThread)(JavaVM*);
        jint        (*GetEnv)(JavaVM*, void**, jint);
        jint        (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);
    };
     
    /*
     * C++ version.
     */
    struct _JavaVM {
        const struct JNIInvokeInterface* functions;
     
    #if defined(__cplusplus)
        jint DestroyJavaVM()
        { return functions->DestroyJavaVM(this); }
        /* 创建 JNIEnv , 每个线程创建一个 , 调用的C语言结构提中的方法, C 与 C++ 方法相同 */
        jint AttachCurrentThread(JNIEnv** p_env, void* thr_args)
        { return functions->AttachCurrentThread(this, p_env, thr_args); }
        /* 释放本线程的 JNIEnv , 调用的C语言结构提中的方法, C 与 C++ 方法相同 */
        jint DetachCurrentThread()
        { return functions->DetachCurrentThread(this); }
        jint GetEnv(void** env, jint version)
        { return functions->GetEnv(this, env, version); }
        jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args)
        { return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); }
    #endif /*__cplusplus*/
    };

    3. JNIEnv 体系结构

    线程相关 : JNIEnv 是线程相关的, 即 在 每个线程中 都有一个 JNIEnv 指针, 每个JNIEnv 都是线程专有的, 其它线程不能使用本线程中的 JNIEnv, 线程 A 不能调用 线程 B 的 JNIEnv;

    JNIEnv 不能跨线程 :

    -- 当前线程有效 : JNIEnv 只在当前线程有效, JNIEnv 不能在 线程之间进行传递, 在同一个线程中, 多次调用 JNI层方法, 传入的 JNIEnv 是相同的;

    -- 本地方法匹配多JNIEnv : 在 Java 层定义的本地方法, 可以在不同的线程调用, 因此 可以接受不同的 JNIEnv;

    JNIEnv 结构 : 由上面的代码可以得出, JNIEnv 是一个指针,  指向一个线程相关的结构, 线程相关结构指向 JNI 函数指针 数组, 这个数组中存放了大量的 JNI 函数指针, 这些指针指向了具体的 JNI 函数;

    4. 分析 JNIEnv 相关代码

    JNIEnv 定义的相关代码 :

    /* 声明结构体, 以便在下面能够使用 */
    struct _JNIEnv;
    struct _JavaVM;
    /* 声明 C 语言环境中的 JNIEnv 为 C_JNIEnv 指针, 指向 JNINativeInterface 结构体 */
    typedef const struct JNINativeInterface* C_JNIEnv;
     
    #if defined(__cplusplus)
    /* C++环境下, JNIEnv 是结构体 */
    typedef _JNIEnv JNIEnv;
    typedef _JavaVM JavaVM;
    #else
    /* C语言环境下, JNIEnv是指针 */
    typedef const struct JNINativeInterface* JNIEnv;
    typedef const struct JNIInvokeInterface* JavaVM;
    #endif
     

    -- JNINativeInterface 结构体 : 该结构体中定义了大量的函数指针, 这些函数指针 指向 与 Java 相关的变量有关的函数, 如果是 C 语言环境中, JNIEnv 就是指向 该结构体的指针;

    -- _JNIEnv 结构体 : C++ 环境中的 JNIEnv 就是该结构体, 该结构体中封装了 一个 JNINativeInterface 结构体指针, 即 C++ 中的 JNIEnv 要比 C 语言中的要多, 并且 完全兼容 C 语言中的 JNIEnv;

    -- _JavaVM 结构体 : 该结构体 是 Java 虚拟机 在 JNI 中的代表, 整个 JNI 层 只存在一个 该 虚拟机映射;

    JNINativeInterface 源码(删减过) : 省略后的, 其中定义了 与 Java 有关的相关方法, 都是 指向对应函数的函数指针;

    -- 解析 JNIEnv* : C语言环境中的 typedef const struct JNINativeInterface* JNIEnv , JNIEnv* env 等价于 JNINativeInterface** env1 (指向结构体地址的指针), 要想 根据 二级指针 env1 获取 JNINativeInterface 结构体中定义的函数指针, 首先获取 指向结构体的一级指针, 获取方法是 (*env1), 因此调用其中的函数指针指向的方法要这样 : (*env1)->FindClass(JNIEnv*, const char*);

    /*
     * Table of interface function pointers.
     */
    struct JNINativeInterface {
        void*       reserved0;
        void*       reserved1;
        void*       reserved2;
        void*       reserved3;
     
        jint        (*GetVersion)(JNIEnv *);
     
        ... ...
     
        jobject     (*NewDirectByteBuffer)(JNIEnv*, void*, jlong);
        void*       (*GetDirectBufferAddress)(JNIEnv*, jobject);
        jlong       (*GetDirectBufferCapacity)(JNIEnv*, jobject);
     
        /* added in JNI 1.6 */
        jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject);
    };

    _JNIEnv 源码(删减过) : 该源码中有一个 JNINativeInterface 结构体指针, 说明 C++ 环境的 JNIEnv 是在 C 语言环境的 JNIEnv 下扩展的;

    -- 解析 JNIEnv* : 定义是这样的 typedef _JNIEnv JNIEnv, JNIEnv* env 等价于 _JNIEnv* env1, 因此调用 _JNIEnv 中定义的函数指针指向的函数的时候, 只需要 使用 env1->FindClass(JNIEnv*, const char*) 即可;

    /*
     * C++ object wrapper.
     *
     * This is usually overlaid on a C struct whose first element is a
     * JNINativeInterface*.  We rely somewhat on compiler behavior.
     */
    struct _JNIEnv {
        /* do not rename this; it does not seem to be entirely opaque */
        const struct JNINativeInterface* functions;
     
    #if defined(__cplusplus)
     
        jint GetVersion()
        { return functions->GetVersion(this); }
     
        ... ... 
     
        jlong GetDirectBufferCapacity(jobject buf)
        { return functions->GetDirectBufferCapacity(this, buf); }
     
        /* added in JNI 1.6 */
        jobjectRefType GetObjectRefType(jobject obj)
        { return functions->GetObjectRefType(this, obj); }
    #endif /*__cplusplus*/
    };
     
     
     
  • 相关阅读:
    LeetCode Merge Two Sorted Lists 归并排序
    LeetCode Add Binary 两个二进制数相加
    LeetCode Climbing Stairs 爬楼梯
    034 Search for a Range 搜索范围
    033 Search in Rotated Sorted Array 搜索旋转排序数组
    032 Longest Valid Parentheses 最长有效括号
    031 Next Permutation 下一个排列
    030 Substring with Concatenation of All Words 与所有单词相关联的字串
    029 Divide Two Integers 两数相除
    028 Implement strStr() 实现 strStr()
  • 原文地址:https://www.cnblogs.com/shaweng/p/4427503.html
Copyright © 2011-2022 走看看