Android系统启动流程图如下,
1,Bootloader引导
当手机按下电源键时,最先运行的就是bootloader。主要作用是初始化基本的硬件环境(如CPU,内存,Flash等),为装载Linux内核准备合适的运行环境。一旦Linux内核装载完毕,bootloader将会从内存中清除掉。
Fastboot 是android设计的一套通过USB更新手机分区映像的协议,方便开发人员快速更新指定的手机分区。
Recovery 是android特有的升级系统。手机可以进行恢复出厂设置或者执行OTA,补丁和固件升级等操作。
2,Linux内核
Android的boot.img存放的就是Linux内核和一个跟文件系统。Bootloader会把boot.img映像装进内存,然后Linux内核会执行整个系统的初始化,完成后装载跟文件系统,最后启动init进程。
3,init进程
Init进程是android系统的第一个用户空间进程,它的进程号为1.主要作用如下,
A,启动android系统中重要的守护进程(USB守护进程,adb,vold,rild等守护进程)
B,启动Zygote进程,会创建Dalivik虚拟机,创建SystemServer进程,响应应用程序的请求。
C,启动ServiceManager,主要用于管理Binder服务,负责Binder服务的注册和查找。
Init进程的源码位于/system/core/init/下,程序的入口函数main()位于文件init.cpp中。
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv); // 执行守护进程ueventd的主函数
}
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv); // 执行看门狗守护进程的主函数
}
umask(0); // 参数为0表示进程创建的文件属性是0777
Init进程代码里包含了另外2个守护进程的代码.
Android.mk文件的部分如下,
# Create symlinks
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdog
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);
}
selinux_initialize(is_first_stage); // 初始化SELinux
init_parse_config_file("/init.rc"); // 解析 init.rc 文件
action_for_each_trigger("early-init", action_add_queue_tail);
// 将指定的action加入到action_queue 中
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
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");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");
•••
while (true) {
if (!waiting_for_exec) {
execute_one_command();
restart_processes(); // 启动服务进程
}
Init.rc脚本使用的是一种初始化语言,其中包含了4类声明:
1)Action
2)Command
3)Service
4)Option
该语言规定,Action和Service是以一种“小节”(Section)的形式出现的,其中每个Action小节可以含有若干Command,而每个Service小节可以含有若干Option。小节只有起始标记,却没有明确的结束标记,也就是说,是用“后一个小节”的起始来结束“前一个小节”的。
脚本中的Action大体上表示一个“行动”,它用一系列Command共同完成该“行动”。Action需要有一个触发器(trigger)来触发它,一旦满足了触发条件,这个Action就会被加到执行队列的末尾。Action的形式如下:
on // trigger 是触发器
// 命令
例如,
on early-init
# Set init and its forked children's oom_adj.
write /proc/1/oom_score_adj -1000
# Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
write /sys/fs/selinux/checkreqprot 0
# Set the security context for the init process.
# This should occur before anything else (e.g. ueventd) is started.
setcon u:r:init:s0
# Set the security context of /adb_keys if present.
restorecon /adb_keys
start ueventd
# create mountpoints
mkdir /mnt 0775 root system
Service表示一个服务程序,会在初始化时启动。因为init.rc脚本中描述的服务往往都是核心服务,所以(基本上所有的)服务会在退出时自动重启。Service的形式如下:
service []*
例如,
service servicemanager /system/bin/servicemanager
class core
user system
group system
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm
其实,除了Action和Service,Init.rc中还有一种小节,就是Import小节。该小节表达的意思有点儿像java中的import,也就是说,Init.rc中还可以导入其他.rc脚本文件的内容。
例如,
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.${ro.zygote}.rc
import /init.trace.rc
解析流程图如下,
主要解析init.rc以及其中import的文件,转化为两个双向链表,分别保存action_list和service_list中。
list_add_tail(&action_list, &act->alist);
list_add_tail(&service_list, &svc->slist);
经过解析一步,init.rc脚本中的actions被整理成双向链表了,但是这些action并没有被实际执行。
在main方法中,
action_for_each_trigger("early-init", action_add_queue_tail);
•••
action_for_each_trigger("init", action_add_queue_tail);
•••
action_for_each_trigger("late-init", action_add_queue_tail);
手机的启动按照先后顺序分为很多子阶段。
action_for_each_trigger方法如下,
void action_for_each_trigger(const char *trigger,
void (*func)(struct action *act))
{
struct listnode *node, *node2;
struct action *act;
struct trigger *cur_trigger;
list_for_each(node, &action_list) {
act = node_to_item(node, struct action, alist);
list_for_each(node2, &act->triggers) {
cur_trigger = node_to_item(node2, struct trigger, nlist);
if (!strcmp(cur_trigger->name, trigger)) {
func(act);
}
}
}
}
可以看到是在遍历action_list链表,找寻所有“action名”和“参数trigger”匹配的节点,并回调“参数func所指的回调函数”。
以boot子阶段为例来解析调用流程, boot子阶段是通过late-init触发的,
init.rc中的boot部分代码如下,
on boot
•••
class_start core
Commands指令关键字和对应执行的方法在system/core/init/Keywords.h中定义,
KEYWORD(class_start, COMMAND, 1, do_class_start)
KEYWORD(class_stop, COMMAND, 1, do_class_stop)
class_start关键字对应的方法为do_class_start,
system/core/init/Builtins.cpp中的do_class_start流程图如下,
和执行action的流程完全一模一样,在此会启动标签为core的一类服务,
例如,
service ueventd /sbin/ueventd // 可执行文件
class core
critical
seclabel u:r:ueventd:s0 // 设置属性
Init.rc中core服务以及对应的执行文件如下,
ueventd |
/sbin/ueventd |
logd |
/system/bin/logd |
healthd |
/sbin/healthd |
console |
/system/bin/sh |
adbd |
/sbin/adbd |
lmkd |
/system/bin/lmkd |
servicemanager |
/system/bin/servicemanager |
vold |
/system/bin/vold |
surfaceflinger |
/system/bin/surfaceflinger |
bootanim |
/system/bin/bootanimation |
netd |
/system/bin/netd |
debuggerd |
/system/bin/debuggerd |
debuggerd64 |
/system/bin/debuggerd64 |
ril-daemon |
/system/bin/rild |
drm |
/system/bin/drmserver |
media |
/system/bin/mediaserver |
installd |
/system/bin/installd |
flash_recovery |
/system/bin/install-recovery.sh |
racoon |
/system/bin/racoon |
mtpd |
/system/bin/mtpd |
keystore |
/system/bin/keystore /data/misc/keystore |
dumpstate |
/system/bin/dumpstate |
mdnsd |
/system/bin/mdnsd |
uncrypt |
/system/bin/uncrypt |
pre-recovery |
/system/bin/uncrypt |
zygote |
/system/bin/app_process |
service_start方法步骤如下,
1,重置service结构中的标志
svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
svc->time_started = 0;
// Running processes require no additional work --- if they're in the
// process of exiting, we've ensured that they will immediately restart
// on exit, unless they are ONESHOT.
if (svc->flags & SVC_RUNNING) {
return;
}
2,判断服务是否需要控制台
bool needs_console = (svc->flags & SVC_CONSOLE);
if (needs_console && !have_console) {
ERROR("service '%s' requires console\n", svc->name);
svc->flags |= SVC_DISABLED;
return;
}
3,检查服务的二进制文件是否存在
struct stat s;
if (stat(svc->args[0], &s) != 0) {
ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
svc->flags |= SVC_DISABLED;
return;
}
4,检查SVC_ONESHOT参数
if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
svc->args[0]);
svc->flags |= SVC_DISABLED;
return;
}
5,设置安全上下文
char* scon = NULL;
if (is_selinux_enabled() > 0) {
if (svc->seclabel) {
scon = strdup(svc->seclabel);
if (!scon) {
ERROR("Out of memory while starting '%s'\n", svc->name);
return;
}
} else {
•••
6,fork子进程
pid_t pid = fork();
7,准备环境变量
if (properties_initialized()) {
get_property_workspace(&fd, &sz);
snprintf(tmp, sizeof(tmp), "%d,%d", dup(fd), sz);
add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
}
for (ei = svc->envvars; ei; ei = ei->next)
add_environment(ei->name, ei->value);
8,创建socket
for (si = svc->sockets; si; si = si->next) {
int socket_type = (
!strcmp(si->type, "stream") ? SOCK_STREAM :
(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
int s = create_socket(si->name, socket_type,
si->perm, si->uid, si->gid, si->socketcon ?: scon);
if (s >= 0) {
publish_socket(si->name, s);
}
}
9,处理标准输出,输入,错误三个文件描述符
if (needs_console) {
setsid();
open_console();
} else {
zap_stdio();
}
10,执行execve
if (!dynamic_args) {
if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
}
} else {
char *arg_ptrs[INIT_PARSER_MAXARGS+1];
int arg_idx = svc->nargs;
char *tmp = strdup(dynamic_args);
char *next = tmp;
char *bword;
/* Copy the static arguments */
memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));
while((bword = strsep(&next, " "))) {
arg_ptrs[arg_idx++] = bword;
if (arg_idx == INIT_PARSER_MAXARGS)
break;
}
arg_ptrs[arg_idx] = NULL;
execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
}
系统中的所有其他进程都是init进程的后代,因此,init进程需要在这些后代死亡时负责清理他们,已防止他们变为僵尸进程。
僵尸进程危害:Linux系统对每个用户能运行的进程数量是有限制的,超过限制以后再创建新的进程将会失败。其实,僵尸进程仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息,僵尸进程并不占用任何内存空间。
流程图如下,
signal_handler_init方法如下,
void signal_handler_init() {
// Create a signalling mechanism for SIGCHLD.
int s[2];
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
ERROR("socketpair failed: %s\n", strerror(errno));
exit(1);
}
signal_write_fd = s[0];
signal_read_fd = s[1];
// Write to signal_write_fd if we catch SIGCHLD.
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = SIGCHLD_handler;
act.sa_flags = SA_NOCLDSTOP; // 信号标志,当子进程终止时才会接收SIGCHLD信号
sigaction(SIGCHLD, &act, 0);
reap_any_outstanding_children();
register_epoll_handler(signal_read_fd, handle_signal); // 回到方法
}
void register_epoll_handler(int fd, void (*fn)()) {
epoll_event ev;
ev.events = EPOLLIN;
ev.data.ptr = reinterpret_cast(fn);
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
ERROR("epoll_ctl failed: %s\n", strerror(errno));
}
}
Init进程启动完毕后,会监听创建的socket,如果有数据到来,主线程会唤醒并调用handle_signal方法。当进程调用exit()方法退出时,会向父进程发出SIGCHLD信号.父进程收到信号后,会释放分配给子进程的资源。如果未发出SIGCHLD信号或者父进程未处理,那么子进程会一直保持当前的退出状态,成为僵尸进程。
handle_signal方法如下,
static void handle_signal() {
// Clear outstanding requests.
char buf[32];
read(signal_read_fd, buf, sizeof(buf));
reap_any_outstanding_children();
}
static void reap_any_outstanding_children() {
while (wait_for_one_process()) { // 循环调用, wait_for_one_process一次仅处理一个子进程。
}
}
wait_for_one_process方法步骤如下,
1,调用waitpid方法等待死亡子进程结束。
pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
if (pid == 0) {
return false;
} else if (pid == -1) {
ERROR("waitpid failed: %s\n", strerror(errno));
return false;
}
2,检查死亡进程是否位于服务列表中
service* svc = service_find_by_pid(pid);
std::string name;
if (svc) {
name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name, pid);
} else {
name = android::base::StringPrintf("Untracked pid %d", pid);
}
NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str());
if (!svc) {
return true;
}
3,如果死亡进程是服务进程,而且需要重启,会杀掉死亡进程的所有子进程。这样当服务进程重启的时候,不会因为子进程已经存在而导致错误。
if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
NOTICE("Service '%s' (pid %d) killing any children in process group\n", svc->name, pid);
kill(-pid, SIGKILL);
}
4,清理死亡子进程的socket
for (socketinfo* si = svc->sockets; si; si = si->next) {
char tmp[128];
snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
unlink(tmp);
}
5,设置服务进程的属性
svc->pid = 0;
svc->flags &= (~SVC_RUNNING);
// Oneshot processes go into the disabled state on exit,
// except when manually restarted.
if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
svc->flags |= SVC_DISABLED;
}
•••
6,到这一步骤意味着进程会重启,并加上重启标志。
time_t now = gettime();
if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
ERROR("critical process '%s' exited %d times in %d minutes; "
"rebooting into recovery mode\n", svc->name,
CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
return true;
}
} else {
svc->time_crashed = now;
svc->nr_crashed = 1;
}
}
svc->flags &= (~SVC_RESTART);
svc->flags |= SVC_RESTARTING;
// Execute all onrestart commands for this service.
struct listnode* node;
list_for_each(node, &svc->onrestart.commands) {
command* cmd = node_to_item(node, struct command, clist);
cmd->func(cmd->nargs, cmd->args);
}
关于init进程,就先说这么多吧。当然还有很多知识点并没有说到,以后有机会可以逐个解析说明。