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]
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]
相关文章推荐
- 关于C++调用jar包,在创建虚拟机时使用JNI_CreateJavaVM调用失败返回-1的问题
- 使用线程创建的三种方法实现j2me联网(PS:我想做android!NND!)
- Android&nbsp;Jni中使用线程及回…
- Android JNI 跨线程使用JniEnv
- android中使用ndk之创建MyTestJni项目
- Android虚拟机器学习总结Dalvik虚拟机创建进程和线程分析
- Android-Jni线程(一)— 创建线程
- 在Android中使用HandlerThread创建线程
- Android使用Sensor感应器实现线程中刷新UI创建android测力计的功能
- Android虚拟机学习总结Dalvik虚拟机进程和线程的创建过程分析
- Android JNI开发(6)--JNI中使用线程
- Cocos2d-x 3.0 JNI BUG 修复。(Android 如何创建一个线程 延迟执行函数 创建一个随机数)
- linux学习笔记1:使用VM创建一台虚拟机
- 在Android中使用HandlerThread创建线程
- Qemu&KVM第三篇之使用Ubuntu-vm-builder 创建虚拟机
- Android Jni中使用线程及回调更新UI
- 在Android中使用HandlerThread创建线程
- 使用eclipse创建android虚拟机时不能使用虚拟键盘
- 在Android中使用HandlerThread创建线程
- android使用handlerthread创建线程示例