Android 源碼 運行 zygote service

在《Android 源碼 啓動 zygote service 流程分析》我們已經知道 zygote service 是在 Init 進程的 service_start 方法啓動的。接下來就會運行 /system/bin/app_process,代表 zygote 運行。

在前一節的分析已知 dynamic_args 參數爲 NULL,所以最終會調用 execve 運行子進程。

system/core/init/init.cpp

void service_start(struct service *svc, const char *dynamic_args)
{
    ......
    pid_t pid = fork();
    if (pid == 0) {
        ......
        if (!dynamic_args) {
            ......
        } else {
            char *arg_ptrs[INIT_PARSER_MAXARGS+1];
            int arg_idx = svc->nargs;
            char *tmp = strdup(dynamic_args);
            char *next = tmp;
            char *bword;

            /* 複製靜態參數 */
            memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));

            while((bword = strsep(&next, " "))) {
                arg_ptrs[arg_idx++] = bword;
                if (arg_idx == INIT_PARSER_MAXARGS)
                    break;
            }
            arg_ptrs[arg_idx] = NULL;
            execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
        }
        _exit(127);
    }
    ......
}

execve 定義在頭文件 unistd.h 中。

int execve(const char * filename,char * const argv[ ],char * const envp[ ]);

在父進程中 fork 一個子進程,在子進程中調用 exec 函數啓動新的程序。exec 函數一共有六個,其中 execve 爲內核級系統調用,其他(execl、execle、execlp、execv 和 execvp)都是調用 execve 的庫函數。

execve() 用來執行參數 filename 字符串所代表的文件路徑,第二個參數是利用指針數組來傳遞給執行文件,並且需要以空指針(NULL)結束,最後一個參數則爲傳遞給執行文件的新環境變量數組。

如果執行成功則函數不會返回,執行失敗則直接返回 -1,失敗原因存於 errno 中。

接下來運行程序:out/target/product/hammerhead/system/bin/app_process,它是 app_main.cpp 編譯而來的二進制產物。

在 app_main main 方法中創建了運行時 AppRuntime,接着準備了運行時參數,最後調用了其 start 方法啓動 ZygoteInit Java 類。

frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
    ......
    // 創建 AppRuntime
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // 處理命令行參數
    // 忽略 argv[0]
    argc--;
    argv++;

    int i;
    for (i = 0; i < argc; i++) {
        if (argv[i][0] != '-') {
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }
        runtime.addOption(strdup(argv[i]));
    }

    // 解析運行時參數
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // 跳過未使用的“父目錄”參數
    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;
        }
    }

    Vector<String8> args;
    if (!className.isEmpty()) {
        ......
    } else {
        // 處於 zygote 模式
        maybeCreateDalvikCache();

        if (startSystemServer) {
            args.add(String8("start-system-server"));
        }

        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                ABI_LIST_PROPERTY);
            return 11;
        }

        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);
        args.add(abiFlag);

        // 將所有剩餘參數傳遞給 zygote main() 方法
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }

    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        ......
    } else {
        ......
    }
}

創建 AppRuntime 對象,將參數傳遞到父類構造器 AndroidRuntime 進行初始化。

frameworks/base/cmds/app_process/app_main.cpp

namespace android {
......
class AppRuntime : public AndroidRuntime
{
public:
    AppRuntime(char* argBlockStart, const size_t argBlockLength)
        : AndroidRuntime(argBlockStart, argBlockLength)
        , mClass(NULL)
    {
    }
    ......
};

}

AndroidRuntime 類定義在頭文件 android_runtime/AndroidRuntime.h 中,最後調用 start 方法啓動 com.android.internal.os.ZygoteInit。

frameworks/base/include/android_runtime/AndroidRuntime.h

namespace android {

class AndroidRuntime
{
public:
    AndroidRuntime(char* argBlockStart, size_t argBlockSize);
    ......
    void start(const char *classname, const Vector<String8>& options, bool zygote);
    .....
}

下面是其實現,位於 AndroidRuntime.cpp 中。

start 方法的作用:

啓動Android運行時。這涉及啓動虛擬機並在 “className” 命名的類中調用 “static void main(String [] args)” 方法。向 main 函數傳遞兩個參數,即類名和指定的選項字符串。

frameworks/base/core/jni/AndroidRuntime.cpp

AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
        mExitWithoutCleanup(false),
        mArgBlockStart(argBlockStart),
        mArgBlockLength(argBlockLength)
{
    SkGraphics::Init();
    // 預分配足夠的空間來容納大量選項。
    mOptions.setCapacity(20);

    assert(gCurRuntime == NULL);        // one per process
    gCurRuntime = this;
}
......
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ......
    /* 啓動虛擬機 */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     * 註冊 android 函數
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    /*
     * 使用包含參數的 String 數組調用 main()。目前,有兩個參數,即類名和選項字符串。
     * 創建一個數組來保存它們。
     */
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;

    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);

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

    /*
     * 啓動 VM。該線程成爲 VM 的主線程,直到 VM 退出後才返回。
     */
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        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 {
            // jni 函數啓動 ZygoteInit 靜態 main 方法。
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
    free(slashClassName);

    ALOGD("Shutting down VM\n");
    if (mJavaVM->DetachCurrentThread() != JNI_OK)
        ALOGW("Warning: unable to detach main thread\n");
    if (mJavaVM->DestroyJavaVM() != 0)
        ALOGW("Warning: VM did not shut down cleanly\n");
}

接下來就開始運行 zygote service,進入了 Java 的世界!在主函數中 zygote 服務實現了本地 socket 服務端監聽,同時也啓動了 system server 進程。這是重中之重的工作!

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {
    ......
    public static void main(String argv[]) {
        try {
            RuntimeInit.enableDdms();
            // 分析器相關:開始
            SamplingProfilerIntegration.start();

            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]);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }
            // 註冊 socket 服務端
            registerZygoteSocket(socketName);
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            // 加載資源
            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            // 分析器相關:結束
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // 啓動後進行初始 gc 清理
            gcAndFinalize();

            // 禁用跟蹤,以便 fork 的進程不會從 Zygote 繼承過時的跟蹤標記
            Trace.setTracingEnabled(false);

            if (startSystemServer) {
                // 啓動 SystemServer
                startSystemServer(abiList, socketName);
            }

            Log.i(TAG, "Accepting command socket connections");
            runSelectLoop(abiList);

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }
    ......
}

最後老規矩,畫時序圖總結。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章