Androidinit启动过程分析1.docx
- 文档编号:11357863
- 上传时间:2023-02-28
- 格式:DOCX
- 页数:24
- 大小:23.89KB
Androidinit启动过程分析1.docx
《Androidinit启动过程分析1.docx》由会员分享,可在线阅读,更多相关《Androidinit启动过程分析1.docx(24页珍藏版)》请在冰豆网上搜索。
Androidinit启动过程分析1
Android_init_启动过程分析1
分析android的启动过程,从内核之上,我们首先应该从文件系统的init开始,因为init是内核进入文件系统后第一个运行的程序,通常我们可以在linux的命令行中指定内核第一个调用谁,如果没指定那么内核将会到/sbin/,/bin/等目录下查找默认的init,如果没有找到那么就报告出错。
下面是曾经用过的几种开发板的命令行参数:
S3C2410启动参数:
noinitrdroot=/dev/nfsnfsroot=192.168.2.56:
/nfsroot/rootfsip=192.168.2.188:
192.168.2.56:
192.168.2.56:
255.255.255.0:
:
eth0:
onconsole=ttySAC0
S3C2440启动参数:
setenvbootargsconsole=ttySAC0root=/dev/nfsnfsroot=192.168.2.56:
/nfsroot/rootfsip=192.168.2.175:
192.168.2.56:
192.168.2.201:
255.255.255.0:
:
eth0:
onmem=64Minit=/init
marvell310启动参数:
bootroot=/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:
-Onconsole=ttyS2,115200mem=64Minit=/init
init的源代码在文件:
./system/core/init/init.c中,init会一步步完成下面的任务:
1.初始化log系统
2.解析/init.rc和/init.%hardware%.rc文件
3.执行early-initactioninthetwofilesparsedinstep2.
4.设备初始化,例如:
在/dev下面创建所有设备节点,下载firmwares.
5.初始化属性服务器,Actuallythepropertysystemisworkingasasharememory.LogicallyitlookslikearegistryunderWindowssystem.
6.执行initactioninthetwofilesparsedinstep2.
7.开启属性服务。
8.执行early-bootandbootactionsinthetwofilesparsedinstep2.
9.执行Executepropertyactioninthetwofilesparsedinstep2.
10.进入一个无限循环towaitfordevice/propertyset/childprocessexitevents.例如,如果SD卡被插入,init会收到一个设备插入事件,它会为这个设备创建节点。
系统中比较重要的进程都是由init来fork的,所以如果他们他谁崩溃了,那么init将会收到一个SIGCHLD信号,把这个信号转化为子进程退出事件,所以在loop中,init会操作进程退出事件并且执行*.rc文件中定义的命令。
例如,在init.rc中,因为有:
servicezygote/system/bin/app_process-Xzygote/system/bin--zygote--start-system-server
socketzygotestream666
onrestartwrite/sys/android_power/request_statewake
onrestartwrite/sys/power/stateon
所以,如果zygote因为启动某些服务导致异常退出后,init将会重新去启动它。
intmain(intargc,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-initactioninthetwofilesparsedinstep2.
action_for_each_trigger("early-init",action_add_queue_tail);
drain_action_queue();
...
/*executeallthebootactionstogetusstarted*/
/*执行initactioninthetwofilesparsedinstep2*/
action_for_each_trigger("init",action_add_queue_tail);
drain_action_queue();
...
/*执行early-bootandbootactionsinthetwofilesparsedinstep2*/
action_for_each_trigger("early-boot",action_add_queue_tail);
action_for_each_trigger("boot",action_add_queue_tail);
drain_action_queue();
/*runallpropertytriggersbasedoncurrentstateoftheproperties*/
queue_all_property_triggers();
drain_action_queue();
/*enablepropertytriggers*/
property_triggers_enabled=1;
...
for(;;){
intnr,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){
/*wegotaSIGCHLD-reapandrestartasneeded*/
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);
}
}
return0;
}
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);
staticlist_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(constchar*fn)
{
char*data;
data=read_file(fn,0);
if(!
data)return-1;
parse_config(fn,data);
DUMP();
return0;
}
staticvoidparse_config(constchar*fn,char*s)
{
...
caseT_NEWLINE:
if(nargs){
intkw=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)
#defineSECTION0x01
#defineCOMMAND0x02
#defineOPTION0x04
关键字属性
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关键字开头的内容进行解析。
...
caseK_service:
state->context=parse_service(state,nargs,args);
if(state->context){
state->parse_line=parse_line_service;
return;
}
break;
caseK_on:
state->context=parse_action(state,nargs,args);
if(state->context){
state->parse_line=parse_line_action;
return;
}
break;
}
...
对on关键字开头的内容进行解析
staticvoid*parse_action(structparse_state*state,intnargs,char**args)
{
...
act=calloc(1,sizeof(*act));
act->name=args[1];
list_init(&act->commands);
list_add_tail(&action_list,&act->alist);
...
}
对service关键字开头的内容进行解析
staticvoid*parse_service(structparse_state*state,intnargs,char**args)
{
structservice*svc;
if(nargs<3){
parse_error(state,"servicesmusthaveanameandaprogram\n");
return0;
}
if(!
valid_name(args[1])){
parse_error(state,"invalidservicename'%s'\n",args[1]);
return0;
}
//如果服务已经存在service_list列表中将会被忽略
svc=service_find_by_name(args[1]);
if(svc){
parse_error(state,"ignoredduplicatedefinitionofservice'%s'\n",args[1]);
return0;
}
nargs-=2;
svc=calloc(1,sizeof(*svc)+sizeof(char*)*nargs);
if(!
svc){
parse_error(state,"outofmemory\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->mands);
//添加该服务到service_list列表
list_add_tail(&service_list,&svc->slist);
returnsvc;
}
服务的表现形式:
service
...
申请一个service结构体,然后挂接到service_list链表上,name为服务的名称pathname为执行的命令argument
为命令的参数。
之后的option用来控制这个service结构体的属性,parse_line_service会对service关键字后的
内容进行解析并填充到service结构中,当遇到下一个service或者on关键字的时候此service选项解析结束。
例如:
servicezygote/system/bin/app_process-Xzygote/system/bin--zygote--start-system-server
socketzygotestream666
onrestartwrite/sys/android_power/request_statewake
服务名称为:
zygote
启动该服务执行的命令:
/system/bin/app_process
命令的参数:
-Xzygote/system/bin--zygote--start-system-server
socketzygotestream666:
创建一个名为:
/dev/socket/zygote的socket,类型为:
stream
当*.rc文件解析完成以后:
action_list列表项目如下:
oninit
onboot
onproperty:
ro.kernel.qemu=1
onproperty:
persist.service.adb.enable=1
onproperty:
persist.service.adb.enable=0
init.marvell.rc文件
onearly-init
oninit
onearly-boot
onboot
service_list列表中的项有:
serviceconsole
serviceadbd
serviceservicemanager
servicemountd
servicedebuggerd
serviceril-daemon
servicezygote
servicemedia
servicebootsound
servicedbus
servicehcid
servicehfag
servicehsag
serviceinstalld
serviceflash_recovery
状态服务器相关:
在init.c的main函数中启动状态服务器。
property_set_fd=start_property_service();
状态读取函数:
Property_service.c(system\core\init)
constchar*property_get(constchar*name)
Properties.c(system\core\libcutils)
intproperty_get(constchar*key,char*value,constchar*default_value)
状态设置函数:
Property_service.c(system\core\init)
intproperty_set(constchar*name,constchar*value)
Properties.c(system\core\libcutils)
intproperty_set(constchar*key,constchar*value)
在终端模式下我们可以通过执行命令setprop
setprop工具源代码所在文件:
Setprop.c(system\core\toolbox)
Getprop.c(system\core\toolbox):
property_get(argv[1],value,default_value);
Property_service.c(system\core\init)
中定义的状态读取和设置函数仅供init进程调用,
handle_property_set_fd(property_set_fd);
property_set()//
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Androidinit 启动 过程 分析