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 启动模式
- 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.
• 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("--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信号来进行处理,即回收哪些已经变成僵尸进程的子进程。
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 ## 触发条件 ##执行命令 ##可以执行多个命令
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事件结构
一个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(&sm));//c++中的<>代表baiC++模板。parser.AddSectionParser("on", std::make_unique(&am));parser.AddSectionParser("import", std::make_unique(&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_doneam.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
-
监听子进程退出。
init 处理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.rcimport /init.usb.rcimport /init.${ro.hardware}.rcimport /vendor/etc/init/hw/init.${ro.hardware}.rcimport /init.usb.configfs.rcimport /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。
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:s0bool 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 ps(ProcessState::self()); ps->startThreadPool(); // instantiate surfaceflinger sp 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 sm(defaultServiceManager()); sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false); // publish GpuService sp 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 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& 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); //******************* 第五部分**********************##### 第五部分——注册系统的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:提前加载后,使用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。
- 关闭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. This258 * could be unified with main(), if the native code in nativeFinishInit()259 * were rationalized with Zygote startup.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");272273 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捕获,
- 创建子进程
- 设置子进程相关函数
- 完成systemserver启动的参数,包括类名和入口函数,然后抛出异常,然后被捕获异常并启动systemserver。
zygote 创建app,处理启动应用的请求
ZygoteInit类的main()方法调用runSelectLoop()方法来监听和处理启动应用的请求
前面提到了注册IPC socket,这里将使用到。
654 /**655 * Runs the zygote process's select loop. Accepts new connections as656 * they happen, and reads commands from connections one spawn-request's657 * worth at a time.658 *659 * @throws MethodAndArgsCaller in a child process when a main() should660 * be executed.661 */662 private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {663 ArrayList fds = new ArrayList();664 ArrayList peers = new ArrayList();665 # fds[0]为sServerSocket,即sServerSocket为位于zygote进程中的socket服务端666 fds.add(sServerSocket.getFileDescriptor());667 peers.add(null);668669 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创建应用流程- 调用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.javaprivate 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中的服务并没有太多不便变之处。
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.txtadb logcat –v threadtime –b events –d > logcat_events.logadb logcat –v threadtime –d *:V > logcat.txt
更多相关文章
- android原生和H5交互(转)
- 《浅谈android进程》
- Android(安卓)电池管理系统
- Android(安卓)call setting 源码分析 从顶层到底层(下)
- 小熊android学习总结:Linux内核怎样启动Android
- Android(安卓)Service组件(1)
- Qt on Android:将Qt调试信息输出到logcat中
- Android(安卓)Media (Audio) Framework Analyse
- Android(安卓)NDK 使用第一步,编译c文件,声明jni并调用。