zoukankan      html  css  js  c++  java
  • 理解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线程,一般地就是指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()。当满足以下任一条件,则该线程将退出循环:

    1. 当前线程状态存在错误,即mStatus != NO_ERROR;
    2. 当前线程即将退出, 即mExitPending = true; 调用Thread::requestExit()可触发该过程。
    3. 当前线程的强引用释放后,无法将弱引用提升成强引用的情况。

    对于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;
    }
    

    该方法主要功能:

    1. 调用javaAttachThread():将当前线程hook到当前进程所在的虚拟机,从而既能执行C/C++代码,也能执行Java代码。
    2. 调用_threadLoop():执行当前线程的核心逻辑代码;
    3. 调用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到虚拟机和从虚拟机移除的功能。调用过程:

    android_thread_create

    1. Native线程(Java版):该过程相对比较复杂,见如上流程图:
    2. Native线程: 相对简单,只有上图中的紫色部分:thread.run -> androidCreateRawThreadEtc -> _threadLoop
    3. Java线程: Thread.start -> Thread_nativeCreate -> CreateNativeThread

    转自:http://gityuan.com/2016/09/24/android-thread/

  • 相关阅读:
    LeetCode 23. 合并K个排序链表
    LeetCode 199. 二叉树的右视图
    LeetCode 560. 和为K的子数组
    LeetCode 1248. 统计「优美子数组」
    LeetCode 200. 岛屿数量
    LeetCode 466. 统计重复个数
    LeetCode 11. 盛最多水的容器
    LeetCode 55. 跳跃游戏
    LeetCode 56. 合并区间
    Java生鲜电商平台-订单架构实战
  • 原文地址:https://www.cnblogs.com/zl1991/p/6879014.html
Copyright © 2011-2022 走看看