Android 启动流程

这篇是自己学习所用,请谨慎观看,具体内容可看下面博客:
Android启动流程简析
Android系统启动(里面含有所有函数和类的源码)

Android启动大纲概念图

安卓启动
Android 架构图
启动分析
init总结

Zygote进程在init进程中以service的方式启动的。通过init.rc中通过"import"的方式引入文件

zygote流程图

zygote是核心进程,支撑着所有android的应用程序。

  • 步骤1、系统加电,执行bootloader。 bootloader负责初始化软件运行所需的最小硬件环境,最后加
    载内核到内存中。
  • 步骤2、内核加载进内存后,将首先进入内核引导阶段,在引导阶段最后,调用start_kernel进入内
    核启动阶段。 start_kernel最终启动用户空间的init程序。
    -步骤3、 init程序负责解析配置文件,开启系统守护进程。两个最重要的守护进程是zygote和
    ServiceManager。前者是Android启动第一个Dalvik虚拟机,它将负责启动Java世界的进程;后者是
    Binder通信的基础。
    - 步骤4、 zygote虚拟机启动子进程system_server,在system_server中开启了Android核心系统服务,并将核心系统服务添加到ServiceManager,然后系统进入systemReady状态
  • 步骤5、在systemReady状态下,ActivityManagerService与zygote中的Socket通讯,通过zygote启动Home应用,进入系统桌面

Android 启动模式

  1. recovery 升级模式:启动recovery模式,内核和文件系统
  2. 正常启动模式:引导内核和启动Android系统


    启动模式

    recovery:清除数据和完成系统升级
    升级:差量包升级和全包升级(最好不要断电)

1、 bootloader介绍

可看博客bootloader
Bootloader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。

调用流程:
crt0.S > kmain > arch_init > target_init > apps_init > aboot_init

1.1、crt0.S

crt0.S代码大体如下,在_start中先主要完成CPU初始化,禁用mmu,禁用cache,初始化异常向量表等操作,最后将直接跳转到函数kmain中

2、 kernel 初始化介绍

Kernel初始化可以分成三部分:zImage解压缩、kernel的汇编启动阶段、Kernel的C启动阶段
内核启动引导地址由bootp.lds决定,内核启动的执行的第一条的代码在head.S文件中,主要功能是实现压缩内核的解压和跳转到内核vmlinux内核的入口,head.S是Linux内核启动的汇编程序入口,但head.S
中并没有直接调用start_kernel
在引导阶段最后,调用start_kernel进入内核启动阶段,start_kernel最终启动用户控件的init程序

3、 init程序

严格上讲,Android系统实际上是运行于Linux内核之上的一系列"服务进程",并不算一个完成意义上的"操作系统";而这一系列进程是维持Android设备正常工作的关键,所以它们肯定有一个"根进程",这个"根进程"衍生出了这一系列进程。这个"根进程"就是init进程。

学习目标:
  1. init进程是如何创建zygote的?zygote对应的service section
  2. property service来管理安卓系统的很多属性,这个属性服务是如何工作的.
    property_init初始化属性相关的资源。start_prperty_service()函数,启动属性服务

init程序负责解析init.rc配置文件来构建出系统的初始形态,开启系统守护进程。最重要的守护进程是zygote和servicemanager。前者是android启动的第一个dalvik虚拟机,负责启动java世界的进程。后者是binder通信的基础。

• 1、初始化文件系统和日志系统,为之后的执行阶段做准备。这部分主要是Linux标准函数的调用。
• 2、解析init.rc和init.<hardware>.rc初始化文件。
• 3、触发需要执行的Action和Service。
• 4、 init循环监听处理事件。 init触发所有Action后,进入一个无限循环,执行在可执行队列中的命令,
重启异常退出的Service,并循环处理来自propertyservice(属性服务)、 signal和keychord的事件。

3.1 init中第一个应用程序(pid=1)

内核起来后的第一个进程(命令ps可看进程)

init进程

ps:解析启动脚本是将服务、环境变量全部解析,然后根据脚本的设置来启动相关的服务、执行相关的命令,启动那个服务之后,就守护所有的服务。
init.cpp的入口函数是mian函数,同时也是ueventd和watchdogd守护进程的入口,通过参数进行控制.
init进程源码位置:system/core/init/init.cpp

int main(int argc, char** argv) {
// ****************** 第一部分 ****************** 
// 检查启动程序的文件名

    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (!strcmp(basename(argv[0]), "watchdogd")) {
        return watchdogd_main(argc, argv);
    }
}

主要是检查启动程序的文件名,这里面分成三种情况

1 如果文件名是"ueventd",则执行守护进程ueventd的主函数ueventd_main()
2 如果文件名是"watchdogd",则执行看门狗守护进程的主函数watchdogd_main()
如果文件名既不是"ueventd"也不是"watchdogd",则往下执行

3.2 init中创建目录,挂载分区

默认情况下,一个进程创建出来的文件和文件夹属性都是022,使用umask()函数能设置文件属性的掩码。参数为0意味着进程创建的文件属性是0777。接着创建一些基本的目录包括dev、proc、sys等,同时把分区mount到对应的目录
system/core/init/first_stage_init.cpp

// ****************** 第二部分 ****************** 
// 设置文件属性为0777
    // Clear the umask.
    umask(0);

// ****************** 第三部分 ****************** 
// 设置环境变量地址
    add_environment("PATH", _PATH_DEFPATH);

// ****************** 第四部分 ****************** 
// 创建一些基本目录,包括/dev、/proc、/sysfc
//把一些文件系统如"tmpfs",sysfs等mount到项目的目录中

    //判断是否是第一次
    bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);

    // 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
    //如果是第一次.
    if (is_first_stage) {
        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
        mkdir("/dev/pts", 0755);
        mkdir("/dev/socket", 0755);
        mount("devpts", "/dev/pts", "devpts", 0, NULL);
        mount("proc", "/proc", "proc", 0, NULL);
        mount("sysfs", "/sys", "sysfs", 0, NULL);
    }


// ****************** 第五部分 ****************** 
//调用open_devnull_stdio()函数把标准输入、标准输出和标准错误重定向到空设备文件"/dev/null",这是创建守护进程常用的手段
    // We must have some place other than / to create the device nodes for
    // kmsg and null, otherwise we won't be able to remount / read-only
    // later on. Now that tmpfs is mounted on /dev, we can actually talk
    // to the outside world.
    open_devnull_stdio();


// ****************** 第六部分 ****************** 
//调用klog_init()函数创建节点/dev/kmsg,这样init进程可以使用kernel的log系统来出log了,同时调用klog_set_level函数来设置输出log的级别。
// 启动kernel log
    klog_init();
    klog_set_level(KLOG_NOTICE_LEVEL);

    // 输出init启动阶段的log      
    NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");

init进程会调用property_init创建一个共享区域来存储属性值,初始化完后获取kernel传过来的cmdline去设置一些属性,然后初始化SELinux和安全上下文。接着会通过property_load_boot_defaults去加载default.prop等文件初始化系统属性
init.cpp
具体实现在:property_service.cpp


// ****************** 第七部分 ****************** 
// 如果不是第一次,则进行一些设置,我又将这里具体划分为4个部分
// 设置系统属性
    if (!is_first_stage) {
        // Indicate that booting is in progress to background fw loaders, etc.
// 7.1 创建初始化标志
        close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
//在/dev目录下创建一个空文件".booting"表示初始化正在进行
//is_booting()函数会依靠空文件".booting"来判断是否进程处于初始化中,初始化结束后,这个文件会被删除

//7.2 初始化Android的属性系统,property_init()函数主要作用是创建一个共享区域来存储属性值
        property_init();

        // If arguments are passed both on the command line and in DT,
        // properties set in DT always have priority over the command-line ones.
//7.3  解析(设备树)DT和命令行中的kernel启动参数
        process_kernel_dt();
        process_kernel_cmdline();

        // Propogate the kernel variables to internal variables
        // used by init as well as the current required properties.
//7.4  设置系统属性,设置ro属性根据之前的ro.boot这类的属性值
        export_kernel_boot_props();
    }

// ****************** 第八部分 ****************** 

    // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
    // 调用selinux_initialize函数启动SELinux
//安全增强型 Linux(Security-Enhanced Linux)它是一个 Linux 内核模块,也是 Linux 的一个安全子系统。

    selinux_initialize(is_first_stage);

    // If we're in the kernel domain, re-exec init to transition to the init domain now
    // that the SELinux policy has been loaded.
    if (is_first_stage) {

        // 按照selinux policy要求,重新设置init文件属性
        if (restorecon("/init") == -1) {
            ERROR("restorecon failed: %s\n", strerror(errno));
            security_failure();
        }
        char* path = argv[0];

        // 设置参数  --second-stage
        char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };

        // 执行init进程,重新进入main函数
        if (execv(path, args) == -1) {
            ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));
            security_failure();
        }
    }

    // These directories were necessarily created before initial policy load
    // and therefore need their security context restored to the proper value.
    // This must happen before /dev is populated by ueventd.
    INFO("Running restorecon...\n");
    restorecon("/dev");
    restorecon("/dev/socket");
    restorecon("/dev/__properties__");
    restorecon_recursive("/sys");

// ******************init 第九部分 ******************

这部分分为上下按两个阶段
第一阶段主要是调用epoll_create1创建epoll句柄,如果创建失败,则退出。
第二阶段是调用signal_handler_init()函数,主要是装载进程信号处理器。
signal_handler_init()函数主要是当子进程被kill之后,会在父进程接受一个信号。处理这个信号的时候往sockpair一段写数据,而另一端的fd是加入epoll中
// 在Linux中,父进程是通过捕捉SIGCHILD信号来得知子进程运行结束的情况
这里我们简单介绍下信号:
Linux进程通过相互发送接收消息来实现进程间通信,这些消息被称为"信号"。每个进程在处理它进程发送的信号时,都要注册处理者,处理者被称为信号处理器。

每个进程在处理其他进程发送的signal信号时都需要先注册,当进程的运行状态改变或终止时会产生某种signal信号,init进程是所有用户空间进程的父进程,当其子进程终止时产生SIGCHLD信号,init进程调用信号安装函数sigaction(),传递参数给sigaction结构体,便完成信号处理的过程。
当init进程调用signal_handler_init后,一旦受到子进程终止带来的SIGCHLD消息后,将利用信号处理者SIGCHLD_handler向signal_write_fd写入信息;epoll句柄监听到signal_read_fd收到消息后,将调用handle_signal进行处理。如下图

image.png

    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) {
        ERROR("epoll_create1 failed: %s\n", strerror(errno));
        exit(1);
    }
    signal_handler_init();{}

// ****************** 第十部分 ******************
上半部分是调用property_load_boot_defaults()函数解析根目录的default.prop的属性,设置默认属性配置的相关工作。下半部分是调用start_prperty_service()函数,启动属性服务,并接受属性的socket的fd加入到epoll中,也定义了处理函数。那我们依次来看下

property_load_boot_defaults();
start_property_service();

// ****************** 第十一部分 ******************

// 重点部分,解析init.rc文件

init_parse_config_file("/init.rc");

// ****************** 第十二部分 ******************
将把Action加入执行队列中

// 执行init.rc中触发器为 on early-init的语句,即将early-init的Action添加到链表action_queue中

    action_for_each_trigger("early-init", action_add_queue_tail);

    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...

    // 等冷插拔设备初始化完成,即创建wait_for_coldboot_done Action并添加到action_queue和action_list中
    queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    // ... so that we can start queuing up actions that require stuff from /dev.
    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

    // 设备组合键的初始化操作,创建keychord_init Action 并添加到链表action_queue和action_list中 
    queue_builtin_action(keychord_init_action, "keychord_init");
    // 创建console_init动作并添加到链表action_queue和action_list中
    queue_builtin_action(console_init_action, "console_init");

    // Trigger all the boot actions to get us started.
    // 执行init.rc文件中触发器为 on init 的语句,将init动作添加到链表action_queue中
    action_for_each_trigger("init", action_add_queue_tail);

    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
    // wasn't ready immediately after wait_for_coldboot_done
    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

    // Don't mount filesystems or start core system services in charger mode.
    char bootmode[PROP_VALUE_MAX];

    // 当处于充电模式,则charger加入执行队列;否则late-init加入队列。
    if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) {
        action_for_each_trigger("charger", action_add_queue_tail);
    } else {
        action_for_each_trigger("late-init", action_add_queue_tail);
    }

    // Run all property triggers based on current state of the properties.
    // 触发器为属性是否设置
    queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");

上面大量的调用了action_for_each_trigger函数、action_add_queue_tai函数和queue_builtin_action.
action_for_each_trigger()
queue_builtin_action函数用来动态生成一个Action并插入到执行列表"action_queue中"。插入的Action由一个函数指针和一个表示名字的字符串组成。Android在以前版本中直接调用这些函数来完成某些初始化的工作,但是,这些函数可能会依赖init.rc里面定义的一些命令和服务的执行情况。现在把这些初始化函数也通过Action的形式插入到执行列表中,这样就能控制他们的执行顺序了。

****************** 第十三部分 ******************

        while (true) {
        // 判断是否还有事件需要处理
        if (!waiting_for_exec) {
             //依次执行每个action中携带的command对应的执行函数
            execute_one_command();
             // 重启一些挂掉的进程
            restart_processes();
        }

        // 决定timeout的时间,将影响while循环的间隔
        int timeout = -1;

       // 有进程需要重启是,等待进程重启
        if (process_needs_restart) {
            timeout = (process_needs_restart - gettime()) * 1000;
            if (timeout < 0)
                timeout = 0;
        }

        if (!action_queue_empty() || cur_action) {
            timeout = 0;
        }

        // 进行性能数据采样
        bootchart_sample(&timeout);

        epoll_event ev;
        // 没有事件来的话,最多阻塞timeout时间
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
        if (nr == -1) {
            ERROR("epoll_wait failed: %s\n", strerror(errno));
        } else if (nr == 1) {
             // 根据上下文知道,epoll句柄(即epoll_fd)主要监听子进程结束,及其他进程设置系统属性的请求 ,根据事件的到来,执行对应处理函数
            ((void (*)()) ev.data.ptr)();
        }
    }

最后init进程会进入到一个无线循环中去,在这个无线循环中,init进程会做以下五件事:

第一件事:调用函数execute_one_command来检查action_queue列表是否为空。如果不为空的话,那么init进程就将保存在列表头部中的action移除,并且执行这个被移除的action。由于前面我们将一个名称为"console_init"的action添加到action_queue列表中,因此,在这个无线循环中,这个action就会被执行,即console_init_action函数会被调用。

第二件事:调用函数restart_processes来检查系统中是否有进程需要重启。在启动脚本init.rc中,我们可以指定一个进程在退出之后会自动重启。在这种情况下,函数restart_processes就会检查是否存在需要重新启动的进程,如果存在的话,那么就将它重新启动起来。

第三件事:处理系统属性变化事件。当我们调用函数property_set来改变一个系统属性时,系统就会通过一个socket(通过调用函数get_property_set_fd可以获得它的文件描述符)来向init进程发送一个属性值改变事件通知。init进程接受到这个属性值改变事件之后,就会调用函数handle_property_set_fd来进行相应的处理。后面在分析第三个开机画面显示过程时,我们就会看到,SurfaceFlinger服务就是通过修改“ctl.start”和“ctl.stop”属性来启动和停止三个开机画面的。

第四件事:处理一种被称为"chorded keyboard"的键盘输入时间。这种类型为"chorded keyboard"的键盘设备通过不同的按键组合来描述不同的命令或者操作,它对应的设备为/dev/keychord。我们可以通过调用函数get_keychord_fd()来获的这个设备的文件描述符,以便可以监控它的输入事件,并且调用函数handle_keychord来对这些输入事件进行处理。

第五件事:回收僵尸进程。我们知道,在Linux内核中,如果父进程不等待子进程结束就退出,那么当子进程结束的时候,就会变成一个僵尸进程,从而占用系统的资源。为了回收这些僵尸进程,init进程会安装一个SIGCHLD信号接收器。当这些父进程已经退出了子进程退出的时候,内核就会发出一个SIGCHLD信号,给init进程,init进程就可以通过一个socket(通过调用函数get_signal_fd可以获得它的文件描述符)来将接受到的SIGCHLD信号读取回来,并且调用函数handle_signal来对接收到的SIGCHLD信号来进行处理,即回收哪些已经变成僵尸进程的子进程。

init源码分析

/proc:内核的信息输出目录。
selinux_klog_callback:这就是把信息写入klog中
在init.cpp中,main函数中,会创建很多的文件夹(如/dev),并且关在一些分区。
get_hardware_name中,
cat /proc/cpu可以显示,getprop ro.boot.hardware具体得到硬件信息。
cat /proc/cmdline:启动时传的参数

3.3 init.rc:启动脚本

init.rc文件是以“块”(section)为单位服务的,,一个“块”(section)可以包含多行。“块”(section)分成两大类:一类称为"动作(action)",另一类称为“服务(service)”.
无论是“动作(action)”块还是“服务(service)”块,并不是按照文件中的编码排序逐一执行的

  • 动作(action):以关键字"on" 开头,表示一堆命令
  • 服务(service):以关键字“service”开头,表示启动某个进程的方式和参数

一个init.rc脚本由4个类型的声明组成,即

Action——行为/动作
commands——命令/启动
services—— 服务
Options—— 选项
Action(动作)

on  <trigger>           ## 触发条件
      <command>     ##执行命令
      <command1>   ##可以执行多个命令

init中在初始化属性和SELinux后,接着解析init.rc的文件内容,通过init.rc进行相关语法配置、启动进程以及启动的顺序

启动脚本

路径:/system/core/rootdir
image.png

parse_config()函数解析脚本文件的逻辑过程可以用一张流程图来表示,如下图所示。通过调用next_token()函数的作用就是寻找单词结束标志或行结束标志。 如果是单词结束符,就先存放在数组args中,如果找到的是行结束符,则根据行中的第一个单词来判断是否是一个"section","section"的标志有3个,关键字"on","service","import"。如果是"section"则调用函数parse_new_section来开启一个新"section"的处理,否则把这一行继续作为当前"section"所属的行来处理。

流程图

第一个函数:把启动脚本的命令解析到列表中,然后调用下面的函数


init 脚本

用parse_config来解析。
service_list:保存脚本中所有的服务
action_list:保存所有的操作
action_queue:把要执行的服务和操作保存在这里

命令和结构:lookup_keyword函数。
parse_new_section:把解析的加入到listaction。

init事件列表(list结构)

init事件列表

init事件结构

init事件结构

一个section下面挂着多个操作。

android 脚本执行和进程守护
启动脚本解析结果
解析后放入两个结构体中,然后放入队列中


都是on打头。
整理事件列表

init构建事件

将自己的函数放入到antion_queue中
service 事件分类

init进程执行命令和启动服务
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
//声明bai了一个类A,类A里声du明了一个成员函数void f(),但没有在类的zhi声明里给出f的定义,那么在类外定义f时,
//就要写成void A::f(),表示这个f()函数是类A的成员函数

ActionManager& am = ActionManager::GetInstance();
ServiceManager& sm = ServiceManager::GetInstance();
Parser& parser = Parser::GetInstance();

parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sm));
//c++中的<>代表baiC++模板。
parser.AddSectionParser("on", std::make_unique<ActionParser>(&am));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
    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);
}

am.QueueEventTrigger("early-init");

// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
am.QueueBuiltinAction(set_kptr_restrict_action, "set_kptr_restrict");
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
am.QueueBuiltinAction(console_init_action, "console_init");

// Trigger all the boot actions to get us started.
am.QueueEventTrigger("init");

// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
// wasn't ready immediately after wait_for_coldboot_done
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

// Don't mount filesystems or start core system services in charger mode.
std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") {
    am.QueueEventTrigger("charger");
} else {
    am.QueueEventTrigger("late-init");
}
    
// Run all property triggers based on current state of the properties.
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

main函数最后会进入一个死循环,每次循环都会去调用ExecuteOneCommand执行命令列表中的一条命令,如果服务挂了还会调用restart_processes重启服务

while (true) {
    // By default, sleep until something happens.
    int epoll_timeout_ms = -1;

    if (do_shutdown && !shutting_down) {
        do_shutdown = false;
        if (HandlePowerctlMessage(shutdown_command)) {
            shutting_down = true;
        }
    }

    if (!(waiting_for_prop || sm.IsWaitingForExec())) {
        am.ExecuteOneCommand();
    }
    if (!(waiting_for_prop || sm.IsWaitingForExec())) {
        if (!shutting_down) 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;
    }

    epoll_event ev;
    int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
    if (nr == -1) {
        PLOG(ERROR) << "epoll_wait failed";
    } else if (nr == 1) {
        ((void (*)()) ev.data.ptr)();
    }
}

init进程初始化系统后,会化身为守护进程来处理子进程的死亡信号、修改属性的请求和组合键事件.
目的:了解init如何守护服务,设置property。
init在for循环中三个动作:

  1. 启动我们的服务,执行脚本命令
  2. 根据Shell或者系统中消息设置系统Prop
  3. 守护系统服务,如果服务退出,重启退出的服务
init与其他进程交互示意图

主要是两个套接字:

  1. 设置prop
  2. 监听子进程退出。


    init 处理prop消息分析

    函数:
    property_service_init_action。
    start_property_service
    property_set_fd
    handle_property_set_fd

init 守护服务分析

queue_builtin_action(signal_init_action,"signal_init")
sigchld_handler会创建两个socket,创建之后,init会监听signal_recv_fd,子进程会继承所有的,然后子进程意外退出时会触发sigchld,然后进行处理两个socket。(signla_fd发送给signal_recv_fd),然后用wait重启。
在init.rc中,import:导入其他的脚本
system/core/rootdir/init.rc, 在init.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
import /init.${ro.zygote}.rc

on:


这四种方式,后面都会跟一些命令,在init.c中会解析on后面跟着的选项,后面的命令代表了执行的时间。
on trigger:条件判断是否执行。
在init.cpp中,启动init.rc各个阶段的顺序是early_init > init > late_init,在late_init中又会去触发其他阶段的启动,所以各个阶段在init中启动的顺序如下:
early_init > init > late_init > early-fs > fs > post-fs > late_fs > post-fs-data > zygote-start > early-boot > boot

在boot阶段会启动class为hal和core的服务

on boot
    ...
    class_start hal
    class_start core

init.rc中支持的命令实现在builtins.cpp中,具体语法使用可以参考system/core/init/README.md

3.4 bootanim 启动

bootanim.rc定义了bootanim属于core服务,但是设置了disable说明bootanim不是自启动的服务,需要别的服务进行唤醒。

service bootanim /system/bin/bootanimation
    class core animation
    user graphics
    group graphics audio
    disabled
    oneshot
    writepid /dev/stune/top-app/tasks

kernel-vfs-bootUI-显示android 主lunch。

  1. init :守护进程
  2. surfaceflinger:界面管理服务,初始化显示,结束后调用startbootanim,启动bootanimation
  3. boot 启动界面服务,然后和surfaceflinger来进行交互,得到显示的层,根据显示机制,刷新屏幕
  4. zygote:用以创建所有的java应用程序和服务
  5. system_service:会在中间创建java层所有的服务

service.bootanim.exit为1时,退出bootanimation。

bootanim工作流程

3.5 surfaceflinger启动

代码里搜索bootanim,可以看到是surfaceflinger服务将bootanim启动,surfaceflinger属于core服务,自启动服务,在init进程的on boot阶段会启动surfaceflinger,surfaceflinger最后会启动StartPropertySetThread从而启动bootanim

service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    onrestart restart zygote
    writepid /dev/stune/foreground/tasks
    socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
    socket pdx/system/vr/display/manager    stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
    socket pdx/system/vr/display/vsync      stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
bool StartPropertySetThread::threadLoop() {
    // Set property service.sf.present_timestamp, consumer need check its readiness
    property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
    // Clear BootAnimation exit flag
    property_set("service.bootanim.exit", "0");
    // Start BootAnimation if not started
    property_set("ctl.start", "bootanim");
    // Exit immediately
    return false;
}

surfaceflinger服务的main函数入口在main_surfaceflinger,主要操作有:

启动Hidl服务,主要是DisplayService
启动线程池
初始化SurfaceFlinger
将SurfaceFlinger和GpuService注册到ServiceManager
启动SurfaceFlinger线程

int main(int, char**) {
    startHidlServices();

    signal(SIGPIPE, SIG_IGN);
    // When SF is launched in its own process, limit the number of
    // binder threads to 4.
    ProcessState::self()->setThreadPoolMaxThreadCount(4);

    // start the thread pool
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();

    // instantiate surfaceflinger
    sp<SurfaceFlinger> flinger = new SurfaceFlinger();

    setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);

    set_sched_policy(0, SP_FOREGROUND);

    // Put most SurfaceFlinger threads in the system-background cpuset
    // Keeps us from unnecessarily using big cores
    // Do this after the binder thread pool init
    if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM);

    // initialize before clients can connect
    flinger->init();

    // publish surface flinger
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);

    // publish GpuService
    sp<GpuService> gpuservice = new GpuService();
    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);

    struct sched_param param = {0};
    param.sched_priority = 2;
    if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
        ALOGE("Couldn't set SCHED_FIFO");
    }

    // run surface flinger in this thread
    flinger->run();

    return 0;
}

surfaceflinger继承了Thread(class Rectangle: public Shape),执行run方法后,本质上是调用c++中的pthread类,线程入口函数是threadLoop,threadLoop的含义是通过一个循环不断的调用该函数,当threadLoop返回false的时候退出循环

由于bootanim的threadLoop返回false,所以启动函数在开机过程中只会执行一次

4、Zygote启动

zygote本身是一个native的应用程序,由init进程根据init.rc文件中的配置项创建的。Zygote初始化时会创建创建虚拟机,同时把需要的系统类库和资源文件加载到内存里面。Zygote fork出子进程后,这个子进程也继承了能正常工作的虚拟机和各类系统资源,接下来子进程只需要装载APK文件的字节码文件就可以运行了。这样应用程序的启动时间就会大大缩短。

4.1 在init.rc脚本中配置

Zygote进程在init进程中以service的方式启动的。 通过init.rc中通过"import"的方式引入文件
当init进程真的启动zygote服务的时候,会走到会走到service_start()函数,
Android系统启动——4 zyogte进程 中详细讲解了service_start函数。

import /init.${ro.zygote}.rc

在init.rc执行过程中,在on boot阶段,会trigger zygote-start,on zygote-start会根据当前的加密状态选择启动服务。

import /init.${ro.zygote}.rc`

on zygote-start && property:ro.crypto.state=unencrypted
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

在init.rc中,import zygote的启动rc文件:import /init.${ro.zygote}.rc
主要是根据属性ro.zygote决定,rc文件位于alps/system/core/rootdir/:
init.zygote32.rc
init.zygote32_64.rc
init.zygote64.rc
init.zygote64_32.rc

4.2 app_main

主要功能由appruntime中的start来实现。
app_main 代码:/frameworks/base/cmds/app_process/app_main.cpp,:

int main(int argc, char* const argv[])
{

    // ******************** 第一部分 *********************
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
        // Older kernels don't understand PR_SET_NO_NEW_PRIVS and return
        // EINVAL. Don't die on such kernels.
        if (errno != EINVAL) {
            LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
            return 12;
        }
    }

    // ******************** 第二部分 *********************
这部分主要是创建了AppRuntime对象,AppRuntime类继承自AndroidRuntime。
接着从命令行参数中找到虚拟机相关的参数,添加到runtime对象
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // Process command line arguments
    // ignore 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]));
    }

    // 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;
        } 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()) {
        // 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 (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }

     // ******************** 第七部分 *********************  
启动Java类,如果启动参数带有 "--zygote"。则执行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.");
        return 10;
    }
}
  • 初始化AppRuntime,AppRuntime继承于AndroidRuntime
  • 解析传入参数
  • 根据参数启动Zygote:从init.rc传入的参数 为-Xzygote /system/bin --zygote --start-system-server
    -Xzygote是传递给虚拟机的参数
    /system/bin 是 parent dir(程序运行目录)
    启动参数带有 "--zygote"。则执行ZygoteInit。

在解析完参数后,最终调用:com.android.internal.os.ZygoteInit进行Zygote的初始化

4.3 AppRuntime

AppRuntime继承于AndroidRuntime的构造函数,并且重载了onVmCreated 、onStarted、onZygoteInit和onExit函数。AndroidRuntime初始化时会初始化Skia图形系统.
AndroidRuntime类是安卓底层系统超级重要的一个类,它负责启动虚拟机以及Java线程。AndroidRuntime类是在一个进程中只有一个实例对象,并将其保存在全局变量gCurRuntime中。

AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
        mExitWithoutCleanup(false),
        mArgBlockStart(argBlockStart),
        mArgBlockLength(argBlockLength)
{
    SkGraphics::Init();

    // Pre-allocate enough space to hold a fair number of options.
    mOptions.setCapacity(20);

    assert(gCurRuntime == NULL);        // one per process
    gCurRuntime = this;
}

SkGraphics::Init();:
这里主要是初始化skia图形系统。skia是google的第一个底层的图形、图像、动画、SVG、文本等多方面的图形图,是Android图形系统的引擎。skia作为第三方软件放在external目录下: external/skia/。后面附了一个skia结构图
mOptions.setCapacity(20);:预先分配空间来存放传入虚拟机的参数
gCurRuntime = this;:首先通过的断言判断gCurRuntime是否为空,保证只能被初始化一次

AppRuntime类:

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

    

AppRuntime启动zygote时调用的是AndroidRuntime的start函数
className的值是“com.android.internal.os.ZygoteInit"

/*
 * 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<String8>& options, bool zygote)
{
    //******************* 第一部分**********************
第一部分——打印log
首先调用了ALOGD方法,用来记录日内容(ALOGD记录的日志在编译的时候时候存在,但是在运行时会被提出),标志着Android的启动。后面跟着的for循环,来判断是否是启动systemServer(即传入的参数是或否有startSystemServer),如果是启动systemServer,同样要打印日志。

    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
            className != NULL ? className : "(unknown)", getuid());

    static const String8 startSystemServer("start-system-server");

    /*
     * 'startSystemServer == true' means runtime is obsolete and not run from
     * init.rc anymore, so we print out the boot start event here.
     */
    for (size_t i = 0; i < options.size(); ++i) {
        if (options[i] == startSystemServer) {
           /* track our progress through the boot sequence */
           const int LOG_BOOT_PROGRESS_START = 3000;
           LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
        }
    }

     //******************* 第二部分**********************
第二部分——获取系统目录
系统目录从环境变量ANDROID_ROOT中读取。如果说去失败,则默认设置目录为"/system"。如果连"/system"也没有,则Zygote进程会退出。
    const char* rootDir = getenv("ANDROID_ROOT");
    if (rootDir == NULL) {
//如果环境变量中没有,则新增该变量,并设置为/system       
 rootDir = "/system";
        if (!hasDir("/system")) {
            LOG_FATAL("No root directory specified, and /android does not exist.");
            return;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }

    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);


    //******************* 第三部分**********************
通过jni_invocation.Init(NULL)完成jni接口的初始化。接着是创建虚拟机的代码,即调用startVm函数。
    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }

    //******************* 第四部分**********************
    onVmCreated(env);


    //******************* 第五部分**********************
<meta charset="utf-8">

##### 第五部分——注册系统的JNI函数

startReg()函数通过调用register_jni_procs()函数将全局的gRegJNI中的本地JNI函数在虚拟机中注册,
这部分的解析请参考[3、Android跨进程通信IPC之3——关于"JNI"的那些事](https://www.jianshu.com/p/cd038167d896)中的**4、JNI查找方式**


    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

   //******************* 第六部分**********************
    /*为启动Java类的main函数做准备
     * 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);
    }


   //******************* 第七部分**********************
    /*调用Zygoteinit类的main()函数
     * 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 {
        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");
}
   

start函数主要做了以下操作:
1、创建了一个JniInvocation的实例,并且调用它的成员函数init来初始化JNI环境。
2、调用AndroidRuntime类的成员函数startVm来创建一个虚拟机即其对应的JNI接口,即创建一个JavaVM接口和一个JNIEnv接口。
3、有了上述的JavaVM接口和JNIEnv接口之后,就可以在Zygote进程中加载指定的class了。

  • 判断是否启动systemserver
  • 启动虚拟机:startVm,里面的参数在这个函数里面确定的。
  • 注册JNI函数:startReg:后续的java世界采用native方式实现,所以必须提前注册这些函数。
  • 调用JNI函数:
    JNI函数是通过调用startReg()实现,主要是注册gRegJNI[]数组,调用了com.android.internal.os.ZygoteInit类中的main函数

4.4 Zygote

AndroidRuntime.cpp的start()函数里面是调用的Zygoteinit类的main()函数来启动zygote:

    public static void main(String argv[]) {
        try {

            //**************** 第一阶段 **********************

            // 启动DDMS
            RuntimeInit.enableDdms();
            // Start profiling the zygote initialization.

            // 启动性能统计 
            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.");
            }

           //**************** 第二阶段 **********************
            registerZygoteSocket(socketName);
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());

           //**************** 第三阶段 **********************
            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            // Finish profiling the zygote initialization.
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // Do an initial gc to clean up after startup
            gcAndFinalize();

            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);

           //**************** 第四阶段 **********************
            if (startSystemServer) {
                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;
        }
    }
zygote启动分析

我将ZygoteInit的main()方法分为5个阶段,阶段解析如下:
第一阶段:主要是解析调用的参数,即argv[],通过for循环遍历解析,通过string的方法来判断,主要出是初始化startSystemServer、abiList和socketName变量
第二阶段:调用registerZygoteSocket(socketName)方法注册Zygote的socket监听接口,用来启动应用程序的消息。建立IPC通信服务端。
第三阶段:调用preload()方法装载系统资源,包括系统预加载类、Framework资源和openGL的资源。这样当程序被fork处理后,应用的进程内已经包含了这些系统资源,大大节省了应用的启动时间。
第四阶段:调用startSystemServer()方法启动SystemServer进程。所有的服务,都在startsystemserver中创建出来。这个函数会创建Java世界中系统Service所驻留的进程 system_server,该进程是framework的核心。
第五阶段:调动runSelectLooper方法进入监听和接收消息的循环

preload

为了加快应用程序的启动,Android把系统公用的Java类和一部分Framework的资源保存在zygote中了,这样就可以保证zygote进程fork子进程的是共享的。


预加载

zygote预加载资源

预加载系统的类。
预加载资源:图片和颜色设置。保存在全局变量中。
如颜色:mResources.getColorStateList(id)。

zygote预加载目的

zygote:提前加载后,使用fork时继承系统资源,然后用java方法进行启动,这样应用不用重新加载资源和类,可以提高应用启动和运行速度。


image.png

加载系统资源,首先创建一个resources,保存系统的资源。导入类的配置文件。最后class.forname,进行加载。

启动systemserver

Zygote类的main()方法里面的第四阶段调用startSystemServer启动系统服务,代码在zygoteinit.java中,

zygote创建system_server主要方法

1、为fork准备参数parsedArgs
2、调用Zygote.forkSystemServer()方法来创建system_server
3、调用handleSystemServerProcess()方法执行system_server的剩余工作

forksystemserver创建子进程的过程中,调用native方法来相关信号的处理。在子进程中调用handlesystemserverprocess。

  1. 关闭Zygote的socket两端的连接
    在fork过程中复制了原来位于zygote进程的socket服务端,这里关闭了从父进程复制而来的socket
    在关闭和子进程退出的时候,用来关闭并清理zygote的socket,
  2. 通过设置umask创建文件的默认权限
    3、设置进程名字 ,即设置当前进程名为"system_server"
    4、获取SYSTEMSERVERCLASSPATH环境变量值(一系列jar),如果需要,则进行dex优化
    5、最后一步,也是最重要的一步:由于invokeWith为null,所以
    会通过RuntimeInit.zygoteInit中调用applicationInit,进而调用invokeStaticMain,然后就会调用SystemServer的main()方法,下面会详细讲解的
Zygote.forkSystemServer()函数解析

主要是调用nativeForkSystemServer方法,通过C层来实现创建system_server进程。在
nativeForkSystemServer中调用ForkAndSpecializeCommon函数来fork子进程。
在ForkAndSpecializeCommon中,有三个核心函数,即SetSigChldHandler()与UnsetSigChldHandler()函数、fork()函数和zygote.callPostForkChildHooks()函数,

handleSystemServerProcess()函数解析

完成fork后新的system server进程的剩余工作

RuntimeInit.zygoteInit函数解析

在调用applicationInit方法前进行一些初始化操作,即日志重定向和zygote初始化
调用applicationInit进行应用初始化

256    /**
257     * The main function called when started through the zygote process. This
258     * could be unified with main(), if the native code in nativeFinishInit()
259     * were rationalized with Zygote startup.<p>

269    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
270            throws ZygoteInit.MethodAndArgsCaller {
271        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
272
273        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
          // 日志重定向
274        redirectLogStreams();
           // 通用的初始化工作
276        commonInit();
            // zygote初始化
277        nativeZygoteInit();
            // 应用的初始化
278        applicationInit(targetSdkVersion, argv, classLoader);
279    }
invokeStaticMain函数解析(runtimeinit.java中)

调用目标类className类的静态main(argv []) 方法。将各种失败异常转化为RuntimeExceptions,并且这些异常将会导致VM实例退出。该函数最后一句抛出异常的语句,根据注释,这个ZygoteInit.MethodAndArgsCaller的"异常"会被ZygoteInit.main()捕获。
在ZygoteInit.main中,

public static void main(String argv[]) {
    try {
        ....
    } catch (MethodAndArgsCaller caller) {
        caller.run();
    } catch (RuntimeException ex) {
        closeServerSocket();
        throw ex;
    }
}
zygote创建system_server

startsystemserver创建子进程。
异常被catch捕获,

  1. 创建子进程
  2. 设置子进程相关函数
  3. 完成systemserver启动的参数,包括类名和入口函数,然后抛出异常,然后被捕获异常并启动systemserver。

zygote 创建app,处理启动应用的请求

ZygoteInit类的main()方法调用runSelectLoop()方法来监听和处理启动应用的请求

zygote 创建应用

前面提到了注册IPC socket,这里将使用到。

654    /**
655     * Runs the zygote process's select loop. Accepts new connections as
656     * they happen, and reads commands from connections one spawn-request's
657     * worth at a time.
658     *
659     * @throws MethodAndArgsCaller in a child process when a main() should
660     * be executed.
661     */
662    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
663        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
664        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
665
         # fds[0]为sServerSocket,即sServerSocket为位于zygote进程中的socket服务端

666        fds.add(sServerSocket.getFileDescriptor());
667        peers.add(null);
668
669        while (true) {
//************************** 第1部分   ************************** 
670            StructPollfd[] pollFds = new StructPollfd[fds.size()];
671            for (int i = 0; i < pollFds.length; ++i) {
672                pollFds[i] = new StructPollfd();
                   // pollFds[0].fd即为sServerSocket,位于zygote进程中的socket服务端。
673                pollFds[i].fd = fds.get(i);
674                pollFds[i].events = (short) POLLIN;
675            }
676            try {
                   // 查询轮训状态,当pollFdd有事件到来则往下执行,否则阻塞在这里
677                Os.poll(pollFds, -1);
678            } catch (ErrnoException ex) {
679                throw new RuntimeException("poll failed", ex);
680            }
681            for (int i = pollFds.length - 1; i >= 0; --i) {
                 // 采用I/O 多路复用机制,当接受到客户端发出的连接请求,或者处理出具时,则往下执行
                 // 否则进入continue,跳出本次循环 
682                if ((pollFds[i].revents & POLLIN) == 0) {
683                    continue;
684                }
//************************** 第2部分   **************************
685                if (i == 0) {
                      // 客户端第一次请求服务端,服务端调用accept与客户端建立连接,客户端在zygote以ZygoteConnection对象表示
686                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
687                    peers.add(newPeer);
688                    fds.add(newPeer.getFileDesciptor());
689                } else {
//*************************** 第3部分   **************************
                      // 经过上个if操作后,客户端与服务端已经建立连接,并开始发送数据
                      //peers.get(index)取得发送数据客户端的ZygoteConnection对象
                      // 然后调用runOnce()方法来出具具体请求
690                    boolean done = peers.get(i).runOnce();
691                    if (done) {
692                        peers.remove(i);
                           // 处理完则从fds中移除该文件描述符
693                        fds.remove(i);
694                    }
695                }
696            }
697        }
698    }
runonce

从socket中读取一个启动命令,如果成功,则在fork一个子进程,并在在子进程中抛出一个异常,但是在父进程中是正常返回的。如果失败,子进程不会被fork出来,并且把错误信息会被答应在日志中。这里会返回一个布尔的状态值,表示是否结束socket。

返回值 false:如果socket还能继续读取,则返回false,如果读取结束,则返回true

zygote创建应用流程
  1. 调用readArgumentList()方法从socket连接中读入个多个参数
  2. 读取完毕后,调用Arguments有参构造函数,new一个Arguments 对象即parsedArgs。将上面的参数解析成列表。这个列表对象就是parsedArgs
  3. 解析完参数后,还要对这些参数进行检查和设置。
  4. 参数检查无误后,将调用Zygote类的forkAndSpecialize来fork子进程
  5. 上面结束后,如果返回的pid等于0,表示处于子进程中,执行handleChildProc(),如果pid不等于0,则表示在zygote进程中,则调用handleParentProc()方法继续处理。

创建socket,监听本地socket,管理好每一个session
解析启动消息,收到connect时,添加session链接,使用android启动的方式进行创建进程。
fds:用以保存我们监听的socket
peers:就是一个session

zygote创建system_server

ZogyteInit的main函数主要操作:

  1. 创建ZogyteServer并标记启动
  2. 设置进程pid和gid为0
  3. 解析参数
  4. 创建本地socket服务
  5. 预加载系统类和资源
  6. fork SystemServer进程
  7. 启动ZogyteServer的selectLoop线程处理子进程的命令
zygote启动流程总结

1 创建AppRuntime对象,并且调用其start函数。之后zygote的核心初始化都由AppRuntime中。
2 调用startVm创建Java虚拟机,然后调用startReg来注册JNI函数
3 通过JNI调用com.android.internal.os.ZygoteInit的main函数,从此进入了Java世界
4 调用registerZygoteSocket创建可以响应子孙后台请求的socket。同时zygote调用preload函数预加载常用的类、资源等,为Java世界添砖加瓦
5 调用startSystemServer函数fork一个system_server来为Java服务
6 Zygote完成了Java的初始工作后,便调用runSelectLoop来让自己无限循环等待。之后,如果收到子孙后代的请求,它便会醒来为他们工作。

zygote

5.0、SystemServer 启动介绍

ZygoteInit中handleSystemServerProcess函数的最后一步,会调用startSystemServer()函数,该函数是system_server启动流程的起点

systemserver启动流程图

上图前4步骤(即颜色为紫色的流程)运行在是Zygote进程,
从第5步(即颜色为蓝色的流程)ZygoteInit.handleSystemServerProcess开始是运行在新创建的system_server,这是fork机制实现的(fork会返回2次)。下面从startSystemServer()开始讲解详细启动流程

5.01~5.05 创建systemserver进程

5.01 startsystemserver

这个里面有开启system_server进程。

//位于ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
        ...
        // 准备启动参数
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,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 {
            ...
// fork一个紫禁城,这个就是system_server进程
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
        // 进入子进程system_server
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            // 完成system_server进程剩余的工作
            handleSystemServerProcess(parsedArgs);
        }
        return true;
    }

这里,zygote进行了一次无性繁殖,分类除了system_server(zygote.forksystemserver)。
准备参数并fork新进程,从上面可以看出system server进程参数信息为uid=1000,gid=1000,进程名为sytem_server,从zygote进程fork新进程后,需要关闭zygote原有的socket。另外,对于有两个zygote进程情况,需等待第2个zygote创建完成。

5.02 forkSystemServer

该函数是一个native函数

public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
    VM_HOOKS.preFork();
    // 调用native方法fork system_server进程【见小节3】
    int pid = nativeForkSystemServer(
            uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
    if (pid == 0) {
        Trace.setTracingEnabled(true);
    }
    VM_HOOKS.postForkCommon();
    return pid;
}

nativeForkSystemServer()方法在AndroidRuntime.cpp中注册的,调用com_android_internal_os_Zygote.cpp中的register_com_android_internal_os_Zygote()方法建立native方法的映射关系,所以接下来进入如下方法。

5.03. nativeForkSystemServer

static jint com_android_internal_os_Zygote_nativeForkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
        jlong effectiveCapabilities) {
  //fork子进程,见【见小节4】
  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                      debug_flags, rlimits,
                                      permittedCapabilities, effectiveCapabilities,
                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                      NULL, NULL);
  if (pid > 0) {
      // zygote进程,检测system_server进程是否创建
      gSystemServerPid = pid;
      int status;
      if (waitpid(pid, &status, WNOHANG) == pid) {
          //当system_server进程死亡后,重启zygote进程
          RuntimeAbort(env);
      }
  }
  return pid;
}

在ForkAndSpecializeCommon()函数中将调用fork()函数来创建子进程之前还调用了SetSigChldHandler函数设置处理SIGCHLD信号的函数SigChldHandler()。

5.04 ForkAndSpecializeCommon

static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, jint debug_flags, jobjectArray javaRlimits, jlong permittedCapabilities, jlong effectiveCapabilities, jint mount_external, jstring java_se_info, jstring java_se_name, bool is_system_server, jintArray fdsToClose, jstring instructionSet, jstring dataDir) {

 # 设置子进程的signal信号处理函数
  SetSigChldHandler(); 
  pid_t pid = fork(); //fork子进程
  if (pid == 0) {
    //进入子进程
    DetachDescriptors(env, fdsToClose); //关闭并清除文件描述符

    if (!is_system_server) {
        //对于非system_server子进程,则创建进程组
        int rc = createProcessGroup(uid, getpid());
    }
    SetGids(env, javaGids); //设置设置group
    SetRLimits(env, javaRlimits); //设置资源limit

    int rc = setresgid(gid, gid, gid);
    rc = setresuid(uid, uid, uid);

    SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
    SetSchedulerPolicy(env); //设置调度策略

     //selinux上下文
    rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);

    if (se_info_c_str == NULL && is_system_server) {
      se_name_c_str = "system_server";
    }
    if (se_info_c_str != NULL) {
      SetThreadName(se_name_c_str); //设置线程名为system_server,方便调试
    }
    UnsetSigChldHandler(); //设置子进程的signal信号处理函数为默认函数
    //等价于调用zygote.callPostForkChildHooks()
    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                              is_system_server ? NULL : instructionSet);
    ...

  } else if (pid > 0) {
    //进入父进程,即zygote进程
  }
  return pid;
}

fork()创建新进程,采用copy on write方式,这是linux创建进程的标准方法,会有两次return,对于pid==0为子进程的返回,对于pid>0为父进程的返回。 到此system_server进程已完成了创建的所有工作,接下来开始了system_server进程的真正工作。在前面startSystemServer()方法中,zygote进程执行完forkSystemServer()后,新创建出来的system_server进程便进入

SetSigChldHandler函数

在ForkAndSpecializeCommon()函数中将调用fork()函数来创建子进程之前还调用了SetSigChldHandler函数设置处理SIGCHLD信号的函数SigChldHandler()。

static void SigChldHandler(int /*signal_number*/) {
  pid_t pid;
  ...
  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
    ...
    if (pid == gSystemServerPid) {
      ALOGE("Exit zygote because system server (%d) has terminated", pid);
      kill(getpid(), SIGKILL); // 如果死亡的是SystemServer进程,zygote将退出
    }
  }
  ...
}

SigChldHandler函数接收到子进程死亡的信号后,除了调用waitpid()来防止子进程变“僵尸”外,还会判断死亡的子进程是否是SystemServer进程,如果是,Zygote进程会“自杀”,这样将导致Init进程杀死所有用户进程并重启Zygote。整个手机相当于重启了一扁,从而达到系统“软重启”的目的。

5.05 handleSystemServerProcess(systemserver的使命)

这个函数调用在startsystemserver中,在fork出SystemServer进程后(handleSystemServerProcess函数的前一个步骤),在fork出的进程中调用handleSystemServerProcess()来初始化SystemServer进程

private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws ZygoteInit.MethodAndArgsCaller {

        * 关闭父进程zygote复制而来的Socket

        closeServerSocket(); 

        /SystemServer进程的umask设为0077(S_IRWXG|S_IRWXO),
        /这样SystemServer创建的文件的属性就是0077,只有SystemServer进程可以访问。

        Os.umask(S_IRWXG | S_IRWXO);

        if (parsedArgs.niceName != null) {
            // 设置当前进程名为 "system_server"
            Process.setArgV0(parsedArgs.niceName);
        }

        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
        if (systemServerClasspath != null) {
            // 执行dex优化操作
            performSystemServerDexOpt(systemServerClasspath);
        }

        if (parsedArgs.invokeWith != null) {// invokeWith通常为null
            String[] args = parsedArgs.remainingArgs;
            if (systemServerClasspath != null) {
                String[] amendedArgs = new String[args.length + 2];
                amendedArgs[0] = "-cp";
                amendedArgs[1] = systemServerClasspath;
                System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);
            }
            // 启动应用进程
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                //创建类加载器,并赋予当前线程
                cl = createSystemServerClassLoader(systemServerClasspath,
                                                   parsedArgs.targetSdkVersion);
                Thread.currentThread().setContextClassLoader(cl);
            }
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
        }
    }

因为参数invokeWith通常为null,所以会调用RuntimeInit.zygoteInit()方法。在zygoteInit()方法中,它最终会以抛出MethodAndArgsCaller异常的方式返回,实现真正调用SystemServer类的main()方法。

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
    redirectLogStreams(); //重定向log输出

    commonInit(); // 通用的一些初始化
SS调用了下面这个函数后,将于Binder通信系统建立联系,这样SS就能使用Binder了
    nativeZygoteInit(); // zygote初始化 nativeZygoteInit()方法在AndroidRuntime.cpp中,进行了jni映射
    applicationInit(targetSdkVersion, argv, classLoader); // 应用初始化

在applicationinit函数中,调用了invokeStaticMain函数,

抛出一个一场,在zygoteinit的main里被截获。

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl = Class.forName(className, true, classLoader);
    ...

    Method m;
    try {
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
        ...
    } catch (SecurityException ex) {
        ...
    }

    int modifiers = m.getModifiers();
    if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
        ...
    }

    //通过抛出异常,回到ZygoteInit.main()。这样做好处是能清空栈帧,提高栈帧利用率。【见小节12】
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

现在已经很明显了,在RuntimeInit.java中invokeStaticMain方法通过创建并抛出异常,ZygoteInit.MethodAndArgsCaller,在ZygoteInit.java中的main()方法会捕捉该异常
并调用caller.run(),再通过反射便会调用到SystemServer.main()方法**

5.06 systemserver的初始化

SystemServer是一个java类,其main()方法中调用了对象的run()方法

    public static void main(String[] args) {
        //先初始化SystemServer对象,再调用对象的run()方法
        new SystemServer().run();
    }

    private void run() {
        try {
            //当系统时间比1970年更早,就设置当前系统时间为1970年 
            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
                SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
            }

            if (!SystemProperties.get("persist.sys.language").isEmpty()) {
                final String languageTag = Locale.getDefault().toLanguageTag();
                SystemProperties.set("persist.sys.locale", languageTag);
                SystemProperties.set("persist.sys.language", "");
                SystemProperties.set("persist.sys.country", "");
                SystemProperties.set("persist.sys.localevar", "");
            }

            //变更虚拟机的库文件,对于Android 6.0默认采用的是libart.so
            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

            if (SamplingProfilerIntegration.isEnabled()) {
                SamplingProfilerIntegration.start();
                mProfilerSnapshotTimer = new Timer();
                //system_server每隔1小时采用一次,并保存结果到system_server文件
                mProfilerSnapshotTimer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            SamplingProfilerIntegration.writeSnapshot("system_server", null);
                        }
                    }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
            }

            VMRuntime.getRuntime().clearGrowthLimit();
            VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
            Build.ensureFingerprintProperty();
            Environment.setUserRequired(true);
            BaseBundle.setShouldDefuse(true);
            BinderInternal.disableBackgroundScheduling(true);
            BinderInternal.setMaxThreads(sMaxBinderThreads);
            android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            // 主线程looper就在当前线程运行
            Looper.prepareMainLooper();
            //加载android_servers.so库,该库包含的源码在frameworks/base/services/目录下
            System.loadLibrary("android_servers");
            // 检查上次关机过程是否失败,该方法可能不会返回
            performPendingShutdown();
            // 初始化系统上下文
            createSystemContext();
            //创建系统服务管理
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            //将mSystemServiceManager添加到本地服务的成员sLocalServiceObjects
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }

        // 创建并运行所有的Java服务
        try {
            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
            startBootstrapServices();   //启动引导服务
            startCoreServices();        //启动核心服务
            startOtherServices();       //启动其它服务
        } catch (Throwable ex) {
            throw ex;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
        // 进入处理消息的循环
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

main()方法的主要是有:
1.调用时间,如果当前系统时间比1970年更早,就设置当前系统时间为1970年 。
2.设置属性persist.sys.dalvik.vm.lib.2的值为当前虚拟机的运行库的路径。
3.调整虚拟机堆的内存。设定虚拟机利用率为0.8。
4.加载android_servers.so库。

5.调用createSystemContext()来获取Context。
6.创建SystemServiceManager的对象mSystemServiceManager,这个对象负责系统Service的启动。
7.启动服务。startBootstrapServices(),startCoreServices()和 startOtherServices()创建并运行所有Java服务。
8.调用Loop.loop(),进入处理消息的循环。

这里重点是:

  1. 调用createSystemContext()来创建系统上下文
  2. 创建SystemServiceManager
  3. 启动各种服务
    private void createSystemContext() {
        //创建ActivityThread对象
        ActivityThread activityThread = ActivityThread.systemMain();
        //创建ContextImpl、LoadedApk对象
        mSystemContext = activityThread.getSystemContext();
        //设置主题
        mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
    }

在createSystemContext()方法里,通过ActivityThread的静态方法systemMain()创建了一个activityThread。然后调用它的getSystemContext()方法来获取系统的Context,最后设置主题。

然后来分析systemmain
    public static ActivityThread systemMain() {
        //对于低内存的设备,禁用硬件加速
        if (!ActivityManager.isHighEndGfx()) {
            ThreadedRenderer.disable(true);
        } else {
            ThreadedRenderer.enableForegroundTrimming();
        }
        // 创建ActivityThread
        ActivityThread thread = new ActivityThread();
        // 创建Application以及调用其onCreate()方法
        thread.attach(true);//代表是系统的应用进程
        return thread;
    }

上面的代码主要是new了一个ActivityThread对象。
同样的我们知道,ActivityThread是应用程序的主线程类,该类同时也存在一个main()主方法,zygote进程在启动过程的最后会在抛出的MethodAndArgsCaller异常中,通过反射来执行ActivityThread类的main()方法。那么这里为什么要用new来创建ActivityThread对象呢?
实际上SystemServer不仅是一个单纯的后台进程,它也是一个运行着组件Service的进程,很多系统的对话框就是从SystemServer中显示出来的,因此,SystemServer本身也需要一个和APK应用类似的上下文环境,创建ActivityThread是获取这个环境的第一步,后面还需要创建SystemContext对象。ActivityThread的attach(boolean)方法中,传入参数true时,表示是在SystemServer中调用。如下代码:

    private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {//进入应用进程的处理流程
            ...
        } else { //进入系统进程。该情况只在SystemServer中处理,设置DDMS时看到的systemserver进程名为system_process
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            try {
                mInstrumentation = new Instrumentation();
                // 创建应用上下文SystemContext
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                // 创建Application
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                // 调用Application的onCreate()方法
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }
        ...
    }

system为true时,创建了ContextImpl和Application对象,最后还调用了Application的onCreate()方法,完全模拟创建一个应用的过程。但是,创建应用上下文环境需要对应的一个apk文件,这个的apk文件是哪个呢?上面的参数中getSystemContext().mPackageInfo正是。
通过跟踪getSystemContext()的代码,最终可以找到在ContextImpl类的createSystemContext(ActivityThread)方法中创建了一个LoadedApk对象。

    LoadedApk(ActivityThread activityThread) {
        mActivityThread = activityThread;
        mApplicationInfo = new ApplicationInfo();
        mApplicationInfo.packageName = "android";
        mPackageName = "android";
        ...
    }

LoadedApk对象保存了一个apk文件的信息,它指明了将使用的包名为“android”,而framework-res.apk的包名正是“android”。因此,getSystemContext()方法返回的对象所对象的apk文件就是framework-res.apk。
因此,ActivityThread的SystemMain()方法相当于创建了一个framework-res.apk的上下文环境

SystemServer是Android系统的核心之一,大部分Android提供的服务都运行在这个进程里,SystemServer中运行的服务总共有60多种。为了防止应用进程对系统造成破坏,Android的应用进程没有权限直接访问设备的底层资源,只能通过SystemService中的代理访问。通过Binder,用户进程在使用SystemService中的服务并没有太多不便变之处。


android 系统服务

5.1 ActivityManagerService 启动

zygote孵化出来的第一个android服务程序(system_server),通过runselectloop等待并处理来之客户的消息,派生启动android系统中所有的核心服务。
activitymanagerservice:核心服务,由systemserver创建

AMS在SystemServer的startBootstrapServices中启动,主要是创建了一个Lifecycle对象创建AMS。
创建AMS后会调用AMS的start方法。setSystemServiceManager方法是把AMS纳入SystemServerManager的管理。
在AMS的构造函数中初始化了很多变量和一些服务,如果管理广播的队列、电池和CPU等相关服务,服务会在start方法中启动,并等待启动完成。
最后,调用AMS的systemReady方法完成初始化,在SystemReady中启动桌面。

// Activity manager runs the show.
traceBeginAndSlog("StartActivityManager");
mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
traceEnd();
public static final class Lifecycle extends SystemService {
    private final ActivityManagerService mService;

    public Lifecycle(Context context) {
        super(context);
        mService = new ActivityManagerService(context);
    }

    @Override
    public void onStart() {
        mService.start();
    }

    @Override
    public void onCleanupUser(int userId) {
        mService.mBatteryStatsService.onCleanupUser(userId);
    }

    public ActivityManagerService getService() {
        return mService;
    }
}

systemReady在SystemServer的startOtherServices的最后被调用,主要是动作是标记和等待各个服务启动完成如等待PMS启动结束,接着启动SystemUI和启动HomeActivity。在Android N之后引入DirectBoot,DirectBoot是一种安全模式,是开机完成但用户还没有解锁的时候处于的一种运行环境。

AMS初始化在启动完成后,在锁屏界面Keyguard绘制完成后(finishKeyguardDrawn),然后调用WindowManagerService的enableScreenAfterBoot,WMS会接着调用performEnableScreen通知SurfaceFlinger关闭开机动画,接着WMS调用AMS的bootAnimationComplete通知AMS开机动画结束,AMS最后通过调用finishBooting设置属性sys.boot_complete通知系统开机完成,可以执行属性sys.boot_complete设置之后的任务

WMS与SurfaceFlingerBinder进行Binder通信的协议:

可以看到WMS通过binder通信,调用IBinder.FIRST_CALL_TRANSACTION函数,也就是android.ui.ISurfaceComposer的BOOT_FINISHED对应的函数bootFinished(),SurfaceFlinger是继承BpSurfaceComposer的,所以最后调用的是SurfaceFlinger::bootFinished(),通过设置属性service.bootanim.exit标记开机动画结束

android system服务启动过程

initandloop:把所有的服务一条一条的初始化完成,加到servermanager中,加载之后,调用loop方法中,处理一些消息。主要的工作都在这个函数里 。

nativeinit:frameworks/base/services/jni/com_android_server_systemserver.cpp
SystemServer需要从Zygote fork SystemServer开始分析,主要是设置参数,然后调用Zygote的forkSystemServer方法,再判断是否有SecondaryZygote启动,有则等待其启动,无则返回

Zygote的forkSystemServer方法主要是调用了native方法nativeForkSystemServer,在native层进行fork动作,并设置pid、gid、selinux安全上下文等,最后启动com.android.server.SystemServer

public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
        int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
    VM_HOOKS.preFork();
    // Resets nice priority for zygote process.
    resetNicePriority();
    int pid = nativeForkSystemServer(
            uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
    // Enable tracing as soon as we enter the system_server.
    if (pid == 0) {
        Trace.setTracingEnabled(true, debugFlags);
    }
    VM_HOOKS.postForkCommon();
    return pid;
}

log 抓取与分析风阀

开机时间主要分析kernel log、events log、logcat log

adb shell dmesg > dmesg.txt
adb logcat –v threadtime –b events –d > logcat_events.log
adb logcat –v threadtime –d *:V > logcat.txt
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,100评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,862评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,993评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,309评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,303评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,421评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,830评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,501评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,689评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,506评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,564评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,286评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,826评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,875评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,114评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,705评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,269评论 2 341