名词解释
ojluni:OpenJDK、 java.lang 、 java.util 、 java.net 、 java.io 的缩写。This relates to "luni" in Android source which stands for lang util net io。
Bionic:Bionic库是Android的基础库之一,也是连接Android和Linux的桥梁。Bionic库中包含了很多基本系统功能接口,这些功能大部分来自 Linux,但是和标准的 Linux 之间有很多细微差别。
源代码来源
我们都知道 Android 在 5.0 后切换到 art (5.0 behavior change),所以搜索相关代码时需要在 art 目录下寻找,避免找错。
- runtime.cc
- native_util.h
- java_long_thread.cc
- thread.cc
- pthread.cpp
关于 Android 源码的下载,可以直接看 官方 也可以参考 MacOS 下载 Android 源码
主题
上文提到的关键 native 调用是 nativeCreate,我们就由此展开
先找到对应的 jni 调用
jni 注册流程
// 代码位于 runtime.cc bool Runtime::Start() { ... Thread* self = Thread::Current(); RegisterRuntimeNativeMethods(self->GetJniEnv()); ... } // 代码位于 runtime.cc void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { ... register_java_lang_Thread(env); ... } //代码位于 java_long_thread.cc void register_java_lang_Thread(JNIEnv* env) { REGISTER_NATIVE_METHODS("java/lang/Thread"); } //代码位于 native_util.h #define REGISTER_NATIVE_METHODS(jni_class_name) RegisterNativeMethodsInternal(env, (jni_class_name), gMethods, arraysize(gMethods)) //代码位于 native_util.h ALWAYS_INLINE inline void RegisterNativeMethodsInternal(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods, jint method_count) { ScopedLocalRef c(env, env->FindClass(jni_class_name)); if (c.get() == nullptr) { LOG(FATAL) GetPeer()); } static jboolean Thread_interrupted(JNIEnv* env, jclass) { ... } static jboolean Thread_isInterrupted(JNIEnv* env, jobject java_thread) { ScopedFastNativeObjectAccess soa(env); MutexLock mu(soa.Self(), *Locks::thread_list_lock_); Thread* thread = Thread::FromManagedThread(soa, java_thread); return (thread != nullptr) ? thread->IsInterrupted() : JNI_FALSE; } static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size, jboolean daemon) { Runtime* runtime = Runtime::Current(); if (runtime->IsZygote() && runtime->IsZygoteNoThreadSection()) { jclass internal_error = env->FindClass("java/lang/InternalError"); CHECK(internal_error != nullptr); env->ThrowNew(internal_error, "Cannot create threads in zygote"); return; } Thread::CreateNativeThread(env, java_thread, stack_size, daemon == JNI_TRUE); } static jint Thread_nativeGetStatus(JNIEnv* env, jobject java_thread, jboolean has_been_started) { ... } static jboolean Thread_holdsLock(JNIEnv* env, jclass, jobject java_object) { ... } static void Thread_interrupt0(JNIEnv* env, jobject java_thread) { ... } static void Thread_setNativeName(JNIEnv* env, jobject peer, jstring java_name) { ... } static void Thread_setPriority0(JNIEnv* env, jobject java_thread, jint new_priority) { ScopedObjectAccess soa(env); MutexLock mu(soa.Self(), *Locks::thread_list_lock_); Thread* thread = Thread::FromManagedThread(soa, java_thread); if (thread != nullptr) { thread->SetNativePriority(new_priority); } } static void Thread_sleep(JNIEnv* env, jclass, jobject java_lock, jlong ms, jint ns) { ScopedFastNativeObjectAccess soa(env); ObjPtr lock = soa.Decode(java_lock); Monitor::Wait(Thread::Current(), lock.Ptr(), ms, ns, true, ThreadState::kSleeping); } static void Thread_yield(JNIEnv*, jobject) { sched_yield(); } static JNINativeMethod gMethods[] = { FAST_NATIVE_METHOD(Thread, currentThread, "()Ljava/lang/Thread;"), FAST_NATIVE_METHOD(Thread, interrupted, "()Z"), FAST_NATIVE_METHOD(Thread, isInterrupted, "()Z"), NATIVE_METHOD(Thread, nativeCreate, "(Ljava/lang/Thread;JZ)V"), NATIVE_METHOD(Thread, nativeGetStatus, "(Z)I"), NATIVE_METHOD(Thread, holdsLock, "(Ljava/lang/Object;)Z"), FAST_NATIVE_METHOD(Thread, interrupt0, "()V"), NATIVE_METHOD(Thread, setNativeName, "(Ljava/lang/String;)V"), NATIVE_METHOD(Thread, setPriority0, "(I)V"), FAST_NATIVE_METHOD(Thread, sleep, "(Ljava/lang/Object;JI)V"), NATIVE_METHOD(Thread, yield, "()V"), }; void register_java_lang_Thread(JNIEnv* env) { REGISTER_NATIVE_METHODS("java/lang/Thread"); } }
art 线程实现
由上可以看到 Thread_nativeCreate 调用的是 Thread::CreateNativeThread,而此 Thread 的代码位于 thread.cc。
void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) { ... Runtime* runtime = Runtime::Current(); ... Thread* child_thread = new Thread(is_daemon); ... SetNativePeer(env, java_peer, child_thread); int pthread_create_result = 0; if (child_jni_env_ext.get() != nullptr) { pthread_t new_pthread; pthread_attr_t attr; ... pthread_create_result = pthread_create(&new_pthread, &attr, gUseUserfaultfd ? Thread::CreateCallbackWithUffdGc : Thread::CreateCallback,child_thread); ... } ... }
由上可以看出, art 中的 thread.cc 角色跟 jdk 中的 Thread.java 其实差不多,都是包装层。
这么说或许也有些不准确,应该是 pthread 是 art thread 中的一个成员,具体线程相关操作由 pthread 去执行。
而具体线程资源的申请由 pthread_create 实现。
pthread
__BIONIC_WEAK_FOR_NATIVE_BRIDGE int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr, void* (*start_routine)(void*), void* arg) { pthread_attr_t thread_attr; if (attr == nullptr) { pthread_attr_init(&thread_attr); } else { thread_attr = *attr; attr = nullptr; } bionic_tcb* tcb = nullptr; void* child_stack = nullptr; int result = __allocate_thread(&thread_attr, &tcb, &child_stack); if (result != 0) { return result; } pthread_internal_t* thread = tcb->thread(); ... int rc = clone(__pthread_start, child_stack, flags, thread, &(thread->tid), tls, &(thread->tid)); __rt_sigprocmask(SIG_SETMASK, &thread->start_mask, nullptr, sizeof(thread->start_mask)); ... int init_errno = __init_thread(thread); ... }
pthread_create 中的 __allocate_thread 函数去创建线程栈等
static int __allocate_thread(pthread_attr_t* attr, bionic_tcb** tcbp, void** child_stack) { ThreadMapping mapping; char* stack_top; bool stack_clean = false; if (attr->stack_base == nullptr) { // The caller didn't provide a stack, so allocate one. // Make sure the guard size is a multiple of page_size(). const size_t unaligned_guard_size = attr->guard_size; attr->guard_size = __BIONIC_ALIGN(attr->guard_size, page_size()); if (attr->guard_size stack_size, attr->guard_size); if (mapping.mmap_base == nullptr) return EAGAIN; stack_top = mapping.stack_top; attr->stack_base = mapping.stack_base; stack_clean = true; } else { mapping = __allocate_thread_mapping(0, PTHREAD_GUARD_SIZE); if (mapping.mmap_base == nullptr) return EAGAIN; stack_top = static_cast(attr->stack_base) + attr->stack_size; } // Carve out space from the stack for the thread's pthread_internal_t. This // memory isn't counted in pthread_attr_getstacksize. // To safely access the pthread_internal_t and thread stack, we need to find a 16-byte aligned boundary. stack_top = align_down(stack_top - sizeof(pthread_internal_t), 16); pthread_internal_t* thread = reinterpret_cast(stack_top); if (!stack_clean) { // If thread was not allocated by mmap(), it may not have been cleared to zero. // So assume the worst and zero it. memset(thread, 0, sizeof(pthread_internal_t)); } // Locate static TLS structures within the mapped region. const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout; auto tcb = reinterpret_cast(mapping.static_tls + layout.offset_bionic_tcb()); auto tls = reinterpret_cast(mapping.static_tls + layout.offset_bionic_tls()); // Initialize TLS memory. __init_static_tls(mapping.static_tls); __init_tcb(tcb, thread); __init_tcb_dtv(tcb); __init_tcb_stack_guard(tcb); __init_bionic_tls_ptrs(tcb, tls); attr->stack_size = stack_top - static_cast(attr->stack_base); thread->attr = *attr; thread->mmap_base = mapping.mmap_base; thread->mmap_size = mapping.mmap_size; thread->mmap_base_unguarded = mapping.mmap_base_unguarded; thread->mmap_size_unguarded = mapping.mmap_size_unguarded; thread->stack_top = reinterpret_cast(stack_top); *tcbp = tcb; *child_stack = stack_top; return 0; }
pthread_create 中的 clone 去申请内核线程等资源,clone 的代码位于 clone.cpp
__BIONIC_WEAK_FOR_NATIVE_BRIDGE int clone(int (*fn)(void*), void* child_stack, int flags, void* arg, ...) { int* parent_tid = nullptr; void* new_tls = nullptr; int* child_tid = nullptr; if (fn != nullptr && child_stack == nullptr) { errno = EINVAL; return -1; } // Extract any optional parameters required by the flags. va_list args; va_start(args, arg); if ((flags & (CLONE_PARENT_SETTID|CLONE_SETTLS|CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID)) != 0) { parent_tid = va_arg(args, int*); } if ((flags & (CLONE_SETTLS|CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID)) != 0) { new_tls = va_arg(args, void*); } if ((flags & (CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID)) != 0) { child_tid = va_arg(args, int*); } va_end(args); // Align 'child_stack' to 16 bytes. uintptr_t child_stack_addr = reinterpret_cast(child_stack); child_stack_addr &= ~0xf; child_stack = reinterpret_cast(child_stack_addr); // Remember the parent pid and invalidate the cached value while we clone. pthread_internal_t* self = __get_thread(); pid_t parent_pid = self->invalidate_cached_pid(); // Remmber the caller's tid so that it can be restored in the parent after clone. pid_t caller_tid = self->tid; // Invalidate the tid before the syscall. The value is lazily cached in gettid(), // and it will be updated by fork() and pthread_create(). We don't do this if // we are sharing address space with the child. if (!(flags & (CLONE_VM|CLONE_VFORK))) { self->tid = -1; } // Actually do the clone. int clone_result; if (fn != nullptr) { clone_result = __bionic_clone(flags, child_stack, parent_tid, new_tls, child_tid, fn, arg); } else { #if defined(__x86_64__) // sys_clone's last two arguments are flipped on x86-64. clone_result = syscall(__NR_clone, flags, child_stack, parent_tid, child_tid, new_tls); #else clone_result = syscall(__NR_clone, flags, child_stack, parent_tid, new_tls, child_tid); #endif } if (clone_result != 0) { self->set_cached_pid(parent_pid); self->tid = caller_tid; } else if (self->tid == -1) { self->tid = syscall(__NR_gettid); self->set_cached_pid(self->tid); } return clone_result; }
而这中的关键调用是 __bionic_clone,代码位于 __bionic_clone.S
ENTRY_PRIVATE(__bionic_clone) # Push 'fn' and 'arg' onto the child stack. stp x5, x6, [x1, #-16]! # Make the system call. mov x8, __NR_clone svc #0 # Are we the child? cbz x0, .L_bc_child # Set errno if something went wrong. cmn x0, #(MAX_ERRNO + 1) cneg x0, x0, hi b.hi __set_errno_internal ret .L_bc_child: # We're in the child now. Set the end of the frame record chain. mov x29, #0 # Setting x30 to 0 will make the unwinder stop at __start_thread. mov x30, #0 # Call __start_thread with the 'fn' and 'arg' we stored on the child stack. ldp x0, x1, [sp], #16 b __start_thread END(__bionic_clone)
arm 64 下通过 svc 指令触发,然后就由用户态转到核态,具体看下一篇文章啦