这篇是自己学习所用,请谨慎观看,具体内容可看下面博客:
Android启动流程简析
Android系统启动(里面含有所有函数和类的源码)
Android启动大纲概念图
Zygote进程在init进程中以service的方式启动的。通过init.rc中通过"import"的方式引入文件
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 启动模式
- recovery 升级模式:启动recovery模式,内核和文件系统
-
正常启动模式:引导内核和启动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进程。
学习目标:
- init进程是如何创建zygote的?zygote对应的service section
- 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可看进程)
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进行处理。如下图
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信号来进行处理,即回收哪些已经变成僵尸进程的子进程。
/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
parse_config()函数解析脚本文件的逻辑过程可以用一张流程图来表示,如下图所示。通过调用next_token()函数的作用就是寻找单词结束标志或行结束标志。 如果是单词结束符,就先存放在数组args中,如果找到的是行结束符,则根据行中的第一个单词来判断是否是一个"section","section"的标志有3个,关键字"on","service","import"。如果是"section"则调用函数parse_new_section来开启一个新"section"的处理,否则把这一行继续作为当前"section"所属的行来处理。
第一个函数:把启动脚本的命令解析到列表中,然后调用下面的函数
用parse_config来解析。
service_list:保存脚本中所有的服务
action_list:保存所有的操作
action_queue:把要执行的服务和操作保存在这里
命令和结构:lookup_keyword函数。
parse_new_section:把解析的加入到listaction。
init事件列表(list结构)
init事件结构
一个section下面挂着多个操作。
android 脚本执行和进程守护
启动脚本解析结果
解析后放入两个结构体中,然后放入队列中
都是on打头。
将自己的函数放入到antion_queue中
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循环中三个动作:
- 启动我们的服务,执行脚本命令
- 根据Shell或者系统中消息设置系统Prop
- 守护系统服务,如果服务退出,重启退出的服务
主要是两个套接字:
- 设置prop
-
监听子进程退出。
函数:
property_service_init_action。
start_property_service
property_set_fd
handle_property_set_fd
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。
- init :守护进程
- surfaceflinger:界面管理服务,初始化显示,结束后调用startbootanim,启动bootanimation
- boot 启动界面服务,然后和surfaceflinger来进行交互,得到显示的层,根据显示机制,刷新屏幕
- zygote:用以创建所有的java应用程序和服务
- system_service:会在中间创建java层所有的服务
service.bootanim.exit为1时,退出bootanimation。
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, ¶m) != 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;
}
}
我将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子进程的是共享的。
预加载系统的类。
预加载资源:图片和颜色设置。保存在全局变量中。
如颜色:mResources.getColorStateList(id)。
zygote:提前加载后,使用fork时继承系统资源,然后用java方法进行启动,这样应用不用重新加载资源和类,可以提高应用启动和运行速度。
加载系统资源,首先创建一个resources,保存系统的资源。导入类的配置文件。最后class.forname,进行加载。
启动systemserver
Zygote类的main()方法里面的第四阶段调用startSystemServer启动系统服务,代码在zygoteinit.java中,
1、为fork准备参数parsedArgs
2、调用Zygote.forkSystemServer()方法来创建system_server
3、调用handleSystemServerProcess()方法执行system_server的剩余工作
forksystemserver创建子进程的过程中,调用native方法来相关信号的处理。在子进程中调用handlesystemserverprocess。
- 关闭Zygote的socket两端的连接
在fork过程中复制了原来位于zygote进程的socket服务端,这里关闭了从父进程复制而来的socket
在关闭和子进程退出的时候,用来关闭并清理zygote的socket, - 通过设置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;
}
}
startsystemserver创建子进程。
异常被catch捕获,
- 创建子进程
- 设置子进程相关函数
- 完成systemserver启动的参数,包括类名和入口函数,然后抛出异常,然后被捕获异常并启动systemserver。
zygote 创建app,处理启动应用的请求
ZygoteInit类的main()方法调用runSelectLoop()方法来监听和处理启动应用的请求
前面提到了注册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
- 调用readArgumentList()方法从socket连接中读入个多个参数
- 读取完毕后,调用Arguments有参构造函数,new一个Arguments 对象即parsedArgs。将上面的参数解析成列表。这个列表对象就是parsedArgs
- 解析完参数后,还要对这些参数进行检查和设置。
- 参数检查无误后,将调用Zygote类的forkAndSpecialize来fork子进程
- 上面结束后,如果返回的pid等于0,表示处于子进程中,执行handleChildProc(),如果pid不等于0,则表示在zygote进程中,则调用handleParentProc()方法继续处理。
创建socket,监听本地socket,管理好每一个session
解析启动消息,收到connect时,添加session链接,使用android启动的方式进行创建进程。
fds:用以保存我们监听的socket
peers:就是一个session
ZogyteInit的main函数主要操作:
- 创建ZogyteServer并标记启动
- 设置进程pid和gid为0
- 解析参数
- 创建本地socket服务
- 预加载系统类和资源
- fork SystemServer进程
- 启动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来让自己无限循环等待。之后,如果收到子孙后代的请求,它便会醒来为他们工作。
5.0、SystemServer 启动介绍
ZygoteInit中handleSystemServerProcess函数的最后一步,会调用startSystemServer()函数,该函数是system_server启动流程的起点
上图前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(),进入处理消息的循环。
这里重点是:
- 调用createSystemContext()来创建系统上下文
- 创建SystemServiceManager
- 启动各种服务
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中的服务并没有太多不便变之处。
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标记开机动画结束
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