JNI基础 了解jni.h

    在知道了如何创建一个包含有jni的Android的工程后,现在就需要进一步的了解其原理,不仅要知其然,还要知其所以然。话虽这么说,其实我对这块内容也是刚刚入门,因此这个仅仅作为我的一个笔记,如果其中内容有误,还希望大家指正。

    之前刚刚接触jni的时候,在网络上看了不少东西,基本是网上的各种demo代码都有两种写法,比如说jni回调常用到的函数FindClass,网上肯定能找到两种调用方法:

(*env)->FindClass(env, "xxx/xxxx/xxxx");

env->FindClass("xxx/xxxx/xxxx");

些文章由于直接贴上了代码,但是在编译时可能就会出错。为什么会这样??写过C/C++代码童鞋可能一眼就能看出其中的原因,但是没有相关经验的人可能就会有些迷糊了。

    其实所有的原因都在jni.h中,这里以\android-ndk-r8b\platforms\android-14\arch-arm\usr\include\jni.h来深入。

我们自己实现jni代码中都会包含jni.h,该头文件中定义所有和JNI相关的类型和接口。

首先基本数据类型定义

# include <inttypes.h>      /* C99 */
typedef uint8_t         jboolean;       /* unsigned 8 bits */
typedef int8_t          jbyte;          /* signed 8 bits */
typedef uint16_t        jchar;          /* unsigned 16 bits */
typedef int16_t         jshort;         /* signed 16 bits */
typedef int32_t         jint;           /* signed 32 bits */
typedef int64_t         jlong;          /* signed 64 bits */
typedef float           jfloat;         /* 32-bit IEEE 754 */
typedef double          jdouble;        /* 64-bit IEEE 754 */
#else
typedef unsigned char   jboolean;       /* unsigned 8 bits */
typedef signed char     jbyte;          /* signed 8 bits */
typedef unsigned short  jchar;          /* unsigned 16 bits */
typedef short           jshort;         /* signed 16 bits */
typedef int             jint;           /* signed 32 bits */
typedef long long       jlong;          /* signed 64 bits */
typedef float           jfloat;         /* 32-bit IEEE 754 */
typedef double          jdouble;        /* 64-bit IEEE 754 */
#endif

/* "cardinal indices and sizes" */
typedef jint            jsize;

知道这个的话,在读jni相关代码的时,就可以无视那个”j“了。

#ifdef __cplusplus
/*
 * Reference types, in C++
 */
class _jobject {};
class _jclass : public _jobject {};
class _jstring : public _jobject {};
class _jarray : public _jobject {};
class _jobjectArray : public _jarray {};
class _jbooleanArray : public _jarray {};
class _jbyteArray : public _jarray {};
class _jcharArray : public _jarray {};
class _jshortArray : public _jarray {};
class _jintArray : public _jarray {};
class _jlongArray : public _jarray {};
class _jfloatArray : public _jarray {};
class _jdoubleArray : public _jarray {};
class _jthrowable : public _jobject {};

typedef _jobject*       jobject;
typedef _jclass*        jclass;
typedef _jstring*       jstring;
typedef _jarray*        jarray;
typedef _jobjectArray*  jobjectArray;
typedef _jbooleanArray* jbooleanArray;
typedef _jbyteArray*    jbyteArray;
typedef _jcharArray*    jcharArray;
typedef _jshortArray*   jshortArray;
typedef _jintArray*     jintArray;
typedef _jlongArray*    jlongArray;
typedef _jfloatArray*   jfloatArray;
typedef _jdoubleArray*  jdoubleArray;
typedef _jthrowable*    jthrowable;
typedef _jobject*       jweak;


#else /* not __cplusplus */

/*
 * Reference types, in C.
 */
typedef void*           jobject;
typedef jobject         jclass;
typedef jobject         jstring;
typedef jobject         jarray;
typedef jarray          jobjectArray;
typedef jarray          jbooleanArray;
typedef jarray          jbyteArray;
typedef jarray          jcharArray;
typedef jarray          jshortArray;
typedef jarray          jintArray;
typedef jarray          jlongArray;
typedef jarray          jfloatArray;
typedef jarray          jdoubleArray;
typedef jobject         jthrowable;
typedef jobject         jweak;

#endif /* not __cplusplus */

这里是一些常见的数据结构的定义,可以看出这里预处理命令”#ifdef __cplusplus“,如果jni是C++实现的话,相关变量其实是一些class的指针;在C里面则更加简单,全部都是”void*“的typedef。

再下面是其他的数据结构的定义,在jni编程中最重要也是最常见的类型 JNIEnv,其定义为:

struct _JNIEnv;
struct _JavaVM;
typedef const struct JNINativeInterface* C_JNIEnv;

#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif  

struct JNINativeInterface {
    void*       reserved0;
    void*       reserved1;
    void*       reserved2;
    void*       reserved3;

    jint        (*GetVersion)(JNIEnv *);

    jclass      (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,
                        jsize);
    jclass      (*FindClass)(JNIEnv*, const char*);// 省略}

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); }

    jclass DefineClass(const char *name, jobject loader, const jbyte* buf,
        jsize bufLen)
    { return functions->DefineClass(this, name, loader, buf, bufLen); }

    jclass FindClass(const char* name)
    { return functions->FindClass(this, name); }
    // 省略多个函数...
}


从上面三个代码段可以看出无论是C或者C++中的定义的核心都是JNINativeInterface,该结构体中保存了4个值,具体内容是什么,我现在也不清楚,但可以肯定和当前调用的线程有关系。JNINativeInterface中其他都是函数的指针。

可以看出在C中JNIEnv其实就是JNINativeInterface*,于是函数的参数JNIEnv *env 其实就是JNINativeInterface**,代码(*env)->FindClass(env, "xxx/xxxx/xxxx")就不难理解了:*env得到JNINativeInterface结构体的地址,然后->FindClass找到具体函数的地址,然后执行相关代码。.

在C++中JNIEnv则是_JNIEnv结构,其实就是一个类,该类有一个成员变量JNINativeInterface* functions;其他的方法仔细看的话其实就是对JNINativeInterface结构中相关方法的一个简单封装而已。于是我们知道JNIEnv *env在C++中表示类_JNIEnv的一个指针,env->FindClass("xxx/xxxx/xxxx");则是类对方法调用的方式。

同理JavaVM在jni.h中定义和JNIEnv 差不多。

JNI中比较重要的两个函数也是在jni.h中声明的:

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved);
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved);


尤其是JNI_OnLoad函数,如果没有实现该函数,那么在load相关so库时会有提示JNI_Onload not found

嗯,感觉写了半天也没什么重点,算了,目前先写这么多,日后有进展再更新。



你可能感兴趣的:(android,jni)