JNI原理研究

这个部分之所以放在我的博客中,因为比较难,自己的功力不见得很够,所以写起来有点天马行空。
如果其他朋友觉得有用就给个赞吧。
1,JNI调用中的JNIEnv是什么?
要回答这个问题,我们必须研究源码
在jni.cpp 中有JNIEnv* dvmCreateJNIEnv(Thread* self)函数,
这个函数的作用是什么呢?创建JNIEnv,我们来看函数实现

    JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
    newEnv->funcTable = &gNativeInterface;
    if (self != NULL) {
        dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
        assert(newEnv->envThreadId != 0);
    } else {
        /* make it obvious if we fail to initialize these later */
        newEnv->envThreadId = 0x77777775;
        newEnv->self = (Thread*) 0x77777779;
    }
    if (gDvmJni.useCheckJni) {
        dvmUseCheckedJniEnv(newEnv);
    }

    ScopedPthreadMutexLock lock(&vm->envListLock);

    /* insert at head of list */
    newEnv->next = vm->envList;
    assert(newEnv->prev == NULL);
    if (vm->envList == NULL) {
        // rare, but possible
        vm->envList = newEnv;
    } else {
        vm->envList->prev = newEnv;
    }
    vm->envList = newEnv;

a,首先我们看到newEnv->funcTable = &gNativeInterface; 他是个函数表,这个就是我们调用的JNI函数表
b,这里根据self进行了分类处理,我们看self等于NULL的情况,此时把JNIEnv的两个变量赋值了
这个和self!=NULL类似,就是把当前这个JNI的环境变量和线程关联起来
c,后面是把这个变量存放到vm的链表中去,这里我们知道,其实每个JNIEnv是和线程相关的,这个也是为什么我们在多线程操作JNI的时候,经常出现JNIEnv找不到的问题。
函数 bool dvmAttachCurrentThread(const JavaVMAttachArgs* pArgs, bool isDaemon)
的实现 调用了
self = allocThread(gDvm.stackSize);
self->jniEnv = dvmCreateJNIEnv(self);
首先创建了一个thread 对象,然后创建要给JNIENV 和这个thread绑定。

这里我们总是用到dvmThreadSelf();函数,他是根据gDvm.pthreadKeySelf查询当前线程的属性,所以dvmAttachCurrentThread就是把linux的线程和dalvik关联起来了,关于java线程,读者可以看我写的关于java线程的C++实现原理。

分享到:

发表评论

昵称

沙发空缺中,还不快抢~