init进程是用户级的第一个进程(UserPlace) 在Linux中所有进程都是init的子进程,Linux中一切都是以文件的形式存在的,主要提供四大功能
建立文件所在目录挂载设备处理Action
职责关注部分: 创建zygote进程 启动属性服务 性能分析(BootChart) 无线循环(启动其他的进程)
1.1.1 解析配置文件init.rc 还有一个rc文件是xx.rc(xx是硬件名),这个文件只是系统的一个镜像文件,更改也没有用。如想改变则需要在boot.ing核镜像中修改。有一个函数parseconfig函数进行解析,其中有一个Section Zygote被放在一个Service中。 1.1.2 解析规则 使用的是Android Init Language 编译的脚本 分为 :
Action (一组被命名的Command序列)Command 五种语句类型Service 由init进程启动或重启的程序Options Services 修饰词 ,指定如何并何时启动Import一个Section 的结构一般是:
on <trigger> <command> <command> service <name> <pathname> [ <argument> ]*#是注释 ,on init 和 onboot是Action类型。 解析rc文件的详细内容: http://blog.csdn.net/yangwen123/article/details/9029959
1.1.3解析Service init中使用一个结构体来保存Service Section 相关信息(使用Socket,action结构体) 函数ParseService 搭建一个servce的架子。 Parse_line_service 将根据配置文件的内容填完service结构体 zygote 解析后的结果:service List 将解析后的Service全部连在一起。 Socketinifo -> Socket链表 onrestart commands 指向一个 Commands 链表
1.1.4 init控制service 其中sygote 就是在其中一个Service中 在rc 文件中一个service
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart media onrestart restart netdclass_start default ->是一个COMMAND 位于boot(引导) section 范围内。 最后执行service_start函数,并在启动前要判断可执行文件,是否存在 /system/bin/applprocress 主要做了以下几个工作:
调用fork()系统调用创建新的进程;获取属性匿名存储空间句柄,并添加为服务配置的环境变量;创建服务配置的socket,调用publish_socket函数将创建的socket句柄添加到环境变量中;该环境变量为:ANDROID_SOCKET_XXX = fd为新进程打开控制台,并设置新进程的PID,GID等;调用execve()系统调用执行新进程运行的程序;设置服务运行状态属性;该属性为:init.svc.XXX = running1.1.5 重启Zygote onrestart是在zygote重启时用的,当内存不足时,Android系统会自动杀死一下进程来释放空间,所以当某些重要的服务被杀,同时该服务进程并未设置为oneshot,则必须重新启动该服务进程。 zygote死后父进程init 会通过Socket接收数据执行代码(Main函数中)->init.rc.main中工作如下:
static int wait_for_one_process(int block) { //block = 0 -->false pid_t pid; int status; struct service *svc; struct socketinfo *si; time_t now; struct listnode *node; struct command *cmd; /*当进程被终止时,将发送SIGCHLD信号,waitpid()函数用来回收进程所占用的资源,第一个参 数pid是指欲等待的子进程的识别码,设置为-1表示查看所有子进程是否发出SIGCHIL信号,第二 个参数status用于返回子进程的结束状态;第三个参数决定waitpid()函数是否应用阻塞处理方式。 waitpid()函数返回产生SIGCHID信号的进程pid */ while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR ); //正常情况下返回的死亡进程pid大于0,因此wait_for_one_process的返回值正常情况下为0 if (pid <= 0) return -1; INFO("waitpid returned pid %d, status = x\n", pid, status); //用于根据pid值在服务链表中查找对应的服务 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); /* 检查服务是否设置了oneshot标志,SVC_ONESHOT表示进程仅运行一次,如果没有设置SVC_ONESHOT标志, 表示需要重启该服务进程,首先将该服务进程组下的所有子进程杀死 */ if (!(svc->flags & SVC_ONESHOT)) { kill(-pid, SIGKILL); NOTICE("process '%s' killing any children in process group\n", svc->name); } /* 删除该服务进程下的创建的所有socket */ for (si = svc->sockets; si; si = si->next) { char tmp[128]; snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name); unlink(tmp); } //设置服务的pid为0 ,并清除SVC_RUNNING标志 svc->pid = 0; svc->flags &= (~SVC_RUNNING); /* 如果设置了SVC_ONESHOT标志,表示服务只能运行一次,因此设置表示位SVC_DISABLED */ if (svc->flags & SVC_ONESHOT) { svc->flags |= SVC_DISABLED; } /* 判断服务标志是否设置了SVC_DISABLED 或 SVC_RESET 对于设置了这两种标志的进程是不能重启的 */ if (svc->flags & (SVC_DISABLED | SVC_RESET) ) { //设置进程运行状态属性值为stopped 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); //手机重启 android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); return 0; } } else { svc->time_crashed = now; svc->nr_crashed = 1; } } //设置服务进程标志SVC_RESTARTING,在restart_processes()函数中会重启持有SVC_RESTARTING svc->flags |= SVC_RESTARTING; /* 运行该service下所有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); } //设置进程运行状态属性值为stopped notify_service_state(svc->name, "restarting"); return 0; } 找到死service杀掉zygote创建的所有子进程清除socket信息如果实质SVC_CRIICAL标志位则4分钟内不超过4次否则进入(recovery模式)系统应用程序将会存储一些属性进入属性表中。即时系统重启,注册表应用程序重启,也能初始化。 property_service (属性服务机制)(socket服务) 属性文件是一些位列于不同目录,系统依次读取的配置文件。 1.启动(Socket服务) init.c文件中函数()与属性服务有关的代码 property_init(); property_set_fd=start_property_service();
1.2.1 属性服务的初始化 在前面分析main函数时涉及到一个property_init函数,该函数调用了init_property_area函数,该函数用于初始化属性内存区域,也就是system_property_area变量。 这个函数加载defaut.prop文件(属性文件) 虽然init进程创建但希望其他进程也能读到内存中的东西,于是做了以下两项工作:
共享内存中 。init.workspace 函数利用gcc的Constructor属性指明_libc_prenit函数,libc_prenit函数.libc_ini_common.c文件中->_libc_init_comment->system.propertis_init()//初始化客户端属性存储区域1.2.2 属性服务器分析 (1)start_property_service函数,该函数在Property_service.c文件中,该文件与init.c文件中同一个目录。 函数如下:
void start_property_service(void) { int fd; // 装载不同的属性文件 load_properties_from_file(PROP_PATH_SYSTEM_BUILD); load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT); load_override_properties(); /* Read persistent properties after all default values have been loaded. */ load_persistent_properties(); // 创建socket服务(属性服务) fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0); if(fd < 0) return; fcntl(fd, F_SETFD, FD_CLOEXEC); fcntl(fd, F_SETFL, O_NONBLOCK); // 开始服务监听 listen(fd, 8); property_set_fd = fd; }在start_property_service 中执行了:load_persistent_properties(); // 创建socket服务(属性服务)。客户端只通过对此进行属性设置。 并定义两个宏(和系统预定属性文件路径有关) 将属性文件加载到属性空间中,四个储存属性的文件分别是:
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop" #define PROP_PATH_SYSTEM_BUILD "/system/build.prop" #define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop" #define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"(2)处理设置请求(在init进程for循环中): handle_property_set_fd进行处理。权限满足,调用property_set进行处理。 (3)客户端发送请求。 property_set 发送请求,由libcutils库进行提供。propertis.c文件中。