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

本文详细剖析了Android Runtime启动虚拟机的入口函数,重点讲解了`startReg`中线程创建的Hook过程,以及Java线程与非Java线程的区别,涉及JNI Attach/Detach、JavaVM获取和线程创建回调。

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

一. 虚拟机的入口

void AndroidRuntime::start(const char* className, const Vector& 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、付费专栏及课程。

余额充值