1,init 进程
system\core\init\init.c
它是用户空间的第一个进程
它负责创建系统中的几个关键进程
重点 init 进程如何创建 zygote
int main(int argc, char **argv)
{
int device_fd = -1;
int property_set_fd = -1;
int signal_recv_fd = -1;
int keychord_fd = -1;
int fd_count;
int s[2];
int fd;
struct sigaction act;
char tmp[PROP_VALUE_MAX];
struct pollfd ufds[4];
char *tmpdev;
char* debuggable;
act.sa_handler = sigchld_handler;
act.sa_flags = SA_NOCLDSTOP;
act.sa_mask = 0;
act.sa_restorer = NULL;
sigaction(SIGCHLD, &act, 0);
/* 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.
* //创建一些文件夹,并挂载设备
*/
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
mount("tmpfs", "/dev", "tmpfs", 0, "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);
/* We must have some place other than / to create the
* device nodes for kmsg and null, otherwise we won't
* be able to remount / read-only later on.
* Now that tmpfs is mounted on /dev, we can actually
* talk to the outside world.
* //重定向标准输入/输出/错误输出到/dev/_null_。
*/
open_devnull_stdio();
/*
设置init的日志输出设备为/dev/__kmsg__,不过该文件打开后,会立即被unlink了,
这样,其他进程就无法打开这个文件读取日志信息了。
*/
log_init();
INFO("reading config file\n");
//解析init.rc配置文件
parse_config_file("/init.rc");
/* pull the kernel commandline and ramdisk properties file in */
qemu_init();
import_kernel_cmdline(0);
get_hardware_name();
snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
parse_config_file(tmp);
action_for_each_trigger("early-init", action_add_queue_tail);
drain_action_queue();
INFO("device init\n");
device_fd = device_init();
//初始化和属性相关的资源
property_init();
// only listen for keychords if ro.debuggable is true
debuggable = property_get("ro.debuggable");
if (debuggable && !strcmp(debuggable, "1")) {
keychord_fd = open_keychord();
}
if (console[0]) {
snprintf(tmp, sizeof(tmp), "/dev/%s", console);
console_name = strdup(tmp);
}
fd = open(console_name, O_RDWR);
if (fd >= 0)
have_console = 1;
close(fd);
//下面这个函数将加载这个文件作为系统的开机画面
if( load_565rle_image(INIT_IMAGE_FILE) ) {
fd = open("/dev/tty0", O_WRONLY);
if (fd >= 0) {
const char *msg;
msg = "\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n" // console is 40 cols x 30 lines
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
" A N D R O I D ";
write(fd, msg, strlen(msg));
close(fd);
}
}
if (qemu[0])
import_kernel_cmdline(1);
if (!strcmp(bootmode,"factory"))
property_set("ro.factorytest", "1");
else if (!strcmp(bootmode,"factory2"))
property_set("ro.factorytest", "2");
else
property_set("ro.factorytest", "0");
property_set("ro.serialno", serialno[0] ? serialno : "");
property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");
property_set("ro.baseband", baseband[0] ? baseband : "unknown");
property_set("ro.carrier", carrier[0] ? carrier : "unknown");
property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
property_set("ro.hardware", hardware);
snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
property_set("ro.revision", tmp);
/* execute all the boot actions to get us started */
//执行位于init阶段的动作
action_for_each_trigger("init", action_add_queue_tail);
drain_action_queue();
/* read any property files on system or data and
* fire up the property service. This must happen
* after the ro.foo properties are set above so
* that /data/local.prop cannot interfere with them.
*/
//启动属性服务
property_set_fd = start_property_service();
/* create a signalling mechanism for the sigchld handler */
if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
signal_fd = s[0];
signal_recv_fd = s[1];
fcntl(s[0], F_SETFD, FD_CLOEXEC);
fcntl(s[0], F_SETFL, O_NONBLOCK);
fcntl(s[1], F_SETFD, FD_CLOEXEC);
fcntl(s[1], F_SETFL, O_NONBLOCK);
}
/* make sure we actually have all the pieces we need */
if ((device_fd < 0) ||
(property_set_fd < 0) ||
(signal_recv_fd < 0)) {
ERROR("init startup failure\n");
return 1;
}
/* execute all the boot actions to get us started */
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
drain_action_queue();
/* run all property triggers based on current state of the properties */
queue_all_property_triggers();
drain_action_queue();
/* enable property triggers */
property_triggers_enabled = 1;
ufds[0].fd = device_fd;//device_fd用于监听来自内核的Uevent事件
ufds[0].events = POLLIN;
ufds[1].fd = property_set_fd;//property_set_fd用于监听来自属性服务器的事件
ufds[1].events = POLLIN;
ufds[2].fd = signal_recv_fd;//signal_recv_fd由socketpair创建,它的事件来自另外一个socket
ufds[2].events = POLLIN;
fd_count = 3;
if (keychord_fd > 0) {
ufds[3].fd = keychord_fd;//如果keychord设备初始化成功,则init也会关注来自这个设备的事件。
ufds[3].events = POLLIN;
fd_count++;
} else {
ufds[3].events = 0;
ufds[3].revents = 0;
}
#if BOOTCHART
bootchart_count = bootchart_init();
if (bootchart_count < 0) {
ERROR("bootcharting init failure\n");
} else if (bootchart_count > 0) {
NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
} else {
NOTICE("bootcharting ignored\n");
}
#endif
for(;;) {
//从此init将进入一个无限循环。
int nr, i, timeout = -1;
for (i = 0; i < fd_count; i++)
ufds[i].revents = 0;
//在循环中执行动作
drain_action_queue();
//重启那些已经死去的进程
restart_processes();
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
#if BOOTCHART
if (bootchart_count > 0) {
if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
timeout = BOOTCHART_POLLING_MS;
if (bootchart_step() < 0 || --bootchart_count == 0) {
bootchart_finish();
bootchart_count = 0;
}
}
#endif
//调用poll等待一些事情的发生
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
//ufds[2]保存的是signal_recv_fd,用于接收来自socket的消息。
if (ufds[2].revents == POLLIN) {
/* we got a SIGCHLD - reap and restart as needed */
read(signal_recv_fd, tmp, sizeof(tmp));
while (!wait_for_one_process(0))
;
continue;
}
if (ufds[0].revents == POLLIN)
handle_device_fd(device_fd);//处理Uevent事件
if (ufds[1].revents == POLLIN)
handle_property_set_fd(property_set_fd);//处理属性服务的事件
if (ufds[3].revents == POLLIN)
handle_keychord(keychord_fd);//处理keychord事件。
}
return 0;
}
解析init.rc 文件
执行各个阶段动作创建Zygote 的工作就是
调用property_init初始化属性相关的资源,并且通过property_start_service启动属性服务
init进入一个无限循环,并且等待一些事情的发生。重点关注init如何处理来自socket和来自属性服务器相关的事情。
解析配置文件
system\core\init\parser.c
int parse_config_file(const char *fn)
{
char *data;
//读取配置文件的内容,这个文件是init.rc。
data = read_file(fn, 0);
if (!data) return -1;
//调用parse_config做真正的解析
parse_config(fn, data);
DUMP();
return 0;
}
static void parse_config(const char *fn, char *s)
{
struct parse_state state;
char *args[SVC_MAXARGS];
int nargs;
nargs = 0;
state.filename = fn;
state.line = 1;
state.ptr = s;
state.nexttoken = 0;
//设置解析函数,不同的内容用不同的解析函数
state.parse_line = parse_line_no_op;
for (;;) {
switch (next_token(&state)) {
case T_EOF:
state.parse_line(&state, 0, 0);
return;
case T_NEWLINE:
if (nargs) {
//得到关键字的类型
int kw = lookup_keyword(args[0]);
//判断关键字类型是不是SECTION。
if (kw_is(kw, SECTION)) {
state.parse_line(&state, 0, 0);
//解析这个SECTION。
parse_new_section(&state, kw, nargs, args);
} else {
state.parse_line(&state, nargs, args);
}
nargs = 0;
}
break;
case T_TEXT:
if (nargs < SVC_MAXARGS) {
args[nargs++] = state.text;
}
break;
}
}
}
init.rc的解析
on init #根据上面的分析,on关键字标示一个section,对应的名字是”init”
#下面所有的内容都属于这个section,直到下一个section开始时。
exportPATH /sbin:/system/sbin:/system/bin:/system/xbin
exportANDROID_BOOTLOGO 1 #根据keywords.h的定义,export表示一个COMMAND
#service也是section的标示,对应section的名为“zygote“
service zygote /system/bin/app_process -Xzygote/system/bin –zygote \
--start-system-server
socket zygote stream 666 #socket关键字表示OPTION
on restart write /sys/android_power/request_state wake #onrestart也是OPTION
on restart write /sys/power/state on
on restart restart media
解析service
解析section的入口函数是parse_new_section
void parse_new_section(struct parse_state *state, int kw,
int nargs, char **args)
{
printf("[ %s %s ]\n", args[0],
nargs > 1 ? args[1] : "");
switch(kw) {
case K_service: //解析service,用parse_service和parse_line_service
state->context = parse_service(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_service;
return;
}
break;
case K_on: //解析on section
state->context = parse_action(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_action;
return;
}
break;
}
state->parse_line = parse_line_no_op;
}
service解析时,用到了parse_service和parse_line_service两个函数
service结构体
struct service {
/* list of all services */
//listnode是一个特殊的结构体,在内核代码中用得非常多,主要用来将结构体链接成一个
//双向链表。init中有一个全局的service_list,专门用来保存解析配置文件后得到的service。
struct listnode slist;
const char *name; //service的名字,对应我们这个例子就是”zygote”
const char *classname;//service所属class的名字,默认是”defult”
unsigned flags;//service的属性
pid_t pid; //进程号
time_t time_started; //上一次启动的时间 /* time of last start */
time_t time_crashed; //上一次死亡的时间 /* first crash within inspection window */
int nr_crashed; //死亡次数 /* number of times crashed within window */
uid_t uid;//uid,gid相关
gid_t gid;
gid_t supp_gids[NR_SVC_SUPP_GIDS];
size_t nr_supp_gids;
/*
有些service需要使用socket,下面这个socketinfo用来描述socket的相关信息。
我们的zygote也使用了socket,配置文件中的内容是socket zygote stream 666。
它表示将创建一个AF_STREAM类型的socket(其实就是TCP socket),该socket的名为“zygote”,
读写权限是666。
*/
struct socketinfo *sockets;
//service一般运行在单独的一个进程中,envvars用来描述创建这个进程时所需的环境变量信息。
struct svcenvinfo *envvars;
struct action onrestart; /* Actions to execute on restart. */
/* keycodes for triggering this service via /dev/keychord */
//和keychord相关的内容
int *keycodes;
int nkeycodes;
int keychord_id;
//参数个数
int nargs;
/* "MUST BE AT THE END OF THE STRUCT" */
//用于存储参数
char *args[1];
};
parse_service
static void *parse_service(struct parse_state *state, int nargs, char **args)
{
struct service *svc; //声明一个service结构体
if (nargs < 3) {
parse_error(state, "services must have a name and a program\n");
return 0;
}
if (!valid_name(args[1])) {
parse_error(state, "invalid service name '%s'\n", args[1]);
return 0;
}
//init维护了一个全局的service链表,先判断是否已经有同名的service了。
svc = service_find_by_name(args[1]);
if (svc) {
parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
//如果有同名的service,则不能继续后面的操作
return 0;
}
nargs -= 2;
svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
if (!svc) {
parse_error(state, "out of memory\n");
return 0;
}
svc->name = args[1];
svc->classname = "default";//设置classname为”default”,这个很关键!
memcpy(svc->args, args + 2, sizeof(char*) * nargs);
svc->args[nargs] = 0;
svc->nargs = nargs;
svc->onrestart.name = "onrestart";
list_init(&svc->onrestart.commands);
//把zygote这个service加到全局链表service_list中。
list_add_tail(&service_list, &svc->slist);
return svc;
}
parse_service函数只是搭建了一个service的架子
static void parse_line_service(struct parse_state *state, int nargs, char **args)
{
struct service *svc = state->context;
struct command *cmd;
int i, kw, kw_nargs;
if (nargs == 0) {
return;
}
//其实还是根据关键字来做各种处理。
kw = lookup_keyword(args[0]);
switch (kw) {
case K_capability:
break;
case K_class:
if (nargs != 2) {
parse_error(state, "class option requires a classname\n");
} else {
svc->classname = args[1];
}
break;
case K_console:
svc->flags |= SVC_CONSOLE;
break;
case K_disabled:
svc->flags |= SVC_DISABLED;
break;
case K_group:
if (nargs < 2) {
parse_error(state, "group option requires a group id\n");
} else if (nargs > NR_SVC_SUPP_GIDS + 2) {
parse_error(state, "group option accepts at most %d supp. groups\n",
NR_SVC_SUPP_GIDS);
} else {
int n;
svc->gid = decode_uid(args[1]);
for (n = 2; n < nargs; n++) {
svc->supp_gids[n-2] = decode_uid(args[n]);
}
svc->nr_supp_gids = n - 2;
}
break;
case K_keycodes:
if (nargs < 2) {
parse_error(state, "keycodes option requires atleast one keycode\n");
} else {
svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));
if (!svc->keycodes) {
parse_error(state, "could not allocate keycodes\n");
} else {
svc->nkeycodes = nargs - 1;
for (i = 1; i < nargs; i++) {
svc->keycodes[i - 1] = atoi(args[i]);
}
}
}
break;
case K_oneshot:
/*
这是service的属性,它一共有五个属性,分别为:
SVC_DISABLED:不随class自动启动。下面将会看到class的作用。
SVC_ONESHOT:退出后不需要重启,也就是这个service只启动一次就可以了。
SVC_RUNNING:正在运行,这是service的状态。
SVC_RESTARTING:等待重启,这也是service的状态。
SVC_CONSOLE:该service需要使用控制台 。
SVC_CRITICAL:如果在规定时间内该service不断重启,则系统会重启并进入恢复模式。
zygote没有使用任何属性,这表明它:会随着class的处理自动启动;
退出后会由init重启;不使用控制台;即使不断重启也不会导致系统进入恢复模式。
*/
svc->flags |= SVC_ONESHOT;
break;
case K_onrestart: //根据onrestart的内容,填充action结构体的内容
nargs--;
args++;
kw = lookup_keyword(args[0]);
if (!kw_is(kw, COMMAND)) {
parse_error(state, "invalid command '%s'\n", args[0]);
break;
}
kw_nargs = kw_nargs(kw);
if (nargs < kw_nargs) {
parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
kw_nargs > 2 ? "arguments" : "argument");
break;
}
//创建command结构体
cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
cmd->func = kw_func(kw);
cmd->nargs = nargs;
memcpy(cmd->args, args, sizeof(char*) * nargs);
//把新建的command加入到双向链表中。
list_add_tail(&svc->onrestart.commands, &cmd->clist);
break;
case K_critical:
svc->flags |= SVC_CRITICAL;
break;
case K_setenv: { /* name value */
struct svcenvinfo *ei;
if (nargs < 2) {
parse_error(state, "setenv option requires name and value arguments\n");
break;
}
ei = calloc(1, sizeof(*ei));
if (!ei) {
parse_error(state, "out of memory\n");
break;
}
ei->name = args[1];
ei->value = args[2];
ei->next = svc->envvars;
svc->envvars = ei;
break;
}
case K_socket: {//创建socket相关信息
/* name type perm [ uid gid ] */
struct socketinfo *si;
if (nargs < 4) {
parse_error(state, "socket option requires name, type, perm arguments\n");
break;
}
if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")) {
parse_error(state, "socket type must be 'dgram' or 'stream'\n");
break;
}
si = calloc(1, sizeof(*si));
if (!si) {
parse_error(state, "out of memory\n");
break;
}
si->name = args[1];//socket的名字
si->type = args[2];//socket的类型
si->perm = strtoul(args[3], 0, 8); //socket的读写权限
if (nargs > 4)
si->uid = decode_uid(args[4]);
if (nargs > 5)
si->gid = decode_uid(args[5]);
si->next = svc->sockets;
svc->sockets = si;
break;
}
case K_user:
if (nargs != 2) {
parse_error(state, "user option requires a user id\n");
} else {
svc->uid = decode_uid(args[1]);
}
break;
default:
parse_error(state, "invalid option '%s'\n", args[0]);
}
}
init控制service
1,启动zygote
init.rc 中 class_start default
void service_start(struct service *svc, const char *dynamic_args)
{
struct stat s;
pid_t pid;
int needs_console;
int n;
/* starting a service removes it from the disabled
* state and immediately takes it out of the restarting
* state if it was in there
*/
svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING));
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;//如果这个service已在运行,则不用处理
}
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一般运行于另外一个进程中,这个进程也是init的子进程,所以启动service前需要判断
对应的可执行文件是否存在,zygote对应的可执行文件是/system/bin/app_process
*/
if (stat(svc->args[0], &s) != 0) {
ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
svc->flags |= SVC_DISABLED;
return;
}
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;
}
NOTICE("starting '%s'\n", svc->name);
pid = fork(); //调用fork创建子进程
if (pid == 0) {
//pid为零,我们在子进程中
struct socketinfo *si;
struct svcenvinfo *ei;
char tmp[32];
int fd, sz;
//得到属性存储空间的信息并加到环境变量中,后面在属性服务一节中会碰到使用它的地方。
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)
add_environment(ei->name, ei->value);
//根据socketinfo创建socket
for (si = svc->sockets; si; si = si->next) {
int s = create_socket(si->name,
!strcmp(si->type, "dgram") ?
SOCK_DGRAM : SOCK_STREAM,
si->perm, si->uid, si->gid);
if (s >= 0) {
//在环境变量中添加socket信息。
publish_socket(si->name, s);
}
}
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
//设置uid,gid等
setpgid(0, getpid());
/* as requested, set our gid, supplemental gids, and uid */
if (svc->gid) {
setgid(svc->gid);
}
if (svc->nr_supp_gids) {
setgroups(svc->nr_supp_gids, svc->supp_gids);
}
if (svc->uid) {
setuid(svc->uid);
}
/*
执行/system/bin/app_process,这样就进入到app_process的main函数中了。
fork、execve这两个函数都是Linux系统上常用的系统调用。
*/
if (!dynamic_args)
execve(svc->args[0], (char**) svc->args, (char**) ENV);
else {
char *arg_ptrs[SVC_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 == SVC_MAXARGS)
break;
}
arg_ptrs[arg_idx] = '\0';
execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
}
_exit(127);
}
if (pid < 0) {
ERROR("failed to start '%s'\n", svc->name);
svc->pid = 0;
return;
}
//父进程init的处理,设置service的信息,如启动时间、进程号,以及状态等。
svc->time_started = gettime();
svc->pid = pid;
svc->flags |= SVC_RUNNING;
//每一个service都有一个属性,zygote的属性为init.svc.zygote,现在设置它的值为running
notify_service_state(svc->name, "running");
}
原来,zygote是通过fork和execv共同创建的
重启zygote
static void sigchld_handler(int s)
{
//当子进程退出时,init的这个信号处理函数会被调用
write(signal_fd, &s, 1);
}
signal_fd,就是在init中通过socketpair创建的两个socket中的一个,既然会往这个signal_fd中发送数据,那么另外一个socket就一定能接收到,这样就会导致init从poll函数中返回