深入理解Android(03)——深入理解init初始化函数
来源:互联网 发布:mac 命令行安装mysql 编辑:程序博客网 时间:2024/06/05 23:40
1、概述
init是一个进程,确切地说,它是Linux系统中用户空间地第一个进程。由于Android是基于Linux内核地,所以init也是Android系统中用户空间地第一个进程,它的进程号是1。
init进程有几个重要地职责:
1)init进程负责创建系统中的几个关键进程。
2)Android系统有很多属性,init提供了一个property service(属性服务)来管理他们。
2、init分析
init进程的入口函数是main,代码如下:
int main(int argc, char **argv){ int fd_count = 0; struct pollfd ufds[4]; char *tmpdev; char* debuggable; char tmp[32]; int property_set_fd_init = 0; int signal_fd_init = 0; int keychord_fd_init = 0; if (!strcmp(basename(argv[0]), "ueventd")) return ueventd_main(argc, argv); /* clear the umask */ umask(0); // 创建一些文件夹 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. */ open_devnull_stdio(); log_init(); INFO("reading config file\n"); init_parse_config_file("/init.rc"); /* pull the kernel commandline and ramdisk properties file in */ import_kernel_cmdline(0); get_hardware_name(hardware, &revision); snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); init_parse_config_file(tmp); action_for_each_trigger("early-init", action_add_queue_tail); queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done"); queue_builtin_action(property_init_action, "property_init"); queue_builtin_action(keychord_init_action, "keychord_init"); queue_builtin_action(console_init_action, "console_init"); queue_builtin_action(set_init_properties_action, "set_init_properties"); /* execute all the boot actions to get us started */ action_for_each_trigger("init", action_add_queue_tail); action_for_each_trigger("early-fs", action_add_queue_tail); action_for_each_trigger("fs", action_add_queue_tail); action_for_each_trigger("post-fs", action_add_queue_tail); queue_builtin_action(property_service_init_action, "property_service_init"); queue_builtin_action(signal_init_action, "signal_init"); queue_builtin_action(check_startup_action, "check_startup"); /* 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); /* run all property triggers based on current state of the properties */ queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");//初始化的操作//......... return 0;}
init的代码还是很长的,主要是用来做初始化操作,init的工作流程精简之后,大概是如下四点:
1)解析两个配置文件,重点是init.rc文件解析
2)执行各个阶段的动作,创建zygote的工作就是在这里完成的
3)调用property_init初始化属性相关的资源,并且通过property_start_service启动属性服务
4)init进入一个无限循环,并且等待一些事情的发生。重点是init如何处理来自socket和来自属性服务器的相关事情。
3、解析配置文件
3.1 init的配置文件
init中会解析两个配置文件,其中一个是系统配置文件init.rc,另外一个是与硬件平台相关的配置文件。虽然解析的是不同的配置文件,但是调用的是同一个函数,代码如下:
int init_parse_config_file(const char *fn){ char *data; data = read_file(fn, 0); //读取配置文件,这里是init.rc if (!data) return -1; parse_config(fn, data); //调用方法解析文件 DUMP(); return 0;}
读取完配置文件之后,调用方法解析,函数代码如下所示:
static void parse_config(const char *fn, char *s){ struct parse_state state; char *args[INIT_PARSER_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 < INIT_PARSER_MAXARGS) { args[nargs++] = state.text; } break; } }}
这里的SECTION是一个关键字,自定义的关键字,都存放在keywords.h中。
3.2 解析init.rc
init.rc的内容如下所示:
system/core/rootdir/init.rc
#on关键字表示是一个section,这里表示init,下面的内容全部是这个section,直到下一个on关键字结束on init# setup the global environment export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin export LD_LIBRARY_PATH /vendor/lib:/system/lib export ANDROID_BOOTLOGO 1 export ANDROID_ROOT /system export ANDROID_ASSETS /system/app export ANDROID_DATA /data export EXTERNAL_STORAGE /mnt/sdcard export ASEC_MOUNTPOINT /mnt/asec export LOOP_MOUNTPOINT /mnt/obb export BOOTCLASSPATH......# 省略部分
#开始boot这个section
on boot# basic network init ifup lo hostname localhost domainname localdomain
#service关键字也表示是一个section,这里表示zygote
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 onrestart restart media onrestart restart netd
service media /system/bin/mediaserver user media group system audio camera graphics inet net_bt net_bt_admin net_raw ioprio rt 4
4、解析service
zygote对应的service section内容是:
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 onrestart restart media onrestart restart netd
解析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: 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; } state->parse_line = parse_line_no_op;}
5、init控制service
5.1 启动service
init.rc中有这样一句话:
class_start defaultclass_start是一个COMMAND,对应的函数为do_class_start,它位于boot section中。// 将boot section节中的command加入到执行队列中 action_for_each_trigger("early-boot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail);
// 执行队列里的命令,class是一个COMMAND,所以它对应的do_class_start会被执行
queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");
这里是do_class_start方法的代码:
int do_class_start(int nargs, char **args){ /* Starting a class does not start services * which are explicitly disabled. They must * be started individually. */ service_for_each_class(args[1], service_start_if_not_disabled); return 0;}
- 深入理解Android(03)——深入理解init初始化函数
- 深入理解Android 中的init
- 深入理解init
- 深入理解init
- android启动--深入理解init进程
- 《深入理解Android》导读之init
- 《深入理解Android》导读之init
- android启动--深入理解init进程
- 《深入理解Android》导读之init
- 《深入理解Android》导读之init
- csdn 深入理解Android》导读之init
- 深入理解Android之init与zygote
- android启动--深入理解init进程
- 深入理解Android—WebView
- 深入理解Android(04)——深入理解属性服务
- 深入理解Android(05)——深入理解zygote
- 深入理解Android(07)——深入理解SystemServer
- java初始化深入理解
- 【设计模式】对六大原则的宏观把控和微观细化
- OCR与VOTEDISK的备份恢复
- springmvc中注册时间类型转换器接受Date类型
- 底子薄之12.01
- Deep Learning(深度学习) 学习笔记(一)
- 深入理解Android(03)——深入理解init初始化函数
- xcode6创建的百度地图项目启动后输出日志”manager start failed!“的解决方案
- 浅析404页面存在的意义和设计技巧
- codeforces New Year Santa Network
- xml_schema
- (转载)linux命令之三十一diff 命令
- 从机器学习谈起
- 百度吴恩达:图像和音视频搜索是人工智能新方向
- 【BZOJ】【P2073】【POI2004】【PRZ】【题解】【状压DP+枚举子集】