滴水成冰的造句:Android init 启动过程分析 - gpephone
来源:百度文库 编辑:偶看新闻 时间:2024/04/29 18:54:36
Android init 启动过程分析分析android的启动过程,从内核之上,我们首先应该从文件系统的init开始,因为 init是内核进入文件系统后第一个运行的程序,通常我们可以在linux的命令行中指定内核第一个调用谁,如果没指定那么内核将会到/sbin/, /bin/等目录下查找默认的init,如果没有找到那么就报告出错。
下面是曾经用过的几种开发板的命令行参数:
S3C2410 启动参数:
noinitrdroot=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs ip=192.168.2.188:192.168.2.56:192.168.2.56:255.255.255.0::eth0:onconsole=ttySAC0
S3C2440 启动参数:
setenv bootargs console=ttySAC0root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfsip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0::eth0:onmem=64M init=/init
marvell 310 启动参数:
boot root=/dev/nfsnfsroot=192.168.2.56:/nfsroot/rootfs,rsize=1024,wsize=1024ip=192.168.2.176:192.168.2.201:192.168.2.201:255.255.255.0::eth0:-On console=ttyS2,115200 mem=64M init=/init
init的源代码在文件:./system/core/init/init.c 中,init会一步步完成下面的任务:
1.初始化log系统
2.解析/init.rc和/init.%hardware%.rc文件
3. 执行 early-init action in the two filesparsed in step 2.
4. 设备初始化,例如:在 /dev 下面创建所有设备节点,下载 firmwares.
5. 初始化属性服务器,Actually the property system is working as ashare memory. Logically it looks like a registry under Windows system.
6.执行 init action in the two files parsed in step 2.
7. 开启 属性服务。
8.执行 early-boot and boot actions in the two files parsed in step 2.
9.执行 Execute property action in the two files parsed in step 2.
10.进入一个无限循环 to wait for device/property set/child process exit events.例如,如果SD卡被插入,init会收到一个设备插入事件,它会为这个设备创建节点。系统中比较重要的进程都是由init来fork的,所以如果他们他谁崩溃了,那么init 将会收到一个 SIGCHLD 信号,把这个信号转化为子进程退出事件, 所以在loop中,init 会操作进程退出事件并且执行*.rc 文件中定义的命令。
例如,在init.rc中,因为有:
service zygote/system/bin/app_process -Xzygote /system/bin --zygote--start-system-server
socket zygote stream 666
onrestartwrite /sys/android_power/request_state wake
onrestart write/sys/power/state on
所以,如果zygote因为启动某些服务导致异常退出后,init将会重新去启动它。
intmain(int argc, char **argv)
{
...
//需要在后面的程序中看打印信息的话,需要屏蔽open_devnull_stdio()函数
open_devnull_stdio();
...
//初始化log系统
log_init();
//解析/init.rc和/init.%hardware%.rc文件
parse_config_file("/init.rc");
...
snprintf(tmp,sizeof(tmp), "/init.%s.rc", hardware);
parse_config_file(tmp);
...
//执行 early-init action in the two files parsed in step 2.
action_for_each_trigger("early-init", action_add_queue_tail);
drain_action_queue();
...
/* execute all the boot actionsto get us started */
/* 执行 init action in the two files parsed instep 2 */
action_for_each_trigger("init",action_add_queue_tail);
drain_action_queue();
...
/* 执行 early-boot and boot actions in the two files parsed in step 2 */
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 oncurrent state of the properties */
queue_all_property_triggers();
drain_action_queue();
/* enable property triggers */
property_triggers_enabled = 1;
...
for(;;) {
int nr, timeout = -1;
...
drain_action_queue();
restart_processes();
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if(timeout < 0)
timeout = 0;
}
...
nr = poll(ufds, 3, timeout);
if (nr <= 0)
continue;
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);
if (ufds[1].revents ==POLLIN)
{
handle_property_set_fd(property_set_fd);
}
}
return 0;
}
2.解析init.rc脚本
init.rc脚本的具体语法可以参考下面文档
http://www.kandroid.org/android_pdk/bring_up.html
名词解释:
Android初始化語言由四大类声明组成:行为类(Actions),命令类(Commands),服务类(Services),选项类(Options).
初始化语言以行为单位,由以空格间隔的语言符号組成。C风格的反斜杠转义符可以用来插入空白到语言符号。双引号也可以用来防止文本被空格分成多个语言符号。当反斜杠在行末时,作为换行符。
* 以#开始(前面允许空格)的行为注释。
*Actions和Services隐含声明一个新的段落。所有该段落下Commands或Options的声明属于该段落。第一段落前的Commands或Options被忽略。
* Actions和Services拥有唯一的命名。在他们之后声明相同命名的类将被当作错误并忽略。
Actions是一系列命令的命名。Actions拥有一个触发器(trigger)用来決定action何時执行。当一个action在符合触发条件被执行时,如果它还没被加入到待执行队列中的话,則加入到队列最后。
队列中的action依次执行,action中的命令也依次执行。Init在执行命令的中间处理其他活动(设备创建/销毁,property 设置,进程重启)。
Actions的表现形式:
on
重要的数据结构
两个列表,一个队列。
staticlist_declare(service_list);
static list_declare(action_list);
staticlist_declare(action_queue);
*.rc 脚本中所有 service关键字定义的服务将会添加到service_list 列表中。
*.rc 脚本中所有 on 关键开头的项将会被会添加到 action_list 列表中。
每个action列表项都有一个列表,此列表用来保存该段落下的 Commands
脚本解析过程:
parse_config_file("/init.rc")
intparse_config_file(const char *fn)
{
char *data;
data =read_file(fn, 0);
if (!data) return -1;
parse_config(fn, data);
DUMP();
return 0;
}
staticvoid parse_config(const char *fn, char *s)
{
...
caseT_NEWLINE:
if (nargs) {
int kw =lookup_keyword(args[0]);
if (kw_is(kw, SECTION)) {
state.parse_line(&state, 0, 0);
parse_new_section(&state, kw, nargs, args);
} else {
state.parse_line(&state, nargs, args);
}
nargs = 0;
}
...
}
parse_config会逐行对脚本进行解析,如果关键字类型为 SECTION ,那么将会执行 parse_new_section()
类型为 SECTION 的关键字有: on 和sevice
关键字类型定义在 Parser.c (system\core\init) 文件中
Parser.c(system\core\init)
#define SECTION 0x01
#define COMMAND 0x02
#defineOPTION 0x04
关键字 属性
capability, OPTION, 0, 0)
class, OPTION, 0, 0)
class_start, COMMAND, 1, do_class_start)
class_stop, COMMAND, 1, do_class_stop)
console, OPTION, 0, 0)
critical, OPTION, 0, 0)
disabled, OPTION, 0, 0)
domainname, COMMAND,1, do_domainname)
exec, COMMAND, 1, do_exec)
export, COMMAND, 2, do_export)
group, OPTION, 0, 0)
hostname, COMMAND, 1, do_hostname)
ifup, COMMAND, 1, do_ifup)
insmod, COMMAND, 1, do_insmod)
import, COMMAND, 1, do_import)
keycodes, OPTION, 0, 0)
mkdir, COMMAND, 1, do_mkdir)
mount, COMMAND, 3, do_mount)
on, SECTION, 0, 0)
oneshot, OPTION, 0, 0)
onrestart, OPTION, 0, 0)
restart, COMMAND,1, do_restart)
service, SECTION, 0, 0)
setenv, OPTION, 2, 0)
setkey, COMMAND, 0, do_setkey)
setprop, COMMAND, 2,do_setprop)
setrlimit, COMMAND, 3, do_setrlimit)
socket, OPTION, 0, 0)
start, COMMAND, 1, do_start)
stop, COMMAND, 1, do_stop)
trigger, COMMAND, 1, do_trigger)
symlink, COMMAND, 1, do_symlink)
sysclktz, COMMAND, 1, do_sysclktz)
user, OPTION, 0, 0)
write, COMMAND, 2, do_write)
chown, COMMAND, 2, do_chown)
chmod, COMMAND, 2, do_chmod)
loglevel, COMMAND, 1, do_loglevel)
device, COMMAND, 4, do_device)
parse_new_section()中再分别对 service 或者 on 关键字开头的内容进行解析。
...
case K_service:
state->context = parse_service(state, nargs, args);
if(state->context) {
state->parse_line =parse_line_service;
return;
}
break;
case K_on:
state->context =parse_action(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_action;
return;
}
break;
}
...
对 on 关键字开头的内容进行解析
staticvoid *parse_action(struct parse_state *state, int nargs, char **args)
{
...
act = calloc(1, sizeof(*act));
act->name =args[1];
list_init(&act->commands);
list_add_tail(&action_list, &act->alist);
...
}
对service 关键字开头的内容进行解析
static void *parse_service(struct parse_state*state, int nargs, char **args)
{
struct service *svc;
if (nargs < 3) {
parse_error(state, "services must have aname and a program\n");
return 0;
}
if(!valid_name(args[1])) {
parse_error(state, "invalid servicename '%s'\n", args[1]);
return 0;
}
//如果服务已经存在service_list列表中将会被忽略
svc =service_find_by_name(args[1]);
if (svc) {
parse_error(state, "ignored duplicate definition of service '%s'\n",args[1]);
return 0;
}
nargs -= 2;
svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
if (!svc){
parse_error(state, "out of memory\n");
return0;
}
svc->name = args[1];
svc->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);
//添加该服务到 service_list列表
list_add_tail(&service_list, &svc->slist);
return svc;
}
服务的表现形式:
service [ ]*
下面是曾经用过的几种开发板的命令行参数:
S3C2410 启动参数:
noinitrdroot=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs ip=192.168.2.188:192.168.2.56:192.168.2.56:255.255.255.0::eth0:onconsole=ttySAC0
S3C2440 启动参数:
setenv bootargs console=ttySAC0root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfsip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0::eth0:onmem=64M init=/init
marvell 310 启动参数:
boot root=/dev/nfsnfsroot=192.168.2.56:/nfsroot/rootfs,rsize=1024,wsize=1024ip=192.168.2.176:192.168.2.201:192.168.2.201:255.255.255.0::eth0:-On console=ttyS2,115200 mem=64M init=/init
init的源代码在文件:./system/core/init/init.c 中,init会一步步完成下面的任务:
1.初始化log系统
2.解析/init.rc和/init.%hardware%.rc文件
3. 执行 early-init action in the two filesparsed in step 2.
4. 设备初始化,例如:在 /dev 下面创建所有设备节点,下载 firmwares.
5. 初始化属性服务器,Actually the property system is working as ashare memory. Logically it looks like a registry under Windows system.
6.执行 init action in the two files parsed in step 2.
7. 开启 属性服务。
8.执行 early-boot and boot actions in the two files parsed in step 2.
9.执行 Execute property action in the two files parsed in step 2.
10.进入一个无限循环 to wait for device/property set/child process exit events.例如,如果SD卡被插入,init会收到一个设备插入事件,它会为这个设备创建节点。系统中比较重要的进程都是由init来fork的,所以如果他们他谁崩溃了,那么init 将会收到一个 SIGCHLD 信号,把这个信号转化为子进程退出事件, 所以在loop中,init 会操作进程退出事件并且执行*.rc 文件中定义的命令。
例如,在init.rc中,因为有:
service zygote/system/bin/app_process -Xzygote /system/bin --zygote--start-system-server
socket zygote stream 666
onrestartwrite /sys/android_power/request_state wake
onrestart write/sys/power/state on
所以,如果zygote因为启动某些服务导致异常退出后,init将会重新去启动它。
intmain(int argc, char **argv)
{
...
//需要在后面的程序中看打印信息的话,需要屏蔽open_devnull_stdio()函数
open_devnull_stdio();
...
//初始化log系统
log_init();
//解析/init.rc和/init.%hardware%.rc文件
parse_config_file("/init.rc");
...
snprintf(tmp,sizeof(tmp), "/init.%s.rc", hardware);
parse_config_file(tmp);
...
//执行 early-init action in the two files parsed in step 2.
action_for_each_trigger("early-init", action_add_queue_tail);
drain_action_queue();
...
/* execute all the boot actionsto get us started */
/* 执行 init action in the two files parsed instep 2 */
action_for_each_trigger("init",action_add_queue_tail);
drain_action_queue();
...
/* 执行 early-boot and boot actions in the two files parsed in step 2 */
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 oncurrent state of the properties */
queue_all_property_triggers();
drain_action_queue();
/* enable property triggers */
property_triggers_enabled = 1;
...
for(;;) {
int nr, timeout = -1;
...
drain_action_queue();
restart_processes();
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if(timeout < 0)
timeout = 0;
}
...
nr = poll(ufds, 3, timeout);
if (nr <= 0)
continue;
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);
if (ufds[1].revents ==POLLIN)
{
handle_property_set_fd(property_set_fd);
}
}
return 0;
}
2.解析init.rc脚本
init.rc脚本的具体语法可以参考下面文档
http://www.kandroid.org/android_pdk/bring_up.html
名词解释:
Android初始化語言由四大类声明组成:行为类(Actions),命令类(Commands),服务类(Services),选项类(Options).
初始化语言以行为单位,由以空格间隔的语言符号組成。C风格的反斜杠转义符可以用来插入空白到语言符号。双引号也可以用来防止文本被空格分成多个语言符号。当反斜杠在行末时,作为换行符。
* 以#开始(前面允许空格)的行为注释。
*Actions和Services隐含声明一个新的段落。所有该段落下Commands或Options的声明属于该段落。第一段落前的Commands或Options被忽略。
* Actions和Services拥有唯一的命名。在他们之后声明相同命名的类将被当作错误并忽略。
Actions是一系列命令的命名。Actions拥有一个触发器(trigger)用来決定action何時执行。当一个action在符合触发条件被执行时,如果它还没被加入到待执行队列中的话,則加入到队列最后。
队列中的action依次执行,action中的命令也依次执行。Init在执行命令的中间处理其他活动(设备创建/销毁,property 设置,进程重启)。
Actions的表现形式:
on
重要的数据结构
两个列表,一个队列。
staticlist_declare(service_list);
static list_declare(action_list);
staticlist_declare(action_queue);
*.rc 脚本中所有 service关键字定义的服务将会添加到service_list 列表中。
*.rc 脚本中所有 on 关键开头的项将会被会添加到 action_list 列表中。
每个action列表项都有一个列表,此列表用来保存该段落下的 Commands
脚本解析过程:
parse_config_file("/init.rc")
intparse_config_file(const char *fn)
{
char *data;
data =read_file(fn, 0);
if (!data) return -1;
parse_config(fn, data);
DUMP();
return 0;
}
staticvoid parse_config(const char *fn, char *s)
{
...
caseT_NEWLINE:
if (nargs) {
int kw =lookup_keyword(args[0]);
if (kw_is(kw, SECTION)) {
state.parse_line(&state, 0, 0);
parse_new_section(&state, kw, nargs, args);
} else {
state.parse_line(&state, nargs, args);
}
nargs = 0;
}
...
}
parse_config会逐行对脚本进行解析,如果关键字类型为 SECTION ,那么将会执行 parse_new_section()
类型为 SECTION 的关键字有: on 和sevice
关键字类型定义在 Parser.c (system\core\init) 文件中
Parser.c(system\core\init)
#define SECTION 0x01
#define COMMAND 0x02
#defineOPTION 0x04
关键字 属性
capability, OPTION, 0, 0)
class, OPTION, 0, 0)
class_start, COMMAND, 1, do_class_start)
class_stop, COMMAND, 1, do_class_stop)
console, OPTION, 0, 0)
critical, OPTION, 0, 0)
disabled, OPTION, 0, 0)
domainname, COMMAND,1, do_domainname)
exec, COMMAND, 1, do_exec)
export, COMMAND, 2, do_export)
group, OPTION, 0, 0)
hostname, COMMAND, 1, do_hostname)
ifup, COMMAND, 1, do_ifup)
insmod, COMMAND, 1, do_insmod)
import, COMMAND, 1, do_import)
keycodes, OPTION, 0, 0)
mkdir, COMMAND, 1, do_mkdir)
mount, COMMAND, 3, do_mount)
on, SECTION, 0, 0)
oneshot, OPTION, 0, 0)
onrestart, OPTION, 0, 0)
restart, COMMAND,1, do_restart)
service, SECTION, 0, 0)
setenv, OPTION, 2, 0)
setkey, COMMAND, 0, do_setkey)
setprop, COMMAND, 2,do_setprop)
setrlimit, COMMAND, 3, do_setrlimit)
socket, OPTION, 0, 0)
start, COMMAND, 1, do_start)
stop, COMMAND, 1, do_stop)
trigger, COMMAND, 1, do_trigger)
symlink, COMMAND, 1, do_symlink)
sysclktz, COMMAND, 1, do_sysclktz)
user, OPTION, 0, 0)
write, COMMAND, 2, do_write)
chown, COMMAND, 2, do_chown)
chmod, COMMAND, 2, do_chmod)
loglevel, COMMAND, 1, do_loglevel)
device, COMMAND, 4, do_device)
parse_new_section()中再分别对 service 或者 on 关键字开头的内容进行解析。
...
case K_service:
state->context = parse_service(state, nargs, args);
if(state->context) {
state->parse_line =parse_line_service;
return;
}
break;
case K_on:
state->context =parse_action(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_action;
return;
}
break;
}
...
对 on 关键字开头的内容进行解析
staticvoid *parse_action(struct parse_state *state, int nargs, char **args)
{
...
act = calloc(1, sizeof(*act));
act->name =args[1];
list_init(&act->commands);
list_add_tail(&action_list, &act->alist);
...
}
对service 关键字开头的内容进行解析
static void *parse_service(struct parse_state*state, int nargs, char **args)
{
struct service *svc;
if (nargs < 3) {
parse_error(state, "services must have aname and a program\n");
return 0;
}
if(!valid_name(args[1])) {
parse_error(state, "invalid servicename '%s'\n", args[1]);
return 0;
}
//如果服务已经存在service_list列表中将会被忽略
svc =service_find_by_name(args[1]);
if (svc) {
parse_error(state, "ignored duplicate definition of service '%s'\n",args[1]);
return 0;
}
nargs -= 2;
svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
if (!svc){
parse_error(state, "out of memory\n");
return0;
}
svc->name = args[1];
svc->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);
//添加该服务到 service_list列表
list_add_tail(&service_list, &svc->slist);
return svc;
}
服务的表现形式:
service
BIOS启动过程分析
启动过程~!
linux不能启动,内核恐慌,init被意外杀死
启动天之痕出现roledatabase init failed
paranoid android中文歌词
综合国力分析过程
数学题:要分析过程
radiohead 的 Paranoid Android 中文翻译
10、有些计算机在启动过程中,会无缘无故的不断地自动重新启动,试分析其产生的原因
windows启动的过程
xp启动过程?
2000启动过程
Windows启动的过程?
windows启动过程
启动过程中的死机
在启动LINUX9.0的时候提示kernel panic:attempted to kill init!如何解决?
PowerQuest Magic启动时出现“Init failed:Error 100. Partition table is bad”
linux启动时,提示:Atempt to kill init! Keyboard: unknown scancode! 怎么回事啊?
Windows Xp 启动时出现“Init失败”信息,是什么问题?怎样解决?
求 综合国力的分析过程?
急:分析linux引导过程!!!
急:分析linux引导过程!!! !!
难题,请写明分析过程
请简要写出分析过程