Android系统启动流程分析
Posted JackOu1110
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android系统启动流程分析相关的知识,希望对你有一定的参考价值。
前言
写这篇blog背景是项目在做系统启动耗时优化,之前看了两遍罗升阳大神《android系统源代码情景分析》都只是看了,没有实践,没有运用到项目中,因此借项目在做系统优化的机会,再次将Android系统的启动流程细细的在撸一遍,边撸边思考哪些点可以优化。
**声明:**由于家里面的代码是去年下的,去年还在做Android O(android-8.0.0_r1)的系统项目,如果博客中有方法在你的代码中找不到,要么选择和我一起看Android O的R1版本代码,要么可以尝试找找你下载版本的源码是否有对我博客中的代码进行封装。因为我经常发现google会将代码在不同版本中封装。大致流程肯定是完全一样的。
**说明:**这篇博客着实有点长,我本来想分几篇写的,但是感觉分几篇就不完整了,分散了心里始终感觉哪里不对头,所有就没分散。**我不能保证你一定能看完这篇博客,但是我可以保证你看完这篇博客,你肯定会对Android系统启动有更深的理解。**为了方便理解,我先丢两张图,先看图有个直观的认识,再看方法实现了什么功能更容易理解,也更容易在跟踪方法调用迷糊时找到调入的地方。
如果看不清楚,原图下载传送门:系统启动分析
1.Android系统大致启动流程
第一步: 启动电源以及系统启动
当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到RAM,然后 执行引导程序。
第二步:引导程序
引导程序是在Android操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针 对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如redboot、uboot、qi bootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运 营商加锁和限制的地方。
引导程序分两个阶段执行。
第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序;
第二阶段,引导程序设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,引导程 序可以根据配置参数或者输入数据设置内核。
Android引导程序可以在\\bootable\\bootloader\\legacy\\usbloader找到。传统的加载器包含两个文件, 需要在这里说明:
init.s初始化堆栈,清零BBS段,调用main.c的_main()函数;
main.c初始化硬件(闹钟、主板、键盘、控制台),创建linux标签
第三步:内核
Android内核与桌面linux内核启动的方式差不多。内核启动时,设置缓存、被保护存储器、计划列表, 加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第 一个进程
第四步:init进程
init进程是Linux系统中用户空间的第一个进程,进程号固定为1。Kernel启动后,在用户空间启动init进 程,并调用init中的main()方法执行init进程的职责。
第五步:启动zygote进程,通过zygote启动SystemServer,当服务都启动完成之后,启动Lancher App,然后退出开机动画。我们就可以看到桌面应用,此时启动过程就结束了。
2.启动init进程
init进程是Android系统中及其重要的第一个进程,是由内核拉起来的第一个用户进程。
init进程主要完成了三件事情。
- 创建和挂载启动所需要的文件目录
- 初始化和启动属性服务
- 解析init.rc配置文件并启动Zygote进程
// \\system\\core\\init\\init.cpp main()
/*
* 1.C++中主函数有两个参数,第一个参数argc表示参数个数,第二个参数是参数列表,也就是具体 的参数
* 2.init的main函数有两个其它入口,一是参数中有ueventd,进入ueventd_main,二是参数中 有watchdogd,进入watchdogd_main
*/
int main(int argc, char** argv) {
/*
* 1.strcmp是String的一个函数,比较字符串,相等返回0
* 2.C++中0也可以表示false
* 3.basename是C库中的一个函数,得到特定的路径中的最后一个'/'后面的内容,
* 比如/sdcard/miui_recovery/backup,得到的结果是backup
*/
if (!strcmp(basename(argv[0]), "ueventd")) {
//当argv[0]的内容为ueventd 时,strcmp的值为0,!strcmp为1
//1表示true,也就执行ueventd_main,ueventd主要是负责设备节点的创建、权限设定等一系列工作
return ueventd_main(argc, argv);
}
if (!strcmp(basename(argv[0]), "watchdogd")) {
//watchdogd俗称看门狗,用于 系统出问题时重启系统
return watchdogd_main(argc, argv);
}
if (REBOOT_BOOTLOADER_ON_PANIC) {
//初始化重启系统的处理信号,内部通过sigaction 注册信号,当监听到该信号时重启系统
install_reboot_signal_handlers();
}
add_environment("PATH", _PATH_DEFPATH);
// 查看是否有环境变量INIT_SECOND_STAGE
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
// 1.init的main方法会执行两次,由is_first_stage控制,first_stage就是第一阶段要做的事
if (is_first_stage) {
boot_clock::time_point start_time = boot_clock::now();
// Clear the umask.
//清空文件权限
umask(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.
//mount是用来挂载文件系统的,mount属于Linux系统调用
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);;//创建目录,第一个参数是目录路径,第二个是读写权限
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
#define MAKE_STR(x) __STRING(x)
mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
// Don't expose the raw commandline to unprivileged processes.
chmod("/proc/cmdline", 0440);//用于修改文件/目录的读写权限
gid_t groups[] = { AID_READPROC };
// 用来将list数组中所标明的组加入到目前进程的组设置中
setgroups(arraysize(groups), groups);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
//mknod用于创建Linux中的设备文件
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
// talk to the outside world...
//将标准输入输出重定向到"/sys/fs/selinux/null"
InitKernelLogging(argv);
LOG(INFO) << "init first stage started!";
if (!DoFirstStageMount()) {
LOG(ERROR) << "Failed to mount required partitions early ...";
panic();
}
//Avb即Android Verfied boot,功能包括Secure Boot, verfying boot 和dm-verity,
//原理都是对二进制文件进行签名,在系统启动时进行认证,确保系统运行的是合法的二进制镜像文件。
//其中认证的范围涵盖:bootloader,boot.img,system.img
// 通过调用FsManagerAvbHandle::Open()->FsManagerAvbOps::AvbSlotVerify->avb_slot_verify最终去验证每个分区。
// 当验证成功之后,会将版本信息写到环境变量 INIT_AVB_VERSION 中
SetInitAvbVersionInRecovery();
// Set up SELinux, loading the SELinux policy.
//加载SELinux policy,也就是安全策略,
selinux_initialize(true);
// We're in the kernel domain, so re-exec init to transition to the init domain now
// that the SELinux policy has been loaded.
// 我们执行第一遍init的main方法是在kernel domain,所以要重新执行init文件,切换到加载了selinux策略的init domain,
if (restorecon("/init") == -1) {
PLOG(ERROR) << "restorecon failed";
security_failure();
}
// 设置进入第二阶段标志位,进入第二阶段
setenv("INIT_SECOND_STAGE", "true", 1);
static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ms).c_str(), 1);
char* path = argv[0];
char* args[] = { path, nullptr };
// 重新执行init,由于标志位置为了,因此再次执行init会进入阶段。
execv(path, args);
// execv() only returns if an error happened, in which case we
// panic and never fall through this conditional.
PLOG(ERROR) << "execv(\\"" << path << "\\") failed";
security_failure();
}
// At this point we're in the second stage of init.
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
// Set up a session keyring that all processes will have access to. It
// will hold things like FBE encryption keys. No process should override
// its session keyring.
keyctl(KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 1);
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
//初始化属性系统,并从指定文件读取属性
// bionic/libc/bionic/system_properties.c
// __system_property_area_init->map_prop_area_rw->打开/dev/__properties__文件->并且映射128kb空间大小内存来存属性键值对。
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.
//接下来的一系列操作都是从各个文件读取一些属性,然后通过property_set设置系统属性
// 1.这句英文的大概意思是,如果参数同时从命令行和DT传过来,DT的优先级总是大于命令行的。
// 2.DT即device-tree,中文意思是设备树,这里面记录自己的硬件配置和系统运行参数,参考http://www.wowotech.net/linux_kenrel/why-dt.html
process_kernel_dt();//处理DT属性
process_kernel_cmdline();//处理命令行属性
// Propagate the kernel variables to internal variables
// used by init as well as the current required properties.
export_kernel_boot_props();//处理其他的一些属性
// Make the time that init started available for bootstat to log.
property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
// Set libavb version for Framework-only OTA match in Treble build.
const char* avb_version = getenv("INIT_AVB_VERSION");
// 将avb版本设置到系统属性中
if (avb_version) property_set("ro.boot.avb_version", avb_version);
// Clean up our environment.
// 清除环境变量
unsetenv("INIT_SECOND_STAGE");
unsetenv("INIT_STARTED_AT");
unsetenv("INIT_SELINUX_TOOK");
unsetenv("INIT_AVB_VERSION");
// Now set up SELinux for second stage.
selinux_initialize(false);
selinux_restore_context();
//创建epoll实例,并返回epoll的文件描述符
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {
PLOG(ERROR) << "epoll_create1 failed";
exit(1);
}
// 主要是创建handler处理子进程终止信号,创建一个匿名 socket并注册到epoll进行监听
signal_handler_init();
// 从文件中加载一些属性,读取usb配置
// 涉及到的文件,/system/etc/prop.default,/odm/default.prop,/vendor/default.prop
property_load_boot_defaults();
export_oem_lock_status();// 设置ro.boot.flash.locked 属性
start_property_service();//开启一个socket监听系统属性的设置
set_usb_controller();//设置sys.usb.controller 属性
//init.rc文件中方法映射,例如“class_start”-> "do_class_start"
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);//将function_map存放到Action中作 为成员属性
// 使用不同的parse解析init.rc文件中的不同字段,并且将service保存在servicelist中
Parser& parser = Parser::GetInstance();
parser.AddSectionParser("service",std::make_unique<ServiceParser>());
parser.AddSectionParser("on", std::make_unique<ActionParser>());
parser.AddSectionParser("import", std::make_unique<ImportParser>());
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
// 以下目录的所有rc文件默认都会被解析
parser.ParseConfig("/init.rc");
parser.set_is_system_etc_init_loaded(
parser.ParseConfig("/system/etc/init"));
parser.set_is_vendor_etc_init_loaded(
parser.ParseConfig("/vendor/etc/init"));
parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
} else {
parser.ParseConfig(bootscript);
parser.set_is_system_etc_init_loaded(true);
parser.set_is_vendor_etc_init_loaded(true);
parser.set_is_odm_etc_init_loaded(true);
}
// Turning this on and letting the INFO logging be discarded adds 0.2s to
// Nexus 9 boot time, so it's disabled by default.
if (false) parser.DumpState();//打印一些当前Parser的信息,默认是不执行的
ActionManager& am = ActionManager::GetInstance();
// QueueEventTrigger用于触发Action,这里触发early-init事件
am.QueueEventTrigger("early-init");
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
//QueueBuiltinAction用于添加Action,第一个参数是 Action要执行的Command,第二个是Trigger
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");
while (true) {
// By default, sleep until something happens.
int epoll_timeout_ms = -1; //epoll超时时间,相当于阻塞时间
if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
am.ExecuteOneCommand();//执行一个command
}
if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
restart_processes();
// If there's a process that needs restarting, wake up in time for that.
if (process_needs_restart_at != 0) {
epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
}
// If there's more work to do, wake up again immediately.
//当还有命令要执行时,将epoll_timeout_ms设置为0
if (am.HasMoreCommands()) epoll_timeout_ms = 0;
}
epoll_event ev;
/*
* 1.epoll_wait与epoll_create1、epoll_ctl是一起使用的
* 2.epoll_create1用于创建epoll的文件描述符,epoll_ctl、epoll_wait都把它创建的fd作为第一个参数传入
* 3.epoll_ctl用于操作epoll,EPOLL_CTL_ADD:注册新的fd到epfd中,
EPOLL_CTL_MOD:修改已经注册的fd的监听事件,EPOLL_CTL_DEL:从epfd中删除一个fd;
* 4.epoll_wait用于等待事件的产生,epoll_ctl调用EPOLL_CTL_ADD时会传入需要监听什么类型的事件,
*比如EPOLLIN表示监听fd可读,当该fd有可读的数据时,调用epoll_wait经过epoll_timeout_ms时间就会把该事件的信息返回给&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) {
//当有event返回时,取出 ev.data.ptr(之前epoll_ctl注册时的回调函数),直接执行
//在signal_handler_init和start_property_service有注册两个fd的监听,一个用于监听SIGCHLD(子进程结束信号),一个用于监听属性设置
((void (*)()) ev.data.ptr)();
}
}
return 0;
}
3.解析init.rc
init.rc是一个非常重要的配置文件,它是由Android初始化语言(Android Init Language)编写的脚本,它主要包含五种类型语句:Action(Action中包含了一系列的Command)、Commands(init语言中的命令)、Services(由init进程启动的服务)、Options(对服务进行配置的选项)和Import(引入其他配置文件)。init.rc的配置代码如下所示。
# \\system\\core\\rootdir\\init.rc
on init # L41
sysclktz 0
# Mix device-specific information into the entropy pool
copy /proc/cmdline /dev/urandom
copy /default.prop /dev/urandom
...
on <trigger> [&& <trigger>]* //设置触发器
<command>
<command> //动作触发之后要执行的命令
service <name> <pathname> [ <argument> ]* #<service的名字><执行程序路径><传递参数>
<option> #Options是Services的参数配置. 它们影响Service如何运行及运行时机
group <groupname> [ <groupname>\\* ] #在启动Service前将group改为第一个 groupname,第一个groupname是必须有的,默认值为root(或许默认值是无),第二个groupname可以不设置,用于追加组(通过 setgroups)
priority <priority> #设置进程优先级. 在-20~19之间,默认值是0,能过 setpriority实现
socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ] #创建 一个unix域的socket,名字叫/dev/socket/name , 并将fd返回给Service. type 只能是 "dgram", "stream" or "seqpacket".
3.1 Action
Action: 通过触发器trigger,即以on开头的语句来决定执行相应的service的时机,具体有如下时机:
- on early-init; 在初始化早期阶段触发;
- on init; 在初始化阶段触发;
- on late-init; 在初始化晚期阶段触发;
- on boot/charger: 当系统启动/充电时触发,还包含其他情况,此处不一一列举;
- on property:=: 当属性值满足条件时触发
3.2 Service
服务Service,以 service开头,由init进程启动,一般运行在init的一个子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service在启动时会通过 fork方式生成子进程。
例如: service servicemanager /system/bin/servicemanager代表的是服务名为 servicemanager,服务执行的路径为/system/bin/servicemanager。
3.3 Command
下面列举常用的命令:
- class_start <service_class_name>: 启动属于同一个class的所有服务;
- start <service_name>: 启动指定的服务,若已启动则跳过;
- stop <service_name>: 停止正在运行的服务
- setprop :设置属性值
- mkdir :创建指定目录
- symlink <sym_link>: 创建连接到的<sym_link>符号链接;
- write : 向文件path中写入字符串;
- exec: fork并执行,会阻塞init进程直到程序完毕;
- exprot:设定环境变量;
- loglevel :设置log级别
3.4 Options
Options是Service的可选项,与service配合使用
- disabled: 不随class自动启动,只有根据service名才启动;
- oneshot: service退出后不再重启;
- user/group: 设置执行服务的用户/用户组,默认都是root;
- class:设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default; onrestart:当服务重启时执行相应命令;
- socket: 创建名为 /dev/socket/的socket
- critical: 在规定时间内该service不断重启,则系统会重启并进入恢复模式
- default: 意味着disabled=false,oneshot=false,critical=false。
下面看看zygote的rc脚本
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote -- start-system-server
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
3.5 逐行解析脚本
// system\\core\\init\\init_parser.cpp
void Parser::ParseData(const std::string& filename, const std::string& data) {
//TODO: Use a parser with const input and remove this copy
std::vector<char> data_copy(data.begin(), data.end());
data_copy.push_back('\\0');
parse_state state;
state.filename = filename.c_str();
state.line = 0;
state.ptr = &data_copy[0];
state.nexttoken = 0;
SectionParser* section_parser = nullptr;
std::vector<std::string> args;
for (;;) {
switch (next_token(&state)) {
case T_EOF:
if (section_parser) {
// 结束解析
section_parser->EndSection();
}
return;
case T_NEWLINE:
state.line++;
if (args.empty()) {
break;
}
if (section_parsers_.count(args[0])) {
if (section_parser) {
section_parser->EndSection();
}
section_parser = section_parsers_[args[0]].get();
std::string ret_err;
// 逐行解析
if (!section_parser->ParseSection(args, &ret_err)) {
parse_error(&state, "%s\\n", ret_err.c_str());
section_parser = nullptr;
}
} else if (section_parser) {
std::string ret_err;
if (!section_parser->ParseLineSection(args, state.filename,
state.line, &ret_err)) {
parse_error(&state, "%s\\n", ret_err.c_str());
}
}
args.clear();
break;
case T_TEXT:
args.emplace_back(state.text);
break;
}
}
}
// \\system\\core\\init\\service.cpp
Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args, const std::string& filename, int line) {
if (args.size() < 3) {
return Error() << "services must have a name and a program"; }
const std::string& name = args[1]; if (!IsValidName(name)) {
return Error() << "invalid service name '" << name << "'"; }
Subcontext* restart_action_subcontext = nullptr; if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
if (StartsWith(filename, subcontext.path_prefix())) { restart_action_subcontext = &subcontext;
break; }
} }
std::vector<std::string> str_args(args.begin() + 2, args.end());
service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);//构建出一个service对象
return Success(); }
// \\system\\core\\init\\service.cpp
void ServiceParser::EndSection() {
if (service_) {
// 如果上面解析的service不为空,就加入到ServiceManager中
ServiceManager::GetInstance().AddService(std::move(service_));
}
}
上面解析完成后,接下来就是启动Service,这里我们以启动Zygote来分析
# \\system\\core\\rootdir\\init.rc L680
on nonencrypted
class_start main #class_start是一个命令,通过do_class_start函数处理
class_start late_start
# system\\core\\init\\builtins.cpp
static Result<Success> do_class_start(const BuiltinArguments& args) {
// Starting a class does not start services which are explicitly disabled.
// They must be started individually.
for (const auto& service : ServiceList::GetInstance()) {
if (service->classnames().count(args[1])) {
// 调用刚刚注册的service的StartIfNotDisabled()方法
if (auto result = service->StartIfNotDisabled(); !result) {
LOG(ERROR) << "Could not start service '" << service->name() << "' as part of class '" << args[1] << "': " << result.error();
}
}
}
return Success();
}
// \\system\\core\\init\\service.cpp
Result<Success> Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start();
} else {
flags_ |= SVC_DISABLED_START; }
return Success();
}
bool Service::Start() {
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
// 如果service已经启动了,就不启动了
if (flags_ & SVC_RUNNING) {
return false;
}
......
struct stat sb;
//判断需要启动的service的对应的执行文件是否存在,不存在则不启动service
if (stat(args_[0].c_str(), &sb) == -1) {
PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
flags_ |= SVC_DISABLED;
return false;
}
std::string scon;
if (!seclabel_.empty()) {
scon = seclabel_;
} else {
LOG(INFO) << "computing context for service '" << name_ << "'";
scon = ComputeContextFromExecutable(name_, args_[0]);
if (scon == "") {
return false;
}
}
LOG(INFO) << "starting service '" << name_ << "'...";
//如果子进程没有启动,则调用fork函数创建子进程
pid_t pid = -1;
if (namespace_flags_) {
pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
} else {
pid = fork();
}
if (pid == 0) {//当期代码逻辑在子进程中运行
umask(077);
if (namespace_flags_ & CLONE_NEWPID) {
// This will fork again to run an init process inside the PID
// namespace.
SetUpPidNamespace(name_);
}
for (const auto& ei : envvars_) {
add_environment(ei.name.c_str(), ei.value.c_str());
}
std::for_each(descriptors_.begin(), descriptors_.end(),
std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
// See if there were "writepid" instructions to write to files under /dev/cpuset/.
auto cpuset_predicate = [](const std::string& path) {
return android::base::StartsWith(path, "/dev/cpuset/");
};
auto iter = std::find_if(writepid_files_.begin(), writepid_files_.end(), cpuset_predicate);
if (iter == writepid_files_.end()) {
以上是关于Android系统启动流程分析的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )(代码片段
Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段