Zygote 進程與服務進程的啓動分析(Android P)

什麼是 Zygote 進程

顧明思議, Zygote 是孵化器的意思, 在 Android 系統中, 全部的應用程序進程以及用來運行系統關鍵服務的 System 進程, 都是由 Zygote 建立的, 它就是孵化器進程java

Zygote 進程何時啓動

儘管 Zygote 進程很是重要, 但它其實並非 Android 系統的第一個進程android

  • Android 系統的第一個進程爲 init 進程, 它在內核加載完成以後就會啓動起來
  • init 進程啓動時, 會讀取根目錄下的 init.zygote(xx).rc 腳本文件, 腳本中配置了 Zygote 的啓動信息
  • 所以 Zygote 進程是在 init 進程啓動過程當中啓動的

Zygote 進程如何啓動

上面瞭解到 Zygote 進程是在 init 進程讀取了 init.zygote(xx).rc 腳本文件後啓動的, 接下來咱們先分析一下, 這個腳本中配置了什麼數組

Zygote 啓動腳本

這裏選取 init.zygote32.rc 分析緩存

// system/core/rootdir/init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    ......
    socket zygote stream 660 root system
複製代碼

簡單的分析一下這個腳本文件bash

  • service zygote: 表示 Zygote 進程是以服務的形式啓動的
  • /system/bing/app_process: 表示 Zygote 進程的應用程序文件
  • 後面四個選項表示 Zygote 進程的啓動參數
    • --start-system-server: 表示在 Zygote 進程啓動過程當中, 須要啓動 System 進程
  • socket zygote stream 660 root system: 表示 Zygote 進程啓動過程當中須要建立一個名爲 zygote 的 Socket
    • 這個 Socket 的用於執行進程間的通訊
    • 訪問權限爲 660 root system, 即全部用戶均可以對它進行讀寫

好的, 咱們關注到, Zygote 的入口在 /system/bing/app_process 目錄中, 接下來分析它的啓動流程app

Zygote 啓動流程

/system/bing/app_process 目錄下的 Zygote 進程入口 main 函數在 app_main.cpp 中socket

一) app_main.cpp 的 main 函數

// frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    if (zygote) {
        // 如果 zygote 則調用了 AppRuntime 的 start 方法, AppRuntime 繼承 AndroidRuntime
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        ......
    } else {
        ......
    }
}
複製代碼

可見 app_main.cpp 中的 main 方法, 將 Zygote 的啓動分發給了 AndroidRuntime.start 中, 咱們接着往下分析函數

// frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ......
    // 1. 建立一個 Java 虛擬機
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);

    // 2. 構建用於調用 java main() 方法的字符串數組
    jclass stringClass;    // 描述 String.class
    jobjectArray strArray; // 描述 String[] 數組
    jstring classNameStr;  // 描述字符串對象
    // 建立 java 字符串數組
    stringClass = env->FindClass("java/lang/String");
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    // 從 app_main.cpp 中的 main 函數可知, className 爲 "com.android.internal.os.ZygoteInit"
    classNameStr = env->NewStringUTF(className);
    // 2.2 將 ZygoteInit 的全限定類名導入
    env->SetObjectArrayElement(strArray, 0, classNameStr);
    // 2.3 將 options 中的參數導入
    for (size_t i = 0; i < options.size(); ++i) {
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr != NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    // 3. 調用 ZygoteInti 中的 main 方法
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ......
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ......
        } else {
            // 調用了 ZygoteInti.main() 方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

    }
    ......
}
複製代碼

好的, 能夠看到 Zygote 進程的啓動調用了 AppRuntime.start 方法這個, 這個方法作了以下幾件事情oop

  • 建立 Java 虛擬機
  • 構建用於調用 java main() 方法的字符串數組
    • 將 ZygoteInit 的全限定類名導入
    • 將 options 中的參數導入
  • 調用 ZygoteInti 中的 main 方法

好的, 至此 Zygote 進程的啓動工做就轉移到了 Java 中了, 咱們看看 ZygoteInit 中作了什麼佈局

二) ZygoteInit 的 main 方法

// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public class ZygoteInit {
    
    public static void main(String argv[]) {
        ZygoteServer zygoteServer = new ZygoteServer();
        // 將 Zygote 標記爲啓動了
        ZygoteHooks.startZygoteNoThreadCreation();
        final Runnable caller;
        try { 
            // 用於判斷在 Zygote 進程啓動以後, 是否啓動 SystemService 進程
            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i < argv.length; i++) {
                // 若 argv 中包含 "start-system-server" 表示緊接着啓動 SystemService 進程
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = 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]);
                }
            }
            // 1. 註冊 Zygote 進程的 Socket, 用於跨進程創建鏈接
            zygoteServer.registerServerSocketFromEnv(socketName);
            // 2. 建立 SystemService 系統服務進程
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
                // r == null 說明當前是 Zygote 進程執行該 main 方法
                // r != null 說明當前是 SystemService 進程執行該 main 方法
                if (r != null) {
                    r.run();
                    return++;++
                }
            }
            // 3. 開啓 Zygote 進程的死循環, 其餘進程發送的進程建立請求
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            ......
        } finally {
            // 關閉
            zygoteServer.closeServerSocket();
        }
        ......
    }
    
}
複製代碼

可見 ZygoteInit 的 main 方法主要作了以下幾件事情

  • 調用 ZygoteServer.registerServerSocketFromEnv() 方法, 註冊 Zygote 進程的 Socket, 用於跨進程創建鏈接
    • 該 Socket 負責與其餘進程通訊, 如: 接收 AMS 的進程建立請求
  • 調用 ZygoteInit.forkSystemServer() 建立 SystemService 系統服務進程
  • 調用 ZygoteServer.runSelectLoop() 開啓 Zygote 進程的死循環, 其餘進程發送的進程建立請求

接下來逐一分析

1. 建立 Zygote 進程的 Socket

// frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
class ZygoteServer {

    private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
    
    /**
     * Listening socket that accepts new server connections.
     */
    private LocalServerSocket mServerSocket;
   
    void registerServerSocketFromEnv(String socketName) {
        if (mServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                // 獲取環境變量的值 ANDROID_SOCKET_zygote
                String env = System.getenv(fullSocketName);
                // 轉化爲一個文件描述符
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }

            try {
                // 建立了一個文件描述對象
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                // 以 fd 爲參, 建立了一個 LocalServerSocket 實例對象
                mServerSocket = new LocalServerSocket(fd);
            } catch (IOException ex) {
                ......
            }
        }
    }
    
}
複製代碼

好的能夠看到建立 Zygote 進程的 Socket 最終 new 了一個 LocalServerSocket, 並將它保存在 ZygoteServer 的成員變量 mServerSocket 中

2. 啓動 SystemService 進程

// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public class ZygoteInit {

    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        ......
        
        // 1. 構建系統服務進程的參數
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;
        int pid;
        try {
            // 2. 將 args 參數封裝成 Arguments對象
            parsedArgs = new ZygoteConnection.Arguments(args);
            ......
           // 3. 調用 Zygote.forkSystemServer() 孵化系統服務進程
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.runtimeFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            ......
        }
        // pid == 0 表示在新 fork 的子進程中調用(即系統服務進程)
        if (pid == 0) {
            ......
            // 處理系統服務進程的啓動操做
            return handleSystemServerProcess(parsedArgs);
        }
        // 表示在 Zygote 進程調用, 返回 null
        return null;
    }

}
複製代碼

經過 Zygote 進程啓動可知, SystemServer 進程在其啓動過程當中

  • 首先會經過 Zygote.forkSystemServer 方法孵化出來
  • 而後調用 handleSystemServerProcess 處理 SystemServer 的啓動

這個放到後面分析, 咱們先接着往下看

3. Zygote 進程的循環等待其餘進程的鏈接請求

// frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
class ZygoteServer {

    Runnable runSelectLoop(String abiList) {
        // Socket 的文件描述集合, 從上面 Zygote 的 Socket 建立可知, 在構造 Socket 實例時, 會傳入其相應的文件描述
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();   
        // 與 Zygote 創建鏈接的集合
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        // 將當前 Zygote 進程的 Socket 文件描述添加進去
        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null);
        // 開啓一個死循環
        while (true) {
            // 1. 經過 fds 持續的判斷 Socket 中是否有數據可讀
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
                // 建立一個 StructPollfd 對象, 給相關屬性賦值
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            for (int i = pollFds.length - 1; i >= 0; --i) {
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                // 2. i == 0 表示 其餘進程經過 Socket 與當前 Zygote 進程創建了鏈接 
                if (i == 0) {
                    // 2.1 建立了一個鏈接對象加入 peers 緩存
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    // 2.2 從鏈接對象中獲取文件描述符加入 fds 緩存
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    // 3. i > 0 執行子進程孵化
                    try {
                        // 獲取鏈接對象
                        ZygoteConnection connection = peers.get(i);
                        // 調用 ZygoteConnection.processOneCommand 孵化進程
                        final Runnable command = connection.processOneCommand(this);
                        if (mIsForkChild) {
                            .......
                            return command;
                        } else {
                            ......
                            // 孵化結束, 移除這個請求
                            if (connection.isClosedByPeer()) {
                                connection.closeSocket();
                                peers.remove(i);
                                fds.remove(i);
                            }
                        }
                    } catch (Exception e) {
                        ......
                    } finally {
                        ......
                    }
                }
            }
        }
    }
    
}
複製代碼

好的, 可見 ZygoteServer 中, 會開啓一個死循環

  • 經過 fds 持續的判斷 Socket 中是否有數據可讀
  • i == 0: 表示其餘進程經過 Socket 與當前 Zygote 進程創建了鏈接
    • 建立了一個鏈接對象加入 peers 緩存
    • 從鏈接對象中獲取文件描述符加入 fds 緩存
  • i > 0: 執行子進程孵化
    • 調用 ZygoteConnection.processOneCommand 孵化進程

Zygote 啓動流程圖

至此 Zygote 的進程啓動分析就結束了, 這裏將上述代碼翻譯成時序圖, 加深一下印象

image.png

系統服務進程的啓動

上面在 Zygote 啓動的過程當中, 咱們同時發起了 SystemServer 進程的啓動, 先回顧一下

// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public class ZygoteInit {

    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        ......
        
        // 1. 構建系統服務進程的參數
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;
        int pid;
        try {
            // 2. 將 args 參數封裝成 Arguments對象
            parsedArgs = new ZygoteConnection.Arguments(args);
            ......
           // 3. 調用 Zygote.forkSystemServer() 孵化系統服務進程
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.runtimeFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            ......
        }
        // pid == 0 表示在新 fork 的子進程中調用(即系統服務進程)
        if (pid == 0) {
            ......
            // 處理系統服務進程的啓動操做
            return handleSystemServerProcess(parsedArgs);
        }
        // 表示在 Zygote 進程調用, 返回 null
        return null;
    }

}
複製代碼

經過 Zygote 進程啓動可知, SystemServer 進程在其啓動過程當中

  • 首先會經過 Zygote.forkSystemServer 方法孵化出來
  • 而後調用 handleSystemServerProcess 處理 SystemServer 的啓動

孵化 SystemServer 進程

接下來就分析一下 Zygote.forkSystemServer() 這個方法

public final class Zygote {
    public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        ......
        int pid = nativeForkSystemServer(
                uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities);
        ......
        return pid;
    }
    
    native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
            
}
複製代碼

可見 Zygote 中 forkSystemServer 將啓動系統服務進程的工做轉發到了 native 層去作, 咱們繼續追蹤

// frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
namespace android {
    
    static jint com_android_internal_os_Zygote_nativeForkSystemServer(
            JNIEnv *env, jclass, uid_t uid, gid_t gid, jintArray gids,
            jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities,
            jlong effectiveCapabilities) {
        // 調用了 ForkAndSpecializeCommon, 來孵化這個系統進程
        pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                            runtime_flags, rlimits,
                                            permittedCapabilities, effectiveCapabilities,
                                            MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                            NULL, false, NULL, NULL);
        ......
        return pid;
    }
    
}

namespace {
    static pid_t ForkAndSpecializeCommon(......) {
        ......
        // fork 了一個 SystemService 進程
        pid_t pid = fork();
        ......
        return pid;
    }
}
複製代碼

能夠看到, 最終會調用一個 fork 方法孵化一個進程, 孵化的過程就不去深究了, 咱們主要關注 SystemServer 的啓動操做

處理 SystemServer 的啓動

// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public class ZygoteInit {
    
    private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
       
        if (parsedArgs.invokeWith != null) {
            ......
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                // 給這個設置類加載器
                cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
                Thread.currentThread().setContextClassLoader(cl);
            }
            // 將剩下參數傳遞給 zygoteInit 方法
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
        }
    }
    
    public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        
        // 調用了 commonInit() 設置 System 進程的時區和鍵盤佈局等信息
        RuntimeInit.commonInit();
        // 初始化了 System 進程中的 Binder 線程池
        ZygoteInit.nativeZygoteInit();
        // 回調 main 方法
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }
    
}
複製代碼

好的能夠看到 ZygoteInit.handleSystemServerProcess 最終將 SystemServer 的啓動, 轉發到了 RuntimeInit.applicationInit 中去, 咱們繼續往下分析

public class RuntimeInit {

   protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        ......
        // 將參數封裝到 Arguments 對象中
        final Arguments args = new Arguments(argv);
        // 找尋 SystemService 進程的 main 函數入口, 而且回調它
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }
    
}
複製代碼

從 ZygoteInit.forkSystemServer 中 args 的構建可知, 這個 main 函數的入口其實在 "com.android.server.SystemServer" 中, 咱們繼續追蹤下去

public final class SystemServer {

    private Context mSystemContext;
    private SystemServiceManager mSystemServiceManager;

    /**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }
    
    private void run() {
        try {
            // 準備主線程的消息循環
            Looper.prepareMainLooper();
            ......
            // 1. 建立系統服務進程的上下文
            createSystemContext();
            // 2. 建立了一個 SystemServiceManager 的實例對象
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            ......
        } finally {
            ......
        }
        
        // 3. 啓動系統服務
        try {
            // 啓動系統輔助服務
            startBootstrapServices();
            // 啓動系統核心服務
            startCoreServices();
            // 啓動系統其餘服務
            startOtherServices();
            ......
        } catch (Throwable ex) {
            ......
        } finally {
            ......
        }
        ......
        // 開啓消息循環
        Looper.loop();
    }
    
    private void createSystemContext() {
        // 1.1 調用 ActivityThread.systemMain 獲取一個 ActivityThread 實例
        ActivityThread activityThread = ActivityThread.systemMain();
        // 1.2 經過這個實例獲取 Context 對象
        mSystemContext = activityThread.getSystemContext();
        mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
        ......
    }
    
}
複製代碼

可見 SystemServer 的 main 函數, 主要作了入下操做

  • 建立了 SystemServer 的上下文
    • 調用 ActivityThread.systemMain 獲取一個 ActivityThread 實例
    • 經過 ActivityThread 實例獲取 Context 對象
  • 建立了 SystemServiceManager 對象, 對於這個對象, 咱們都很是的熟悉, 它就是系統的服務管理的 Binder 實體對象
  • 啓動系統服務: AMS, WMS, PMS.....

至此這個系統服務進程便啓動完成了

總結

Zygote

從 ZygoteInit.main 中能夠很清晰的看到 Zygote 進程的職責, 這裏總結一下

  • Zygote 是在 init 進程啓動過程當中啓動的
  • Zygote 的啓動分爲以下幾步
    • 調用 app_main.cpp 的 main 函數
    • 調用 ZygoteInit 的 main 方法
  • 在 Zygote 啓動過程當中作了以下三件事情
    • 建立 Zygote 進程的 Socket, 用於和其餘進程創建鏈接, 進行跨進程通訊
    • 孵化 SystemService 進程
    • 開啓死循環, 持續監聽 Socket 中是否有進程孵化請求

SystemServer

從 SystemServer 對象的 run 方法中能夠很清晰的瞭解到它啓動時的工做

  • 建立了 SystemServer 的上下文
    • 調用 ActivityThread.systemMain 獲取一個 ActivityThread 實例
      • 須要注意的是, 這裏並不是跨進程調用, 而是在當前進程調用了靜態方法
    • 經過 ActivityThread 實例獲取 Context 對象
  • 建立了 SystemServiceManager 對象, 對於這個對象, 咱們都很是的熟悉, 它就是系統的服務管理的 Binder 實體對象
  • 啓動系統服務: AMS, WMS, PMS.....
相關文章
相關標籤/搜索