从Android 8.0源码的角度剖析Android系统启动过程(1)

 在《嵌入式Linux应用开发完全手册》一书中,我们可以较为清晰地了解到Android系统启动的大体流程:当用户按下Android设备的电源键时,CPU上电后会从0x00000000地址开始执行引导程序BootLoader。BootLoader是Android系统在上电后执行的第一段代码,它被固化在ROM中,当系统上电后就会被加载到RAM中执行,该段代码的目的是初始化硬件设备、准备好软件环境,然后将Android系统镜像装载到RAM中,最后拉起Linux内核(通过调用start_kernel函数)。Linux内核被拉起后,首先会完成设置缓存、加载驱动等系统设置,然后会在系统文件中寻找init.rc文件,并启动init进程,进程编号pid=1。该进程是Linux内核启动的第一个用户级进程,是所有其他进程的父进程,引导用户空间服务,至此系统的运行由内核空间切换到用户空间。init进程在完成初始化和启动属性服务后,会启动Zygote进程(“孵化器”),该进程将完成Dalvik/ART虚拟机实例的创建和启动SystemServer进程等操作。SystemServer进程会启动各种系统服务,包括PMS、AMS、WMS等等,其中AMS服务被启动后就会去启动Launcher应用(桌面启动器)。至此,Android系统启动流程执行完毕。

1. init进程启动过程

 init进程启动时序图如下:
在这里插入图片描述
 前面说到,Linux内核在加载完成后,它会在系统文件中寻找init.rc文件,并启动init进程。init进程的入口函数位于Android源码目录system/core/init.cpp源文件中,函数名称为"main",它的源码如下:

// 源码路径:system/core/init.cpp
int main(int argc, char** argv) {
   ...

    if (is_first_stage) {
        boot_clock::time_point start_time = boot_clock::now();

        // Clear the umask.
        umask(0);
        // 1. 创建和挂载启动所需的文件目录
        // Get the basic filesystem setup we need put together in the initramdisk
        // on / and then we'll let the rc file figure out the rest.
        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
        mkdir("/dev/pts", 0755);
        mkdir("/dev/socket", 0755);
        mount("devpts", "/dev/pts", "devpts", 0, NULL);
        #define MAKE_STR(x) __STRING(x)
        mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
        // Don't expose the raw commandline to unprivileged processes.
        chmod("/proc/cmdline", 0440);
        gid_t groups[] = { AID_READPROC };
        setgroups(arraysize(groups), groups);
        mount("sysfs", "/sys", "sysfs", 0, NULL);
        mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
        mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
        mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
        mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));

        // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
        // talk to the outside world...
        // 初始化内核的LOG系统,便于从外界获取Kernel的日志
        InitKernelLogging(argv);

        LOG(INFO) << "init first stage started!";

        if (!DoFirstStageMount()) {
            LOG(ERROR) << "Failed to mount required partitions early ...";
            panic();
        }
        ...
    }

    // 2. 初始化属性服务
    property_init();

    ...
    // 创建epoll句柄
    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) {
        PLOG(ERROR) << "epoll_create1 failed";
        exit(1);
    }
    // 3. 设置子进程异常捕获处理函数 
    signal_handler_init();
    // 导入默认的环境变量
    property_load_boot_defaults();
    export_oem_lock_status();
    // 2. 启动属性服务
    start_property_service();
    set_usb_controller();

    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);
    // 4. 获取一个Parser解析器对象
    Parser& parser = Parser::GetInstance();
    parser.AddSectionParser("service",std::make_unique<ServiceParser>());
    parser.AddSectionParser("on", std::make_unique<ActionParser>());
    parser.AddSectionParser("import", std::make_unique<ImportParser>());
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        // 4. 解析/init.rc文件
        parser.ParseConfig("/init.rc");
        parser.set_is_system_etc_init_loaded(
                parser.ParseConfig("/system/etc/init"));
        parser.set_is_vendor_etc_init_loaded(
                parser.ParseConfig("/vendor/etc/init"));
        parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
    } else {
        parser.ParseConfig(bootscript);
        parser.set_is_system_etc_init_loaded(true);
        parser.set_is_vendor_etc_init_loaded(true);
        parser.set_is_odm_etc_init_loaded(true);
    }

    ...
    ActionManager& am = ActionManager::GetInstance();
    ...

    while (true) {
        // By default, sleep until something happens.
        int epoll_timeout_ms = -1;
        // 5. 遍历执行每个action中携带的command对应的执行函数
        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
            am.ExecuteOneCommand();
        }
        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
            // 重启死去的进程
            restart_processes();

            // If there's a process that needs restarting, wake up in time for that.
            if (process_needs_restart_at != 0) {
                epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
                if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
            }

            // If there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
        }
		...
    }

    return 0;

}

 从上述源码可知,init进程的入口函数main主要完成以下工作:

  • 创建和挂载启动所需的文件目录(1)。其中挂载了五种文件系统,包含tmpfsdevptsprocsysfsselinuxfs,它们都是系统运行时目录,只有系统运行时才会存在 ,当系统停止后会被删除。
  • 初始化、启动属性服务(2)。类似于Windows的注册表(使用键值对的形式记录用户和软件的一些信息),属性服务存储一些属性值,当系统或软件需要这些属性时便于直接读取。init进程启动时会为这些属性分配内存,并将其存储到属性服务中。
    // 初始化属性服务
    property_init();
    // 启动属性服务
    start_property_service();
  • 设置子进程异常捕获处理函数(3)。signal_handler_init函数用于设置子进程信号处理函数,主要是防止init进程的子进程变成僵尸进程。所谓僵尸进程,是指父进程通过fork创建子进程,在子进程终止后,但是父进程并不知道子进程已经终止了,就会导致系统进程表中为子进程保存的进程号、运行时间等信息无法被删除。由于系统进程表资源是有限的,随着这种僵尸进程数量的增多,系统进程表将会被消耗殆尽,最终导致系统无法创建新的进程。因此,为了防止僵尸进程,系统在子进程暂停或终止时发出SIGGHLD信号,而函数signal_handler_init接收到SIGGHLD信号后做进一步处理,以移除终止子进程的信息。
 	// 设置子进程信号处理函数
	// 接收SIGCHLD信号
	signal_handler_init();
  • 解析init.rc文件,循环执行
	// 解析init.rc文件
	Parser& parser = Parser::GetInstance();
	parser.ParseConfig("/init.rc");
	// 循环执行action中的Command
	ActionManager& am = ActionManager::GetInstance();
	while(true) {
       am.ExecuteOneCommand();
    }

 接下来,我们就详细分析init.rc文件和init进程是如何启动Zygoye进程的。

1.1 解析init.rc文件

 init.rc文件是Android系统启动过程中必不可少的配置文件,它由AIL语言(Android Init Language,Android初始化语言)编写,该语言主要包含五种类型语句:Action(行动)Command(命令)Service(服务)Option(选项)Import。AIL语言编写的文件以.rc为后缀,所有类型语句以为单位,各种记号由空格隔开,注释以井号(#)开头,行末的反斜杠(\)用于换行。

  • Actions(行动)

 Actions实际上就是一个Commands(命令)序列。每个Actions有唯一的名字,都有一个trigger(触发器),该trigger被用于决定action的执行时间。当一个符号action触发条件的事件发生时,action会被加入到执行队列的末尾。当然,队列中的每一个action都会被依次提出,被提出的action中的每个command都将被依次执行。Actions的形式如下所示:

on <trigger>  # 设置触发器,比如boot为init进程启动后第一个被触发的Triggers
   <command>  # 动作触发之后要执行的Command
   <command>
   ...
  • Command(命令)
# 创建和执行一个程序,<path>程序路径 
 exec <path> [ <argument> ]*
 # 修改文件权限
 chmod <octal-mode> <path>
 # 创建目录
 mkdir <path> [mode] [owner] [group]
 # 复制操作
 copy <path> <path>
 ...
  • Services(服务)

 Services是一个程序,它在初始化时启动,并在退出时重启(可选)。

# service <service名字> <执行程序路径> [传递参数(可选,多个)]
service <name> <pathname> [<argument>]*
	<option>  # option是service的修饰词,影响什么时候,如何启动service
	<option>
	...
  • Options(选项)

 Options是Services的修正者,它们影响Service在何时,并以何种方式运行。

# 指定一个服务类,所有同一类的服务可以同时启动和停止
# 如果不通过class选项指定一个类,则默认为"default"类服务
class <name>
# 在启动这个服务前改变该服务的组名
group <groupname> [ <groupname> ]*
# 当服务重启,执行一个命令
onrestart <command>
# 在启动这个服务前改变该服务的用户名
# 默认为root
user <username>
# 创建一个Uinx域的名为/dev/socket/<name>的套接字
# 并传递它的文件描述符给已启动的进程
socket <name> <type> <perm> [ <user> [ <group> ] ]
  • Imports(引入)

 Imports用来引入一个要解析的其他配置文件,通常用于当前配置文件的扩展。如果path是一个目录,则该目录下的每个.rc文件都会被引入。

import <path>

 有了AIL语言基础后,我们再来看init.rc配置文件,该文件位于Android源码目录/system/core/rootdir。

# 导入其他.rc文件
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
# init.zygote32.rc
# init.zygote64.rc
# init.zygote32_64.rc
import /init.${ro.zygote}.rc

on init
    sysclktz 0

    copy /proc/cmdline /dev/urandom
    copy /default.prop /dev/urandom
    ...
on boot
    # basic network init
    ifup lo
    hostname localhost
    domainname localdomain
 	...
# 启动所有名为classname为main的Service    
on nonencrypted
    class_start main
    class_start late_start
...    
## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0

service healthd /system/bin/healthd
    class core
    critical
    group root system wakelock

service console /system/bin/sh
    class core
    console
    disabled
    user shell
    group shell log readproc
    seclabel u:r:shell:s0
...

 init.rc配置文件内容很多,但是基本可以看出它在Android系统启动过程中所起的作用,即根据不同的触发条件完成各种操作,比如创建目录、目录文件拷贝、挂载等等,以及使用service语句通知init进程创建指定的进程,这些进程均是init进程的子进程,比如Zygote进程。需要注意的是,在Android8.0源码中,init.rc文件中并没有直接写明创建zygote进程的语句,而是将相关的service语句写到其他.rc文件中(每个service语句对应一个.rc文件),然后使用import语句导入。这里以init.zygote64.rc为例:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

 该Service语句的作用是:通知init进程创建一个名为zygote的进程,这个进程执行程序的路径为/system/bin/app_process64,传给程序app_process64的参数为-Xzygote /system/bin --zygote --start-system-server。class main指的是Zygote的classname为main;onrestart …表示当服务重启时,执行执行的命令;等等。

1.2 启动Zygote进程

 在1.1小节到谈到,init进程是通过解析init.rc配置文件,来执行各种初始化、创建启动进程等操作,其中就包括zygote进程。在init.rc有这么一个Actions,即on nonencrypted,它有一个Command为class_start main,这条语句的目的就是启动那些classname为main的Services,又由上面的分析可知,Zygote进程的classname就是main,因此,class_start这个Commands就是创建Zygote进程的起始点,它对应于函数do_class_start,被定义在system/core/init/builtins.cpp中。do_class_start函数源码如下:

// system/core/init/builtins.cpp
static int do_class_start(const std::vector<std::string>& args) {
    // 遍历Service链,依次执行StartIfNotDisabled()
    ServiceManager::GetInstance().
        ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
    return 0;
}

 在do_class_start函数中,它通过调用Services管理类ServiceManager的ForEachServiceInClass函数,去遍历保存了一系列Service对象的链表,找到classname为main的Zygote,并执行与之对应的Service对象的StartIfNotDisabled函数,被定义在system/core/init/service.cpp中。StartIfNotDisabled函数源码如下:

// system/core/init/service.cpp
bool Service::StartIfNotDisabled() {
    // Service没有在其对应的rc文件中设置disable选项
    if (!(flags_ & SVC_DISABLED)) {
        return Start();
    } else {
        flags_ |= SVC_DISABLED_START;
    }
    return true;
}

 StartIfNotDisabled函数实现很简单,它会根据Service是否有在其对应的rc文件中设置disable选项,如果没有,则执行Serivce对象的Start函数来启动该Service。通过上面对init.zygote64.rc配置文件的分析,在Service语句中并没有设置disable选项,因此SVC_DISABLED为false。Start函数源码如下:

// system/core/init/service.cpp
bool Service::Start() {
    // 如果Service已经运行,则不启动
    if (flags_ & SVC_RUNNING) {
        return false;
    }
    ...
    // 判断需要启动的Service的对应的执行文件是否存在
    // 如果不存在,则不启动Service。比如,这个Serivce名为zygote
    // 那么该Service对应的执行程序为/system/bin/app_process64
    int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
    if (console_fd < 0) {
        flags_ |= SVC_DISABLED;
        return false;
    }
    close(console_fd);
    ...
    // init进程调用fork函数创建子进程
    pid_t pid = -1;
    if (namespace_flags_) {
        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
    } else {
        pid = fork();
    }
    ...
    // 当pid=0时
	// 说明当前代码逻辑执行在子进程中
    if (pid == 0) {
        umask(077);
        
        ...
        // 启动Service子进程,并进入该Service可执行文件的mian函数中
        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
            PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
        }
    }
}

 在Service对象的Start函数中,首先,它会去判断当前Service是否运行,如果正在运行则不再执行下面的流程;然后,检查当前Service对应的可执行文件是否存在,如果不存在则不启动该Service。关于Service对应的可执行文件,假如当前Service名为"zygote",根据我们对分析init.zygote64.rc可知,名为"zygote"的Service对应的执行程序为/system/bin/app_process64,该执行程序对应的文件为app_main.cpp再然后,init进程调用fork函数创建Service子进程;最后,根据pid=0时,当前代码逻辑在子进程中运行,调用execve函数启动被创建的Service子进程,并进入Service对应执行文件的main函数。假如当前Service名为zygote,那么随着execve函数被调用,将进入app_main.cpp的main函数中执行。app_main.cpp的main函数源码如下所示:

// Android8.0\frameworks\base\cmds\app_main.cpp
// argv[] = "-Xzygote /system/bin --zygote --start-system-server"
int main(int argc, char* const argv[])
{
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    ...
        
    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;
    // 解析argv[]参数
    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;
        }
    }
    // 调用AppRuntime的start函数
    // 启动ZygoteInit
    if (zygote) {
        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.");
    }
}

 从上述代码可知,app_main.cpp的main函数首先会去循环解析由之前init.zgote64.rc中Service语句传入进来的参数列表(-Xzygote /system/bin --zygote --start-system-server),根据参数信息将zygotestartSystemServer属性置为true,其中,startSystemServer后面会用到,这里只用到当zygote为true时,会去调用AppRuntime的start方法来启动Zygote。也就是说,执行到这里就进入了Zygote进程的启动过程。

init进程启动过程中做了很多工作,主要有如下四点:

  • 创建和挂载启动所需的文件目录;
  • 初始化和启动属性服务;
  • 设置子进程信号处理函数,防止子进程变成僵尸进程;
  • 解析init.rc配置文件并启动Zygote进程;

2. Zygote进程启动过程

 在常见内存泄漏与优化(二)一文中,我们曾谈到所有的Android应用程序都是运行在独立的Dalvik/ART虚拟机上的,而这个Dalvik或ART虚拟机就是由Zygote进程创建的。Zygote进程是Android中的"孵化器",在Android中,Dalvik/ART实例,所有的Android应用进程以及运行系统关键服务的SystemServer进程都是由Zygote进程创建的。Zygote进程在启动时会创建Dalvik或ART的实例,在创建(“孵化”)其他进程时通过fork(复制)自身的方式实现。因此,通过Zygote进程fork自身创建的应用进程和SystemServer进程“天生”就拥有了Dalvik或ART的实例,这就避免了每个应用启动在启动时都要运行和初始化一个虚拟机所带来的启动/运行延迟。接下来,我们就接着1.2小节进一步分析Zygote进程的启动过程,Zygote启动过程是从AppRuntime$start函数开始的,由于AppRuntime继承于AndroidRuntime(运行时类),因此,实际调用的时AndroidRuntime的start函数。start函数源码如下:

// Android8.0\frameworks\base\core\jni\AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote){
	...
    JniInvocation jni_invocation;
    // 初始化,判断是启动Dalvik还是ART
    jni_invocation.Init(NULL);
    JNIEnv* env;
	// 1. 启动虚拟机
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);

    // 为虚拟机注册JNI方法
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    ...
    // 将“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);
        /* keep going */
    } else {
    	// 2. 找到ZygoteInit的main方法,且ZygoteInit是一个Java类
    	// 位于Java层
        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 {
        	// 3. 通过JNI调用ZygoteInit的main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
    }
    free(slashClassName);
}

 AndroidRuntime的main函数主要完成两件事:(1) 创建虚拟机,并为虚拟机注册JNI方法;(2) 将“com.android.internal.os.ZygoteInit”替换为"com/android/internal/os/ZygoteInit",然后通过JNI方法找到ZygoteInit的main方法,并调用该方法。由于ZygoteInit类由Java语言编写,且位于Framework层(Java层),这也意味着Android系统的启动流程由Native层进入Framework层。ZygoteInit的main方法源码如下:

// Android8.0\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String argv[]) {
    ZygoteServer zygoteServer = new ZygoteServer();
    ...
    try{
        boolean startSystemServer = false;
        String socketName = "zygote";
        String abiList = null;
        boolean enableLazyPreload = false;
        // 解析传入的参数
        // 这里可以得到startSystemServer=true
        for (int i = 1; i < argv.length; i++) {
            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: );
            }
        }
		...
        // 1. 创建一个Server端的Socket
        // 这个Socket的名称为"zygote"
        zygoteServer.registerServerSocket(socketName);
        // 2. startSystemServer=true,启动SystemServer进程
        if (startSystemServer) {
            startSystemServer(abiList, socketName, zygoteServer);
        }

        Log.i(TAG, "Accepting command socket connections");
        // 3. 循环等待client端的Socket请求服务
        //   这个client端指的是ActivityManagerService
        zygoteServer.runSelectLoop(abiList);
        zygoteServer.closeServerSocket();
    } catch (Zygote.MethodAndArgsCaller caller) {
        // 捕获ygote.MethodAndArgsCaller异常
        caller.run();
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        zygoteServer.closeServerSocket();
        throw ex;
    }
}

 在ZygoteInit的main方法中,它首先会创建一个名为"zygote"的Socket作为服务端,这个Socket Server监听等待作为Socket client端的ActivityManagerService向其发送创建新的应用程序进程的请求;然后创建SystemServer进程,该进程主要用于启动Android中各种关键的系统服务。下面,我们着重分析Zygote进程是如何创建SystemServer进程和创建一个Server Socket用于监听AMS发送过来的请求。

2.1 启动SystemServer进程

 在ZygoteInit的main方法中,通过调用ZygoteInit的startSystemServer方法发起创建SystemServer进程流程的,并向该方法传入之前创建的Socket的名称和Socket对象。startSystemServer方法源码如下:

// Android8.0\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName, 
                                         ZygoteServer zygoteServer)
    throws Zygote.MethodAndArgsCaller, RuntimeException {
    ...
        // SystemServer进程启动参数
        String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "--setgroups=1001,1002,1003,1004,1005,1006,1007,\
            1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
        "--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server",
        "--runtime-args",
        "com.android.server.SystemServer",
    };
    ZygoteConnection.Arguments parsedArgs = null;

    int pid;

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

        // Zygote进程通过fork自身创建一个子进程
        // 即SystemServer进程
        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);
        }

        zygoteServer.closeServerSocket();
        // 处理SystemServer进程
        handleSystemServerProcess(parsedArgs);
    }

    return true;
}

 由上述源码可知,Zygote进程创建SystemServer子进程是通过调用Zygote的forkSystemServer方法实现,该方法又调用了Zygote的nativeForkSystemServer方法,这个方法是一个native方法,最终由它在native层通过调用fork函数实现在当前进程(Zygote进程)创建一个子进程(SystemServer进程)。如果pid=0,说明SystemServer进程被创建成功,此时当前代码逻辑运行在SystemServer子进程,接下来就会去调用Zygote的handleSystemServerProcess方法进入SystemServer进程的启动过程。

2.2 创建Zygote进程的Server socket

 Zygote进程的Server Socket是通过调用ZygoteServer的registerServerSocket方法,该Server Socket的作用就是等待AMS请求Zygote进程来创建一个新的应用程序进程。registerServerSocket方法源码如下:

// Android8.0\frameworks\base\core\java\com\android\internal\os\zygoteServer.java
void registerServerSocket(String socketName) {
    if (mServerSocket == null) {
        int fileDesc;
        // 拼接Socket的名称
        // 即,ANDROID_SOCKET_PREFIX_zygote
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
        try {
            // 将Socket全称转换为环境变量的值
            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);
            // 创建一个Server Socket
            // LocalServerSocket构造方法中为创建Socket的流程
            mServerSocket = new LocalServerSocket(fd);
        } catch (IOException ex) {
            throw new RuntimeException(
                "Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}

 Zygote进程启动SystemServer进程后(因为SystemServer进程会去启动各种系统关键服务,包括AMS,因此在等待请求之前需要提前创建它。),再去调用ZygoteServer的runSelectLoop方法无限等待AMS请求Zygote进程来创建一个新的应用程序进程。ZygoteServer的runSelectLoop方法源码如下:

// Android8.0\frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
    void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
		// 获取Server Socket的fd字段的值
		// 添加到fds列表中
        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null);
		// 无限等待AMS的请求
        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
		
            for (int i = pollFds.length - 1; i >= 0; --i) {
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
				// AMS与Zygote进程建立连接
                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    // 收到AMS发送的请求
					// 调用runOnce创建一个新的应用程序进程
                    boolean done = peers.get(i).runOnce(this);
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

 从runSelectLoop方法源码可知,它首先会将存储在Server Socket中的文件描述符fd取出,并插入到fds列表中;然后开启循环等待,当i=0时,说明AMS与Zygote进程建立了Socket链接,并通过acceptCommandPeer方法获取一个ZygoteConnection对象和将该对象的fd添加到fds列表中,以便可以接收到AMS发送过来的请求;最后,当i!=0时,说明AMS发送了一个新的创建应用程序进程的请求,此时Zygote进程就会去调用ZygoteConnection的runOnce方法进入新应用程序进程的创建工作。ZygoteConnection$runOnce方法源码如下:

// Android8.0\frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
    ...
        FileDescriptor fd = mSocket.getFileDescriptor();

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

    fd = zygoteServer.getServerSocketFileDescriptor();

    if (fd != null) {
        fdsToClose[1] = fd.getInt$();
    }

    fd = null;
    // Zygote进程fork自身创建新的应用程序进程
    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                                   parsedArgs.debugFlags, rlimits, 
                                   parsedArgs.mountExternal, parsedArgs.seInfo,
                                   parsedArgs.niceName, fdsToClose, fdsToIgnore, 
                                   parsedArgs.instructionSet,
                                   parsedArgs.appDataDir);
	...
	// pid=0
    // 当前代码逻辑运行在子进程中
    try {
        if (pid == 0) {
            // in child
            zygoteServer.closeServerSocket();
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            // 处理子进程启动逻辑
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

            // should never get here, the child is expected to either
            // throw Zygote.MethodAndArgsCaller or exec().
            return true;
        } else {
            // in parent...pid of < 0 means failure
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

 runOnce方法主要完成两个任务,一是调用Zygote的forkAndSpecialize方法创建一个子进程,该方法最终会调用Zygote的nativeForkAndSpecialize方法,这个方法是一个native方法,它将在native层调用fork函数实现子进程的创建;二是当pid=0时,说明子进程被创建成功且当前代码运行在子进程中,接着就会去调用ZygoteConnection的handleChildProc方法进入子进程(新的应用程序进程)的启动过程,这个我们下一节详谈。至此,Zygote进程的启动过程大体分析完毕,它主要完成以下工作:

  • 创建Dalvik/ART虚拟机,为虚拟机注册JNI方法;
  • 通过JNI调用ZygoteInit的main方法进入Zygote的Java层;
  • 启动SystemServer进程;
  • 创建Server Socket并等待AMS请求,然后创建新的应用程序进程。

Zygote进程启动过程时序图如下:
在这里插入图片描述
 最后,再解释一下为什么在system\core\rootdir目录下启动Zygote进程的脚本有多个,这是因为从Android5.0开始,Android开始支持64位程序,因此,Zygote也有了32位和64位之分,从之前分析的init.rc配置文件可知,Zygote进程的版本是通过ro.zygote属性来控制使用对应的脚本文件的。如果是32位程序,则选择脚本init.zygote32.rc来创建32位的Zygote进程;如果是64位程序,则选择脚本init.zygote64.rc;如果32和64均支持,则选择init.zygote32_64.rcinit.zygote64_32.rc脚本,执行其中的一个脚本都会创建两个Zygote进程。以init.zygote32_64.rc为例:

service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    priority -20
    user root
    group root readproc
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

 该脚本会创建两个Zygote进程,一个名为zygote,执行程序为/system/bin/app_process32,作为主模式;另一个名为zygote_secondary,执行程序为/system/bin/app_process64,作为辅模式。init.zygote64_32.rc脚本恰好与init.zygote32_64.rc功能相反。

发布了83 篇原创文章 · 获赞 293 · 访问量 30万+

猜你喜欢

转载自blog.csdn.net/AndrExpert/article/details/103399844