理解Android進程創建流程

櫻桃大丸子 8年前發布 | 67K 次閱讀 移動開發 Android開發 Android

基于Android 6.0的源碼剖析, 分析Android進程是如何一步步創建的,本文涉及到的源碼:

/frameworks/base/core/java/android/os/Process.java
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

/frameworks/base/core/java/com/android/internal/os/Zygote.java /frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

/frameworks/base/cmds/app_process/App_main.cpp (內含AppRuntime類) /frameworks/base/core/jni/AndroidRuntime.cpp

/libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java /art/runtime/native/dalvik_system_ZygoteHooks.cc /art/runtime/Runtime.cc /art/runtime/Thread.cc /art/runtime/signal_catcher.cc </code></pre>

概述

本文要介紹的是進程的創建,先簡單說說進程與線程的區別。

進程:每個App在啟動前必須先創建一個進程,該進程是由Zygote fork出來的,進程具有獨立的資源空間,用于承載App上運行的各種Activity/Service等組件。進程對于上層應用來說是完全透明的,這也是google有意為之,讓App程序都是運行在Android Runtime。大多數情況一個App就運行在一個進程中,除非在AndroidManifest.xml中配置Android:process屬性,或通過native代碼fork進程。

線程:線程對應用開發者來說非常熟悉,比如每次new Thread().start()都會創建一個新的線程,該線程并沒有自己獨立的地址空間,而是與其所在進程之間資源共享。從Linux角度來說進程與線程都是一個task_struct結構體,除了是否共享資源外,并沒有其他本質的區別。

對于大多數的應用開發者來說創建線程比較熟悉,而對于創建進程并沒有太多的概念。對于系統工程師或者高級開發者,還是有很必要了解Android系統是如何一步步地創建出一個進程的。先來看一張進程創建過程的簡要圖:

理解Android進程創建流程

圖解:

  1. App發起進程:當從桌面啟動應用,則發起進程便是Launcher所在進程;當從某App內啟動遠程進程,則發送進程便是該App所在進程。發起進程先通過binder發送消息給system_server進程;
  2. system_server進程:調用Process.start()方法,通過socket向zygote進程發送創建新進程的請求;
  3. zygote進程:在執行ZygoteInit.main()后便進入runSelectLoop()循環體內,當有客戶端連接時便會執行ZygoteConnection.runOnce()方法,再經過層層調用后fork出新的應用進程;
  4. 新進程:執行handleChildProc方法,最后調用ActivityThread.main()方法。

可能朋友不是很了解system_server進程和Zygote進程,下面簡要說說:

  • system_server進程:是用于管理整個Java framework層,包含ActivityManager,PowerManager等各種系統服務;
  • Zygote進程:是Android系統的首個Java進程,Zygote是所有Java進程的父進程,包括 system_server進程以及所有的App進程都是Zygote的子進程,注意這里說的是子進程,而非子線程。

如果想更進一步了解system_server進程和Zygote進程在整個Android系統所處的地位,可查看我的另一個文章Android系統-開篇

接下來從Android 6.0源碼,展開講解進程創建是一個怎樣的過程。

1. Process.start

public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] zygoteArgs) {
    try {
         //【見流程2】
        return startViaZygote(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
        throw new RuntimeException("");
    }
}

2. startViaZygote

[-> Process.java]

private static ProcessStartResult startViaZygote(final String processClass,
                              final String niceName,
                              final int uid, final int gid,
                              final int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] extraArgs)
                              throws ZygoteStartFailedEx {
    synchronized(Process.class) {
        ArrayList<String> argsForZygote = new ArrayList<String>();

    argsForZygote.add("--runtime-args");
    argsForZygote.add("--setuid=" + uid);
    argsForZygote.add("--setgid=" + gid);
    argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

    if (niceName != null) {
        argsForZygote.add("--nice-name=" + niceName);
    }
    if (appDataDir != null) {
        argsForZygote.add("--app-data-dir=" + appDataDir);
    }
    argsForZygote.add(processClass);

    if (extraArgs != null) {
        for (String arg : extraArgs) {
            argsForZygote.add(arg);
        }
    }
     //【見流程3】
    return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}

} </code></pre>

該過程主要工作是生成argsForZygote數組,該數組保存了進程的uid、gid、groups、target-sdk、nice-name等一系列的參數。

3. zygoteSendArgsAndGetResult

[-> Process.java]

Step 3-1. openZygoteSocketIfNeeded

private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        try {
            primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
        }
    }

if (primaryZygoteState.matches(abi)) {
    return primaryZygoteState;
}

//當主zygote沒能匹配成功,則嘗試第二個zygote
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
    try {
    secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
    } catch (IOException ioe) {
        throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
    }
}

if (secondaryZygoteState.matches(abi)) {
    return secondaryZygoteState;
}

throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);

} </code></pre>

openZygoteSocketIfNeeded(abi)方法是根據當前的abi來選擇與zygote還是zygote64來進行通信。

Step 3-2. zygoteSendArgsAndGetResult

private static ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, ArrayList<String> args)
        throws ZygoteStartFailedEx {
    try {
        //
        final BufferedWriter writer = zygoteState.writer;
        final DataInputStream inputStream = zygoteState.inputStream;

    writer.write(Integer.toString(args.size()));
    writer.newLine();

    int sz = args.size();
    for (int i = 0; i < sz; i++) {
        String arg = args.get(i);
        if (arg.indexOf('\n') >= 0) {
            throw new ZygoteStartFailedEx(
                    "embedded newlines not allowed");
        }
        writer.write(arg);
        writer.newLine();
    }

    writer.flush();

    ProcessStartResult result = new ProcessStartResult();
    //等待socket服務端(即zygote)返回新創建的進程pid;
    //對于等待時長問題,Google正在考慮此處是否應該有一個timeout,但目前是沒有的。
    result.pid = inputStream.readInt();
    if (result.pid < 0) {
        throw new ZygoteStartFailedEx("fork() failed");
    }
    result.usingWrapper = inputStream.readBoolean();
    return result;
} catch (IOException ex) {
    zygoteState.close();
    throw new ZygoteStartFailedEx(ex);
}

} </code></pre>

這個方法的主要功能是通過socket通道向Zygote進程發送一個參數列表,然后進入阻塞等待狀態,直到遠端的socket服務端發送回來新創建的進程pid才返回。

既然system_server進程通過socket向Zygote進程發送消息,這是便會喚醒Zygote進程,來響應socket客戶端的請求(即system_server端),接下來的操作便是在Zygote進程中執行。

4. runSelectLoop

[–>ZygoteInit.java]

public static void main(String argv[]) {
    try {
        runSelectLoop(abiList);
        ....
    } catch (MethodAndArgsCaller caller) {
        caller.run(); //【見流程13】
    } catch (RuntimeException ex) {
        closeServerSocket();
        throw ex;
    }
}

后續會講到runSelectLoop()方法會拋出異常MethodAndArgsCaller,從而進入caller.run()方法。

[-> ZygoteInit.java]

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ...

ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
while (true) {
    for (int i = pollFds.length - 1; i >= 0; --i) {
        //采用I/O多路復用機制,當客戶端發出連接請求或者數據處理請求時,跳過continue,執行后面的代碼
        if ((pollFds[i].revents & POLLIN) == 0) {
            continue;
        }
        if (i == 0) {
            //創建客戶端連接
            ZygoteConnection newPeer = acceptCommandPeer(abiList);
            peers.add(newPeer);
            fds.add(newPeer.getFileDesciptor());
        } else {
            //處理客戶端數據事務 【見流程5】
            boolean done = peers.get(i).runOnce();
            if (done) {
                peers.remove(i);
                fds.remove(i);
            }
        }
    }
}

} </code></pre>

沒有連接請求時會進入休眠狀態,當有創建新進程的連接請求時,喚醒Zygote進程,創建Socket通道ZygoteConnection,然后執行ZygoteConnection的runOnce()方法。

5. runOnce

[-> ZygoteConnection.java]

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;

try {
    //讀取socket客戶端發送過來的參數列表
    args = readArgumentList(); 
    descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
    closeSocket();
    return true;
}

PrintStream newStderr = null;
if (descriptors != null && descriptors.length >= 3) {
    newStderr = new PrintStream(new FileOutputStream(descriptors[2]));
}

int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;

try {
    //將binder客戶端傳遞過來的參數,解析成Arguments對象格式
    parsedArgs = new Arguments(args);
    ...

    int [] fdsToClose = { -1, -1 };

    FileDescriptor fd = mSocket.getFileDescriptor();
    if (fd != null) {
        fdsToClose[0] = fd.getInt$();
    }

    fd = ZygoteInit.getServerSocketFileDescriptor();
    if (fd != null) {
        fdsToClose[1] = fd.getInt$();
    }
    fd = null;
    【見流程6】
    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) {
        //子進程執行
        IoUtils.closeQuietly(serverPipeFd);
        serverPipeFd = null;
        【見流程7】
        handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

        // 不應到達此處,子進程預期的是拋出異常ZygoteInit.MethodAndArgsCaller或者執行exec().
        return true;
    } else {
        //父進程執行
        IoUtils.closeQuietly(childPipeFd);
        childPipeFd = null;
        return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
    }
} finally {
    IoUtils.closeQuietly(childPipeFd);
    IoUtils.closeQuietly(serverPipeFd);
}

} </code></pre>

6. forkAndSpecialize

[-> Zygote.java]

public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
      int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
      String instructionSet, String appDataDir) {
    VM_HOOKS.preFork(); 【見流程6-1】
    int pid = nativeForkAndSpecialize(
              uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
              instructionSet, appDataDir); 【見流程6-2】
    ...
    VM_HOOKS.postForkCommon(); 【見流程6-3】
    return pid;
}

這里VM_HOOKS是做什么的呢?

先說說Zygote進程,如下圖: 理解Android進程創建流程

從圖中可知Zygote進程有4個子線程,分別是ReferenceQueueDaemonFinalizerDaemonFinalizerWatchdogDaemonHeapTaskDaemon,此處稱為為Zygote的4個Daemon子線程。圖中線程名顯示的并不完整是由于底層的進程結構體task_struct是由長度為16的char型數組保存,超過15個字符便會截斷。

可能有人會問zygote64進程不是還有system_server,com.android.phone等子線程,怎么會只有4個呢?那是因為這些并不是Zygote子線程,而是Zygote的子進程。在圖中用紅色圈起來的是進程的VSIZE,virtual size),代表的是進程虛擬地址空間大小。線程與進程的最為本質的區別便是是否共享內存空間,圖中VSIZE和Zygote進程相同的才是Zygote的子線程,否則就是Zygote的子進程。

6-1 preFork

[-> ZygoteHooks.java]

 public void preFork() {
    Daemons.stop(); //停止4個Daemon子線程【見流程6-1-1】
    waitUntilAllThreadsStopped(); //等待所有子線程結束【見流程6-1-2】
    token = nativePreFork(); //完成gc堆的初始化工作【見流程6-1-3】
}

Step 6-1-1. Daemons.stop

public static void stop() {
    HeapTaskDaemon.INSTANCE.stop(); //Java堆整理線程
    ReferenceQueueDaemon.INSTANCE.stop(); //引用隊列線程
    FinalizerDaemon.INSTANCE.stop(); //析構線程
    FinalizerWatchdogDaemon.INSTANCE.stop(); //析構監控線程
}

Step 6-1-2. waitUntilAllThreadsStopped

private static void waitUntilAllThreadsStopped() {
    File tasks = new File("/proc/self/task");
    // 當/proc中線程數大于1,就出讓CPU直到只有一個線程,才退出循環
    while (tasks.list().length > 1) {
        Thread.yield(); 
    }
}

Step 6-1-3. nativePreFork

nativePreFork通過JNI最終調用的是dalvik_system_ZygoteHooks.cc中的ZygoteHooks_nativePreFork()方法,如下:

static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) {
    Runtime* runtime = Runtime::Current();
    CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";
    runtime->PreZygoteFork(); 【見流程6-1-3-1】
    if (Trace::GetMethodTracingMode() != TracingMode::kTracingInactive) {
      Trace::Pause();
    }
    //將線程轉換為long型并保存到token,該過程是非安全的
    return reinterpret_cast<jlong>(ThreadForEnv(env));
}

Step 6-1-3-1. PreZygoteFork

void Runtime::PreZygoteFork() {
    // 堆的初始化工作。這里就不繼續再往下追了,等后續有空專門謝謝關于art虛擬機
    heap_->PreZygoteFork(); 
}

VM_HOOKS.preFork()的主要功能便是停止Zygote的4個Daemon子線程的運行,等待并確保Zygote是單線程(用于提升fork效率),并等待這些線程的停止,初始化gc堆的工作。

6-2 nativeForkAndSpecialize

nativeForkAndSpecialize()通過JNI最終調用的是com_android_internal_os_Zygote.cpp中的 com_android_internal_os_Zygote_nativeForkAndSpecialize()方法,如下:

[-> com_android_internal_os_Zygote.cpp]

static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
    JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
    jint debug_flags, jobjectArray rlimits,
    jint mount_external, jstring se_info, jstring se_name,
    jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
    // 將CAP_WAKE_ALARM賦予藍牙進程
    jlong capabilities = 0;
    if (uid == AID_BLUETOOTH) {
        capabilities |= (1LL << CAP_WAKE_ALARM);
    }
    【見流程6-2-1】
    return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
            rlimits, capabilities, capabilities, mount_external, se_info,
            se_name, false, fdsToClose, instructionSet, appDataDir);
}

Step 6-2-1.ForkAndSpecializeCommon

[-> com_android_internal_os_Zygote.cpp]

static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                     jint debug_flags, jobjectArray javaRlimits,
                                     jlong permittedCapabilities, jlong effectiveCapabilities,
                                     jint mount_external,
                                     jstring java_se_info, jstring java_se_name,
                                     bool is_system_server, jintArray fdsToClose,
                                     jstring instructionSet, jstring dataDir) {
  SetSigChldHandler(); //設置子進程的signal信號處理函數
  pid_t pid = fork(); //fork子進程 【見流程6-2-1-1】
  if (pid == 0) {
    //進入子進程
    DetachDescriptors(env, fdsToClose); //關閉并清除文件描述符

if (!is_system_server) {
    //對于非system_server子進程,則創建進程組
    int rc = createProcessGroup(uid, getpid());
}
SetGids(env, javaGids); //設置設置group
SetRLimits(env, javaRlimits); //設置資源limit

int rc = setresgid(gid, gid, gid);
rc = setresuid(uid, uid, uid);

SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
SetSchedulerPolicy(env); //設置調度策略

 //selinux上下文
rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);

if (se_info_c_str == NULL && is_system_server) {
  se_name_c_str = "system_server";
}
if (se_info_c_str != NULL) {
  SetThreadName(se_name_c_str); //設置線程名為system_server,方便調試
}
UnsetSigChldHandler(); //設置子進程的signal信號處理函數為默認函數
//等價于調用zygote.callPostForkChildHooks() 【見流程6-2-2-1】
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                          is_system_server ? NULL : instructionSet);
...

} else if (pid > 0) { //進入父進程,即Zygote進程 } return pid; } </code></pre>

Step 6-2-1-1. fork()

fork()采用copy on write技術,這是linux創建進程的標準方法,調用一次,返回兩次,返回值有3種類型。

  • 父進程中,fork返回新創建的子進程的pid;
  • 子進程中,fork返回0;
  • 當出現錯誤時,fork返回負數。(當進程數超過上限或者系統內存不足時會出錯)

fork()的主要工作是尋找空閑的進程號pid,然后從父進程拷貝進程信息,例如數據段和代碼段空間等,當然也包含拷貝fork()代碼之后的要執行的代碼到新的進程。

下面,說說zygote的fork()過程:

理解Android進程創建流程

Zygote進程是所有Android進程的母體,包括system_server進程以及App進程都是由Zygote進程孵化而來。zygote利用fork()方法生成新進程,對于新進程A復用Zygote進程本身的資源,再加上新進程A相關的資源,構成新的應用進程A。何為copy on write(寫時復制)?當進程A執行修改某個內存數據時(這便是on write時機),才發生缺頁中斷,從而分配新的內存地址空間(這便是copy操作),對于copy on write是基于內存頁,而不是基于進程的。關于Zygote進程的libc、vm、preloaded classes、preloaded resources是如何生成的,可查看另一個文章Android系統啟動-zygote篇

Step 6-2-2-1. Zygote.callPostForkChildHooks

private static void callPostForkChildHooks(int debugFlags, boolean isSystemServer,
        String instructionSet) {
    VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
}

public void postForkChild(int debugFlags, String instructionSet) { 【見流程6-2-2-1-1】 nativePostForkChild(token, debugFlags, instructionSet); Math.setRandomSeedInternal(System.currentTimeMillis()); } </code></pre>

在這里,設置了新進程Random隨機數種子為當前系統時間,也就是在進程創建的那一刻就決定了未來隨機數的情況,也就是偽隨機。

Step 6-2-2-1-1. nativePostForkChild

最終調用dalvik_system_ZygoteHooks的ZygoteHooks_nativePostForkChild

[-> dalvik_system_ZygoteHooks.cc]

static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags,
                                            jstring instruction_set) {
    Thread* thread = reinterpret_cast<Thread*>(token);
    //設置新進程的主線程id
    thread->InitAfterFork();
    ..
    if (instruction_set != nullptr) {
      ScopedUtfChars isa_string(env, instruction_set);
      InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
      Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
      if (isa != kNone && isa != kRuntimeISA) {
        action = Runtime::NativeBridgeAction::kInitialize;
      }
      【見流程6-2-2-1-1-1】
      Runtime::Current()->DidForkFromZygote(env, action, isa_string.c_str());
    } else {
      Runtime::Current()->DidForkFromZygote(env, Runtime::NativeBridgeAction::kUnload, nullptr);
    }
}

Step 6-2-2-1-1-1. DidForkFromZygote

[-> Runtime.cc]

void Runtime::DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa) {
  is_zygote_ = false;
  if (is_native_bridge_loaded_) {
    switch (action) {
      case NativeBridgeAction::kUnload:
        UnloadNativeBridge(); //卸載用于跨平臺的橋連庫
        is_native_bridge_loaded_ = false;
        break;
      case NativeBridgeAction::kInitialize:
        InitializeNativeBridge(env, isa);//初始化用于跨平臺的橋連庫
        break;
    }
  }
  //創建Java堆處理的線程池
  heap_->CreateThreadPool();
  //重置gc性能數據,以保證進程在創建之前的GCs不會計算到當前app上。
  heap_->ResetGcPerformanceInfo();
  if (jit_.get() == nullptr && jit_options_->UseJIT()) {
    //當flag被設置,并且還沒有創建JIT時,則創建JIT
    CreateJit();
  }
  //設置信號處理函數
  StartSignalCatcher();
  //啟動JDWP線程,當命令debuger的flags指定"suspend=y"時,則暫停runtime
  Dbg::StartJdwp();
}

關于信號處理過程,其代碼位于signal_catcher.cc文件中,后續會單獨講解。

6-3 postForkCommon

[-> ZygoteHooks.java]

public void postForkCommon() {
    Daemons.start(); 【見流程6-3-1】
}

Step 6-3-1. Daemons.start

public static void start() {
    ReferenceQueueDaemon.INSTANCE.start();
    FinalizerDaemon.INSTANCE.start();
    FinalizerWatchdogDaemon.INSTANCE.start();
    HeapTaskDaemon.INSTANCE.start();
}

VM_HOOKS.postForkCommon的主要功能是在fork新進程后,啟動Zygote的4個Daemon線程,java堆整理,引用隊列,以及析構線程。

forkAndSpecialize小結

調用關系鏈:

Zygote.forkAndSpecialize
    ZygoteHooks.preFork
        Daemons.stop
        ZygoteHooks.nativePreFork
            dalvik_system_ZygoteHooks.ZygoteHooks_nativePreFork
                Runtime::PreZygoteFork
                    heap_->PreZygoteFork()
    Zygote.nativeForkAndSpecialize
        com_android_internal_os_Zygote.ForkAndSpecializeCommon
            fork()
            Zygote.callPostForkChildHooks
                ZygoteHooks.postForkChild
                    dalvik_system_ZygoteHooks.nativePostForkChild
                        Runtime::DidForkFromZygote
    ZygoteHooks.postForkCommon
        Daemons.start

時序圖:

點擊查看大圖

理解Android進程創建流程

到此App進程已完成了創建的所有工作,接下來開始新創建的App進程的工作。在前面ZygoteConnection.runOnce方法中,zygote進程執行完forkAndSpecialize()后,新創建的App進程便進入handleChildProc()方法,下面的操作運行在App進程。

7. handleChildProc

[-> ZygoteConnection.java]

private void handleChildProc(Arguments parsedArgs,
        FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
        throws ZygoteInit.MethodAndArgsCaller {

//關閉Zygote的socket兩端的連接
closeSocket();
ZygoteInit.closeServerSocket();

if (descriptors != null) {
    try {
        Os.dup2(descriptors[0], STDIN_FILENO);
        Os.dup2(descriptors[1], STDOUT_FILENO);
        Os.dup2(descriptors[2], STDERR_FILENO);
        for (FileDescriptor fd: descriptors) {
            IoUtils.closeQuietly(fd);
        }
        newStderr = System.err;
    } catch (ErrnoException ex) {
        Log.e(TAG, "Error reopening stdio", ex);
    }
}

if (parsedArgs.niceName != null) {
    //設置進程名
    Process.setArgV0(parsedArgs.niceName);
}

if (parsedArgs.invokeWith != null) {
    //據說這是用于檢測進程內存泄露或溢出時場景而設計,后續還需要進一步分析。
    WrapperInit.execApplication(parsedArgs.invokeWith,
            parsedArgs.niceName, parsedArgs.targetSdkVersion,
            VMRuntime.getCurrentInstructionSet(),
            pipeFd, parsedArgs.remainingArgs);
} else {
    //執行目標類的main()方法 【見流程8】
    RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
            parsedArgs.remainingArgs, null);
}

} </code></pre>

8. zygoteInit

[–>RuntimeInit.java]

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
redirectLogStreams(); //重定向log輸出

commonInit(); // 通用的一些初始化【見流程9】
nativeZygoteInit(); // zygote初始化 【見流程10】
applicationInit(targetSdkVersion, argv, classLoader); // 應用初始化【見流程11】

} </code></pre>

9. commonInit

[–>RuntimeInit.java]

private static final void commonInit() {
    // 設置默認的未捕捉異常處理方法
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());

// 設置市區,中國時區為"Asia/Shanghai"
TimezoneGetter.setInstance(new TimezoneGetter() {
    @Override
    public String getId() {
        return SystemProperties.get("persist.sys.timezone");
    }
});
TimeZone.setDefault(null);

//重置log配置
LogManager.getLogManager().reset(); 
new AndroidConfig(); 

// 設置默認的HTTP User-agent格式,用于 HttpURLConnection。
String userAgent = getDefaultUserAgent();
System.setProperty("http.agent", userAgent);

// 設置socket的tag,用于網絡流量統計
NetworkManagementSocketTagger.install();

} </code></pre>

默認的HTTP User-agent格式,例如:

 "Dalvik/1.1.0 (Linux; U; Android 6.0.1;LenovoX3c70 Build/LMY47V)".

10. nativeZygoteInit

nativeZygoteInit()方法在AndroidRuntime.cpp中,進行了jni映射,對應下面的方法。

[–>AndroidRuntime.cpp]

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit(); //此處的gCurRuntime為AppRuntime,是在AndroidRuntime.cpp中定義的
}

[–>app_main.cpp]

virtual void onZygoteInit()
{
    sp<ProcessState> proc = ProcessState::self();
    proc->startThreadPool(); //啟動新binder線程
}

ProcessState::self()是單例模式,主要工作是調用open()打開/dev/binder驅動設備,再利用mmap()映射內核的地址空間,將Binder驅動的fd賦值ProcessState對象中的變量mDriverFD,用于交互操作。startThreadPool()是創建一個新的binder線程,不斷進行talkWithDriver(),在binder系列文章中的注冊服務(addService)詳細這兩個方法的執行原理。

11. applicationInit

[–>RuntimeInit.java]

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    //true代表應用程序退出時不調用AppRuntime.onExit(),否則會在退出前調用
    nativeSetExitWithoutCleanup(true);

//設置虛擬機的內存利用率參數值為0.75
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

final Arguments args;
try {
    args = new Arguments(argv); //解析參數
} catch (IllegalArgumentException ex) {
    Slog.e(TAG, ex.getMessage());
    return;
}

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

//調用startClass的static方法 main() 【見流程12】
invokeStaticMain(args.startClass, args.startArgs, classLoader);

} </code></pre>

此處args.startClass為”android.app.ActivityThread”。

12. invokeStaticMain

[–>RuntimeInit.java]

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;

try {
    cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
    throw new RuntimeException(
            "Missing class when invoking static main " + className, ex);
}

Method m;
try {
    m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
    throw new RuntimeException( "Missing static main on " + className, ex);
} catch (SecurityException ex) {
    throw new RuntimeException(
            "Problem getting static main on " + className, ex);
}

int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
    throw new RuntimeException(
            "Main method is not public and static on " + className);
}

//通過拋出異常,回到ZygoteInit.main()。這樣做好處是能清空棧幀,提高棧幀利用率。【見流程13】
throw new ZygoteInit.MethodAndArgsCaller(m, argv);

} </code></pre>

invokeStaticMain()方法中拋出的異常MethodAndArgsCaller,根據前面的【流程4】中可知,下一步進入caller.run()方法。

13. MethodAndArgsCaller

[–>ZygoteInit.java]

public static class MethodAndArgsCaller extends Exception
        implements Runnable {

public void run() {
    try {
        //根據傳遞過來的參數,可知此處通過反射機制調用的是ActivityThread.main()方法
        mMethod.invoke(null, new Object[] { mArgs }); 
    } catch (IllegalAccessException ex) {
        throw new RuntimeException(ex);
    } catch (InvocationTargetException ex) {
        Throwable cause = ex.getCause();
        if (cause instanceof RuntimeException) {
            throw (RuntimeException) cause;
        } else if (cause instanceof Error) {
            throw (Error) cause;
        }
        throw new RuntimeException(ex);
    }
}

} </code></pre>

到此,總算是進入到了ActivityThread類的main()方法。

總結

當App第一次啟動時或者啟動遠程Service,即AndroidManifest.xml文件中定義了process:remote屬性時,都需要創建進程。比如當用戶點擊桌面的某個App圖標,桌面本身是一個app(即Launcher App),那么Launcher所在進程便是這次創建新進程的發起進程,該通過binder發送消息給system_server進程,該進程承載著整個java framework的核心服務。system_server進程從Process.start開始,執行創建進程,流程圖(以進程的視角)如下:

理解Android進程創建流程

上圖中,system_server進程通過socket IPC通道向zygote進程通信,zygote在fork出新進程后由于fork調用一次,返回兩次,即在zygote進程中調用一次,在zygote進程和子進程中各返回一次,從而能進入子進程來執行代碼。該調用流程圖的過程:

  1. system_server進程即流程1~3):通過Process.start()方法發起創建新進程請求,會先收集各種新進程uid、gid、nice-name等相關的參數,然后通過socket通道發送給zygote進程;
  2. zygote進程即流程4~6):接收到system_server進程發送過來的參數后封裝成Arguments對象,圖中綠色框forkAndSpecialize()方法是進程創建過程中最為核心的一個環節(詳見流程6),其具體工作是依次執行下面的3個方法:
    • preFork():先停止Zygote的4個Daemon子線程(java堆內存整理線程、對線下引用隊列線程、析構線程以及監控線程)的運行以及初始化gc堆;
    • nativeForkAndSpecialize():調用linux的fork()出新進程,創建Java堆處理的線程池,重置gc性能數據,設置進程的信號處理函數,啟動JDWP線程;
    • postForkCommon():在啟動之前被暫停的4個Daemon子線程。
  3. 新進程即流程7~13):進入handleChildProc()方法,設置進程名,打開binder驅動,啟動新的binder線程;然后設置art虛擬機參數,再反射調用目標類的main()方法,即Activity.main()方法。

再之后的流程,如果是startActivity則將要進入Activity的onCreate/onStart/onResume等生命周期;如果是startService則將要進入Service的onCreate等生命周期。

來源:http://gityuan.com/2016/03/26/app-process-create/

 本文由用戶 櫻桃大丸子 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!