android启动过程分析——init进程

概要

android启动过程包含从Linux内核加载到Home应用程序启动的整个过程。

android启动过程

  • Linux 内核

    android是基于Linux内核的系统平台。启动的时候,首先通过bootloader(系统加载器),加载Linux内核。在Linux加载启动时,与普通的Linux启动过程相同,先初始化内核,然后调用init进程。

  • init进程

    android的init进程对各种设备进行初始化,运行android framework所需要的各种daemon、context manager、media server、zygote等。以下是init进程执行的daemon进程:

    • USB daemon(usbd):管理USB连接
    • android debug bridge daemon(adbd):android debug bridge连接管理
    • debugger daemon(debuggerd):启动debugger系统
    • radio interface layer daemon(rild):管理无线通信连接
  • context manager

    context manager是一个管理android系统服务的重要进程。系统服务是组成android framework的重要组件,提供从相机、音频、视频处理到各种应用程序制作所需要得到重要的API

    context manager提供运行于android内的各种系统服务信息。应用程序或framework内部模块在调用系统服务时,需要先向服务器申请,而后通过binder IPC调用系统服务。

    在系统启动的时候,android所有系统服务都要把各自的handle信息注册到context manager,此时,binder IPC用来进行进程间通信。

  • media server

    media server用于运行基于C/C++的本地系统服务,如audio flinger(负责音频输出)、camera等。

  • zygote

    zygote进程用于缩短android应用程序加载的时间。每当执行Java应用程序的时候,zygote就会派生出一个子进程来执行应用程序,该子进程就是用来执行Java应用程序的虚拟机。

  • system server

    system server是android系统的一个核心进程,它是由zygote进程创建的,在android启动过程中位于zygote之后。在system server中可以看到它建立的android中的大部分服务,如activity manager service(管理应用程序的生命周期)、location manager service(提供终端的地理位置信息)等。

    为了将运行在system server中Java系统服务提供给android应用程序或framework内部模块使用,需要将它们先注册到context manager中。

    在通过binder IPC 将Java系统服务注册到基于C语言的服务管理器时,需要使用JNI本地编程接口。JNI允许Java与其他编程语言(如C、C++、汇编语言)编写的应用程序和库进行交互操作。

以上就是对android启动过程的简单介绍,这仅仅是android启动过程的一部分,当所有Java系统服务加载完毕后,activity manager service会运行HOME应用,启动过程继续进行。

init进程

众所周知,Linux中的所有进程都是有init进程创建并运行的。首先Linux内核启动,然后在用户空间中启动init进程,再依次启动系统运行所需要的其他进程。在系统启动完成后,init进程会作为守护进程监视所有其他进程。若某个监视中的进程一旦终结,进入僵死状态时,它就会释放进程所占用的系统资源。在android平台中也存在init进程,除了提供以上常见的功能外,还提供几种额外的功能。android的init进程主要做以下两件事:

  • 解析配置文件init.rc,然后启动系统各种native进程,例如非常重要的zygote进程、surfaceFlinger进程和media进程,这个是它的主要工作之一,也是它最重要的工作,因为native进程靠它来启动。
  • 维护一个属性服务property service,并且管理它。应用程序客户端可以通过set操作来设置属性,通过get操作来获取属性,常用的setProperty()方法和getProperty()方法就是通过框架层连接到这个属性服务的。当然,也可以使用abd shell 来获取属性和设置属性,如adb shell 通过getprop命令获取手机的所有系统属性。

init进程的源代码在system/core/init/目录下,主要文件是init.cpp,以下是这个文件的main函数。

int main(int argc, char** argv) {

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}
// 清mask操作,这样做是为了后面创建文件,解决权限问题。
umask(0);
// 添加环境变量
add_environment("PATH", _PATH_DEFPATH);
bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
// 建立各种用户控件的目录,如/dev、/proc、/sys等,然后挂载分区
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();
// 将log写到dev/kmsg中,其信息就是init进程启动相关的log
klog_init();
klog_set_level(KLOG_NOTICE_LEVEL);
NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");
if (!is_first_stage) {
// 尝试在dev目录下创建.booting文件,创建完后关闭,目的是查看dev是不是有权限写
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
// 初始化属性服务
property_init();
// 解析内核启动参数
process_kernel_dt();
process_kernel_cmdline();
export_kernel_boot_props();
}
// 初始化SELinux policy权限管理机制
selinux_initialize(is_first_stage);
if (is_first_stage) {
if (restorecon("/init") == -1) {
ERROR("restorecon failed: %s\n", strerror(errno));
security_failure();
}
char* path = argv[0];
char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
if (execv(path, args) == -1) {
ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));
security_failure();
}
}
NOTICE("Running restorecon...\n");
restorecon("/dev");
restorecon("/dev/socket");
restorecon("/dev/__properties__");
restorecon("/property_contexts");
restorecon_recursive("/sys");
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();
export_oem_lock_status();
// 启动属性服务
start_property_service();
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");
ActionManager& am = ActionManager::GetInstance();
am.QueueEventTrigger("early-init");
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
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(keychord_init_action, "keychord_init");
am.QueueBuiltinAction(console_init_action, "console_init");
am.QueueEventTrigger("init");
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
std::string bootmode = property_get("ro.bootmode");
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
am.QueueEventTrigger("late-init");
}
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
// 进入死循环
while (true) {
if (!waiting_for_exec) {
// 执行子进程对应的命令,即执行init.rc文件里配置的命令
am.ExecuteOneCommand();
// 这个函数用于重启死掉的service
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是一个性能统计工具,这个函数用来分析性能
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;

}

从init.cpp的main函数中,可以看到其主要做了以下几件事

  • klog_init()函数将log写到/dev/kmsg中,对应代码位于system/core/libcutils/klog.c中

void klog_init(void) {

1
2
3
4
5
6
7
8
9
10
11
12
if (klog_fd >= 0) return;
// 打开“/dev/kmsg”
klog_fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
if (klog_fd >= 0) {
return;
}
// 建立/dev/__kmsg__节点,创建完之后通过open打开,得到一个全局的文件描述符klog_fd并且保存起来
static const char* name = "/dev/__kmsg__";
if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
klog_fd = open(name, O_WRONLY | O_CLOEXEC);
unlink(name);
}

}

​ 之后,klog.c的klog_writev()的函数就会把log信息写在新创建的klog_fd文件描述符代表的文件当中。在init.cpp文件中有大量的ERROR()、NOTICE() 和 INFO(),这些函数都对应init_klog_write()函数,init_klog_write()函数调用init_klog_vwrite(),init_klog_vwrite()函数调用了klog_writev()函数来处理这个log。

  • process_kernel_cmdline()函数解析内核启动参数

    static void process_kernel_cmdline() {

    1
    2
    3
    4
    5
    // 内核启动参数信息保存在/proc/cmdline里main,它是uboot启动时传给内核的信息
    chmod("/proc/cmdline", 0440);
    // 解析内核启动参数
    import_kernel_cmdline(false, import_kernel_nv);
    if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);

    }

  • signal_handler_init()函数设置信号处理函数

    void signal_handler_init() {

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // 创建socket
    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发送数据的文件描述符,signal_read_fd接收数据的文件描述符
    signal_write_fd = s[0];
    signal_read_fd = s[1];
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = SIGCHLD_handler; // 发送数据的函数
    act.sa_flags = SA_NOCLDSTOP;
    sigaction(SIGCHLD, &act, 0);
    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
    // handle_signal接收数据的函数
    register_epoll_handler(signal_read_fd, handle_signal);

    }

    signal_handler_init函数初始化了发送数据的SIGCHLD_handler函数和接收数据的handle_signal函数

    static void SIGCHLD_handler(int) {

    1
    2
    3
    if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
    ERROR("write(signal_write_fd) failed: %s\n", strerror(errno));
    }

    }

    static void handle_signal() {

    1
    2
    3
    char buf[32];
    read(signal_read_fd, buf, sizeof(buf));
    ServiceManager::GetInstance().ReapAnyOutstandingChildren();

    }

    当子进程异常退出的时候,SIGCHLD_handler函数会被调用,然后往signal_write_fd中写入数据,让接收数据的函数handle_signal接收,handle_signal函数接收到数据后,会调用ReapAnyOutstandingChildren函数来进行下一步操作。

    void ServiceManager::ReapAnyOutstandingChildren() {

    1
    2
    while (ReapOneProcess()) {
    }

    }

    bool ServiceManager::ReapOneProcess() {

    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
    int status;
    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;
    }
    // 找到死掉的service
    Service* svc = FindServiceByPid(pid);
    std::string name;
    if (svc) {
    name = android::base::StringPrintf("Service '%s' (pid %d)",
    svc->name().c_str(), pid);
    } else {
    name = android::base::StringPrintf("Untracked pid %d", pid);
    }
    if (WIFEXITED(status)) {
    NOTICE("%s exited with status %d\n", name.c_str(), WEXITSTATUS(status));
    } else if (WIFSIGNALED(status)) {
    NOTICE("%s killed by signal %d\n", name.c_str(), WTERMSIG(status));
    } else if (WIFSTOPPED(status)) {
    NOTICE("%s stopped by signal %d\n", name.c_str(), WSTOPSIG(status));
    } else {
    NOTICE("%s state changed", name.c_str());
    }
    if (!svc) {
    return true;
    }
    if (svc->Reap()) { // 杀死死掉service的所有子进程
    waiting_for_exec = false;
    RemoveService(*svc);
    }
    return true;

    }

    ReapAnyOutstandingChildren简单调用了ReapOneProcess函数来进行下一步操作。ReapOneProcess会杀死死掉的service及其子进程。之后,守护进程init.cpp的main函数会调用死掉的service的onrestart方法重启系统服务。

  • property_load_boot_defaults()函数导入默认环境变量

    void property_load_boot_defaults() {

    1
    2
    // 导入PROP_PATH_RAMDISK_DEFAULT文件的内容
    load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);

    }

  • property_init()函数初始化属性服务和start_property_service()函数启动属性服务

    void property_init() {

    1
    2
    3
    4
    if (__system_property_area_init()) {
    ERROR("Failed to initialize property area\n");
    exit(1);
    }

    }

    void start_property_service() {

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 创建socket服务,即属性服务,用于进程间通信
    property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
    0666, 0, 0, NULL);
    if (property_set_fd == -1) {
    ERROR("start_property_service socket creation failed: %s\n", strerror(errno));
    exit(1);
    }
    // 监听property_set_fd文件描述符
    listen(property_set_fd, 8);
    // 当应用程序设置属性的时候,框架会通过socket连接过来,于是就会调用handle_property_set_fd函数
    register_epoll_handler(property_set_fd, handle_property_set_fd);

    }

    static void handle_property_set_fd()
    {

    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
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    prop_msg msg;
    int s;
    int r;
    struct ucred cr;
    struct sockaddr_un addr;
    socklen_t addr_size = sizeof(addr);
    socklen_t cr_size = sizeof(cr);
    char * source_ctx = NULL;
    struct pollfd ufds[1];
    const int timeout_ms = 2 * 1000; /* Default 2 sec timeout for caller to send property. */
    int nr;
    // 接受连接
    if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
    return;
    }
    /* Check socket options here */
    if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
    close(s);
    ERROR("Unable to receive socket options\n");
    return;
    }
    ufds[0].fd = s;
    ufds[0].events = POLLIN;
    ufds[0].revents = 0;
    nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
    if (nr == 0) {
    ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid);
    close(s);
    return;
    } else if (nr < 0) {
    ERROR("sys_prop: error waiting for uid=%d to send property message: %s\n", cr.uid, strerror(errno));
    close(s);
    return;
    }
    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
    if(r != sizeof(prop_msg)) {
    ERROR("sys_prop: mis-match msg size received: %d expected: %zu: %s\n",
    r, sizeof(prop_msg), strerror(errno));
    close(s);
    return;
    }
    switch(msg.cmd) {
    case PROP_MSG_SETPROP:
    msg.name[PROP_NAME_MAX-1] = 0;
    msg.value[PROP_VALUE_MAX-1] = 0;
    if (!is_legal_property_name(msg.name, strlen(msg.name))) {
    ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
    close(s);
    return;
    }
    getpeercon(s, &source_ctx);
    // 如果属性是以ctl.开头就是控制属性,控制属性用于执行命令
    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)) {
    property_set((char*) msg.name, (char*) msg.value);
    } else {
    ERROR("sys_prop: permission denied uid:%d name:%s\n",
    cr.uid, msg.name);
    }
    close(s);
    }
    freecon(source_ctx);
    break;
    default:
    close(s);
    break;
    }

    }

    handle_property_set_fd函数的变量name用来表示系统属性的名称,而变量value用来表示系统属性的值。系统属性分为两种类型,一种是普通类型的系统属性,另一种是控制类型的系统属性,而控制属性的系统属性名称以ctl.开头。回到函数中,如果属性是普通类型的系统属性,就会调用check_mac_perms来检查相应的权限,然后调用property_set函数来设置系统属性的值,如果是控制类型的系统属性,就会调用handle_control_message函数来设置系统属性的值。

    void handle_control_message(const std::string& msg, const std::string& name) {

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
    if (svc == nullptr) {
    ERROR("no such service '%s'\n", name.c_str());
    return;
    }
    if (msg == "start") {
    svc->Start(); // 启动一个服务
    } else if (msg == "stop") {
    svc->Stop(); // 停止一个服务
    } else if (msg == "restart") {
    svc->Restart(); //重启一个服务
    } else {
    ERROR("unknown control msg '%s'\n", msg.c_str());
    }

    }

    int property_set(const char name, const char value) {

    1
    2
    3
    4
    5
    int rc = property_set_impl(name, value);
    if (rc == -1) {
    ERROR("property_set(\"%s\", \"%s\") failed\n", name, value);
    }
    return rc;

    }

    property_set通过调用property_set_impl来实现属性设置

    static int property_set_impl(const char name, const char value) {

    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
    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;
    }
    }
    // 如果属性是以net.开头,主要与DNS有关
    if (strncmp("net.", name, strlen("net.")) == 0) {
    if (strcmp("net.change", name) == 0) {
    return 0;
    }
    property_set("net.change", name);
    } else if (persistent_properties_loaded &&
    strncmp("persist.", name, strlen("persist.")) == 0) {// persist.开头的属性,需要调用write_persistent_property设置value值
    write_persistent_property(name, value);
    }
    property_changed(name, value);
    return 0;

    }

  • parser.ParseConfig(“/init.rc”);函数解析配置文件和使用for循环调用execute_one_command()函数来启动子进程

    init.rc文件是android中一个非常重要的配置文件,这个文件并不是普通的一般配置文件,而是被成为android init language(android初始化语言)。

    import /init.environ.rc
    import /init.usb.rc
    import /init.${ro.hardware}.rc
    import /init.usb.configfs.rc
    import /init.${ro.zygote}.rc
    
    on early-init
    # 设置init和它的子进程的oom_adj值,用于内存管理
    write /proc/1/oom_score_adj -1000
    # Disable sysrq from keyboard
    write /proc/sys/kernel/sysrq 0
    # Set the security context of /adb_keys if present.
    restorecon /adb_keys
    # Shouldn't be necessary, but sdcard won't start without it. http://b/22568628.
    mkdir /mnt 0775 root system
    # Set the security context of /postinstall if present.
    restorecon /postinstall
    #启动ueventd,ueventd是init进程
    start ueventd
    
    on init
    ...
    on late-init
    ...
    on boot
    ...
    on nonencrypted
    ...
    ...
    .......
    ...
    service ueventd /sbin/ueventd
        class core
        critical
        seclabel u:r:ueventd:s0
    
    service healthd /sbin/healthd
        class core
        critical
        seclabel u:r:healthd:s0
        group root system wakelock
    
    service console /system/bin/sh
        class core
        console
        disabled
        user shell
        group shell log readproc
        seclabel u:r:shell:s0
    
    on property:ro.debuggable=1
        # Give writes to anyone for the trace folder on debug builds.
        # The folder is used to store method traces.
        chmod 0773 /data/misc/trace
        start console
    
    service flash_recovery /system/bin/install-recovery.sh
        class main
        oneshot
    

init.rc文件的关键字解析

通过KEYWORD定义知道,KEYWORD只有三种类型,分别是SECTION、OPTION、COMMAND

  • SECTION:只包括import、on、service这三个关键字
  • OPTION:包括user、socket等关键字
  • COMMAND:包括class_start、start等关键字

bool Parser::ParseConfig(const std::string& path) {

1
2
3
4
if (is_dir(path.c_str())) {
return ParseConfigDir(path);
}
return ParseConfigFile(path);

}

bool Parser::ParseConfigDir(const std::string& path) {

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
INFO("Parsing directory %s...\n", path.c_str());
std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir);
if (!config_dir) {
ERROR("Could not import directory '%s'\n", path.c_str());
return false;
}
dirent* current_file;
while ((current_file = readdir(config_dir.get()))) {
std::string current_path =
android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
// Ignore directories and only process regular files.
if (current_file->d_type == DT_REG) {
if (!ParseConfigFile(current_path)) {
ERROR("could not import file '%s'\n", current_path.c_str());
}
}
}
return true;

}

bool Parser::ParseConfigFile(const std::string& path) {

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
INFO("Parsing file %s...\n", path.c_str());
Timer t;
std::string data;
if (!read_file(path.c_str(), &data)) {
return false;
}
data.push_back('\n');
// 读取解析init.rc文件的具体实现
ParseData(path, data);
//解析每个SECTION的内容,然后把解析后的内容保存在一个svc结构体中
for (const auto& sp : section_parsers_) {
sp.second->EndFile(path);
}
if (false) DumpState();
NOTICE("(Parsing %s took %.2fs.)\n", path.c_str(), t.duration());
return true;

}

  • 启动service进程

    解析分析完init.rc文件后,就会通过while循环中的am.ExecuteOneCommand()函数去执行相对应的命令,触发条件到boot阶段的时候,就启动那些core类型和main类型的service,而service的启动主要是通过Service::Start()函数

bool Service::Start() {

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
time_started_ = 0;
// 如果这个service已经在运行,就return回去
if (flags_ & SVC_RUNNING) {
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;
}
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;
}
std::string scon;
if (!seclabel_.empty()) {
scon = seclabel_;
} else {
char* mycon = nullptr;
char* fcon = nullptr;
INFO("computing context for service '%s'\n", args_[0].c_str());
int rc = getcon(&mycon);
if (rc < 0) {
ERROR("could not get context while starting '%s'\n", name_.c_str());
return false;
}
rc = getfilecon(args_[0].c_str(), &fcon);
if (rc < 0) {
ERROR("could not get context while starting '%s'\n", name_.c_str());
free(mycon);
return false;
}
char* ret_scon = nullptr;
rc = security_compute_create(mycon, fcon, string_to_security_class("process"),
&ret_scon);
if (rc == 0) {
scon = ret_scon;
free(ret_scon);
}
if (rc == 0 && scon == mycon) {
ERROR("Service %s does not have a SELinux domain defined.\n", name_.c_str());
free(mycon);
free(fcon);
return false;
}
free(mycon);
free(fcon);
if (rc < 0) {
ERROR("could not get context while starting '%s'\n", name_.c_str());
return false;
}
}
NOTICE("Starting service '%s'...\n", name_.c_str());
// 调用fork创建一个新的子进程
pid_t pid = 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);
}
}
std::string pid_str = StringPrintf("%d", getpid());
for (const auto& file : writepid_files_) {
if (!WriteStringToFile(pid_str, file)) {
ERROR("couldn't write %s to %s: %s\n",
pid_str.c_str(), file.c_str(), strerror(errno));
}
}
if (ioprio_class_ != IoSchedClass_NONE) {
if (android_set_ioprio(getpid(), ioprio_class_, ioprio_pri_)) {
ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
getpid(), ioprio_class_, ioprio_pri_, strerror(errno));
}
}
if (needs_console) {
setsid();
OpenConsole();
} else {
ZapStdio();
}
// 设置子进程uid,gid
setpgid(0, getpid());
if (gid_) {
if (setgid(gid_) != 0) {
ERROR("setgid failed: %s\n", strerror(errno));
_exit(127);
}
}
if (!supp_gids_.empty()) {
if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
ERROR("setgroups failed: %s\n", strerror(errno));
_exit(127);
}
}
if (uid_) {
if (setuid(uid_) != 0) {
ERROR("setuid failed: %s\n", strerror(errno));
_exit(127);
}
}
if (!seclabel_.empty()) {
if (setexeccon(seclabel_.c_str()) < 0) {
ERROR("cannot setexeccon('%s'): %s\n",
seclabel_.c_str(), strerror(errno));
_exit(127);
}
}
std::vector<char*> strs;
for (const auto& s : args_) {
strs.push_back(const_cast<char*>(s.c_str()));
}
strs.push_back(nullptr);
// 调用execve函数,这个service子进程就被启动起来了,并且会进入到它的main函数
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);
}
if (pid < 0) {
ERROR("failed to start '%s'\n", name_.c_str());
pid_ = 0;
return false;
}
time_started_ = gettime();
pid_ = pid;
flags_ |= SVC_RUNNING;
if ((flags_ & SVC_EXEC) != 0) {
INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",
pid_, uid_, gid_, supp_gids_.size(),
!seclabel_.empty() ? seclabel_.c_str() : "default");
}
NotifyStateChange("running");
return true;

}

总结

至此,init.rc文件的解析和启动service就分析完成了。init.rc文件的解析主要就是对关键字的解析,而service的启动主要是通过调用Linux的fork()函数创建一个子进程,execve()函数执行可执行程序,最终把service启动起来并且进入它的main()函数。