Android Zygote系统服务孵化器启动大概流程分析

之前用Github 的git page 搭配 Hexo来写文章,非常的繁琐。现在改用来记录自己学习的点滴。欢迎各位观看文章的朋友可以一起学习。
目前我所下载的Android系统源码版本为android-7.1.0_r7不算太旧。目前市场上的大部分系统解读的书籍,基本都是在android4.0到5.0之间,大部分没有到5.0。本人也是看书之后,发现新旧源码还是有较大差别的。

启动配置文件读取

启动之初,会读取一个文件 init.rc 这个文件是最初进行读取的配置文件,作用

  • 初始化
  • 生成设备文件夹
  • 初始化应用服务孵化器 Zygote,在代码中有所体现。如图

文件地址system/core/rootdir/init.rc

Android Zygote系统服务孵化器启动大概流程分析_第1张图片
图片.png

根据上面代码,应该可以看出,在系统读取这个文件并导入相关的孵化器的初始化文件,其中 ro.zygote 应该为系统加载读取这个文件时传入的参数,这个参数应该是系统启动时,根据硬件的一些特殊信息生成的。
具体加载了什么文件? 这里有个列表:

Android Zygote系统服务孵化器启动大概流程分析_第2张图片
图片.png

在上面的文件目录中可以看出,在执行import 的代码时,真正导入的文件便是框出的几个文件,根据不同的硬件基础生成的不同文件。选取init.zygote64.rc进行观察。

Android Zygote系统服务孵化器启动大概流程分析_第3张图片
图片.png

这个文件中的配置命令的语法我还没具体搞清楚。但是,不凡可以进行大胆的猜想。在红色框中框出的,貌似应该是个可执行文件,根据以往在Ubuntu系统的命令行程序中的写法,的确十分相似。那么这个 app_process的可执行文件是在哪里生成的?(在这里,如果是小白,极力推荐去买本书,参考的看代码,不然你根本找不到,也摸不清来龙去脉。)

frameworks/bash/cmds/app_process/app_main.cpp

Android Zygote系统服务孵化器启动大概流程分析_第4张图片
图片.png

可以先看看 Android.mk编译配置文件,其中就是如何生成上面所讲的app_process命令的过程。

# 定位编译根目录
LOCAL_PATH:= $(call my-dir)

# This is a list of libraries that need to be included in order to avoid
# bad apps. This prevents a library from having a mismatch when resolving
# new/delete from an app shared library.
# See b/21032018 for more details.
app_process_common_shared_libs := \
    libwilhelm \

# 清空之前编译的缓存变量
include $(CLEAR_VARS)

# 本地需要编译的C++文件
LOCAL_SRC_FILES:= \
    app_main.cpp

LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic

LOCAL_SHARED_LIBRARIES := \
    libdl \
    libcutils \
    libutils \
    liblog \
    libbinder \
    libnativeloader \
    libandroid_runtime \
    $(app_process_common_shared_libs) \

LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain

# 生成动态库模块名称
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both

# !!!!!这里就是关键!!!!!生成32位和64位的Zygote初始化可执行命令文件。
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64

LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code

# 生成可执行.so动态库文件,如果有点印象,在app的jni开发中经常会使用到BUILD_SHARE_LIBRARY。
# 下面的也可以这么理解了。
include $(BUILD_EXECUTABLE)

# Create a symlink from app_process to app_process32 or 64
# depending on the target configuration.
include  $(BUILD_SYSTEM)/executable_prefer_symlink.mk

# Build a variant of app_process binary linked with ASan runtime.
# ARM-only at the moment.
ifeq ($(TARGET_ARCH),arm)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    app_main.cpp

LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \
    liblog \
    libbinder \
    libandroid_runtime \
    $(app_process_common_shared_libs) \

LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain

LOCAL_LDFLAGS := -ldl -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
LOCAL_CPPFLAGS := -std=c++11

LOCAL_MODULE := app_process__asan
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64

LOCAL_SANITIZE := address
LOCAL_CLANG := true
LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan

LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code

include $(BUILD_EXECUTABLE)

endif # ifeq($(TARGET_ARCH),arm)

那么到这里,肯定是要看看这个app_main.cpp文件中的具体代码是干什么的了。
如果是可执行文件,自然肯定会有main函数

int main(int argc, char* const argv[]){
...代码省略
    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

//读取在执行该命令时,给出的参数
    ++i;  // Skip unused "parent dir" argument.
    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; //初始化Android系统服务的配置
        } 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 args;
    if (!className.isEmpty()) {
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make
        // copies of them before we overwrite them with the process name.
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
    } else {
        // We're in zygote mode.
        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);

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }
...代码省略
    if (zygote) {  // !!!!通过jni,C++代码调用具体的java类中的main函数。并传入参数
//在这里,孵化器的初始化工作才刚刚开始执行
        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;
    }  //到这里,代码结束
}

上面的runtime.start("com.android.internal.os.ZygoteInit", args, zygote);个人觉得应该可以去看看,理解一下是如何调用com.android.internal.os.ZygoteInit这个类的main函数的。
AndroidRuntime.cpp文件的具体位置

frameworks/base/core/jni/AndroidRuntime.cpp
/*
 * Start the Android runtime.  This involves starting the virtual machine
 * and calling the "static void main(String[] args)" method in the class
 * named by "className".
 *
 * Passes the main function two arguments, the class name and the specified
 * options string.
 */
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
    ...代码省略
    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);

    /* start the virtual machine */  //初始化java虚拟机环境,方便后面用jni调用java类的函数
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {
        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;

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

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    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 {
            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");
}

根据上面最后的注释,执行完这个命令之后,孵化器的初始化工作就开始了。
接下来分析一下ZygoteInit.java的代码
一样,从main函数开始

public static void main(String argv[]) {
...省略代码
            if (startSystemServer) {// 初始化系统服务,所有的子系统服务都从这里开始
                startSystemServer(abiList, socketName);
            }
}

这里需要注意的一个关键的地方,如下图:

Android Zygote系统服务孵化器启动大概流程分析_第5张图片
图片.png

这里的代码有些奇怪不同以往的代码编写方式,将Runnable用作异常在底层函数抛出,然后在抓取异常的时候,执行里面的run方法。在文章的最后截图中可以看到向上抛出的异常。

    /**
     * Prepare the arguments and fork for the system server process.
     */
    private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
        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) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            handleSystemServerProcess(parsedArgs); //进入到这个方法内部查看代码,可找到启动系统服务的入口
        }
}
    /**
     * Finish remaining work for the newly forked system server process.
     */
    private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws ZygoteInit.MethodAndArgsCaller {
...省略代码
            /*
             * Pass the remaining arguments to SystemServer.
             */
//!!!!这句话关键,进入去看看
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
Android Zygote系统服务孵化器启动大概流程分析_第6张图片
图片.png
Android Zygote系统服务孵化器启动大概流程分析_第7张图片
图片.png
Android Zygote系统服务孵化器启动大概流程分析_第8张图片
图片.png
Android Zygote系统服务孵化器启动大概流程分析_第9张图片
图片.png

到这里,就会去执行SystemServer.java文件的main函数,初始化剩余的系统服务了。

你可能感兴趣的:(Android Zygote系统服务孵化器启动大概流程分析)