/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線程,一般地就是指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
,那么接下來進入該方法。
2.2 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_create
pthread_create是pthread庫中的函數,通過syscall再調用到clone來請求內核創建線程。
- 原型:int pthread_create((pthread_t thread, pthread_attr_t *attr, void *(start_routine)(void *), void *arg)
- 頭文件:#include
- 輸入參數: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; }
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函數。
4.3 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線程: 相對簡單,只有上圖中的紫色部分:thread.run -> androidCreateRawThreadEtc -> _threadLoop
- Java線程: Thread.start -> Thread_nativeCreate -> CreateNativeThread