framework 學(xué)習(xí)筆記19. 知識(shí)點(diǎn)1(framework 線(xiàn)程類(lèi) Thread)

Linux 系統(tǒng)中没隘,創(chuàng)建線(xiàn)程函數(shù)為:pthread_create();在 Android 中,通過(guò)調(diào)用 pthread_create() 封裝了一個(gè)為線(xiàn)程操作的 Thread類(lèi)熄云;在創(chuàng)建線(xiàn)程的時(shí)候膨更,只需要繼承于這個(gè) Thread 類(lèi)并實(shí)現(xiàn)虛函數(shù) thread_loop()妙真。下面就簡(jiǎn)單介紹一下這個(gè) Thread 類(lèi):

1. 頭文件中的定義

// frameworks/base/include/utils/threads.h
frameworks/base/include/utils/threads.h
class Thread : virtual public RefBase
{
public:
    // canCallJava 為 true
    Thread(bool canCallJava = true);
    virtual ~Thread();
    // 線(xiàn)程啟動(dòng)函數(shù),調(diào)用的是threadLoop
    virtual status_t run(const char*name = 0, int32_t prority = PRIORITY_DEFAULT,
                size_t stack = 0);
    // 申請(qǐng)退出這個(gè)線(xiàn)程
    virtual void requestExit();
    virtual status_t readyToRun();
    // 調(diào)用requestExit()等待直到這個(gè)線(xiàn)程退出
        status_t requestExitAndWait();
    // 等待直到線(xiàn)程退出荚守,如果沒(méi)有啟動(dòng)立即返回
        status_t join();
protected:
    // 如果調(diào)用了 requestExit() 返回true
    bool exitPending() const;
private:
    // 實(shí)際的線(xiàn)程函數(shù)珍德,繼承類(lèi)必須實(shí)現(xiàn)該方法:threadLoop()
    // 返回 true 時(shí)會(huì)一直調(diào)用,返回 false 的時(shí)會(huì)退出該線(xiàn)程矗漾;
    virtual bool threadLoop() = 0;
    // 禁止賦值
    Thread& operator = (const Thread&);
    // 被 run() 函數(shù)調(diào)用锈候,實(shí)際調(diào)用threadLoop();
    static int _threadLoop(void* user);
    const bool mCanCallJava;
        thread_id_t mThread;    // thread_id_t 是 void*類(lèi)型
    mutable Mutex mLock;
        Condition mThreadExitedCondition;
        status_t mStatus;
    // 注意:操作這兩個(gè)變量的地方都需要上鎖
    volatile bool mExitPending;
    volatile bool mRunning;
        sp<Thread> mHoldSelf;
};

2. Thread 類(lèi)的構(gòu)造函數(shù)

Thread::Thread(bool canCallJava) 
        :   mCanCallJava(canCallJava),
            mThread(thread_id_t(-1)),
            mLock("Thrad::mLock"),
            mStatus(NO_ERROR),
            mExitPending(false), mRunnig(false)
{
}

3. run() 方法

status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
    Mutex::Autolock _l(mLock);

    if (mRunning) {
        // thread already started
        return INVALID_OPERATION;
    }

    // reset status and exitPending to their default value, so we can
    // try again after an error happened (either below, or in readyToRun())
    mStatus = NO_ERROR;
    mExitPending = false;
    mThread = thread_id_t(-1);
    
    // hold a strong reference on ourself 
    mHoldSelf = this;  // 保存當(dāng)前對(duì)象的引用

    mRunning = true;

    bool res;
   // 如果 mCanCallJava為真敞贡,則調(diào)用createThreadEtc函數(shù)泵琳,線(xiàn)程函數(shù)是_threadLoop(Thread.cpp中定義的一個(gè)函數(shù))。
    if (mCanCallJava) {  // 這里初始化的時(shí)候?yàn)?true誊役; 見(jiàn) 3.1
        res = createThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);
    } else {    // 見(jiàn) 3.2
        res = androidCreateRawThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);
    }
    
    if (res == false) {
        mStatus = UNKNOWN_ERROR;   // something happened!
        mRunning = false;
        mThread = thread_id_t(-1);
        mHoldSelf.clear();  // "this" may have gone away after this.

        return UNKNOWN_ERROR;
    }
    
    // Do not refer to mStatus here: The thread is already running (may, in fact
    // already have exited with a valid mStatus result). The NO_ERROR indication
    // here merely indicates successfully starting the thread and does not
    // imply successful termination/execution.
    return NO_ERROR;

    // Exiting scope of mLock is a memory barrier and allows new thread to run
}

3.1 createThreadEtc() 方法:這里 mCanCallJava 為 true 時(shí)获列,調(diào)用的方法;其實(shí)最終調(diào)用的方法都是同一個(gè)線(xiàn)程創(chuàng)建函數(shù)蛔垢,只不過(guò)傳入?yún)?shù)的回調(diào)函數(shù)不一樣击孩,之后會(huì)有分析:

//(1)創(chuàng)建線(xiàn)程:Create thread with lots of parameters
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)
{
    return androidCreateThreadEtc(entryFunction, userData, threadName,
        threadPriority, threadStackSize, threadId) ? true : false;
}


//(2)調(diào)用的函數(shù):
static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;  // 函數(shù)指針;
// 線(xiàn)程創(chuàng)建函數(shù):gCreateThreadFn是函數(shù)指針鹏漆,初始化時(shí)和 mCanCallJava 為 false 時(shí)使用的是同一個(gè)
int androidCreateThreadEtc(android_thread_func_t entryFunction,
                            void *userData,
                            const char* threadName,
                            int32_t threadPriority,
                            size_t threadStackSize,
                            android_thread_id_t *threadId)
{
    return gCreateThreadFn(entryFunction, userData, threadName,
        threadPriority, threadStackSize, threadId);
}

3.2 androidCreateRawThreadEtc() 方法:

// 
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);

#ifdef HAVE_ANDROID_OS  /* valgrind is rejecting RT-priority create reqs */
    if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
        // Now that the pthread_t has a method to find the associated
        // android_thread_id_t (pid) from pthread_t, it would be possible to avoid
        // this trampoline in some cases as the parent could set the properties
        // for the child.  However, there would be a race condition because the
        // child becomes ready immediately, and it doesn't work for the name.
        // prctl(PR_SET_NAME) only works for self; prctl(PR_SET_THREAD_NAME) was
        // proposed but not yet accepted.
        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;            
    }
#endif

    if (threadStackSize) {
        pthread_attr_setstacksize(&attr, threadStackSize);
    }
    
    errno = 0;
    pthread_t thread; 
    // 從這里可以看出線(xiàn)程的創(chuàng)建最終還是通過(guò) pthread_create() 封裝而成的巩梢;
    int result = pthread_create(&thread, &attr,
                    (android_pthread_entry)entryFunction, userData);
    pthread_attr_destroy(&attr);
    if (result != 0) {
        ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n"
             "(android threadPriority=%d)",
            entryFunction, result, errno, threadPriority);
        return 0;
    }

    // Note that *threadID is directly available to the parent only, as it is
    // assigned after the child starts.  Use memory barrier / lock if the child
    // or other threads also need access.
    if (threadId != NULL) {
        *threadId = (android_thread_id_t)thread; // XXX: this is not portable
    }
    return 1;
}
/**
簡(jiǎn)單介紹 pthread_create() :pthread_create 是(Unix、Linux艺玲、Mac OS X)等操作系統(tǒng)的創(chuàng)建線(xiàn)程的函
數(shù)括蝠。它的功能是創(chuàng)建線(xiàn)程(實(shí)際上就是確定調(diào)用該線(xiàn)程函數(shù)的入口點(diǎn)),在線(xiàn)程創(chuàng)建以后饭聚,就開(kāi)始運(yùn)行相關(guān)的線(xiàn)程函數(shù)又跛。

pthread_create的返回值表示成功,返回0若治;表示出錯(cuò)慨蓝,返回表示-1。

參數(shù)說(shuō)明:int pthread_create (pthread_t * tid, const pthread_attr_t * attr, void * (*start_rtn)(void*), void *arg);
各個(gè)參數(shù)說(shuō)明:
第一個(gè)參數(shù)為指向線(xiàn)程標(biāo)識(shí)符的指針端幼。
第二個(gè)參數(shù)用來(lái)設(shè)置線(xiàn)程屬性礼烈。
第三個(gè)參數(shù)是線(xiàn)程運(yùn)行函數(shù)的起始地址(也就是傳入的entryFunction)。
最后一個(gè)參數(shù)是運(yùn)行函數(shù)的參數(shù)婆跑。
**/

上述中當(dāng) mCanCallJava 為 true 時(shí)最終調(diào)用的是 gCreateThreadFn這個(gè)函數(shù)此熬,gCreateThreadFn是個(gè)全局的函數(shù)指針(static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc),而這個(gè)與 mCanCallJava 為 false 時(shí)看上去是一模一樣的,那么這兩者是不是有所區(qū)別呢(答案是肯定有的犀忱,不然搞這么麻煩作甚)募谎?

3.3 布爾變量 mCanCallJava 取值不同時(shí)的區(qū)別:
過(guò)程:
(1)mCanCallJava 為 false 時(shí):直接調(diào)用的是 androidCreateRawThreadEtc() 這個(gè)方法;
(2)mCanCallJava 為 true 時(shí):createThreadEtc() -> android_create_thread_fn () -> androidCreateRawThreadEtc()阴汇;
區(qū)別:
在 3.1分析 mCanCallJava 為 true 的過(guò)程中其實(shí)就多執(zhí)行了一步数冬,即調(diào)用了 androidCreateThreadEtc() 方法,而在這個(gè)方法中也只是引入了 static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc 這個(gè)函數(shù)指針搀庶,并調(diào)用 gCreateThreadFn 方法創(chuàng)建線(xiàn)程拐纱;那么接下來(lái)就跟蹤這個(gè) gCreateThreadFn 變量的初始化就行了;

3.4 gCreateThreadFn() 的賦值:代碼中有的地方是會(huì)修改這個(gè)函數(shù)指針的指向的哥倔,比如在 zygote 中創(chuàng)建線(xiàn)程秸架,AndroidRuntime 調(diào)用 startReg() 的地方,就有修改這個(gè)函數(shù)指針咆蒿,其代碼如下所示(這里順便簡(jiǎn)單介紹一下 zygote 進(jìn)程的啟動(dòng)):

//(1)zygote 是由 init 進(jìn)程通過(guò)解析 init.rc 文件而創(chuàng)建并啟動(dòng)的:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd


//(2)frameworks/base/cmds/app_process/app_main.cpp 中的 main() 方法:
int main(int argc, char* const argv[])
{
    // AppRuntime 繼承 AndoirdRuntime
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // 跳過(guò)第一個(gè)參數(shù)
    argc--;
    argv++;

    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    // 解析參數(shù)
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    //  省略部分代碼 ...
    //設(shè)置進(jìn)程名
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }
    // 如果 zygote 东抹,AndroidRuntime 執(zhí)行 com.android.internal.os.ZygoteInit 
    if (zygote) {  // 根據(jù)上面解析的腳本參數(shù),執(zhí)行的是此分支沃测;
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        return 10;
    }
}

//(3)在 zygote 的啟動(dòng)過(guò)程中會(huì)調(diào)用到 AndroidRuntime的 start 方法:
void AndroidRuntime::start(const char* className, const Vector<String8>& options)
{
    // ... 
    // 創(chuàng)建一個(gè)虛擬機(jī)的實(shí)例
    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);

    // JNI 方法注冊(cè)
    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {  // ********* 此處為下面的關(guān)注點(diǎn) *********
        ALOGE("Unable to register all android natives\n");
        return;
    }

    /*
     * We want to call main() with a String array with arguments in it.
     * At present we have two arguments, the class name and an option string.
     * Create an array to hold them.
     */
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;

    // strArray= new String[options.size() + 1];
    stringClass = env->FindClass("java/lang/String");
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    // strArray[0] = "com.android.internal.os.ZygoteInit"
    classNameStr = env->NewStringUTF(className);
    env->SetObjectArrayElement(strArray, 0, classNameStr);

    // strArray[1] = "start-system-server"缭黔;
    // strArray[2] = "--abi-list=系統(tǒng)響應(yīng)的cpu架構(gòu)類(lèi)型";
    for (size_t i = 0; i < options.size(); ++i) {
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    // slashClassName = "com/android/internal/os/ZygoteInit"
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        // 獲取 ZygoteInit.java 的 main 方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            // 執(zhí)行 ZygoteInit.java 的 main 方法芽突,從 Native 世界進(jìn)入 Java 世界
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
    // ...
}

//(4)Java 代碼是運(yùn)行在 Java 虛擬機(jī)上的试浙,而 Java 與 native 通信采用的是 JNI ,從這里就開(kāi)始進(jìn)入 Java 層的代碼:
public static void main(String argv[]) {
    try {
        // 解析參數(shù)
        boolean startSystemServer = false;
        String socketName = "zygote";
        String abiList = null;
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                startSystemServer = true;
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                abiList = argv[i].substring(ABI_LIST_ARG.length());
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                socketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else {
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }
        // 省略部分代碼...
        // 為 Zygote 注冊(cè) socket 用于通信
        registerZygoteSocket(socketName);
        // 預(yù)加載類(lèi)和資源
        preload(); 
        // 啟動(dòng) system_server
        if (startSystemServer) {
            startSystemServer(abiList, socketName);
        }
        // 進(jìn)入循環(huán)模式寞蚌,等待孵化進(jìn)程
        runSelectLoop(abiList); 
        closeServerSocket();
    } catch (MethodAndArgsCaller caller) {
        caller.run();
    } catch (RuntimeException ex) {
        closeServerSocket();
        throw ex;
    }
}

private static void registerZygoteSocket(String socketName) {
    if (sServerSocket == null) {
        int fileDesc;
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
        try {
            String env = System.getenv(fullSocketName);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            // 省略部分代碼...
        }

        try {
            FileDescriptor fd = new FileDescriptor();
            // 設(shè)置文件描述符
            fd.setInt$(fileDesc);
            // 創(chuàng)建 Socket 的本地服務(wù)端
            sServerSocket = new LocalServerSocket(fd); 
        } catch (IOException ex) {
            // 省略部分代碼...
        }
    }
}

static void preload() {
    // 預(yù)加載位于 /system/etc/preloaded-classes 文件中的類(lèi)
    preloadClasses();

    // 預(yù)加載資源田巴,包含 drawable 和 color 資源
    preloadResources();

    // 預(yù)加載 OpenGL
    preloadOpenGL();

    // 通過(guò) System.loadLibrary() 方法,
    // 預(yù)加載 "android", "compiler_rt", "jnigraphics" 這3個(gè)共享庫(kù)
    preloadSharedLibraries();

    // 預(yù)加載 文本連接符資源
    preloadTextResources();

    // 僅用于 zygote 進(jìn)程挟秤,用于內(nèi)存共享的進(jìn)程
    WebViewFactory.prepareWebViewInZygote();
}

private static boolean startSystemServer(String abiList, String socketName) throws 
                  MethodAndArgsCaller, RuntimeException {

    // 省略部分代碼...
    // 設(shè)置一些參數(shù) 
    String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007",
        "--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server",
        "--runtime-args",
        "com.android.server.SystemServer",
    };

    ZygoteConnection.Arguments parsedArgs = null;
    int pid;
    try {
        // 省略部分代碼...
        // fork 創(chuàng)建 system_server 進(jìn)程壹哺,后面會(huì)具體分析
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    //  pid == 0 代表子進(jìn)程,也就是 system_server 進(jìn)程
    if (pid == 0) {
        // 執(zhí)行初始化 system_server 進(jìn)程
        handleSystemServerProcess(parsedArgs);
    }
    return true;
}

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    // sServerSocket 是 registerZygoteSocket 中創(chuàng)建的艘刚,即 zygote 進(jìn)程管宵。保存到 fds[0]
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    while (true) {
        // 給 pollFds 設(shè)置參數(shù),fds.size 是 1 攀甚,也就是說(shuō) pollFds 里面只有 sServerSocket.getFileDescriptor() 
        StructPollfd[] pollFds = new StructPollfd[fds.size()];
        for (int i = 0; i < pollFds.length; ++i) {
            pollFds[i] = new StructPollfd();
            pollFds[i].fd = fds.get(i);
            pollFds[i].events = (short) POLLIN;
        }
        try {
            // 處理輪詢(xún)狀態(tài)箩朴,當(dāng) pollFds 有事件到來(lái)則往下執(zhí)行,否則阻塞在這里
            Os.poll(pollFds, -1);
        } catch (ErrnoException ex) {
            // 省略部分代碼...
        }
        
        for (int i = pollFds.length - 1; i >= 0; --i) {
            if (i == 0) {
                // 即fds[0]秋度,代表的是 sServerSocket炸庞,則意味著有客戶(hù)端連接請(qǐng)求;
                // 則創(chuàng)建 ZygoteConnection 對(duì)象,并添加到 fds荚斯。
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                //添加到 fds.
                fds.add(newPeer.getFileDesciptor()); 
            } else {
                // i>0埠居,則代表通過(guò) socket 接收來(lái)自對(duì)端的數(shù)據(jù)查牌,并執(zhí)行相應(yīng)操作
                boolean done = peers.get(i).runOnce();
                if (done) {
                    peers.remove(i);
                    // 處理完則從fds中移除該文件描述符
                    fds.remove(i); 
                }
            }
        }
    }
}

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;

    try {
        // 讀取 socket 客戶(hù)端發(fā)送過(guò)來(lái)的參數(shù)列表
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        // 省略部分代碼...
        return true;
    }
    // 省略部分代碼...

    try {
        // 將 binder 客戶(hù)端傳遞過(guò)來(lái)的參數(shù),解析成 Arguments 對(duì)象格式
        parsedArgs = new Arguments(args);
        // 省略部分代碼...
        // fork 創(chuàng)建一個(gè)新的進(jìn)程
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
    } catch (Exception e) {
        // 省略部分代碼...
    }

    try {
        if (pid == 0) {
            // pid == 0 執(zhí)行子進(jìn)程的邏輯
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            // 進(jìn)入子進(jìn)程流程
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
            return true;
        } else {
            // pid>0 執(zhí)行父進(jìn)程的邏輯
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

在 startReg(env) 方法中:

//(1)AndroidRuntime.cpp 中 startReg():
/*
 * Register android native functions with the VM.
 */
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
    /*
     * This hook causes all future threads created in this process to be
     * attached to the JavaVM.  (This needs to go away in favor of JNI
     * Attach calls.)
     */
    // 這里會(huì)修改函數(shù)指針為 javaCreateThreadEtc滥壕,不再是 mCanCallJava 為 false 時(shí)調(diào)用的 androidCreateRawThreadEtc
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

    ALOGV("--- registering native functions ---\n");

    /*
     * Every "register" function calls one or more things that return
     * a local reference (e.g. FindClass).  Because we haven't really
     * started the VM yet, they're all getting stored in the base frame
     * and never released.  Use Push/Pop to manage the storage.
     */
    env->PushLocalFrame(200);

    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);

    //createJavaThread("fubar", quickTest, (void*) "hello");

    return 0;
}


//(2)Threads.cpp 中 androidSetCreateThreadFunc():
void androidSetCreateThreadFunc(android_create_thread_fn func)
{
    gCreateThreadFn = func;  // 也就是說(shuō) gCreateThreadFn 為 javaCreateThreadEtc
}


//(3)AndroidRuntime.cpp 中 javaCreateThreadEtc():
/*static*/ 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*));   // javaThreadShell must free
    int result;

    if (!threadName)
        threadName = "unnamed thread";

    args[0] = (void*) entryFunction;
    args[1] = userData;
    args[2] = (void*) strdup(threadName);   // javaThreadShell must free
    // 最終調(diào)用的還是 androidCreateRawThreadEtc纸颜,但把線(xiàn)程函數(shù)(回調(diào)函數(shù))換成了 javaThreadShell
    result = androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args,
        threadName, threadPriority, threadStackSize, threadId);
    return result;
}


//(4)AndroidRuntime.cpp 中 javaThreadShell():
/*static*/ int AndroidRuntime::javaThreadShell(void* args) {
    void* start = ((void**)args)[0];
    void* userData = ((void **)args)[1];
    char* name = (char*) ((void **)args)[2];        // we own this storage
    free(args);
    JNIEnv* env;
    int result;

    /* hook us into the VM */
    //把這個(gè)線(xiàn)程 attach 到 JNI 環(huán)境中,調(diào)用了JavaVM* vm 的 vm->AttachCurrentThread()
    if (javaAttachThread(name, &env) != JNI_OK)
        return -1;

    /* start the thread running */ 
    result = (*(android_thread_func_t)start)(userData);

    /* unhook us */
    // 當(dāng)在一個(gè)線(xiàn)程里面調(diào)用AttachCurrentThread后绎橘,如果不需要用的時(shí)候一定要DetachCurrentThread胁孙,否則線(xiàn)程無(wú)法正常退出。
    javaDetachThread();  // 從JNI環(huán)境中detach出來(lái)金踪,調(diào)用了 vm->DetachCurrentThread()
    free(name);

    return result;  // 返回當(dāng)前線(xiàn)程的JNIEnv浊洞,這樣就可以調(diào)用 JNI 中的方法使用了
}
目的:
  • 在調(diào)用線(xiàn)程函數(shù)之前會(huì) attach 到 JNI 環(huán)境中牵敷,這樣胡岔,線(xiàn)程函數(shù)就可以使用JNI中的方法了。
  • 線(xiàn)程函數(shù)退出后枷餐,它會(huì)從 JNI 環(huán)境中 detach靶瘸,釋放資源。

4 _threadLoop() 與 threadLoop():

4.1 _threadLoop():前面的代碼講到了 Thread 中 mCanCallJava 取值到 zygote 啟動(dòng)時(shí)創(chuàng)建線(xiàn)程時(shí)通過(guò)修改函數(shù)指針 gCreateThreadFn毛肋,從而綁定到 JNI 環(huán)境中怨咪;現(xiàn)在回到之前的代碼,跟蹤一下傳入創(chuàng)建線(xiàn)程時(shí)的回調(diào)函數(shù) _threadLoop() 润匙;

  // 之前的代碼:
  // 從上面 3.3诗眨、 3.4 中可知,當(dāng) mCanCallJava 為 true 時(shí)孕讳,可以通過(guò)重新給 gCreateThreadFn 賦值匠楚,
  // 從而執(zhí)行不同的線(xiàn)程回調(diào)函數(shù);
  if(mCanCallJava) {  
       res = createThreadEtc(_threadLoop, this, name, priority,
                                   stack,&mThread);
    } else{
       res = androidCreateRawThreadEtc(_threadLoop, this, name, priority,
                                   stack,&mThread);
    }
int Thread::_threadLoop(void* user)
{
    Thread* const self = static_cast<Thread*>(user);  // self代表繼承Thread類(lèi)的對(duì)象

    sp<Thread> strong(self->mHoldSelf);
    wp<Thread> weak(strong);
    self->mHoldSelf.clear();

#ifdef HAVE_ANDROID_OS
    // this is very useful for debugging with gdb
    self->mTid = gettid();
#endif

    bool first = true;

    do {  // 這段代碼運(yùn)行在一個(gè)do-while循環(huán)中厂财。 即使我們的threadLoop()返回了芋簿,線(xiàn)程也不一定會(huì)退出
        bool result;
        if (first) {  // 只執(zhí)行一次
            first = false;
            self->mStatus = self->readyToRun();  // 第一次進(jìn)來(lái)調(diào)用 readyToRun(),檢查是否準(zhǔn)備完成
            result = (self->mStatus == NO_ERROR);

            if (result && !self->exitPending()) { 
                result = self->threadLoop();  // 調(diào)用派生類(lèi)的threadLoop
            }
        } else {
            result = self->threadLoop();  // 如果不是第一次執(zhí)行此循環(huán)
        }

        // 建立 mLock 的作用域
        {
    //線(xiàn)程退出的條件:
    //(1)result 為 false璃饱。如果子類(lèi)在 threadLoop 中返回 false与斤,線(xiàn)程就可以退出,這種屬于主動(dòng)退出的情況荚恶;
    //(2)mExitPending為true撩穿,這個(gè)變量可由Thread類(lèi)的requestExit函數(shù)設(shè)置,這屬于被動(dòng)退出谒撼,因?yàn)橛赏饨鐝?qiáng)制設(shè)置了退出條件食寡。
        Mutex::Autolock _l(self->mLock);
        if (result == false || self->mExitPending) {
            self->mExitPending = true;
            self->mRunning = false;
            // clear thread ID so that requestExitAndWait() does not exit if
            // called by a new thread using the same thread ID as this one.
            self->mThread = thread_id_t(-1);
            // note that interested observers blocked in requestExitAndWait are
            // awoken by broadcast, but blocked on mLock until break exits scope
            self->mThreadExitedCondition.broadcast();
            break;
        }
        }
        
        // Release our strong reference, to let a chance to the thread
        // to die a peaceful death.
        strong.clear();
        // And immediately, re-acquire a strong reference for the next loop
        strong = weak.promote();
    } while(strong != 0);
    
    return 0;
}

4.2 threadLoop():
(1)run() -> _threadLoop() -> threadLoop():如果線(xiàn)程是第一次執(zhí)行 _threadLoop()方法,會(huì)先行線(xiàn)程的readyToRun()方法嗤栓,再執(zhí)行threadLoop()冻河,否則箍邮,直接執(zhí)行threadLoop() ;
(2)threadLoop() 方法有返回值叨叙,如果 threadLoop() 返回 false 時(shí)锭弊,線(xiàn)程會(huì)做清理工作;然后退出 while 循環(huán)擂错,結(jié)束執(zhí)行味滞;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者钮呀。
  • 序言:七十年代末剑鞍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子爽醋,更是在濱河造成了極大的恐慌蚁署,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚂四,死亡現(xiàn)場(chǎng)離奇詭異光戈,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)遂赠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)久妆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人跷睦,你說(shuō)我怎么就攤上這事筷弦。” “怎么了抑诸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵烂琴,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我哼鬓,道長(zhǎng)监右,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任异希,我火速辦了婚禮健盒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘称簿。我一直安慰自己扣癣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布憨降。 她就那樣靜靜地躺著父虑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪授药。 梳的紋絲不亂的頭發(fā)上士嚎,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天呜魄,我揣著相機(jī)與錄音,去河邊找鬼莱衩。 笑死爵嗅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的笨蚁。 我是一名探鬼主播睹晒,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼括细!你這毒婦竟也來(lái)了伪很?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤奋单,失蹤者是張志新(化名)和其女友劉穎锉试,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體辱匿,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡键痛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年炫彩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了匾七。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡江兢,死狀恐怖昨忆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杉允,我是刑警寧澤邑贴,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站叔磷,受9級(jí)特大地震影響拢驾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜改基,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一繁疤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秕狰,春花似錦稠腊、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至我衬,卻和暖如春叹放,著一層夾襖步出監(jiān)牢的瞬間饰恕,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工井仰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留懂盐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓糕档,卻偏偏與公主長(zhǎng)得像莉恼,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子速那,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容