S20nfs-kernel-server S20samba S20xinetd S30gdm S98usplash S99rc.local 总结: 这样一来,upstart管理的ubuntu启动过程应该就清楚了。梳理一下: 1,内核启动init 2,init找到/etc/event.d/rc-default文件,确定默认的运行级别(X) 3,触发相应的runlevel事件,开始运行/etc/event.d/rcX 4,rcX运行/etc/init.d/rc,传入参数X 5,/etc/init.d/rc脚本进行一系列设置,最后运行相应的/etc/rcX.d/中的脚本 6,/etc/rcX.d/中的脚本按事先设定的优先级依次启动,直至最后给出登录画面(启动X服务器和GDM) 理解了这些,手动配置开机服务的启动与否就很简单了。Ubutnu默认的启动级别是2,不想启动的程序,只要把相应的符号链接从/etc/rc2.d/中删去即可 注意: 想redat ,federa 这些系统,他们用的是sysvinit ,有 /etc/inittab 文件,里面定义了 : id:5:initdefault: si::sysinit:/etc/init.d/rcS init 直接解析 id:5:initdefault 字段,然后执行 /etc/rc5.d/ 下面的脚本 ================ 参考文档: linux教程:upstart 和ubuntu启动过程原理介绍 http://www./jiaocheng/2009-06/12500.htm 6.2 小型嵌入式系统启动流程 小型嵌入式的 init 通常使用busybox中自带的, 6.3 android 系统启动流程 参考文档: init 是内核进入文件系统后第一个运行的程序,我们可以在linux的命令行中进行指定,如果没指定,内核将会到/sbin/, /bin/ 等目录下 查找默认的init,如果没有找到那么就报告出错。 init 源代码分析 init的mian函数在文件:./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 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 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 onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on 所以,如果zygote因为启动某些服务导致异常退出后,init将会重新去启动它。 int main(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 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 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(); /* 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 重要的数据结构 两个列表,一个队列。 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(const 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(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 #define OPTION 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 关键字开头的内容进行解析 static void *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 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 [ ]* ... 申请一个service结构体,然后挂接到service_list链表上,name 为服务的名称 pathname 为执行的命令 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/request_state wake 服务名称为: zygote 启动该服务执行的命令: /system/bin/app_process 命令的参数: -Xzygote /system/bin --zygote --start-system-server socket zygote stream 666: 创建一个名为:/dev/socket/zygote 的 socket ,类型为:stream 当*.rc 文件解析完成以后: action_list 列表项目如下: on init on boot on property:ro.kernel.qemu=1 on property:persist.service.adb.enable=1 on property:persist.service.adb.enable=0 init.marvell.rc 文件 on early-init on init on early-boot on boot service_list 列表中的项有: service console service adbd service servicemanager service mountd service debuggerd service ril-daemon service zygote service media service bootsound service dbus service hcid service hfag service hsag service installd service flash_recovery 设备初始化 early-init 初始化 初始化属性服务器 在init.c 的main函数中启动状态服务器。 property_set_fd = start_property_service(); 状态读取函数: Property_service.c (system\core\init) const char* property_get(const char *name) Properties.c (system\core\libcutils) int property_get(const char *key, char *value, const char *default_value) 状态设置函数: Property_service.c (system\core\init) int property_set(const char *name, const char *value) Properties.c (system\core\libcutils) int property_set(const char *key, const char *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() //Property_service.c (system\core\init) property_changed(name, value) //Init.c (system\core\init) queue_property_triggers(name, value) drain_action_queue() 只要属性一改变就会被触发,然后执行相应的命令: 例如: 在init.rc 文件中有 on property:persist.service.adb.enable=1 start adbd on property:persist.service.adb.enable=0 stop adbd 所以如果在终端下输入: setprop property:persist.service.adb.enable 1或者0 那么将会开启或者关闭adbd 程序。 执行action_list 中的命令: 从action_list 中取出 act->name 为 early-init 的列表项,再调用 action_add_queue_tail(act)将其插入到 队列 action_queue 尾部。drain_action_queue() 从action_list队列中取出队列项 ,然后执行act->commands 列表中的所有命令。 所以从 ./system/core/init/init.c mian()函数的程序片段: action_for_each_trigger("early-init", action_add_queue_tail); drain_action_queue(); action_for_each_trigger("init", action_add_queue_tail); drain_action_queue(); 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(); 可以看出,在解析完init.rc init.marvell.rc 文件后,action 命令执行顺序为: 执行act->name 为 early-init,act->commands列表中的所有命令 执行act->name 为 init, act->commands列表中的所有命令 执行act->name 为 early-boot,act->commands列表中的所有命令 执行act->name 为 boot, act->commands列表中的所有命令 关键的几个命令: class_start default 启动所有service 关键字定义的服务。 class_start 在act->name为boot的 act->commands列表中,所以当 class_start 被触发后,实际 上调用的是函数 do_class_start() int do_class_start(int nargs, char **args) |
|
来自: shaobin0604@1... > 《Android》