您的位置:首页 > 移动开发 > Android开发

Android虚拟机中线程的创建,VM, JNI线程的使用

2017-01-19 15:49 531 查看
一. 虚拟机的入口

void AndroidRuntime::start(const char* className, const Vector<String8>& options)

{

..........

    JNIEnv* env;

    if (startVm(&mJavaVM, &env) != 0) {

        return;

    }

    onVmCreated(env);

    if (startReg(env) < 0) {

        ALOGE("Unable to register all android natives\n");

        return;

    }

}

二. 设置thread中线程创建的函数

int AndroidRuntime::startReg(JNIEnv* env)

{

    /*

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

}

int AndroidRuntime::javaCreateThreadEtc(

                                android_thread_func_t entryFunction,

                                void* userData,

                                const char* threadName,

                                int32_t threadPriority,

                                size_t threadStackSize,

                                android_thread_id_t* threadId)

{

    void** args = (void**) malloc(3 * sizeof(void*));   // javaThreadShell must free

    int result;

    if (!threadName)

        threadName = "unnamed thread";

    args[0] = (void*) entryFunction;

    args[1] = userData;

    args[2] = (void*) strdup(threadName);   // javaThreadShell must free

    result = androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args,  这个函数是虚拟机中java线程的入口,在其中会调用用户指定的函数

        threadName, threadPriority, threadStackSize, threadId);

    return result;

}

int AndroidRuntime::javaThreadShell(void* args) {

    void* start = ((void**)args)[0];

    void* userData = ((void **)args)[1];

    char* name = (char*) ((void **)args)[2];        // we own this storage

    free(args);

    JNIEnv* env;

    int result;

    /* hook us into the VM */

    if (javaAttachThread(name, &env) != JNI_OK)    先把当前进程attach到java环境中

        return -1;

    /* start the thread running */

    result = (*(android_thread_func_t)start)(userData);    
执行用户指定的回调函数

    /* unhook us */

    javaDetachThread();   从java环境中detach当前进程

    free(name);

    return result;

}

static int javaAttachThread(const char* threadName, JNIEnv** pEnv)

{

    JavaVMAttachArgs args;

    JavaVM* vm;

    jint result;

    vm = AndroidRuntime::getJavaVM();  注意VM的获取方法

    assert(vm != NULL);

    args.version = JNI_VERSION_1_4;

    args.name = (char*) threadName;

    args.group = NULL;

    result = vm->AttachCurrentThread(pEnv, (void*) &args);

    if (result != JNI_OK)

        ALOGI("NOTE: attach of thread '%s' failed\n", threadName);

    return result;

}

一般JavaVM的获取方法有三种:三种方法的本质都是获取art中Runtime类中的JavaVM变量

1. vm = AndroidRuntime::getJavaVM();

2. 在JNI_OnLoad函数中,System.loadLibrary函数执行后,默认要调用这个函数;

jint JNI_OnLoad(JavaVM* vm, void* reserved) {

    JNIEnv* env = NULL;

    jint result = -1;

    if (vm->GetEnv((void**) &env,JNI_VERSION_1_4) == JNI_OK) {

        if (NULL != env && registerNativeMethods(env) == 0) {

            result = JNI_VERSION_1_4;

        }

    }

    return result;

}

3. 通过JNIEnv->GetJavaVM(JNIEnv*, JavaVM*); 函数获得,也就是在jni的环境下获得。

JNIEnv的获取方法

如果已经AttachCurrentThread了,那么可以调用AndroidRuntime::getJNIEnv方法获取当前线程的JNIEnv

JNIEnv* AndroidRuntime::getJNIEnv()

{

    JNIEnv* env;

    JavaVM* vm = AndroidRuntime::getJavaVM();

    assert(vm != NULL);

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)

        return NULL;

    return env;

}


/*

 * Detach the current thread from the set visible to the VM.

 */

static int javaDetachThread(void)

{

    JavaVM* vm;

    jint result;

    vm = AndroidRuntime::getJavaVM();

    assert(vm != NULL);

    result = vm->DetachCurrentThread();

    if (result != JNI_OK)

        ALOGE("ERROR: thread detach failed\n");

    return result;

}

三. Android namespace中的thread类

在thread中,分为java线程和非java线程,如下:

status_t Thread::run(const char* name, int32_t priority, size_t stack)

{

    bool res;

    if (mCanCallJava) { java线程,默认为java线程,用户也可以创建非java线程要节省资源

        res = createThreadEtc(_threadLoop,

                this, name, priority, stack, &mThread);

    } else {

        res = androidCreateRawThreadEtc(_threadLoop,

                this, name, priority, stack, &mThread);

    }

}

inline bool createThreadEtc(thread_func_t entryFunction,

                            void *userData,

                            const char* threadName = "android:unnamed_thread",

                            int32_t threadPriority = PRIORITY_DEFAULT,

                            size_t threadStackSize = 0,

                            thread_id_t *threadId = 0)

{

    return androidCreateThreadEtc(entryFunction, userData, threadName,

        threadPriority, threadStackSize, threadId) ? true : false;

}

int androidCreateThread(android_thread_func_t fn, void* arg)

{

    return createThreadEtc(fn, arg);

}

int androidCreateThreadGetID(android_thread_func_t fn, void *arg, android_thread_id_t *id)

{

    return createThreadEtc(fn, arg, "android:unnamed_thread",

                           PRIORITY_DEFAULT, 0, id);

}

static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;

int androidCreateThreadEtc(android_thread_func_t entryFunction,

                            void *userData,

                            const char* threadName,

                            int32_t threadPriority,

                            size_t threadStackSize,

                            android_thread_id_t *threadId)

{

    return gCreateThreadFn(entryFunction, userData, threadName,

        threadPriority, threadStackSize, threadId);

}

默认情况下,java和非java线程没有区别,但是如果在AndroidRuntime设置了gCreateThreadFn回调函数,那就不同了。

1. 非java线程,直接调用androidCreateRawThreadEtc创建。

2. java线程的创建流程。

createThreadEtc --> androidCreateThreadEtc --> gCreateThreadFn(==AndroidRuntime::javaCreateThreadEtc)

--> androidCreateRawThreadEtc --> AndroidRuntime::javaThreadShell

在[b]javaThreadShell函数中[/b]

int AndroidRuntime::[b]javaThreadShell(void*
args) {
    /* hook us into the VM */
    if (javaAttachThread(name, &env) != JNI_OK)    先把当前进程attach到java环境中
        return -1;

    /* start the thread running */
    result = (*(android_thread_func_t)start)(userData);     执行用户指定的回调函数

    javaDetachThread();   从java环境中detach当前进程
    free(name);
    return result;
}
[/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: