Android init进程解析
来源:互联网 发布:js代码注解 编辑:程序博客网 时间:2024/04/29 22:15
使用的版本:Android 2.3
Linux中的所有进程都是由init进程创建并运行的,Android中也存在init进程,首先Android内核启动,然后在用户空间中启动init进程,再依次启动系统运行所需的其他进程。
init进程是守护进程,用来监视其他进程,当某个进程终结后,变成僵尸进程(Zombie process),僵尸进程会占据进程列表中的位置,这时init进程就负责回收僵尸进程,Android平台中,Init进程除了负责回收僵尸进程外,还提供几种额外的功能。
·init进程运行过程
start_kernet() => init_post() =>run_initprocess() =>运行init进程
·init进程四大功能
1.分析及运行init.rc文件
2.生成设备驱动节点
3.处理子进程终止
4.属性服务
1.分析及运行init.rc文件
init.rc文件在system/core/rootdir目录下。
init.rc启动脚本是Android启动时,用来设置系统环境的脚本文件。action list与service list相关的内容是由init进程根据init.rc文件生成的。下面是init.rc文件的大致结构。
on early-init start ueventdon initsysclktz 0loglevel 3# 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
......
on boot# basic network init ifup lo hostname localhost domainname localdomain
......
<pre name="code" class="plain">on property:ro.secure=0 start console# adbd is controlled by the persist.service.adb.enable system propertyservice adbd /sbin/adbd disabled# adbd on at boot in emulatoron property:ro.kernel.qemu=1 start adbdon property:persist.service.adb.enable=1 start adbdon property:persist.service.adb.enable=0 stop adbd
......
service servicemanager /system/bin/servicemanager user system critical onrestart restart zygote onrestart restart mediaservice vold /system/bin/vold socket vold stream 0660 root mount ioprio be 2service netd /system/bin/netd socket netd stream 0660 root systemservice debuggerd /system/bin/debuggerdservice ril-daemon /system/bin/rild socket rild stream 660 root radio socket rild-debug stream 660 radio system user root group radio cache inet misc audio sdcard_rw
......init.rc文件分为两部分,一部分是以"on"关键字开头的动作列表(Action list),一部分是以"service"关键字开头的服务列表(Service list)。
1.1 动作列表
动作列表有三个段落,on init ,on boot ,on property段落。on init段落主要设置环境变量,生成系统运行所需的文件或目录,修改相应的权限,并挂载与系统运行相关的目录。环境变量设置主要设置运行根文件系统命令的目录以及程序编译时需要的库目录,根文件的挂载主要是/system和/data两个目录,挂载完毕后Android的根文件系统就准备好了。on boot段落主要用于设置应用程序终止条件,应用程序驱动目录及文件权限等。on property段落中,记录属性值改变时执行的命令,在默认的init.rc初始化脚本中,还记录adbd服务启动、终止的条件。Android平台中的共享属性存储区域中的值,只能通过通知init进程,由init进程负责改变,增强安全性。
1.2服务列表
service列表用来记录init进程启动的进程。由init进程启动的子进程或者是一次性程序,或者是运行在后台的与应用程序、系统管理相关的Daemon进程。
1.3 init.rc文件分析函数
system/core/init目录下的init_parser.c文件中有一个名为init_parse_config_file()函数
int init_parse_config_file(const char *fn){ char *data; data = read_file(fn, 0); if (!data) return -1; parse_config(fn, data); DUMP(); return 0;}fn是指定待分析文件的路径,read_file函数读取文件,并作为字符串保存在data中,再调用parse_config函数分析读入的字符串。
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]); 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; } break; case T_TEXT: if (nargs < INIT_PARSER_MAXARGS) { args[nargs++] = state.text; } break; } }}next_token()函数以行为单位分割传递过来的字符串,然后调用lookup_keyword()函数。
lookup_keyword()函数用于返回init.rc脚本中每行首个单词在keyword_list结构体数组中的数组编号。Keyword_list结构体数组由KEYWORD列表构成
#define __MAKE_KEYWORD_ENUM__#define KEYWORD(symbol, flags, nargs, func) K_##symbol,enum { K_UNKNOWN,#endif KEYWORD(capability, OPTION, 0, 0) KEYWORD(chdir, COMMAND, 1, do_chdir) KEYWORD(chroot, COMMAND, 1, do_chroot) KEYWORD(class, OPTION, 0, 0) KEYWORD(class_start, COMMAND, 1, do_class_start) KEYWORD(class_stop, COMMAND, 1, do_class_stop) KEYWORD(console, OPTION, 0, 0) KEYWORD(critical, OPTION, 0, 0) KEYWORD(disabled, OPTION, 0, 0) KEYWORD(domainname, COMMAND, 1, do_domainname) KEYWORD(exec, COMMAND, 1, do_exec) KEYWORD(export, COMMAND, 2, do_export) KEYWORD(group, OPTION, 0, 0) KEYWORD(hostname, COMMAND, 1, do_hostname) KEYWORD(ifup, COMMAND, 1, do_ifup) KEYWORD(insmod, COMMAND, 1, do_insmod) KEYWORD(import, COMMAND, 1, do_import) KEYWORD(keycodes, OPTION, 0, 0) KEYWORD(mkdir, COMMAND, 1, do_mkdir) KEYWORD(mount, COMMAND, 3, do_mount) KEYWORD(on, SECTION, 0, 0) KEYWORD(oneshot, OPTION, 0, 0) KEYWORD(onrestart, OPTION, 0, 0) KEYWORD(restart, COMMAND, 1, do_restart) KEYWORD(service, SECTION, 0, 0) KEYWORD(setenv, OPTION, 2, 0) KEYWORD(setkey, COMMAND, 0, do_setkey) KEYWORD(setprop, COMMAND, 2, do_setprop) KEYWORD(setrlimit, COMMAND, 3, do_setrlimit) KEYWORD(socket, OPTION, 0, 0) KEYWORD(start, COMMAND, 1, do_start) KEYWORD(stop, COMMAND, 1, do_stop) KEYWORD(trigger, COMMAND, 1, do_trigger) KEYWORD(symlink, COMMAND, 1, do_symlink) KEYWORD(sysclktz, COMMAND, 1, do_sysclktz) KEYWORD(user, OPTION, 0, 0) KEYWORD(wait, COMMAND, 1, do_wait) KEYWORD(write, COMMAND, 2, do_write) KEYWORD(copy, COMMAND, 2, do_copy) KEYWORD(chown, COMMAND, 2, do_chown) KEYWORD(chmod, COMMAND, 2, do_chmod) KEYWORD(loglevel, COMMAND, 1, do_loglevel) KEYWORD(ioprio, OPTION, 0, 0)KEYWORD宏定义在platform/system/core/init目录下的keyword.h文件中,用来把关键字和相关函数对应起来,如stop关键字与do_stop()函数相对应。用户如果想向init.rc中添加新命令,必须在KEYWORD列表中定义新命令,并定义与之对应的函数。
1.4 动作列表与服务列表的运行
关键的函数:queue_buildin_action();
void queue_builtin_action(int (*func)(int nargs, char **args), char *name){ struct action *act; struct command *cmd; act = calloc(1, sizeof(*act)); act->name = name; list_init(&act->commands); cmd = calloc(1, sizeof(*cmd)); cmd->func = func; cmd->args[0] = name; list_add_tail(&act->commands, &cmd->clist); list_add_tail(&action_list, &act->alist); action_add_queue_tail(act);}
该函数用来运行动作列表,位于system/core/init目录下的init_parser.c文件中。
do_class_start()和service_start_if_not_disabled()函数
static void service_start_if_not_disabled(struct service *svc){ if (!(svc->flags & SVC_DISABLED)) { service_start(svc, NULL); }}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;}
这两个函数用来运行服务列表,位于system/core/init目录下的builtins.c文件中。
2.创建设备节点文件
与linux相同,Android中的应用程序通过设备驱动来访问硬件设备。在Linux中,提供mknod实用程序来创建设备节点文件,但出于安全考虑,Android未提供类似mknod的实用程序。
在linux中,运行所需要的设备节点文件都被事先定义在"/dev"目录下,应用程序通过事先定义好的设备节点文件就能访问设备驱动程序。在Android根文件系统的映像中不存在"/dev"目录,需要有一个进程(init进程)创建设备节点文件。
init进程通过两种方式创建设备节点文件,第一种是连接已定义的设备的方法,成为“冷插拔”,第二种方法是在系统运行状态下连接设备,称为“热插拔”。
udev实用程序作为守护进程运行,当设备驱动被加载时,它会掌握主设备号、次设备号,以及设备类型,然后在"/dev"目录下自动创建设备节点文件。首先由驱动程序初始化函数,注册驱动信息到"/sys"目录下,发生uevent,被udev守护进程监听到。udev守护进程会比较uevent信息与注册在"/sys"中的设备信息,然后在"/dev"中创建设备节点文件。uevent是内核向用户空间进程传递信息的信号系统,在添加或删除设备时,内核使用uevent将设备信息传递到用户空间。
Linux系统中,在udev守护进程运行前,通过提供与加载的设备驱动程序冷插拔机制,来解决设备节点文件没被创建的问题。当插入设备时,热插拔机制会立即进行处理。
3.进程的终止与再启动
init进程读取并分析init.rc文件,获得服务列表,而后从列表中依次启动服务子进程,Init进程启动的主要进程如下:
1.sh:搭载android的机器终端,连接串口或adbd时,提供控制台输入输出的shell程序
2.adbd:Android Debug Bridge,用来管理QEWU模拟器或实际机器的状态,该工具运行在目标机器上,充当服务器。PC连接服务器的客户端。
3.serviceManager:Android中比较重要的一个进程,在init进程启动后启动,用来管理系统中的服务。
4.vold:指Volume Demeaon,用来挂载/管理USB存储或SD卡设备
5.playmp3:在Android启动时,输出启动声音。
init进程中有一个事件处理循环
static void sigchld_handler(int s){ write(signal_fd, &d, 1);}发生SIGCHLD信号时,该函数被调用,参数S是用来接收SIGCHLD信号的编号。
sigchld_handler写入SIGCHLD编号到signal_fd中,通过套接字传递数据到signal_recv_fd,发生事件poll()到wait_for_one_process(0)中。
下面是wait_for_one_process源代码,在system/core/init/signal_handler.c中
static int wait_for_one_process(int block){ pid_t pid; int status; struct service *svc; struct socketinfo *si; time_t now; struct listnode *node; struct command *cmd; while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR ); if (pid <= 0) return -1; INFO("waitpid returned pid %d, status = %08x\n", pid, status); svc = service_find_by_pid(pid); if (!svc) { ERROR("untracked pid %d exited\n", pid); return 0; } NOTICE("process '%s', pid %d exited\n", svc->name, pid); if (!(svc->flags & SVC_ONESHOT)) { kill(-pid, SIGKILL); NOTICE("process '%s' killing any children in process group\n", svc->name); } /* remove any sockets we may have created */ for (si = svc->sockets; si; si = si->next) { char tmp[128]; snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name); unlink(tmp); } svc->pid = 0; svc->flags &= (~SVC_RUNNING); /* oneshot processes go into the disabled state on exit */ if (svc->flags & SVC_ONESHOT) { svc->flags |= SVC_DISABLED; } /* disabled processes do not get restarted automatically */ if (svc->flags & SVC_DISABLED) { notify_service_state(svc->name, "stopped"); return 0; } now = gettime(); if (svc->flags & SVC_CRITICAL) { if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) { if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) { ERROR("critical process '%s' exited %d times in %d minutes; " "rebooting into recovery mode\n", svc->name, CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60); sync(); __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, "recovery"); return 0; } } else { svc->time_crashed = now; svc->nr_crashed = 1; } } svc->flags |= SVC_RESTARTING; /* Execute all onrestart commands for this service. */ list_for_each(node, &svc->onrestart.commands) { cmd = node_to_item(node, struct command, clist); cmd->func(cmd->nargs, cmd->args); } notify_service_state(svc->name, "restarting"); return 0;}
4.属性服务
Andorid平台中,为了让运行中的所有进程共享系统运行时所需要的各种属性值,系统开辟了属性存储区域。属性由Key-Value构成,在访问属性值时,添加了访问权限控制,增加了访问的安全性。当其他进程修改属性值时,必须向init进程提出请求,最终由init进程负责修改属性值,init进程会先检查各属性的访问权限,而后再修改属性值。
在init目录下的property_service.c文件中包含了属性的初始化和访问修改函数
如property_set()函数
int property_set(const char *name, const char *value){ prop_area *pa; prop_info *pi; int namelen = strlen(name); int valuelen = strlen(value); if(namelen >= PROP_NAME_MAX) return -1; if(valuelen >= PROP_VALUE_MAX) return -1; if(namelen < 1) return -1; pi = (prop_info*) __system_property_find(name); if(pi != 0) { /* ro.* properties may NEVER be modified once set */ if(!strncmp(name, "ro.", 3)) return -1; pa = __system_property_area__; update_prop_info(pi, value, valuelen); pa->serial++; __futex_wake(&pa->serial, INT32_MAX); } else { pa = __system_property_area__; if(pa->count == PA_COUNT_MAX) return -1; pi = pa_info_array + pa->count; pi->serial = (valuelen << 24); memcpy(pi->name, name, namelen + 1); memcpy(pi->value, value, valuelen + 1); pa->toc[pa->count] = (namelen << 24) | (((unsigned) pi) - ((unsigned) pa)); pa->count++; pa->serial++; __futex_wake(&pa->serial, INT32_MAX); } /* If name starts with "net." treat as a DNS property. */ if (strncmp("net.", name, strlen("net.")) == 0) { if (strcmp("net.change", name) == 0) { return 0; } /* * The 'net.change' property is a special property used track when any * 'net.*' property name is updated. It is _ONLY_ updated here. Its value * contains the last updated 'net.*' property. */ property_set("net.change", name); } else if (persistent_properties_loaded && strncmp("persist.", name, strlen("persist.")) == 0) { /* * Don't write properties to disk until after we have read all default properties * to prevent them from being overwritten by default values. */ write_persistent_property(name, value); } property_changed(name, value); return 0;}property_get()函数
const char* property_get(const char *name){ prop_info *pi; if(strlen(name) >= PROP_NAME_MAX) return 0; pi = (prop_info*) __system_property_find(name); if(pi != 0) { return pi->value; } else { return 0; }}init_property_area()函数
static int init_property_area(void){ prop_area *pa; if(pa_info_array) return -1; if(init_workspace(&pa_workspace, PA_SIZE)) return -1; fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC); pa_info_array = (void*) (((char*) pa_workspace.data) + PA_INFO_START); pa = pa_workspace.data; memset(pa, 0, PA_SIZE); pa->magic = PROP_AREA_MAGIC; pa->version = PROP_AREA_VERSION; /* plug into the lib property services */ __system_property_area__ = pa; property_area_inited = 1; return 0;}
0 0
- Android init进程解析
- android init进程解析init.rc过程
- Android init进程——解析配置文件
- android init进程分析 init脚本解析和处理
- Android init进程之解析及运行init.rc文件`
- Android系统init进程启动及init.rc全解析
- Busybox ---------- init进程解析
- android init进程 init.rc
- Android init 进程 init.rc init.*.rc
- Android init 进程 init.rc init.*.rc
- Android init 进程 init.rc init.*.rc
- Android开机流程分析 -- init进程之配置文件解析
- Android系统启动流程(一)解析init进程启动过程
- Android Framework学习(一)之init进程解析
- Android Framework学习(一)之init进程解析
- Android系统启动流程(一)解析init进程启动过程
- init进程 && 解析Android启动脚本init.rc && 修改它使不启动android
- Android中init.rc文件的解析&&Android init进程启动过程分析
- ant replace的使用
- Android中native进程内存泄露的调试技巧【转】
- 绘制曲线图2(完善平滑移动)
- C++语言基础 —— 一个Java程序员的视角
- 用友nc57 一些跟当前登陆环境相关的方法
- Android init进程解析
- linux suse设置中文系统
- java 通过网络地址获取图片宽高
- 关于ZBar生成高密度二维码
- python核心编程--第七章 7.12 练习
- shell 基本计算、逻辑运算、位运算详解
- VMWare 网络连接模式(bridged、NAT、host-only)详解
- iOS下拉列表
- 使用Hazelcast搭建openfire Clustering