JNI 的调用(ongoing)

进行 JNI 开发的时候,JNI 的 native 方法第一个入参为 JNIEnv,这个 JNIEnv 实质上的JNINativeInterface*

//@jni.h
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

...
jclass FindClass(const char* name){
  return functions->FindClass(this, name);
}
...

形如CallStaticVoidMethod 的有返回值的方法,是宏定义的方法。而对于 CallStaticVoidMethod则是直接定义的。同时像GetStaticFieldID也都是再次定义。可以说这里申明了 JNI 的方法表。

#define CALL_STATIC_TYPE_METHOD(_jtype, _jname)                             \
    _jtype CallStatic##_jname##Method(jclass clazz, jmethodID methodID,     \
        ...)                                                                \
    {                                                                       \
        _jtype result;                                                      \
        va_list args;                                                       \
        va_start(args, methodID);                                           \
        result = functions->CallStatic##_jname##MethodV(this, clazz,        \
                    methodID, args);                                        \
        va_end(args);                                                       \
        return result;                                                      \
    }
#define CALL_STATIC_TYPE_METHODV(_jtype, _jname)                            \
    _jtype CallStatic##_jname##MethodV(jclass clazz, jmethodID methodID,    \
        va_list args)                                                       \
    { return functions->CallStatic##_jname##MethodV(this, clazz, methodID,  \
        args); }
#define CALL_STATIC_TYPE_METHODA(_jtype, _jname)                            \
    _jtype CallStatic##_jname##MethodA(jclass clazz, jmethodID methodID,    \
        jvalue* args)                                                       \
    { return functions->CallStatic##_jname##MethodA(this, clazz, methodID,  \
        args); }

#define CALL_STATIC_TYPE(_jtype, _jname)                                    \
    CALL_STATIC_TYPE_METHOD(_jtype, _jname)                                 \
    CALL_STATIC_TYPE_METHODV(_jtype, _jname)                                \
    CALL_STATIC_TYPE_METHODA(_jtype, _jname)

    CALL_STATIC_TYPE(jobject, Object)
    CALL_STATIC_TYPE(jboolean, Boolean)
    CALL_STATIC_TYPE(jbyte, Byte)
    CALL_STATIC_TYPE(jchar, Char)
    CALL_STATIC_TYPE(jshort, Short)
    CALL_STATIC_TYPE(jint, Int)
    CALL_STATIC_TYPE(jlong, Long)
    CALL_STATIC_TYPE(jfloat, Float)
    CALL_STATIC_TYPE(jdouble, Double)

void CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...)
    {
        va_list args;
        va_start(args, methodID);
        functions->CallStaticVoidMethodV(this, clazz, methodID, args);
        va_end(args);
    }
    void CallStaticVoidMethodV(jclass clazz, jmethodID methodID, va_list args)
    { functions->CallStaticVoidMethodV(this, clazz, methodID, args); }
    void CallStaticVoidMethodA(jclass clazz, jmethodID methodID, jvalue* args)
    { functions->CallStaticVoidMethodA(this, clazz, methodID, args); }

从上面也能看到, CallStatic##_jname##Method会调用CallStatic##_jname##MethodV。
同时这些方法都会转调到 functions 的同名方法。各同名方法指针在

@Jni.cpp
static const struct JNINativeInterface gNativeInterface

其中的 CallStaticVoidMethodV也都是宏定义函数
@Jni.cpp

/*
 * Call a static method.
 */
#define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref)               \
    static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz,    \
        jmethodID methodID, ...)                                            \
    {                                                                       \
        UNUSED_PARAMETER(jclazz);                                           \
        ScopedJniThreadState ts(env);                                       \
        JValue result;                                                      \
        va_list args;                                                       \
        va_start(args, methodID);                                           \
        dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
        va_end(args);                                                       \
        if (_isref && !dvmCheckException(ts.self()))                        \
            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
        return _retok;                                                      \
    }                                                                       \
    static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz,   \
        jmethodID methodID, va_list args)                                   \
    {                                                                       \
        UNUSED_PARAMETER(jclazz);                                           \
        ScopedJniThreadState ts(env);                                       \
        JValue result;                                                      \
        dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
        if (_isref && !dvmCheckException(ts.self()))                        \
            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
        return _retok;                                                      \
    }                                                                       \
    static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz,   \
        jmethodID methodID, jvalue* args)                                   \
    {                                                                       \
        UNUSED_PARAMETER(jclazz);                                           \
        ScopedJniThreadState ts(env);                                       \
        JValue result;                                                      \
        dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\
        if (_isref && !dvmCheckException(ts.self()))                        \
            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
        return _retok;                                                      \
    }
CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true);
CALL_STATIC(jboolean, Boolean, 0, result.z, false);
CALL_STATIC(jbyte, Byte, 0, result.b, false);
CALL_STATIC(jchar, Char, 0, result.c, false);
CALL_STATIC(jshort, Short, 0, result.s, false);
CALL_STATIC(jint, Int, 0, result.i, false);
CALL_STATIC(jlong, Long, 0, result.j, false);
CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
CALL_STATIC(jdouble, Double, 0.0, result.d, false);
CALL_STATIC(void, Void, , , false);

宏替换

static void CallStaticVoidMethod(JNIEnv* env, jclass jclazz,    \
        jmethodID methodID, ...)                                            \
    {                                                                       \
        UNUSED_PARAMETER(jclazz);                                           \
        ScopedJniThreadState ts(env);                                       \
        JValue result;                                                      \
        va_list args;                                                       \
        va_start(args, methodID);                                           \
        dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
        va_end(args);                                                       \
        if (false && !dvmCheckException(ts.self()))                        \
            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
        return _retok;                                                      \
    }                                                                       \
    static void CallStaticVoidMethodV(JNIEnv* env, jclass jclazz,   \
        jmethodID methodID, va_list args)                                   \
    {                                                                       \
        UNUSED_PARAMETER(jclazz);                                           \
        ScopedJniThreadState ts(env);                                       \
        JValue result;                                                      \
        dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
        if (false && !dvmCheckException(ts.self()))                        \
            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
        return _retok;                                                      \
    }                                                                       \
    static void CallStaticVoidMethodA(JNIEnv* env, jclass jclazz,   \
        jmethodID methodID, jvalue* args)                                   \
    {                                                                       \
        UNUSED_PARAMETER(jclazz);                                           \
        ScopedJniThreadState ts(env);                                       \
        JValue result;                                                      \
        dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\
        if (false && !dvmCheckException(ts.self()))                        \
            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
        return _retok;                                                      \
    }

于是找到了实际调用点 dvmCallMethodV( );该方法定义在 Stack.h,实现于 Stack.cpp

/*
 * Issue a method call with a variable number of arguments.  We process
 * the contents of "args" by scanning the method signature.
 *
 * Pass in NULL for "obj" on calls to static methods.
 *
 * We don't need to take the class as an argument because, in Dalvik,
 * we don't need to worry about static synchronized methods.
 */
void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
    bool fromJni, JValue* pResult, va_list args)
{
    const char* desc = &(method->shorty[1]); // [0] is the return type.
    int verifyCount = 0;
    ClassObject* clazz;
    u4* ins;

    clazz = callPrep(self, method, obj, false);
    if (clazz == NULL)
        return;

    /* "ins" for new frame start at frame pointer plus locals */
    ins = ((u4*)self->interpSave.curFrame) +
           (method->registersSize - method->insSize);

    //LOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);

    /* put "this" pointer into in0 if appropriate */
    if (!dvmIsStaticMethod(method)) {
#ifdef WITH_EXTRA_OBJECT_VALIDATION
        assert(obj != NULL && dvmIsHeapAddress(obj));
#endif
        *ins++ = (u4) obj;
        verifyCount++;
    }

    while (*desc != '\0') {
        switch (*(desc++)) {
            case 'D': case 'J': {
                u8 val = va_arg(args, u8);
                memcpy(ins, &val, 8);       // EABI prevents direct store
                ins += 2;
                verifyCount += 2;
                break;
            }
            case 'F': {
                /* floats were normalized to doubles; convert back */
                float f = (float) va_arg(args, double);
                *ins++ = dvmFloatToU4(f);
                verifyCount++;
                break;
            }
            case 'L': {     /* 'shorty' descr uses L for all refs, incl array */
                void* arg = va_arg(args, void*);
                assert(obj == NULL || dvmIsHeapAddress(obj));
                jobject argObj = reinterpret_cast(arg);
                if (fromJni)
                    *ins++ = (u4) dvmDecodeIndirectRef(self, argObj);
                else
                    *ins++ = (u4) argObj;
                verifyCount++;
                break;
            }
            default: {
                /* Z B C S I -- all passed as 32-bit integers */
                *ins++ = va_arg(args, u4);
                verifyCount++;
                break;
            }
        }
    }

#ifndef NDEBUG
    if (verifyCount != method->insSize) {
        LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
            method->insSize, clazz->descriptor, method->name);
        assert(false);
        goto bail;
    }
#endif

    //dvmDumpThreadStack(dvmThreadSelf());

    if (dvmIsNativeMethod(method)) {
        TRACE_METHOD_ENTER(self, method);
        /*
         * Because we leave no space for local variables, "curFrame" points
         * directly at the method arguments.
         */
        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
                              method, self);
        TRACE_METHOD_EXIT(self, method);
    } else {
        dvmInterpret(self, method, pResult);
    }

#ifndef NDEBUG
bail:
#endif
    dvmPopFrame(self);
}

你可能感兴趣的:(JNI 的调用(ongoing))