init进程(system\core\init)是Linux Kernal启动之后,在用户空间运行的第一个进程。init进程是一个守护进程,它的生命周期贯穿整个Linux内核运行的始终,在Linux系统中的所有进程都是由init进程创建并运行的。因为Android是基于Linux内核的,所以Google为启动并运行整个Android系统,实现了自己的init进程。
一、init进程职责
init作为所有进程的父进程,被赋予了至关重要的工作职责,那么它做了哪些事情呢?
1、首先系统内核启动完成后,到用户空间启动init进程,然后再启动系统运行的其他进程。在系统启动完成后,init进程作为守护进程运行。
init进程作为守护进程,用来监视其他进程,若某个被监视的进程一旦终结,进入僵死状态,就会释放掉进程所占用的系统资源。若有时候父进程先于子进程死掉,则一般会让init进程领养,init进程成为其父进程。
2、init进程负责创建系统中的几个关键进程,最重要的是zygote,zygote更是java世界的创建者。那么,init进程是如何创建zygote的呢?
3、Android系统有很多属性,于是init提供了一个property service(属性服务)来管理它们。那么这个属性服务是怎么工作的呢?
二、init分析
(一)、init中main函数分析(system\core\init\init.c)
(1)、先看一下这个变量的定义:strcut pollfd ufds[4];在后面的poll轮训中用到了该数组。
ufds是一个指向pollfd的结构体数组,pollfd的定义如下:
#include <sys/poll.h> int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct pollfd { int fd; /* 想查询的文件描述符. */ short int events; /* 等待的事件*/ short int revents; /* 实际发生了的事件 */ };
ufds 指向 struct pollfd 数组,pollfd是用于存放需要监控事件的文件描述符;nfds 指定 pollfd 数组元素的个数,也就是要监测几个 pollfd;timeout用于标记poll函数调用的阻塞时间,如果timeout为0,表示不阻塞,直接返回;poll函数返回ufds中revents不为0的fd个数;如果超时没有任何事件发生,返回0;失败时返回-1。
(2)、启动ueventd、watchdog进程if (!strcmp(basename(argv[0]), "ueventd"))
return ueventd_main(argc, argv); if (!strcmp(basename(argv[0]), "watchdogd")) return watchdogd_main(argc, argv); 可以看出传入到mian函数的命令行参数有ueventd和watchdogd,通过比较它们的值,进入到相应的main函数中,启动uevent和watchdog进程,分别是冷插拔进程和看门狗进程。ueventd伺服程序将解析/ueventd.rc文件,并创建相应的设备结点。watchdogd伺服程序是一个看门狗程序,它的任务就是定期向看门狗设备文件执行写操作,以判断系统是否正常运行。(3)、将当前umask值设置为0
/* clear the umask */ umask(0);
调用umask(0)函数(函数原型:mode_t umask(mode_t mask)),将当前umask值设置为0(实际上是参数值mask & 0777 之后的值),先前默认值为022;引用该函数的主要作用是在创建文件时设置或屏蔽掉文件的一些权限。这里将mask设置成0,说明后面的文件创建时的权限是多少实际权限就是多少。(4)、创建文件系统目录并挂载文件系统
/* Get the basic filesystem setup we need put * together in the initramdisk on / and then we'll * let the rc file figure out the rest. */ mkdir("/dev", 0755); mkdir("/proc", 0755); mkdir("/sys", 0755); mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "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);
首先构建dev、proc、sys三个主要目录(其他目录从init.rc中读取建立),再调用mount函数对文件系统挂载。在这里分别挂载了tmpfs、devpts、proc、sysfs四类文件系统。
mount函数定义:int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);source是要挂上的文件系统,通常是设备名;target是文件系统所要挂载的目标目录;filesystemtype是文件系统类型,只要有“ext2”、“ext3”、“proc”、“sysfs”、“ntfs”、“tmpfs”等;mountflags是文件系统的读写访问标志;data是文件系统特有的参数。tmpfs:是一种虚拟内存文件系统,典型的tmpfs文件系统是完全驻留在ARM中(虚拟内存)的,因此读写速度远远快于闪存和硬盘文件系统。并且tmpfs下的内容均为临时性内容,因此如果将tmpfs卸载后,其里面的内容将不再存在。