1、Androidinit启动过程分析1Android_init_启动过程分析1分析android的启动过程,从内核之上,我们首先应该从文件系统的init开始,因为 init 是内核进入文件系统后第一个运行的程序,通常我们可以在linux的命令行中指定内核第一个调用谁,如果没指定那么内核将会到/sbin/, /bin/ 等目录下查找默认的init,如果没有找到那么就报告出错。下面是曾经用过的几种开发板的命令行参数:S3C2410 启动参数:noinitrd root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs ip=192.168.2.188:192
2、.168.2.56:192.168.2.56:255.255.255.0:eth0:on console=ttySAC0S3C2440 启动参数:setenv bootargs console=ttySAC0 root=/dev/nfs nfsroot=192.168.2.56:/nfsroot/rootfs ip=192.168.2.175:192.168.2.56:192.168.2.201:255.255.255.0:eth0:on mem=64M init=/init marvell 310 启动参数:boot root=/dev/nfs nfsroot=192.168.2.56:/n
3、fsroot/rootfs,rsize=1024,wsize=1024 ip=192.168.2.176:192.168.2.201:192.168.2.201:255.255.255.0:eth0:-On console=ttyS2,115200 mem=64M init=/initinit的源代码在文件:./system/core/init/init.c 中,init会一步步完成下面的任务:1.初始化log系统 2.解析/init.rc和/init.%hardware%.rc文件 3. 执行 early-init action in the two files parsed in step
4、 2. 4. 设备初始化,例如:在 /dev 下面创建所有设备节点,下载 firmwares. 5. 初始化属性服务器,Actually the property system is working as a share 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 i
5、n 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 文件
6、中定义的命令。例如,在init.rc中,因为有:service zygote /system/bin/app_process -Xzygote /system/bin -zygote -start-system-server socket zygote stream 666 onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on所以,如果zygote因为启动某些服务导致异常退出后,init将会重新去启动它。int main(int argc, char *argv) .
7、/需要在后面的程序中看打印信息的话,需要屏蔽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
8、_each_trigger(early-init, action_add_queue_tail); drain_action_queue(); . /* execute all the boot actions to get us started */ /* 执行 init action in the two files parsed in step 2 */ action_for_each_trigger(init, action_add_queue_tail); drain_action_queue(); . /* 执行 early-boot and boot actions in the
9、 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 on current state of the properties */ queue_all_property_triggers(); drain_action_queue(); /* enab
10、le 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
11、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 (ufds0.revents = POLLIN) handle_device_fd(device_fd); if (ufds1.revents = POLLIN) handle_property_set_fd(property_set_fd); return 0;2.解析init.r
12、c脚本init.rc 脚本的具体语法可以参考下面文档http:/www.kandroid.org/android_pdk/bring_up.html名词解释:Android初始化語言由四大类声明组成:行为类(Actions),命令类(Commands),服务类(Services),选项类(Options).初始化语言以行为单位,由以空格间隔的语言符号組成。C风格的反斜杠转义符可以用来插入空白到语言符号。双引号也可以用来防止文本被空格分成多个语言符号。当反斜杠在行末时,作为换行符。* 以#开始(前面允许空格)的行为注释。* Actions和Services隐含声明一个新的段落。所有该段落下Com
13、mands或Options的声明属于该段落。第一段落前的Commands或Options被忽略。* Actions和Services拥有唯一的命名。在他们之后声明相同命名的类将被当作错误并忽略。Actions是一系列命令的命名。Actions拥有一个触发器(trigger)用来決定action何時执行。当一个action在符合触发条件被执行时,如果它还没被加入到待执行队列中的话,則加入到队列最后。队列中的action依次执行,action中的命令也依次执行。Init在执行命令的中间处理其他活动(设备创建/销毁,property 设置,进程重启)。 Actions的表现形式:on 重要的数据结构
14、两个列表,一个队列。static list_declare(service_list);static list_declare(action_list);static list_declare(action_queue);*.rc 脚本中所有 service关键字定义的服务将会添加到 service_list 列表中。*.rc 脚本中所有 on 关键开头的项将会被会添加到 action_list 列表中。每个action列表项都有一个列表,此列表用来保存该段落下的 Commands脚本解析过程:parse_config_file(/init.rc)int parse_config_file(c
15、onst char *fn) char *data; data = read_file(fn, 0); if (!data) return -1; parse_config(fn, data); DUMP(); return 0;static void parse_config(const char *fn, char *s) . case T_NEWLINE: if (nargs) int kw = lookup_keyword(args0); if (kw_is(kw, SECTION) state.parse_line(&state, 0, 0); parse_new_section(&
16、state, kw, nargs, args); else state.parse_line(&state, nargs, args); nargs = 0; .parse_config会逐行对脚本进行解析,如果关键字类型为 SECTION ,那么将会执行 parse_new_section()类型为 SECTION 的关键字有: on 和 sevice关键字类型定义在 Parser.c (systemcoreinit) 文件中Parser.c (systemcoreinit)#define SECTION 0x01#define COMMAND 0x02#define OPTION 0x04
17、关键字 属性 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, O
18、PTION, 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_r
19、estart)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, CO
20、MMAND, 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, nar
21、gs, 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 关键字开头的内容进行解析static void *parse_action(struct parse_state *state, int nargs, c
22、har *args) . act = calloc(1, sizeof(*act); act-name = args1; 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 name = args1; svc-classname = default; me
23、mcpy(svc-args, args + 2, sizeof(char*) * nargs); svc-argsnargs = 0; svc-nargs = nargs; svc-onrestart.name = onrestart; list_init(&svc-mands); /添加该服务到 service_list 列表 list_add_tail(&service_list, &svc-slist); return svc;服务的表现形式:service *.申请一个service结构体,然后挂接到service_list链表上,name 为服务的名称 pathname 为执行的命令
24、 argument为命令的参数。之后的 option 用来控制这个service结构体的属性,parse_line_service 会对 service关键字后的内容进行解析并填充到 service 结构中 ,当遇到下一个service或者on关键字的时候此service选项解析结束。例如:service zygote /system/bin/app_process -Xzygote /system/bin -zygote -start-system-server socket zygote stream 666 onrestart write /sys/android_power/reque
25、st_state wake服务名称为: zygote启动该服务执行的命令: /system/bin/app_process命令的参数: -Xzygote /system/bin -zygote -start-system-serversocket zygote stream 666: 创建一个名为:/dev/socket/zygote 的 socket ,类型为:stream当*.rc 文件解析完成以后:action_list 列表项目如下:on initon booton property:ro.kernel.qemu=1on property:persist.service.adb.ena
26、ble=1on property:persist.service.adb.enable=0init.marvell.rc 文件on early-initon initon early-booton bootservice_list 列表中的项有:service consoleservice adbdservice servicemanagerservice mountdservice debuggerdservice ril-daemonservice zygoteservice mediaservice bootsoundservice dbusservice hcidservice hfa
27、gservice hsagservice installdservice flash_recovery状态服务器相关:在init.c 的main函数中启动状态服务器。property_set_fd = start_property_service();状态读取函数:Property_service.c (systemcoreinit)const char* property_get(const char *name)Properties.c (systemcorelibcutils)int property_get(const char *key, char *value, const cha
28、r *default_value)状态设置函数:Property_service.c (systemcoreinit)int property_set(const char *name, const char *value)Properties.c (systemcorelibcutils)int property_set(const char *key, const char *value)在终端模式下我们可以通过执行命令 setprop setprop 工具源代码所在文件: Setprop.c (systemcoretoolbox)Getprop.c (systemcoretoolbox): property_get(argv1, value, default_value);Property_service.c (systemcoreinit)中定义的状态读取和设置函数仅供init进程调用,handle_property_set_fd(property_set_fd); property_set() /
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1