Android Java线程的创建过程

作者: lbtrace | 来源:发表于2018-07-02 22:07 被阅读21次

    基于Android 7.0源码分析,涉及的主要源码如下

    ~/aosp/libcore/ojluni/src/main/java/java/lang/Thread.java
    
    ~/aosp/art/runtime/native/java_lang_Thread.cc
    ~/aosp/art/runtime/thread.cc
    ~/aosp/art/runtime/jni_env_ext.cc
    ~/aosp/art/runtime/jni_internal.cc
    ~/aosp/art/runtime/reflection.cc
    
    ~/aosp/bionic/libc/bionic/pthread_create.cpp
    ~/aosp/bionic/libc/bionic/pthread_internal.cpp
    

    Java线程的启动方式

    (1)
    new Thread() {
        @Override
        public void run() {
            // Do something
        }
    }.start();
    
    (2)
    new Thread(new Runnable() {
        @Override
        public void run() {
            // Do something
        }
    }).start();
    

    两种方式原理相同,下面以(1)方式为例分析。

    Java线程创建的过程

    下面从Thread的构造函数开始分析。

    public Thread() {
        // 对于匿名线程,线程名为“Thread-xxx(整数)”
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    
    private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
        // 新线程的父线程
        Thread parent = currentThread();
        if (g == null) {
            g = parent.getThreadGroup();
        }
        g.addUnstarted();
        this.group = g;
        this.target = target;
        // 线程优先级,映射到linux进程优先级
        this.priority = parent.getPriority();
        // 是否为守护线程
        this.daemon = parent.isDaemon();
        // 设置线程名,并未真正执行
        setName(name);
        // 设置线程上下文类加载器,通常为应用类加载器
        init2(parent);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;
        // 线程序列号
        tid = nextThreadID();
    }
    

    Thread的构造方法相对简单,只是简单设置线程参数,下面看Threadstart方法。

    public synchronized void start() {
        ......
        // 添加到线程组,修改统计信息
        group.add(this);
        started = false;
        try {
            // 创建启动线程
            nativeCreate(this, stackSize, daemon);
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
    

    nativeCreate是个Native方法,它的实现在java_lang_Thread.cc中。

    static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size,
                                    jboolean daemon) {
      // There are sections in the zygote that forbid thread creation.
      Runtime* runtime = Runtime::Current();
      // 不能在Zygote进程的初始阶段创建线程
      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);
    }
    
    void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) {
      CHECK(java_peer != nullptr);
      Thread* self = static_cast<JNIEnvExt*>(env)->self;
      ......
      Runtime* runtime = Runtime::Current();
      ......
      // 为新线程创建Native层的Thread对象
      Thread* child_thread = new Thread(is_daemon);
      // Use global JNI ref to hold peer live while child thread starts.
      // 创建JNI全局引用
      child_thread->tlsPtr_.jpeer = env->NewGlobalRef(java_peer);
      // 计算线程栈的大小,这里stack_size = 1040KB
      stack_size = FixStackSize(stack_size);
    
      // Thread.start is synchronized, so we know that nativePeer is 0, and know that we're not racing to
      // assign it.
      // Native Thread对象地址保存到Java Thread对象的nativePeer域
      env->SetLongField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer,
                        reinterpret_cast<jlong>(child_thread));
    
      // Try to allocate a JNIEnvExt for the thread. We do this here as we might be out of memory and
      // do not have a good way to report this on the child's side.
      // 创建JNIEnvExt
      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;
        // 保存JNIEnvExt
        child_thread->tlsPtr_.tmp_jni_env = child_jni_env_ext.get();
        // 调用pthread_attr_init初始化线程属性
        CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), "new thread");
        // 调用pthread_attr_setdetachstate设置state为PTHREAD_ATTR_FLAG_DETACHED
        CHECK_PTHREAD_CALL(pthread_attr_setdetachstate, (&attr, PTHREAD_CREATE_DETACHED),
                           "PTHREAD_CREATE_DETACHED");
        // 调用pthread_attr_setstacksize设置栈大小到线程属性中
        CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, stack_size), stack_size);
        // 创建新的线程,线程启动后调用Thread::CreateCallback方法
        pthread_create_result = pthread_create(&new_pthread,
                                               &attr,
                                               Thread::CreateCallback,
                                               child_thread);
        CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), "new thread");
        ......
      }
      ......
    }
    

    下面首先分析线程栈大小的计算,接下来分析JNIEnvExt的创建,最后看pthread_create的实现

    static size_t FixStackSize(size_t stack_size) {
      // A stack size of zero means "use the default".
      if (stack_size == 0) {
        // 系统默认的栈大小为0  
        stack_size = Runtime::Current()->GetDefaultStackSize();
      }
    
      // Dalvik used the bionic pthread default stack size for native threads,
      // so include that here to support apps that expect large native stacks.
      // 加上1MB用作Native stack
      stack_size += 1 * MB;
      ......
      if (Runtime::Current()->ExplicitStackOverflowChecks()) {
        // It's likely that callers are trying to ensure they have at least a certain amount of
        // stack space, so we should add our reserved space on top of what they requested, rather
        // than implicitly take it away from them.
        stack_size += GetStackOverflowReservedBytes(kRuntimeISA);
      } else {
        // If we are going to use implicit stack checks, allocate space for the protected
        // region at the bottom of the stack.
        // 加上(8K + 8K)
        stack_size += Thread::kStackOverflowImplicitCheckSize +
            GetStackOverflowReservedBytes(kRuntimeISA);
      }
    
      // Some systems require the stack size to be a multiple of the system page size, so round up.
      stack_size = RoundUp(stack_size, kPageSize);
      // stack_size = 1040KB
      return stack_size;
    }
    

    这里虚拟机栈与Native栈共用。下面看JNIEnvExt的创建。

    JNIEnvExt* JNIEnvExt::Create(Thread* self_in, JavaVMExt* vm_in) {
      std::unique_ptr<JNIEnvExt> ret(new JNIEnvExt(self_in, vm_in));
      if (CheckLocalsValid(ret.get())) {
        return ret.release();
      }
      return nullptr;
    }
    
    JNIEnvExt::JNIEnvExt(Thread* self_in, JavaVMExt* vm_in)
        : self(self_in),
          vm(vm_in),
          local_ref_cookie(IRT_FIRST_SEGMENT),
          // JNI本地引用表
          locals(kLocalsInitial, kLocalsMax, kLocal, false),
          check_jni(false),
          runtime_deleted(false),
          critical(0),
          monitors("monitors", kMonitorsInitial, kMonitorsMax) {
      // 初始化JNINativeInterface(实现在jni_internal.cc中)        
      functions = unchecked_functions = GetJniNativeInterface();
      if (vm->IsCheckJniEnabled()) {
        SetCheckJniEnabled(true);
      }
    }
    
    • JNIEnvExt管理JNI本地引用表
    • JavaVMExt管理JNI全局引用表

    下面看pthread_create的实现

    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 == NULL) {
        pthread_attr_init(&thread_attr);
      } else {
        thread_attr = *attr;
        attr = NULL; // Prevent misuse below.
      }
    
      pthread_internal_t* thread = NULL;
      void* child_stack = NULL;
      // 分配新(子)线程栈空间以及初始化TLS
      int result = __allocate_thread(&thread_attr, &thread, &child_stack);
      if (result != 0) {
        return result;
      }
    
      // 用于父线程与子线程同步  
      thread->startup_handshake_lock.init(false);
      thread->startup_handshake_lock.lock();
      // 入口函数  
      thread->start_routine = start_routine;
      // 入口函数参数
      thread->start_routine_arg = arg;
    
      ......
      // clone新的进程(线程),线程启动后执行__pthread_start
      int rc = clone(__pthread_start, child_stack, flags, thread, &(thread->tid), tls, &(thread->tid));
      ......
      // pthread_internal_t添加到全局g_thread_list中
      *thread_out = __pthread_internal_add(thread);
      // 解锁让新线程运行
      thread->startup_handshake_lock.unlock();
    
      return 0;
    }
    
    static int __allocate_thread(pthread_attr_t* attr, pthread_internal_t** threadp, void** child_stack) {
      size_t mmap_size;
      uint8_t* stack_top;
    
      if (attr->stack_base == NULL) {
        // The caller didn't provide a stack, so allocate one.
        // Make sure the stack size and guard size are multiples of PAGE_SIZE.
        // 32位系统中1KB < sizeof(pthread_internal_t) < 2KB
        // 64为系统上2KB < sizeof(pthread_internal_t) < 3KB
        // mmap_size = 1044KB
        mmap_size = BIONIC_ALIGN(attr->stack_size + sizeof(pthread_internal_t), PAGE_SIZE);
        // guard_size = 4K
        attr->guard_size = BIONIC_ALIGN(attr->guard_size, PAGE_SIZE);
        // 映射线程栈空间
        attr->stack_base = __create_thread_mapped_space(mmap_size, attr->guard_size);
        if (attr->stack_base == NULL) {
          return EAGAIN;
        }
        stack_top = reinterpret_cast<uint8_t*>(attr->stack_base) + mmap_size;
      } else {
        // Remember the mmap size is zero and we don't need to free it.
        mmap_size = 0;
        stack_top = reinterpret_cast<uint8_t*>(attr->stack_base) + attr->stack_size;
      }
      //  调整栈顶,为了安全访问pthread_internal_t和线程栈,边界进行16字节对齐
      stack_top = reinterpret_cast<uint8_t*>(
                    (reinterpret_cast<uintptr_t>(stack_top) - sizeof(pthread_internal_t)) & ~0xf);
    
      pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(stack_top);
      if (mmap_size == 0) {
        // 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));
      }
      // 更新stack_size
      attr->stack_size = stack_top - reinterpret_cast<uint8_t*>(attr->stack_base);
    
      thread->mmap_size = mmap_size;
      // 线程属性拷贝至线程TLS
      thread->attr = *attr;
      // 初始化TLS
      __init_tls(thread);
    
      *threadp = thread;
      *child_stack = stack_top;
      return 0;
    }
    

    小结

    • Android Java线程栈内存空间布局


    从stack_begin到stack_end的8KB空间,如果调用Java方法且栈顶指针sp位于stack_end之下则抛出栈溢出错误,此时仍然可以调用Native方法。stack_begin之下的4KB空间,处理栈溢出错误时可能使用。

    • Java线程栈内存映射


    Java线程启动后执行Threadrun方法的过程

    static int __pthread_start(void* arg) {
      pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(arg);
    
      // Wait for our creating thread to release us. This lets it have time to
      // notify gdb about this thread before we start doing anything.
      // This also provides the memory barrier needed to ensure that all memory
      // accesses previously made by the creating thread are visible to us.
      // 等待父线程释放锁
      thread->startup_handshake_lock.lock();
      // 创建信号栈
      __init_alternate_signal_stack(thread);
      // 调用start_routine,也就是Thread::CreateCallback方法
      void* result = thread->start_routine(thread->start_routine_arg);
      pthread_exit(result);
    
      return 0;
    }
    
    void __init_alternate_signal_stack(pthread_internal_t* thread) {
      // Create and set an alternate signal stack.
      // 映射信号栈地址空间(16KB + 4KB)
      void* stack_base = mmap(NULL, SIGNAL_STACK_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
      if (stack_base != MAP_FAILED) {
    
        // Create a guard page to catch stack overflows in signal handlers.
        // 创建guard page(4KB)捕获信号栈溢出
        if (mprotect(stack_base, PAGE_SIZE, PROT_NONE) == -1) {
          munmap(stack_base, SIGNAL_STACK_SIZE);
          return;
        }
        stack_t ss;
        // 信号栈起始地址
        ss.ss_sp = reinterpret_cast<uint8_t*>(stack_base) + PAGE_SIZE;
        // 信号栈大小
        ss.ss_size = SIGNAL_STACK_SIZE - PAGE_SIZE;
        ss.ss_flags = 0;
        // 通知内核信号栈信息
        sigaltstack(&ss, NULL);
        thread->alternate_signal_stack = stack_base;
    
        // We can only use const static allocated string for mapped region name, as Android kernel
        // uses the string pointer directly when dumping /proc/pid/maps.
        // 设置虚拟内存区域名称
        prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ss.ss_sp, ss.ss_size, "thread signal stack");
        prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, stack_base, PAGE_SIZE, "thread signal stack guard page");
      }
    }
    
    • 信号栈映射信息


    下面看Thread::CreateCallback的实现

    void* Thread::CreateCallback(void* arg) {
      Thread* self = reinterpret_cast<Thread*>(arg);
      Runtime* runtime = Runtime::Current();
      .....
      {
        ......
        // 调用Thread的Init方法
        CHECK(self->Init(runtime->GetThreadList(), runtime->GetJavaVM(), self->tlsPtr_.tmp_jni_env));
        self->tlsPtr_.tmp_jni_env = nullptr;
        ......
      }
      {
        ScopedObjectAccess soa(self);
        // 初始化字符串构造入口
        self->InitStringEntryPoints();
    
        // Copy peer into self, deleting global reference when done.
        CHECK(self->tlsPtr_.jpeer != nullptr);
        // opeer指向Java Thread对象在堆中的镜像
        self->tlsPtr_.opeer = soa.Decode<mirror::Object*>(self->tlsPtr_.jpeer);
        self->GetJniEnv()->DeleteGlobalRef(self->tlsPtr_.jpeer);
        self->tlsPtr_.jpeer = nullptr;
        // 设置线程名
        self->SetThreadName(self->GetThreadName(soa)->ToModifiedUtf8().c_str());
    
        ArtField* priorityField = soa.DecodeField(WellKnownClasses::java_lang_Thread_priority);
        // Java线程优先级转换为Linux进程优先级
        self->SetNativePriority(priorityField->GetInt(self->tlsPtr_.opeer));
        Dbg::PostThreadStart(self);
    
        // Invoke the 'run' method of our java.lang.Thread.
        // 调用Java Thread对象的run方法
        mirror::Object* receiver = self->tlsPtr_.opeer;
        jmethodID mid = WellKnownClasses::java_lang_Thread_run;
        ScopedLocalRef<jobject> ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
        InvokeVirtualOrInterfaceWithJValues(soa, ref.get(), mid, nullptr);
      }
      // Detach and delete self.
      Runtime::Current()->GetThreadList()->Unregister(self);
    
      return nullptr;
    }
    
    bool Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm, JNIEnvExt* jni_env_ext) {
      // This function does all the initialization that must be run by the native thread it applies to.
      // (When we create a new thread from managed code, we allocate the Thread* in Thread::Create so
      // we can handshake with the corresponding native thread when it's ready.) Check this native
      // thread hasn't been through here already...
      CHECK(Thread::Current() == nullptr);
    
      // Set pthread_self_ ahead of pthread_setspecific, that makes Thread::Current function, this
      // avoids pthread_self_ ever being invalid when discovered from Thread::Current().
      tlsPtr_.pthread_self = pthread_self();
      CHECK(is_started_);
      // 实现在thread_android.cc中,空函数
      SetUpAlternateSignalStack();
      // 获取栈信息并设置隐式栈溢出保护
      if (!InitStackHwm()) {
        return false;
      }
      InitCpu();
      // 初始化JNI以及Quick entrypoints
      InitTlsEntryPoints();
      RemoveSuspendTrigger();
      InitCardTable();
      InitTid();
      // Mterp解释器信息保存到TLS
      interpreter::InitInterpreterTls(this);
    
    #ifdef ART_TARGET_ANDROID
      // 线程本地存储(在pthread_internal_t内部)
      __get_tls()[TLS_SLOT_ART_THREAD_SELF] = this;
    #else
      CHECK_PTHREAD_CALL(pthread_setspecific, (Thread::pthread_key_self_, this), "attach self");
    #endif
      DCHECK_EQ(Thread::Current(), this);
    
      tls32_.thin_lock_thread_id = thread_list->AllocThreadId(this);
    
      if (jni_env_ext != nullptr) {
        DCHECK_EQ(jni_env_ext->vm, java_vm);
        DCHECK_EQ(jni_env_ext->self, this);
        tlsPtr_.jni_env = jni_env_ext;
      } else {
        tlsPtr_.jni_env = JNIEnvExt::Create(this, java_vm);
        if (tlsPtr_.jni_env == nullptr) {
          return false;
        }
      }
      // 线程添加到thread_list
      thread_list->Register(this);
      return true;
    }
    
    bool Thread::InitStackHwm() {
      void* read_stack_base;
      size_t read_stack_size;
      size_t read_guard_size;
      // 从线程本地存储中获取线程栈信息
      GetThreadStack(tlsPtr_.pthread_self, &read_stack_base, &read_stack_size, &read_guard_size);
    
      tlsPtr_.stack_begin = reinterpret_cast<uint8_t*>(read_stack_base);
      tlsPtr_.stack_size = read_stack_size;
      ......
      // 设置stack_end = stack_begin + 8KB
      ResetDefaultStackEnd();
    
      // Install the protected region if we are doing implicit overflow checks.
      if (implicit_stack_check && !valgrind_on_arm) {
        // The thread might have protected region at the bottom.  We need
        // to install our own region so we need to move the limits
        // of the stack to make room for it.
        // 调整stack_begin、stack_end以及stack_size,通常read_guard_size + kStackOverflowProtectedSize = 8KB
        tlsPtr_.stack_begin += read_guard_size + kStackOverflowProtectedSize;
        tlsPtr_.stack_end += read_guard_size + kStackOverflowProtectedSize;
        tlsPtr_.stack_size -= read_guard_size;
    
        InstallImplicitProtection();
      }
    
      // Sanity check.
      CHECK_GT(FindStackTop(), reinterpret_cast<void*>(tlsPtr_.stack_end));
    
      return true;
    }
    

    下面看InvokeVirtualOrInterfaceWithJValues的实现

    JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
                                               jobject obj, jmethodID mid, jvalue* args) {
      // We want to make sure that the stack is not within a small distance from the
      // protected region in case we are calling into a leaf function whose stack
      // check has been elided.
      // 编译器内建函数__builtin_frame_address(0)返回当前函数的帧地址
      // See http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html
      if (UNLIKELY(__builtin_frame_address(0) < soa.Self()->GetStackEnd())) {
        // 当前的栈顶地址低于stack_end,抛出栈溢出错误
        ThrowStackOverflowError(soa.Self());
        return JValue();
      }
    
      // 解引用获取堆中的镜像
      mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
      // 获取run方法的ArtMethod
      ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
      bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
      if (is_string_init) {
        // Replace calls to String.<init> with equivalent StringFactory call.
        // 如果是Java String类的构造方法,替换为StringFactory的构造方法
        method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
        receiver = nullptr;
      }
      uint32_t shorty_len = 0;
      const char* shorty =
          method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
      JValue result;
      ArgArray arg_array(shorty, shorty_len);
      arg_array.BuildArgArrayFromJValues(soa, receiver, args);
      // 调用Thread的run方法
      InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
      if (is_string_init) {
        // For string init, remap original receiver to StringFactory result.
        UpdateReference(soa.Self(), obj, result.GetL());
      }
      return result;
    }
    

    文中涉及Android ART运行时原理的一些知识暂不详细讨论,以后研究ART运行时再做分析。

    相关文章

      网友评论

        本文标题:Android Java线程的创建过程

        本文链接:https://www.haomeiwen.com/subject/mbdruftx.html