copy from : http://gityuan.com/2016/09/24/android-thread/
基于AndroID 6.0源码剖析,分析AndroID线程的创建过程
/androID/libcore/libart/src/main/java/java/lang/Thread.java/art/runtime/native/java_lang_Thread.cc/art/runtime/native/java_lang_Object.cc/art/runtime/thread.cc/system/core/libutils/Threads.cpp/system/core/include/utils/AndroIDThreads.h/frameworks/base/core/jni/AndroIDRuntime.cpp
一.概述AndroID平台上的Java线程,就是AndroID虚拟机线程,而虚拟机线程由是通过系统调用而创建的linux线程。纯粹的linux线程与虚拟机线程的区别在于虚拟机线程具有运行Java代码的Runtime. 除了虚拟机线程,还有Native线程,对于Native线程有分为是否具有访问Java代码的两类线程。接下来,本文分析介绍这3类线程的创建过程。
二. Java线程2.1 Thread.start[-> Thread.java]
public synchronized voID start() { checkNotStarted(); //保证线程只有启动一次 hasBeenStarted = true; //[见流程2.2] nativeCreate(this, stackSize, daemon);}
nativeCreate
()这是一个native方法,那么其所对应的JNI方法在哪呢?在java_lang_Thread.cc中通过gMethods是一个JNINativeMethod数组,其中一项为:
NATIVE_METHOD(Thread, nativeCreate, "(Ljava/lang/Thread;JZ)V"),
这里的NATIVE_METHOD定义在java_lang_Object.cc文件,如下:
#define NATIVE_METHOD(classname, functionname, signature) \ { #functionname, signature, reinterpret_cast<voID*>(classname ## _ ## functionname) }
将宏定义展开并代入,可得所对应的方法名为Thread_nativeCreate
,那么接下来进入该方法。
[-> java_lang_Thread.cc]
static voID Thread_nativeCreate(jnienv* env, jclass, jobject java_thread, jlong stack_size, jboolean daemon) { //【见小节2.3】 Thread::CreateNativeThread(env, java_thread, stack_size, daemon == JNI_TRUE);}
2.3 CreateNativeThread[-> thread.cc]
voID Thread::CreateNativeThread(jnienv* env, jobject java_peer, size_t stack_size, bool is_daemon) { Thread* self = static_cast<jnienvExt*>(env)->self; Runtime* runtime = Runtime::Current(); ... Thread* child_thread = new Thread(is_daemon); child_thread->tlsPtr_.jpeer = env->NewGlobalRef(java_peer); stack_size = FixStackSize(stack_size); env->SetLongFIEld(java_peer, WellKNownClasses::java_lang_Thread_nativePeer, reinterpret_cast<jlong>(child_thread)); std::unique_ptr<jnienvExt> child_jni_env_ext( jnienvExt::Create(child_thread, Runtime::Current()->GetJavaVM())); int pthread_create_result = 0; if (child_jni_env_ext.get() != nullptr) { pthread_t new_pthread; pthread_attr_t attr; child_thread->tlsPtr_.tmp_jni_env = child_jni_env_ext.get(); //创建线程【见小节2.4】 pthread_create_result = pthread_create(&new_pthread, &attr, Thread::CreateCallback, child_thread); if (pthread_create_result == 0) { child_jni_env_ext.release(); return; } } ...}
2.4 pthread_createpthread_create是pthread库中的函数,通过syscall再调用到clone来请求内核创建线程,该方法头文件:#include ,其原型如下:
int pthread_create((pthread_t *thread, pthread_attr_t *attr, voID *(*start_routine)(voID *), voID *arg)
说明:
输入参数:thread:线程标识符;attr:线程属性设置;start_routine:线程函数的起始地址;arg:传递给start_routine的参数;返回值:成功则返回0;出错则返回-1。功能:创建线程,并调用线程起始地址所指向的函数start_routine。更多关于pthread_create分析,见Linux进程创建
三. Native线程(C/C++)3.1 Thread.run[-> Threads.cpp]
status_t Thread::run(const char* name, int32_t priority, size_t stack){ Mutex::autolock _l(mlock); //保证只会启动一次 if (mRunning) { return INVALID_OPERATION; } ... mRunning = true; bool res; if (mCanCallJava) { //还能调用Java代码的Native线程【见小节4.1】 res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } else { //只能调用C/C++代码的Native线程【见小节3.2】 res = androIDCreaterawThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } if (res == false) { ...//清理 return UNKNowN_ERROR; } return NO_ERROR;}
mCanCallJava在Thread对象创建时,在构造函数中默认设置mCanCallJava=true.
当mCanCallJava=true,则代表是不仅能调用C/C++代码,还能调用Java代码的Native线程;当mCanCallJava=false,则代表是只能调用C/C++代码的Native线程。3.2 androIDCreaterawThreadEtc[-> Threads.cpp]
int androIDCreaterawThreadEtc(androID_thread_func_t entryFunction, voID *userData, const char* threadname __androID_unused, int32_t threadPriority, size_t threadStackSize, androID_thread_ID_t *threadID) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (threadPriority != PRIORITY_DEFAulT || threadname != NulL) { thread_data_t* t = new thread_data_t; t->priority = threadPriority; t->threadname = threadname ? strdup(threadname) : NulL; t->entryFunction = entryFunction; t->userData = userData; entryFunction = (androID_thread_func_t)&thread_data_t::trampoline; userData = t; } if (threadStackSize) { pthread_attr_setstacksize(&attr, threadStackSize); } errno = 0; pthread_t thread; //通过pthread_create创建线程 int result = pthread_create(&thread, &attr, (androID_pthread_entry)entryFunction, userData); pthread_attr_destroy(&attr); if (result != 0) { ... //创建失败,则返回 return 0; } if (threadID != NulL) { *threadID = (androID_thread_ID_t)thread; } return 1;}
此处entryFunction所指向的是由[小节3.1]传递进来的,其值为_threadLoop。
3.3 _threadLoop[-> Threads.cpp]
int Thread::_threadLoop(voID* user){ //user是指Thread对象 Thread* const self = static_cast<Thread*>(user); sp<Thread> strong(self->mHoldSelf); wp<Thread> weak(strong); self->mHoldSelf.clear(); //该参数对于gdb调试很有作用 self->mTID = gettID(); bool first = true; do { bool result; if (first) { first = false; //首次运行时会调用readyToRun()做一些初始化准备工作 self->mStatus = self->readyToRun(); result = (self->mStatus == NO_ERROR); if (result && !self->exitPending()) { result = self->threadLoop(); } } else { result = self->threadLoop(); } { Mutex::autolock _l(self->mlock); if (result == false || self->mExitPending) { self->mExitPending = true; self->mRunning = false; self->mThread = thread_ID_t(-1); self->mThreadExitedCondition.broadcast(); break; } } strong.clear(); //释放强引用 strong = weak.promote(); //重新请求强引用,用于下一次的循环 } while(strong != 0); return 0;}
不断循环地调用成员方法threadLoop()。当满足以下任一条件,则该线程将退出循环:
当前线程状态存在错误,即mStatus != NO_ERROR;当前线程即将退出, 即mExitPending = true; 调用Thread::requestExit()可触发该过程。当前线程的强引用释放后,无法将弱引用提升成强引用的情况。对于Native线程的实现方法,往往是通过继承Thread对象,通过覆写父类的readyToRun()和threadLoop()完成自定义线程的功能。
四. Native线程(Java)4.1 createThreadEtc[-> AndroIDThreads.h]
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){ //【见小节4.2】 return androIDCreateThreadEtc(entryFunction, userData, threadname, threadPriority, threadStackSize, threadID) ? true : false;}
@H_502_148@4.2 androIDCreateThreadEtc[-> Threads.cpp]
int androIDCreateThreadEtc(androID_thread_func_t entryFunction, voID *userData, const char* threadname, int32_t threadPriority, size_t threadStackSize, androID_thread_ID_t *threadID) { //【见小节4.3】 return gCreateThreadFn(entryFunction, userData, threadname, threadPriority, threadStackSize, threadID);}
此处gCreateThreadFn
默认指向androIDCreaterawThreadEtc函数。 文章Android系统启动-zygote篇的小节[3.3.1]已介绍 通过androIDSetCreateThreadFunc()方法,gCreateThreadFn指向javaCreateThreadEtc函数。
[-> AndroIDRuntime.cpp]
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*)); int result; if (!threadname) threadname = "unnamed thread"; args[0] = (voID*) entryFunction; args[1] = userData; args[2] = (voID*) strdup(threadname); //【见小节4.4】 result = androIDCreaterawThreadEtc(AndroIDRuntime::javaThreadShell, args, threadname, threadPriority, threadStackSize, threadID); return result;}
4.4 androIDCreaterawThreadEtc[-> Threads.cpp]
int androIDCreaterawThreadEtc(androID_thread_func_t entryFunction, voID *userData, const char* threadname __androID_unused, int32_t threadPriority, size_t threadStackSize, androID_thread_ID_t *threadID) { ... if (threadStackSize) { pthread_attr_setstacksize(&attr, threadStackSize); } ... //通过pthread_create创建线程 int result = pthread_create(&thread, &attr, (androID_pthread_entry)entryFunction, userData); pthread_attr_destroy(&attr); ... return 1;}
此处entryFunction所指向的是由[小节4.3]传递进来的AndroIDRuntime::javaThreadShell,接下来,进入该方法。
4.5 javaThreadShell[-> AndroIDRuntime.cpp]
int AndroIDRuntime::javaThreadShell(voID* args) { voID* start = ((voID**)args)[0]; //指向_threadLoop voID* userData = ((voID **)args)[1]; //线程对象 char* name = (char*) ((voID **)args)[2]; //线程名 free(args); jnienv* env; int result; //hook虚拟机【见小节4.5.1】 if (javaAttachThread(name, &env) != JNI_OK) return -1; // 调用_threadLoop()方法见小节4.5.2】 result = (*(androID_thread_func_t)start)(userData); //unhook虚拟机见小节4.5.3】 javaDetachThread(); free(name); return result;}
该方法主要功能:
调用javaAttachThread():将当前线程hook到当前进程所在的虚拟机,从而既能执行C/C++代码,也能执行Java代码。调用_threadLoop():执行当前线程的核心逻辑代码;调用javaDetachThread():到此说明线程_threadLoop方法执行完成,则从当前进程的虚拟机中移除该线程。4.5.1 javaAttachThread[-> AndroIDRuntime.cpp]
static int javaAttachThread(const char* threadname, jnienv** pEnv){ JavaVMAttachArgs args; JavaVM* vm; jint result; vm = AndroIDRuntime::getJavaVM(); args.version = JNI_VERSION_1_4; args.name = (char*) threadname; args.group = NulL; // 将当前线程hook到当前进程所在的虚拟机 result = vm->AttachCurrentThread(pEnv, (voID*) &args); return result;}
4.5.2 _threadLoop[-> Threads.cpp]
int Thread::_threadLoop(voID* user){ ... do { if (first) { ... self->mStatus = self->readyToRun(); result = (self->mStatus == NO_ERROR); if (result && !self->exitPending()) { result = self->threadLoop(); } } else { result = self->threadLoop(); } Mutex::autolock _l(self->mlock); //当result=false则退出该线程 if (result == false || self->mExitPending) { self->mExitPending = true; self->mRunning = false; self->mThread = thread_ID_t(-1); self->mThreadExitedCondition.broadcast(); break; } } //释放强引用,让线程有机会退出 strong.clear(); //再次获取强引用,用于下一轮循环 strong = weak.promote(); } while(strong != 0); return 0;}
该过程与【小节3.3】完全一致,见上文。
4.5.3 javaDetachThread[-> AndroIDRuntime.cpp]
static int javaDetachThread(voID) { JavaVM* vm; jint result; vm = AndroIDRuntime::getJavaVM(); //当前进程的虚拟机中移除该线程 result = vm->DetachCurrentThread(); return result;}
在创建Native进程的整个过程,涉及到JavaVM的AttachCurrentThread和DetachCurrentThread方法,都已深入虚拟机内部原理,本文就先讲到这里。
五. 总结本文介绍了3类线程的创建过程,它们都有一个共同的特点,那就是真正的线程创建过程都是通过调用pthread_create
方法(见小节[2.3],[3.2],[4.4]),该方法经过层层调用,最终都会进入clone系统调用,这是linux创建线程或进程的通用接口。
Native线程中是否可以执行Java代码的区别,在于通过javaThreadShell()方法从而实现在_threadLoop()执行前后增加分别将当前线程增加hook到虚拟机和从虚拟机移除的功能。调用过程:
说明:
Native线程(还能执行Java):该过程相对比较复杂,见上面的流程图:Native线程(只能执行C/C++): 只有上图中的紫色部分:thread.run -> androIDCreaterawThreadEtc -> _threadLoopJava线程: Thread.start -> Thread_nativeCreate -> CreateNativeThread总结
以上是内存溢出为你收集整理的理解Android线程创建流程全部内容,希望文章能够帮你解决理解Android线程创建流程所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)