Android Zygote源碼分析

目錄

目錄 概述 zygote分析 AppRuntime分析 創建虛擬機startVm 註冊JNI函數startReg 進入JAVA世界 建立IPC通信服務端registerZygoteSocket 預加載類和資源preload 啟動system_server 有求必應之等待請求runSelectLoop


概述

在Android系統中,所有的應用程序進程,以及用來運行系統關鍵服務的System進程都是由zygote進程負責創建的。因此,我們將它稱為進程孵化器。zygote進程是通過復制自身的方式來創建System進程和應用程序進程的。由於zygote進程在啟動時會在內部創建一個虛擬機實例,因此,通過復制zygote進程而得到的System進程和應用程序進程可以快速地在內部獲得一個虛擬機實例拷貝。
zygote進程在啟動完成之後,會馬上將System進程啟動起來,以便它可以將系統的關鍵服務啟動起來。下面我們將介紹zygote進程的啟動腳本,然後分析它和System進程的啟動過程。


zygote分析

zygote進程的啟動腳本如下:

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

在我之前的一篇博客中已經分析瞭init進程是如何啟動service服務瞭,需要瞭解的同學可以參考這篇文章:Android init進程——解析配置文件

通過zygote服務的啟動腳本,我們可以知道,zygote進程的實際是二進制文件app_process的調用,我們就從這個應用程序的main函數入手去分析一下zygote進程的啟動過程,源碼如下(/frameworks/base/cmds/app_process/app_main.cpp):

/**
 * 將-Xzygote加入到JavaVMOption中,返回/system/bin參數指向的下標
 */
int AndroidRuntime::addVmArguments(int argc, const char* const argv[])
{
    int i;

    for (i = 0; i < argc; i ++) {
        if (argv[i][0] != '-') {
            return i;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            return i + 1;
        }

        JavaVMOption opt;
        memset(&opt, 0, sizeof(opt));
        opt.optionString = (char*)argv[i];
        mOptions.add(opt);
    }
    return i;
}

int main(int argc, char* const argv[])
{
    // zygote call parameters
    // /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

    // These are global variables in ProcessState.cpp
    mArgC = argc;
    mArgV = argv;

    mArgLen = 0;
    for (int i = 0; i < argc; i ++) {
        mArgLen += strlen(argv[i]) + 1;
    }
    // 去除末尾的空格
    mArgLen--;

    AppRuntime runtime;
    const char* argv0 = argv[0];

    // Process command line arguments
    // ignore argv[0]
    argc --;
    argv ++;

    // Everything up tp '--' or first non '-' arg goes to the vm
    int i = runtime.addVmArguments(argc, argv);

    // Parse runtime arguments. Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    const char* parentDir = NULL;
    const char* niceName = NULL;
    const char* className = NULL;
    while (i < argc) {
        const char* arg = argv[i ++];
        if (!parentDir) {
            parentDir = arg;
        } else if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = "zygote";
        } 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)) {
            niceName = arg + 12;
        } else {
            className = arg;
            break;
        }
    }

    if (niceName && *niceName) {
        setArgv0(argv0, niceName);
        set_process_name(niceName);
    }

    runtime.mParentDir = parentDir;

    if (zygote) {
        // 進入到AppRuntime的start函數
        runtime.start("com.android.internal.os.ZygoteInit",
            startSystemServer? "start-system-server" : "");
    } else if (className) {
        runtime.mClassName = className;
        runtime.mArgc = argc - i;
        runtime.mArgv = argv + i;
        runtime.start("com.android.internal.os.RuntimeInit", application ? "application" : "tool");
    } 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;
    }
}

在zygote的main函數中,通過AppRuntime runtime代碼創建瞭一個AppRuntime對象runtime,接下來Zygote進程就是通過它來進一步啟動的。
init.rc中關於啟動zygote命令中包含瞭–zygote參數,所以在if(strcmp(arg, “–zygote”) == 0)判斷的時候,會將niceName賦值為”zygote”,然後通過set_process_name(niceName)函數將當前進程的名稱設置為zygote。這也是為什麼調用的腳本為/system/bin/app_process,而進程名為zygote的原因。set_process_name函數的源碼如下(/system/core/libcutils/process_name.c):

static const char* process_name = "unknown";
void set_process_name(const char* new_name)
{
    if (new_name == NULL) {
        return;
    }

    int len = strlen(new_name);
    char* copy = (char*)malloc(len + 1);
    strcpy(copy, new_name);
    process_name = (const char*) copy;
}

從init.rc文件中關於zygote進程的配置參數可知,Zygote進程傳遞給應用程序app_process的啟動參數arg還包含一個”–start-system-server”選項。因此,在調用AppRuntime對象runtime的成員函數start時,第二個參數為”start-system-server”,表示zygote進程啟動完成之後,需要將system進程啟動起來。


AppRuntime分析

AppRuntime類的成員函數start是從父類AndroidRuntime繼承下來的,因此,接下來我們就繼續分析AndroidRuntime類的成員函數start的實現,函數源碼位置:/frameworks/base/core/jni/AndroidRuntime.cpp:

char* AndroidRuntime::toSlashClassName(const char* className)
{
    char* result = strdup(className);
    for (char* cp = result; *cp != '\0'; cp ++) {
        if (*cp == '.') {
            *cp = '/';
        }
    }

    return result;
}

/**
 * Start the Android runtime. This involves starting the virtual machine
 * and calling the "static void main(String[] args)" method int the class
 * named by "className".
 *
 * 這兩個參數的值分別為:
 * const char* className = "com.android.internal.os.ZygoteInit";
 * const char* options = "start-system-server";
 */
void AndroidRuntime::start(const char* className, const char* options)
{
    ALOGD("\n>>>>> AndroidRuntime START %s <<<<<<\n",
        className != NULL ? className : "(unknown)");

    /**
     * 'startSystemServer == true' means runtime is obsolete and not run from
     * init.rc anymore, so we print out the boot start event here.
     */
    if (strcmp(options, "start-system-server") == 0) {
        const int LOG_BOOT_PROGRESS_START = 3000;
        LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
    }

    // 設置ANDROID_ROOT環境變量
    const char* rootDir = getenv("ANDROID_ROOT");
    if (rootDir == NULL) {
        rootDir = "/system";
        if (!hasDir("/system")) {
            LOG_FATAL("No root directory specified, and /android dose not exist.");
            return;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }


    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    // 1. 創建虛擬機
    if (startVm(&mJavaVM, &env) != 0) {
        return;
    }
    onVmCreated(env);

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

    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;
    jstring optionsStr;

    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    // 創建一個有兩個元素的String數組,用Java代碼表示為:String[] strArray = new String[2];
    strArray = env->NewObjectArray(2, stringClass, NULL);
    assert(strArray != NULL);
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    // 設置第一個元素為"com.android.internal.os.ZygoteInit"
    env->SetObjectArrayElement(strArray, 0, classNameStr);
    optionsStr = env->NewStringUTF(options);
    // 設置第二個元素為"start-system-server"
    env->SetObjectArrayElement(strArray, 1, optionsStr);

    // 將字符串"com.android.internal.os.ZygoteInit"轉換為"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);
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s\n'", className);
        } else {
            // 3.
            // 通過JNI調用java函數,註意調用的是main函數,所屬的類是"com.android.internal.os.ZygoteInit".
            // 傳遞的參數是"com.android.internal.os.ZygoteInit true"
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
    free(slashClassName);

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

上述代碼有幾處關鍵點,分別是:

創建虛擬機。 註冊JNI函數。 進入Java世界。

接下來,我們分別分析這三個關鍵點。


創建虛擬機——startVm

startVm並沒有特別之處,就是調用JNI的虛擬機創建函數,但是創建虛擬機時的一些參數卻是在startVm中確定的,其源碼如下:

#define PROPERTY_VALUE_MAX 92
/**
 * Start the Dalvik Virtual Machine.
 *
 * Various arguments, most determined by system properties, are passed in.
 * The "mOptions" vector is updated.
 *
 * Returns 0 on success.
 */
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIENV** pEnv)
{
    int result = -1;
    JavaVMInitArgs initArgs;
    JavaVMOption opt;
    char propBuf[PROPERTY_VALUE_MAX];
    char stackTraceFileBuf[PROPERTY_VALUE_MAX];
    char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
    char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
    char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
    char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char heapsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
    char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
    char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
    char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
    char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
    char extraOptsBuf[PROPERTY_VALUE_MAX];
    char* stackTraceFile = NULL;
    bool checkJni = false;
    bool checkDexSum = false;
    bool logStdio = false;
    enum {
        KEMDefault,
        KEMIntPortable,
        KEMIntFast,
        KEMJitCompiler,
    } executionMode = KEMDefault;

    /**
     * 這段代碼是用瞭設置JNI_check選項的。JNI_check指的是Native層調用JNI函數時,系統所做的一些檢查動作。
     * 這個選項雖然能增加可靠性,但是還有一些副作用:
     * 1. 因為檢查工作比較耗時,所以會影響系統運行速度。
     * 2. 有些檢查工作比較耗時,一旦出錯,整個進程會abort。
     * 所以,JNI_check選項一般隻在eng版本設置。
     */
    property_get("dalvik.vm.checkjni", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
        checkJni = true;
    } else if (strcmp(propBuf, "false") != 0) {
        property_get("ro.kernel.android.checkjni", propBuf, "");
        if (propBuf[0] == '1') {
            checkJni = true;
        }
    }

    property_get("dalvik.vm.execution-mode", propBuf, "");
    if (strcmp(propBuf, "int:portable") == 0) {
        executionMode = KEMIntPortable;
    } else if (strcmp(propBuf, "int:fast") == 0) {
        executionMode = KEMIntFast;   
    } else if (strcmp(propBuf, "int:jit") == 0) {
        executionMode = KEMJitCompiler;
    }

    // ... 省略大部分參數設置

    /**
     * 設置虛擬機的heapsize,默認為16m。絕大多數廠商都會在build.prop文件裡修改這個屬性,一般是256m。
     * heapsize不能設置得過小,否則在操作大尺寸的圖片時無法分配所需的內存。
     */
    strcpy(heapsizeOptsBuf, "-Xmx");
    property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
    opt.optionString = heapsizeOptsBuf;
    mOptions.add(opt);

    // ......

    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed\n");
        goto bail;
    }

    result = 0;

bail:
    free(stackTraceFile);
    return result;
}

更多虛擬機參數的設置,我這裡就不做特殊說明瞭,大傢感興趣可以自行google。(ps:因為我不太懂虛擬機這一塊…)


註冊JNI函數——startReg

上面講瞭如何創建虛擬機,接下來需要給這個虛擬機註冊一些JNI函數。正是因為後續的Java世界用到的一些函數是采用native方式實現的,所以才必須提前註冊這些函數。

接下來,我們來看一下startReg函數的源碼實現:

int AndroidRuntime::startReg(JNIEnv* env)
{
    // 設置Thread類的線程創建函數為javaCreateThreadEtc
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

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

    env->PushLocalFrame(200);

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

    return 0;
}

關鍵是需要註冊JNI函數,具體實現是由register_jni_procs函數實現的,我們來看一下這個函數的具體實現(/frameworks/base/core/jni/AndroidRuntime.cpp):

static int register_jni_procs(const RegJNIRec array[], size_T count, JNIEnv* env)
{
    for (size_t i = 0; i < count; i ++) {
        if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
            ALOGD("------!!! %s failed to load\n", array[i].mName);
#endif
            return -1;
        }
    }

    return 0;
}

通過源碼,我們可以看到,register_jni_procs隻是對array數組的mProc函數的封裝,而array數組指向的是gRegJNI數組,我們來看一下這個數組的實現:

static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_debug_JNITest),
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_android_os_SystemClock),
    REG_JNI(register_android_util_EventLog),
    REG_JNI(register_android_util_Log),
    REG_JNI(register_android_util_FloatMath),
    REG_JNI(register_android_text_format_Time),
    REG_JNI(register_android_content_AssetManager),
    REG_JNI(register_android_content_StringBlock),
    REG_JNI(register_android_content_XmlBlock),
    REG_JNI(register_android_emoji_EmojiFactory),
    REG_JNI(register_android_text_AndroidCharacter),
    REG_JNI(register_android_text_AndroidBidi),
    REG_JNI(register_android_view_InputDevice),
    REG_JNI(register_android_view_KeyCharacterMap),
    REG_JNI(register_android_os_Process),
    REG_JNI(register_android_os_SystemProperties),
    REG_JNI(register_android_os_Binder),
    REG_JNI(register_android_os_Parcel),
    REG_JNI(register_android_view_DisplayEventReceiver),
    REG_JNI(register_android_nio_utils),
    REG_JNI(register_android_graphics_Graphics),
    REG_JNI(register_android_view_GraphicBuffer),
    REG_JNI(register_android_view_GLES20DisplayList),
    REG_JNI(register_android_view_GLES20Canvas),
    REG_JNI(register_android_view_HardwareRenderer),
    REG_JNI(register_android_view_Surface),
    REG_JNI(register_android_view_SurfaceControl),
    REG_JNI(register_android_view_SurfaceSession),
    REG_JNI(register_android_view_TextureView),
    REG_JNI(register_com_google_android_gles_jni_EGLImpl),
    REG_JNI(register_com_google_android_gles_jni_GLImpl),
    REG_JNI(register_android_opengl_jni_EGL14),
    REG_JNI(register_android_opengl_jni_EGLExt),
    REG_JNI(register_android_opengl_jni_GLES10),
    REG_JNI(register_android_opengl_jni_GLES10Ext),
    REG_JNI(register_android_opengl_jni_GLES11),
    REG_JNI(register_android_opengl_jni_GLES11Ext),
    REG_JNI(register_android_opengl_jni_GLES20),
    REG_JNI(register_android_opengl_jni_GLES30),

    REG_JNI(register_android_graphics_Bitmap),
    REG_JNI(register_android_graphics_BitmapFactory),
    REG_JNI(register_android_graphics_BitmapRegionDecoder),
    REG_JNI(register_android_graphics_Camera),
    REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
    REG_JNI(register_android_graphics_Canvas),
    REG_JNI(register_android_graphics_ColorFilter),
    REG_JNI(register_android_graphics_DrawFilter),
    REG_JNI(register_android_graphics_Interpolator),
    REG_JNI(register_android_graphics_LayerRasterizer),
    REG_JNI(register_android_graphics_MaskFilter),
    REG_JNI(register_android_graphics_Matrix),
    REG_JNI(register_android_graphics_Movie),
    REG_JNI(register_android_graphics_NinePatch),
    REG_JNI(register_android_graphics_Paint),
    REG_JNI(register_android_graphics_Path),
    REG_JNI(register_android_graphics_PathMeasure),
    REG_JNI(register_android_graphics_PathEffect),
    REG_JNI(register_android_graphics_Picture),
    REG_JNI(register_android_graphics_PorterDuff),
    REG_JNI(register_android_graphics_Rasterizer),
    REG_JNI(register_android_graphics_Region),
    REG_JNI(register_android_graphics_Shader),
    REG_JNI(register_android_graphics_SurfaceTexture),
    REG_JNI(register_android_graphics_Typeface),
    REG_JNI(register_android_graphics_Xfermode),
    REG_JNI(register_android_graphics_YuvImage),
    REG_JNI(register_android_graphics_pdf_PdfDocument),

    REG_JNI(register_android_database_CursorWindow),
    REG_JNI(register_android_database_SQLiteConnection),
    REG_JNI(register_android_database_SQLiteGlobal),
    REG_JNI(register_android_database_SQLiteDebug),
    REG_JNI(register_android_os_Debug),
    REG_JNI(register_android_os_FileObserver),
    REG_JNI(register_android_os_MessageQueue),
    REG_JNI(register_android_os_SELinux),
    REG_JNI(register_android_os_Trace),
    REG_JNI(register_android_os_UEventObserver),
    REG_JNI(register_android_net_LocalSocketImpl),
    REG_JNI(register_android_net_NetworkUtils),
    REG_JNI(register_android_net_TrafficStats),
    REG_JNI(register_android_net_wifi_WifiNative),
    REG_JNI(register_android_os_MemoryFile),
    REG_JNI(register_com_android_internal_os_ZygoteInit),
    REG_JNI(register_android_hardware_Camera),
    REG_JNI(register_android_hardware_camera2_CameraMetadata),
    REG_JNI(register_android_hardware_SensorManager),
    REG_JNI(register_android_hardware_SerialPort),
    REG_JNI(register_android_hardware_UsbDevice),
    REG_JNI(register_android_hardware_UsbDeviceConnection),
    REG_JNI(register_android_hardware_UsbRequest),
    REG_JNI(register_android_media_AudioRecord),
    REG_JNI(register_android_media_AudioSystem),
    REG_JNI(register_android_media_AudioTrack),
    REG_JNI(register_android_media_JetPlayer),
    REG_JNI(register_android_media_RemoteDisplay),
    REG_JNI(register_android_media_ToneGenerator),

    REG_JNI(register_android_opengl_classes),
    REG_JNI(register_android_server_NetworkManagementSocketTagger),
    REG_JNI(register_android_server_Watchdog),
    REG_JNI(register_android_ddm_DdmHandleNativeHeap),
    REG_JNI(register_android_backup_BackupDataInput),
    REG_JNI(register_android_backup_BackupDataOutput),
    REG_JNI(register_android_backup_FileBackupHelperBase),
    REG_JNI(register_android_backup_BackupHelperDispatcher),
    REG_JNI(register_android_app_backup_FullBackup),
    REG_JNI(register_android_app_ActivityThread),
    REG_JNI(register_android_app_NativeActivity),
    REG_JNI(register_android_view_InputChannel),
    REG_JNI(register_android_view_InputEventReceiver),
    REG_JNI(register_android_view_InputEventSender),
    REG_JNI(register_android_view_InputQueue),
    REG_JNI(register_android_view_KeyEvent),
    REG_JNI(register_android_view_MotionEvent),
    REG_JNI(register_android_view_PointerIcon),
    REG_JNI(register_android_view_VelocityTracker),

    REG_JNI(register_android_content_res_ObbScanner),
    REG_JNI(register_android_content_res_Configuration),

    REG_JNI(register_android_animation_PropertyValuesHolder),
    REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
    REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
};

#ifdef NDEBUG
    #define REG_JNI(name) {name}
    struct RegJNIRec {
        int (*mProc)(JNIEnv*);
    };
#else
    #define REG_JNI(name) {name, #name}
    struct RegJNIRec {
        int (*mProc)(JNIEnv*);
        const char* mName;
    };
#endif

可以看到,REG_JNI是一個宏,宏裡面包括的就是那個參數為JNIEnv*,返回值為int的函數指針mProc,我們以register_android_debug_JNITest為例,源碼位置為/frameworks/base/core/jni/android_debug_JNITest.cpp:

#define NELEM(x) (sizeof(x)/sizeof(*(x)))

int register_android_debug_JNITest(JNIEnv* env)
{
    return jniRegisterNativeMethods(env, "android/debug/JNITest", gMethods, NELEM(gMethods));
}

可以看到,mProc其實就是為Java類註冊JNI函數。


進入JAVA世界

可以看到CallStaticVoidMethod最終將調用com.android.internal.os.ZygoteInit的main函數,下面就來看一下這個Java世界的入口函數。源碼位置:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,源碼如下:

public static void main(String argv[])
{
    try {
        SamplingProfilerIntegration.start();

        // 1. 註冊zygote用的socket
        registerZygoteSocket();
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis());

        // 2. 預加載類和資源
        preload();
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis());

        SamplingProfilerIntegration.writeZygoteSnapshot();

        // 強制執行一次垃圾收集
        gc();

        Trace.setTracingEnabled(false);

        if (argv.length != 2) {
            throw new RuntimeException(argv[0] + USAGE_STRING);
        }

        if (argv[1].equals("start-system-server")) {
            // 3. 啟動system-server
            startSystemServer();
        } else if (!argv[1].equals("")) {
            throw new RuntimeException(argv[0] + USAGE_STRING);
        }

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

        // 4. 進入請求應答模式
        runSelectLoop();
        closeServerSocket();

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

上述代碼中有5個重要的點,我已經通過標號標記出來瞭,接下來我們分別分析一下這5點函數的具體實現。


建立IPC通信服務端——registerZygoteSocket

zygote及系統中其他程序的通信沒有使用Binder,而是采用瞭基於AF_UNIX類型的socket。registerZygoteSocket函數的使命正是建立這個Socket,實現代碼如下:

private static void registerZygoteSocket()
{
    if (sServerSocket == null) {
        int fileDesc;
        try {
            String env = System.getenv(ANDROID_SOCKET_ENV);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException(ANDROID_SOCKET_ENV + " unset or invalid", ex);
        }

        try {   
            sServerSocket = new LocalServerSocket(createFileDescriptor(fileDesc));
        } catch(IOException ex) {   
            throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}

public class LocalServerSocket {
    private final LocalSocketImpl impl;
    private final LocalSocketAddress localAddress;

    private static final int LISTEN_BACKLOG = 50;

    /**
     * Create a LocalServerSocket from a file descriptor that's already
     * been created and bound. listen() will be called immediately on it.
     * Used for cases where file descriptors are passed in via environment
     * variables.
     */
    public LocalServerSocket(FileDescriptor fd) throws IOException {
        impl = new LocalSocketImpl(fd);
        impl.listen(LISTEN_BACKLOG);
        localAddress = impl.getSockAddress();
    }
}

registerZygoteSocket很簡單,就是創建一個服務端的socket。


預加載類和資源——preload

我們先來看一下preload函數實現:

static void preload()
{
    preloadClasses();
    preloadResources();
    preloadOpenGL();
}

preload函數裡面分別調用瞭三個預加載函數,我們分別來分析一下這幾個函數的實現。

首先是preloadClasses,函數實現如下:

private static final int UNPRIVILEGED_UID = 9999;
private static final int UNPRIVILEGED_GID = 9999;

private static final int ROOT_UID = 0;
private static final int ROOT_GID = 0;

private static void preloadClasses()
{
    final VMRuntime runtime = VMRuntime.getRuntime();

    InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(PRELOADED_CLASSES);
    if (is == null) {
        Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
    } else {
        Log.i(TAG, "Preloading classes...");
        long startTime = SystemClock.uptimeMillis();

        setEffectiveGroup(UNPRIVILEGED_GID);
        setEffectiveGroup(UNPRIVILEGED_UID);

        float defaultUtilization = runtime.getTargetHeapUtilization();
        runtime.setTargetHeapUtilization(0.8f);

        System.gc();
        runtime.runFinalizationSync();
        Debug.startAllocCounting();

        try {
            // 創建一個緩沖區為256字符的輸入流
            BufferedReader br = new BufferdReader(new InputStreamReader(is), 256);
            int count = 0;
            String line;
            while ((line = br.readLine()) != null) {
                // skip comments and blank lines.
                line = line.trim();
                if (line.startsWith("#") || line.equals("")) {
                    continue;
                }

                try {
                    if (false) {
                        Log.v(TAG, "Preloading " + line + "...");
                    }
                    Class.forName(line);
                    count ++;
                } catch (ClassNotFoundException e) {
                    Log.w(TAG, "Class not found for preloading: " + line);
                } catch (UnsatisfiedLinkError e) {
                    Log.w(TAG, "Problem preloading " + line + ": " + e);
                } catch(Throwable t) {
                    Log.e(TAG, "Error preloading " + line + ".", t);
                }
            }
            Log.i(TAG, "...preloaded " + count + " classes in " + (SystemClock.uptimeMillis()-startTime) + "ms.");
        } catch (IOException e) {
            Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
        } finally {
            IoUtils.closeQuietly(is);
            runtime.setTargetHeapUtilization(defaultUtilization);

            runtime.preloadDexCaches();
            Debug.stopAllocCounting();

            setEffectiveUser(ROOT_UID);
            setEffectiveGroup(ROOT_GID);
        }
    }
}

preloadClasses看起來很簡單,但是實際上它有很多的類需要加載。可以查看一下/frameworks/base/preloaded-classes文件,這裡面都是需要預加載的類。

接下來,分析一下preloadResources函數的源碼:

private static final boolean PRELOAD_RESOURCES = true;
private static void preloadResources()
{
    final VMRuntime runtime = VMRuntime.getRuntime();
    Debug.startAllocCounting();

    try {
        System.gc();
        runtime.runFinalizationSync();
        mResources = Resources.getSystem();
        mResources.startPreloading();
        if (PRELOAD_RESOURCES) {
            Log.i(TAG, "Preloading resources...");

            long startTime = SystemClock.uptimeMillis();
            TypedArray ar = mResources.obtainTypedArray(com.android.internal.R.array.preloaded_drawables);
            int N = preloadDrawables(runtime, ar);
            ar.recycle();
            Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis()-startTime) + "ms.");

            startTime = SystemClock.uptimeMillis();
            ar = mResources.obtainTypedArray(com.android.internal.R.array.preloaded_color_state_lists);
            N = preloadColorstateLists(runtime, ar);
            ar.recycle();
            Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis() - startTime) + "ms.");
        }
        mResources.finishPreloading();
    } catch (RuntimeException e) {
        Log.w(TAG, "Failure preloading resources", e);
    } finally {
        Debug.stopAllocCounting();
    }
}

接下來,是預加載OpenGL。源碼如下:

private static void preloadOpenGL()
{
    if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {
        EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
    }
}

啟動system_server

現在我們要分析第三個關鍵點:startSystemServer。這個函數會創建java世界中系統Service所駐留的進程system_server,該進程是framework的核心。如何system_server掛掉,會導致zygote自殺。我們來看一下startSystemServer()實現源碼。

/**
 * Prepare the arguments and fork for the system server process.
 */
private static boolean startSystemServer() throws MethodAndArgsCaller, RuntimeException
{
    long capabilities = posixCapabilitiesAsBits(
        OsConstants.CAP_KILL,
        OsConstants.CAP_NET_ADMIN,
        OsConstants.CAP_NET_BIND_SERVICE,
        OsConstants.CAP_NET_BROADCAST,
        OsConstants.CAP_NET_RAW,
        OsConstants.CAP_SYS_MODULE,
        OsConstants.CAP_SYS_NICE,
        OsConstants.CAP_SYS_RESOURCE,
        OsConstants.CAP_SYS_TIME,
        OsConstants.CAP_SYS_TTY_CONFIG
    );

    // 設置參數
    String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
        "--capabilities=" + capabilities + "," + capabilities,
        "--runtime-init",
        "--nice-name=system_server", // 進程名為system_server
        "com.android.server.SystemServer",
    };

    ZygoteConnection.Arguments parsedArgs = null;

    int pid;

    try {
        parsedArgs = new ZygoteConnection.Arguments(args);
        ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
        ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

        /* Request to fork the system server process */
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities
        );
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    /* For child process */
    if (pid == 0) {
        handleSystemServerProcess(parsedArgs);
    }

    return true;
}

有求必應之等待請求——runSelectLoop

zygote從startSystemServer返回後,將進入第四個關鍵的函數:runSelectLoop。我們來看一下這個函數的實現:

static final int GC_LOOP_COUNT = 10;
private static void runSelectLoop() throws MethodAndArgsCaller {
    ArrayList fds = new ArrayList();
    ArrayList peers = new ArrayList();
    FileDescriptor[] fdArray = new FileDescriptor[4];

    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    int loopCount = GC_LOOP_COUNT;
    while (true) {
        int index;
        if (loopCount <= 0) {
            gc();
            loopCount = GC_LOOP_COUNT;
        } else {
            loopCount --;
        }

        try {
            fdArray = fds.toArray(fdArray);
            index = selectReadable(fdArray);
        } catch(IOException ex) {
            throw new RuntimeException("Error in select()", ex);
        }

        if (index < 0) {
            throw new RuntimeException("Error in select()");
        } else if (index == 0) {
            ZygoteConnection newPeer = acceptCommandPeer();
            peers.add(newPeer);
        }
    }
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。