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

本文详细介绍了Android虚拟机中线程的创建过程,包括通过`AndroidRuntime::start`启动虚拟机、设置线程创建函数`javaCreateThreadEtc`、`javaThreadShell`中的线程入口以及如何通过`javaAttachThread`和`javaDetachThread`进行线程的附加与分离。此外,还讨论了Android namespace中的`Thread`类以及如何创建Java线程和非Java线程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. 虚拟机的入口

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

javaThreadShell函数中

int AndroidRuntime::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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值