#############################################
本文为极度寒冰原创,转载请注明出处
#############################################
for(;;) {
int nr, i, timeout = -1;
execute_one_command();
restart_processes();
.....
}
这个for循环的处理有很多,但是我们现在暂时关心的只有这短短的两个函数。
execute_one_command();
restart_processes();
void execute_one_command(void)
{
int ret, i;
char cmd_str[256] = "";
if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) { // 在第一次的启动中,因为都是NULL,所以肯定可以进入这个判断,如果不是第一次的话,因为得到cur_action或者cur_command都是null,并且如果这个command是当前action的最后一个command的话,会进入到下面的这个判断。
cur_action = action_remove_queue_head(); // 依次获取action从action_queue中
cur_command = NULL; // 在获取新的action之后,将cur_command设置为null
if (!cur_action) // 如果没有action了,则返回
return;
INFO("processing action %p (%s)\n", cur_action, cur_action->name);
cur_command = get_first_command(cur_action); // 如果是一个新的action的话,会执行到这一步去获得first command
} else {
cur_command = get_next_command(cur_action, cur_command); // 仍然在action的内部链表中,如果仍然存在没有被获取到的command的话,则会去获得下一个command。
}
if (!cur_command) // 如果获取到的command为空的话,会返回,反之,继续
return;
ret = cur_command->func(cur_command->nargs, cur_command->args); // 会调用这个command的func区执行,执行的参数个数为nargs,命令为args
if (klog_get_level() >= KLOG_INFO_LEVEL) { // Log的打印
for (i = 0; i < cur_command->nargs; i++) {
strlcat(cmd_str, cur_command->args[i], sizeof(cmd_str));
if (i < cur_command->nargs - 1) {
strlcat(cmd_str, " ", sizeof(cmd_str));
}
}
INFO("command '%s' action=%s status=%d (%s:%d)\n",
cmd_str, cur_action ? cur_action->name : "", ret, cur_command->filename,
cur_command->line);
}
}
其实这个逻辑是比较好理解的,我们要着重分析的仅仅是如何获取action以及command.
struct action *action_remove_queue_head(void)
{
if (list_empty(&action_queue)) { // 首先我们去判断当前待执行的action是否已经为null,即是否还有action没有被执行
return 0;
} else {
struct listnode *node = list_head(&action_queue); // 如果仍然有未被执行的队列的话,就将node指向现在action_queue的头指针
struct action *act = node_to_item(node, struct action, qlist); // 取出action
list_remove(node); // 将这个节点从整个action _queue的列表中删除
list_init(node); // 删除这个节点后,为了安全起见,将node自己指向自己,以避免出现野指针。
return act; // 返回已经查找到的action
}
}
我们可以看到,其实是从action_queue中拿每一个结构体的。
static struct command *get_first_command(struct action *act) // 从一个actoin里面寻找其第一个command,所以只用传递action即可
{
struct listnode *node;
node = list_head(&act->commands); // 将node指向action的commands的结构体
if (!node || list_empty(&act->commands)) // 如果这个节点不存在,或者这个action的commands结构体为空,则返回null
return NULL;
return node_to_item(node, struct command, clist); // 返回第一个节点
}
static struct command *get_next_command(struct action *act, struct command *cmd) // 返回当前commands的下一个command
{
struct listnode *node;
node = cmd->clist.next; 指针向后移动next
if (!node) // 如果不存在,则返回null
return NULL;
if (node == &act->commands) // 如果这个节点已经是头节点了,则返回null
return NULL;
return node_to_item(node, struct command, clist); // 返回next节点
}
在获取到了command之后,我们会去调用command的方法:
ret = cur_command->func(cur_command->nargs, cur_command->args);
去执行command里面的每一个func。
on boot .... class_start core
on nonencrypted
class_start main
class_start late_start
我们看到在action里面,会有一些commands是class_start, 而后面跟的参数,好像与我们service的class name 是一致的。
service adbd /sbin/adbd --root_seclabel=u:r:su:s0
class core
socket adbd stream 660 system system
disabled
seclabel u:r:adbd:s0
# adbd on at boot in emulator
on property:ro.kernel.qemu=1
start adbd
service lmkd /system/bin/lmkd
class core
critical
socket lmkd seqpacket 0660 system system
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
从keywords里面,我们找到了对应的function:
./init/keywords.h:53: KEYWORD(class_start, COMMAND, 1, do_class_start)
来看一下do_class_start的实现:
int do_class_start(int nargs, char **args)
{
/* Starting a class does not start services
* which are explicitly disabled. They must
* be started individually.
*/
service_for_each_class(args[1], service_start_if_not_disabled);
return 0;
}
这个函数的实现很简单,仅仅是传递调用了service_for_each_class, 并且在传递service name的时候,多传递了一个参数为service_start_if_not_disable.
void service_for_each_class(const char *classname,
void (*func)(struct service *svc))
{
struct listnode *node;
struct service *svc;
list_for_each(node, &service_list) { // 遍历service的结构体,这里是不会重复的,因为service的name如果有重复的时候,在解析过程中就已经处理了
svc = node_to_item(node, struct service, slist); // 从slist里取出每一个结构体
if (!strcmp(svc->classname, classname)) { // 如果名字是匹配的话,就会进入这个判断
func(svc); // 执行service_start_if_not_disable, 并且将当前的service结构体给传递进去
}
}
}
接下来要执行的就是
service_start_if_not_disable了,我们来看一下具体的实现:
static void service_start_if_not_disabled(struct service *svc)
{
if (!(svc->flags & SVC_DISABLED)) {
service_start(svc, NULL);
} else {
svc->flags |= SVC_DISABLED_START;
}
}
如果这个service被设置为disabled的话,就不会被启动,如果没有设置的话,我们会去启动这个service。
void service_start(struct service *svc, const char *dynamic_args)
{ /// ****************************** start service 的第一个阶段
struct stat s;
pid_t pid;
int needs_console;
int n;
char *scon = NULL;
int rc;
/* 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
*/
svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START)); // 这个service即将被启动,将其从disable或reset的状态给移除掉,置其为重新运行的状态
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) { // 如果这个service仍然是运行态的话,即return
return;
}
needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
if (needs_console && (!have_console)) {
ERROR("service '%s' requires console\n", svc->name);
svc->flags |= SVC_DISABLED;
return;
} // 如果这个service的flags是初始console,但是这个已经启动了的话,就会设置当前的flags为disabled
if (stat(svc->args[0], &s) != 0) { // 如果要执行的这个service的start的command不存在的话,返回error
ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
svc->flags |= SVC_DISABLED;
return;
}
if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) { // 因为dynamic_args为null,所以这边不会进入这个判断
ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
svc->args[0]);
svc->flags |= SVC_DISABLED;
return;
}
// ***********************************************************这里我们可以认为是第二个阶段,selinux是信息安全相关的操作,这边我们忽略掉
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 {
char *mycon = NULL, *fcon = NULL;
INFO("computing context for service '%s'\n", svc->args[0]);
rc = getcon(&mycon);
if (rc < 0) {
ERROR("could not get context while starting '%s'\n", svc->name);
return;
}
rc = getfilecon(svc->args[0], &fcon);
if (rc < 0) {
ERROR("could not get context while starting '%s'\n", svc->name);
freecon(mycon);
return;
}
rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
if (rc == 0 && !strcmp(scon, mycon)) {
ERROR("Warning! Service %s needs a SELinux domain defined; please fix!\n", svc->name);
}
freecon(mycon);
freecon(fcon);
if (rc < 0) {
ERROR("could not get context while starting '%s'\n", svc->name);
return;
}
}
}
// ***************************************** selinux的操作结束,进入到第三个阶段
NOTICE("starting '%s'\n", svc->name);
pid = fork(); // fork一个自进程,即所有从init.rc启动的service,都是一个子进程
if (pid == 0) { // pid = 0, 进入到子进程中
struct socketinfo *si;
struct svcenvinfo *ei;
char tmp[32];
int fd, sz;
umask(077);
if (properties_inited()) {
get_property_workspace(&fd, &sz); // 得到属性存储空间的信息并加入到环境变量中
sprintf(tmp, "%d,%d", dup(fd), sz);
add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
}
for (ei = svc->envvars; ei; ei = ei->next) // 将service自己声明的env加入到环境变量中
add_environment(ei->name, ei->value);
for (si = svc->sockets; si; si = si->next) { // 根据socket info设置socket
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);
}
}
freecon(scon);
scon = NULL;
if (svc->ioprio_class != IoSchedClass_NONE) {
if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno));
}
}
if (needs_console) {
setsid();
open_console();
} else {
zap_stdio();
}
#if 0
for (n = 0; svc->args[n]; n++) {
INFO("args[%d] = '%s'\n", n, svc->args[n]);
}
for (n = 0; ENV[n]; n++) {
INFO("env[%d] = '%s'\n", n, ENV[n]);
}
#endif
setpgid(0, getpid());
/* as requested, set our gid, supplemental gids, and uid */
if (svc->gid) { // 设置gid
if (setgid(svc->gid) != 0) {
ERROR("setgid failed: %s\n", strerror(errno));
_exit(127);
}
}
if (svc->nr_supp_gids) {
if (setgroups(svc->nr_supp_gids, svc->supp_gids) != 0) {
ERROR("setgroups failed: %s\n", strerror(errno));
_exit(127);
}
}
if (svc->uid) { // 设置uid
if (setuid(svc->uid) != 0) {
ERROR("setuid failed: %s\n", strerror(errno));
_exit(127);
}
}
if (svc->seclabel) {
if (is_selinux_enabled() > 0 && setexeccon(svc->seclabel) < 0) {
ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno));
_exit(127);
}
}
if (!dynamic_args) { // 因为dynamic_args设置的为null,我们在第一次从init.rc启动的时候,一定会进入到这个判断。
if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) { // !!! 执行当前的service的启动的命令,也就是说从这边开始,我们就可以理解为已经从init进程中,去像kernel执行init一样,就去执行各个service所对应的启动函数了!
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] = '\0';
execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
}
_exit(127);
}
freecon(scon);
if (pid < 0) {
ERROR("failed to start '%s'\n", svc->name);
svc->pid = 0;
return;
}
svc->time_started = gettime();
svc->pid = pid;
svc->flags |= SVC_RUNNING;
if (properties_inited())
notify_service_state(svc->name, "running");
}
终于结束了漫长的init进程的分析,估计这十篇文章可以基本概括了init进程启动过程中的每一个细节。