一卷旌收千骑虏,万全身出百重围。这篇文章主要讲述Android系统启动流程解析init进程启动过程相关的知识,希望能为你提供帮助。
前言
作为“android框架层”这个大系列中的第一个系列,我们首先要了解的是Android系统启动流程,在这个流程中会涉及到很多重要的知识点,这个系列我们就来一一讲解它们,这一篇我们就来学习init进程。
1.init简介
init进程是Android系统中用户空间的第一个进程,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建zygote(孵化器)和属性服务等。init进程是由多个源文件共同组成的,这些文件位于源码目录system/core/init。本文将基于Android7.0源码来分析Init进程。
2.引入init进程
说到init进程,首先要提到Android系统启动流程的前几步:
1.启动电源以及系统启动
当电源按下时引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序Bootloader到RAM,然后执行。
2.引导程序Bootloader
引导程序是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。
3.linux内核启动
内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。
4.init进程启动
讲到第四步就发现我们这一节要讲的init进程了。关于Android系统启动流程的所有步骤会在本系列的最后一篇做讲解。
3.init入口函数
init的入口函数为main,代码如下所示。
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);
}
umask(0);
add_environment("PATH", _PATH_DEFPATH);
bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
//创建文件并挂载
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);
#define MAKE_STR(x) __STRING(x)
mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
mount("sysfs", "/sys", "sysfs", 0, NULL);
}
open_devnull_stdio();
klog_init();
klog_set_level(KLOG_NOTICE_LEVEL);
NOTICE("init %s started!\\n", is_first_stage ? "first stage" : "second stage");
if (!is_first_stage) {
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
//初始化属性相关资源
property_init();
//1
process_kernel_dt();
process_kernel_cmdline();
export_kernel_boot_props();
}
...
//启动属性服务
start_property_service();
//2
const BuiltinFunctionMap function_map;
Action::set_function_map(&
function_map);
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>
());
//解析init.rc配置文件
parser.ParseConfig("/init.rc");
//3
...
while (true) {
if (!waiting_for_exec) {
am.ExecuteOneCommand();
restart_processes();
}
int timeout = -1;
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout <
0)
timeout = 0;
}
if (am.HasMoreCommands()) {
timeout = 0;
}
bootchart_sample(&
timeout);
epoll_event ev;
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) {
((void (*)()) ev.data.ptr)();
}
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
4.init.rc
init.rc是一个配置文件,内部由Android初始化语言编写(Android Init Language)编写的脚本,它主要包含五种类型语句:
Action、Commands、Services、Options和Import。init.rc的配置代码如下所示。
system/core/rootdir/init.rc
on init
sysclktz 0
# Mix device-specific information into the entropy pool
copy /proc/cmdline /dev/urandom
copy /default.prop /dev/urandom
...on boot
# basic network init
ifup lo
hostname localhost
domainname localdomain
# set RLIMIT_NICE to allow priorities from 19 to -20
setrlimit 13 40 40
...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
on <
trigger>
[&
&
<
trigger>
]*//设置触发器
<
command>
<
command>
//动作触发之后要执行的命令
- 1
- 2
- 3
service <
name>
<
pathname>
[ <
argument>
]*//<
service的名字>
<
执行程序路径>
<
传递参数>
<
option>
//option是service的修饰词,影响什么时候、如何启动services
<
option>
...
- 1
- 2
- 3
- 4
system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
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
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
5.解析service
接下来我们来解析service,会用到两个函数,一个是ParseSection,它会解析service的rc文件,比如上文讲到的init.zygote64.rc,ParseSection函数主要用来搭建service的架子。另一个是ParseLineSection,用于解析子项。代码如下所示。
system/core/init/service.cpp
bool ServiceParser::ParseSection(const std::vector<
std::string>
&
args,
std::string* err) {
if (args.size() <
3) {
*err = "services must have a name and a program";
return false;
}
const std::string&
name = args[1];
if (!IsValidName(name)) {
*err = StringPrintf("invalid service name \'%s\'", name.c_str());
return false;
}
std::vector<
std::string>
str_args(args.begin() + 2, args.end());
service_ = std::make_unique<
Service>
(name, "default", str_args);
//1
return true;
}bool ServiceParser::ParseLineSection(const std::vector<
std::string>
&
args,
const std::string&
filename, int line,
std::string* err) const {
return service_ ? service_->
HandleLine(args, err) : false;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
void ServiceParser::EndSection() {
if (service_) {
ServiceManager::GetInstance().AddService(std::move(service_));
}
}
- 1
- 2
- 3
- 4
- 5
void ServiceManager::AddService(std::unique_ptr<
Service>
service) {
Service* old_service = FindServiceByName(service->
name());
if (old_service) {
ERROR("ignored duplicate definition of service \'%s\'",
service->
name().c_str());
return;
}
services_.emplace_back(std::move(service));
//1
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
6.init启动zygote
讲完了解析service,接下来该讲init是如何启动service,在这里我们主要讲解启动zygote这个service。在zygote的启动脚本中我们得知zygote的class name为main。在init.rc有如下配置代码:
system/core/rootdir/init.rc
...
on nonencrypted
# A/B update verifier that marks a successful boot.
exec - root -- /system/bin/update_verifier nonencrypted
class_start main
class_start late_start
...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
system/core/init/builtins.cpp
static int do_class_start(const std::vector<
std::string>
&
args) {
/* Starting a class does not start services
* which are explicitly disabled.They must
* be started individually.
*/
ServiceManager::GetInstance().
ForEachServiceInClass(args[1], [] (Service* s) { s->
StartIfNotDisabled();
});
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
system/core/init/service.cpp
bool Service::StartIfNotDisabled() {
if (!(flags_ &
SVC_DISABLED)) {
return Start();
} else {
flags_ |= SVC_DISABLED_START;
}
return true;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
bool Service::Start() {
flags_ &
= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
time_started_ = 0;
if (flags_ &
SVC_RUNNING) {//如果Service已经运行,则不启动
return false;
}
bool needs_console = (flags_ &
SVC_CONSOLE);
if (needs_console &
&
!have_console) {
ERROR("service \'%s\' requires console\\n", name_.c_str());
flags_ |= SVC_DISABLED;
return false;
}
//判断需要启动的Service的对应的执行文件是否存在,不存在则不启动该Service
struct stat sb;
if (stat(args_[0].c_str(), &
sb) == -1) {
ERROR("cannot find \'%s\' (%s), disabling \'%s\'\\n",
args_[0].c_str(), strerror(errno), name_.c_str());
flags_ |= SVC_DISABLED;
return false;
}...
pid_t pid = fork();
//1.fork函数创建子进程
if (pid == 0) {//运行在子进程中
umask(077);
for (const auto&
ei : envvars_) {
add_environment(ei.name.c_str(), ei.value.c_str());
}
for (const auto&
si : sockets_) {
int socket_type = ((si.type == "stream" ? SOCK_STREAM :
(si.type == "dgram" ? SOCK_DGRAM :
SOCK_SEQPACKET)));
const char* socketcon =
!si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str();
int s = create_socket(si.name.c_str(), socket_type, si.perm,
si.uid, si.gid, socketcon);
if (s >
= 0) {
PublishSocket(si.name, s);
}
}
...
//2.通过execve执行程序
if (execve(args_[0].c_str(), (char**) &
strs[0], (char**) ENV) <
0) {
ERROR("cannot execve(\'%s\'): %s\\n", args_[0].c_str(), strerror(errno));
}_exit(127);
}
...
return true;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
...
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
//1
} 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;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
7.属性服务
Windows平台上有一个注册表管理器,注册表的内容采用键值对的形式来记录用户、软件的一些使用信息。即使系统或者软件重启,它还是能够根据之前在注册表中的记录,进行相应的初始化工作。Android也提供了一个类似的机制,叫做属性服务。
在本文的开始,我们提到在init.cpp代码中和属性服务相关的代码有:
system/core/init/init.cpp
property_init();
start_property_service();
- 1
- 2
属性服务初始化与启动property_init函数具体实现的代码如下所示。
system/core/init/property_service.cpp
void property_init() {
if (__system_property_area_init()) {
ERROR("Failed to initialize property area\\n");
exit(1);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
void start_property_service() {
property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
0666, 0, 0, NULL);
//1
if (property_set_fd == -1) {
ERROR("start_property_service socket creation failed: %s\\n", strerror(errno));
exit(1);
}
listen(property_set_fd, 8);
//2
register_epoll_handler(property_set_fd, handle_property_set_fd);
//3
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
在linux新的内核中,epoll用来替换select,epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为内核中的select实现是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。
属性服务处理请求
从上文我们得知,属性服务接收到客户端的请求时,会调用handle_property_set_fd函数进行处理:
system/core/init/property_service.cpp
static void handle_property_set_fd()
{
...if(memcmp(msg.name,"ctl.",4) == 0) {
close(s);
if (check_control_mac_perms(msg.value, source_ctx, &
cr)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);
} else {
ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\\n",
msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
}
} else {
//检查客户端进程权限
if (check_mac_perms(msg.name, source_ctx, &
cr)) {//1
property_set((char*) msg.name, (char*) msg.value);
//2
} else {
ERROR("sys_prop: permission denied uid:%dname:%s\\n",
cr.uid, msg.name);
}
close(s);
}
freecon(source_ctx);
break;
default:
close(s);
break;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
int property_set(const char* name, const char* value) {
int rc = property_set_impl(name, value);
if (rc == -1) {
ERROR("property_set(\\"%s\\", \\"%s\\") failed\\n", name, value);
}
return rc;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
static int property_set_impl(const char* name, const char* value) {
size_t namelen = strlen(name);
size_t valuelen = strlen(value);
if (!is_legal_property_name(name, namelen)) return -1;
if (valuelen >
= PROP_VALUE_MAX) return -1;
if (strcmp("selinux.reload_policy", name) == 0 &
&
strcmp("1", value) == 0) {
if (selinux_reload_policy() != 0) {
ERROR("Failed to reload policy\\n");
}
} else if (strcmp("selinux.restorecon_recursive", name) == 0 &
&
valuelen >
0) {
if (restorecon_recursive(value) != 0) {
ERROR("Failed to restorecon_recursive %s\\n", value);
}
}
//从属性存储空间查找该属性
prop_info* pi = (prop_info*) __system_property_find(name);
//如果属性存在
if(pi != 0) {
//如果属性以"ro."开头,则表示是只读,不能修改,直接返回
if(!strncmp(name, "ro.", 3)) return -1;
//更新属性值
__system_property_update(pi, value, valuelen);
} else {
//如果属性不存在则添加该属性
int rc = __system_property_add(name, namelen, value, valuelen);
if (rc <
0) {
return rc;
}
}
/* If name starts with "net." treat as a DNS property. */
if (strncmp("net.", name, strlen("net.")) == 0){
if (strcmp("net.change", name) == 0) {
return 0;
}
//以net.开头的属性名称更新后,需要将属性名称写入net.change中
property_set("net.change", name);
} else if (persistent_properties_loaded &
&
strncmp("persist.", name, strlen("persist.")) == 0) {
/*
* Don\'t write properties to disk until after we have read all default properties
* to prevent them from being overwritten by default values.
*/
write_persistent_property(name, value);
}
property_changed(name, value);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
8.init进程总结
讲到这,总结起来init进程主要做了三件事:
1.创建一些文件夹并挂载设备
2.初始化和启动属性服务
3.解析init.rc配置文件并启动zygote进程
参考资料:
《深入理解Android系统》
《深入理解Android卷I》
Android的init过程详解(一)
Android启动过程深入解析
Android7.0解析Init.rc文件
Android 7.0 init.rc的一点改变
Android7.0 init进程源码分析
Android情景分析之属性服务
推荐阅读
- 安卓初次完美调试,并成功编程!
- Android中实现OkHttp上传文件到服务器并带进度
- 安卓延时执行代码
- Unity20172.0 Android平台打包
- Android后端服务器的搭建方法
- android app出现红叉
- Windows 10如何修复外部硬盘驱动器不断断开连接的问题()
- 如何修复Windows 10上的红屏错误(解决办法教程)
- Windows和Mac的11款最佳视频压缩软件推荐合集(哪个最好用())