尊天命,尽人事
分类: 嵌入式
2011-08-28 08:17:36
http://blog.csdn.net/fu_shuwu/article/details/6017403
Linux kernel起来后运行的第一个应用程序就是init,
Init属于linux下一个应用程序,其源码在 system/core/init中,main是应用程序的入口。从main()函数就可以知道init主要功能。
main()
(1)安装SIGCHLD信号。(如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。因此需要对SIGCHLD信号做出处理,回收僵尸进程的资源,避免造成不必要的资源浪费。
act.sa_handler = sigchld_handler;
act.sa_flags = SA_NOCLDSTOP;
act.sa_mask = 0;
act.sa_restorer = NULL;
sigaction(SIGCHLD, &act, 0);
(2)为rootfs建立必要的文件夹,并挂载适当的分区。
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);
(3)创建/dev/null和/dev/kmsg节点。
open_devnull_stdio();
log_init();
(4)解析/init.rc,将所有服务和操作信息加入链表。
parse_config_file("/init.rc");
(5)从/proc/cmdline中提取信息内核启动参数,并保存到全局变量。
/* pull the kernel commandline and ramdisk properties file in */
qemu_init();
import_kernel_cmdline(0);
(6)先从上一步获得的全局变量中获取硬件信息和版本号,如果没有则从/proc/cpuinfo中提取,并保存到全局变量。
get_hardware_name();
(7)根据硬件信息选择一个/init.%hardware%.rc,并解析,将服务和操作信息加入链表。
snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
parse_config_file(tmp);
(8)执行链表中带有“early-init”触发的的命令。
action_for_each_trigger("early-init", action_add_queue_tail);
drain_action_queue();
(9)遍历/sys文件夹,是内核产生设备添加事件(为了自动产生设备节点)。
device_init();
{int fd;
fd = open_uevent_socket();
if(fd < 0) return -1;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
coldboot(fd, "/sys/class");
coldboot(fd, "/sys/block");
coldboot(fd, "/sys/devices");
return fd;
}
(10)初始化属性系统,并导入初始化属性文件。
property_init();
(11)从属性系统中得到ro.debuggable,若为1,则初始化keychord
debuggable = property_get("ro.debuggable");
if (debuggable && !strcmp(debuggable, "1"))
keychord_fd = open_keychord();
(12)打开console,如果cmdline中没有指定console,则打开却省的/dev/console。
if (console[0]) {
snprintf(tmp, sizeof(tmp), "/dev/%s", console);
console_name = strdup(tmp);
}
fd = open(console_name, O_RDWR);
if (fd >= 0)
have_console = 1;
close(fd);
(14)读取/initlogo.rle(一张565 rle 压缩的位图logo),如果成功则在/dev/graphics/fb0显示出Logo,如果失败,则将/dev/tty0设置为TEXT模式并打开/dev/tty0,输出“ANDROID”字符串。
if( load_565rle_image(/initlogo.rle) ) {
fd = open("/dev/tty0", O_WRONLY);
if (fd >= 0) {
const char *msg;
msg = "/n" "/n"
A N D R O I D ";
write(fd, msg, strlen(msg));
close(fd);
}
}
(15)判断cmdline 中的参数,并设置属性系统中的参数:
if (qemu[0])
import_kernel_cmdline(1);
if (!strcmp(bootmode,"factory"))
property_set("ro.factorytest", "1");
else if (!strcmp(bootmode,"factory2"))
property_set("ro.factorytest", "2");
else
property_set("ro.factorytest", "0");
property_set("ro.serialno", serialno[0] ? serialno : "");
property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");
property_set("ro.baseband", baseband[0] ? baseband : "unknown");
property_set("ro.carrier", carrier[0] ? carrier : "unknown");
property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
property_set("ro.hardware", hardware);
snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
property_set("ro.revision", tmp);
(16)执行所有触发标识为init的action。
/* execute all the init actions to get us started */
action_for_each_trigger("init", action_add_queue_tail);
drain_action_queue();
(17)开始property service
/* read any property files on system or data and
* fire up the property service. This must happen
* after the ro.foo properties are set above so
* that /data/local.prop cannot interfere with them.
*/
property_set_fd = start_property_service();
(18)为sigchld handler创建信号机制。
/* create a signalling mechanism for the sigchld handler */
if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
signal_fd = s[0];
signal_recv_fd = s[1];
fcntl(s[0], F_SETFD, FD_CLOEXEC);
fcntl(s[0], F_SETFL, O_NONBLOCK);
fcntl(s[1], F_SETFD, FD_CLOEXEC);
fcntl(s[1], F_SETFL, O_NONBLOCK);
}
(19) 执行所有触发标识为early-boot和boot的action
/* 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);
drain_action_queue();
(20)基于当前property状态,执行所有触发标识为property的action
/* run all property triggers based on current state of the properties */
queue_all_property_triggers();
drain_action_queue();
(21)注册轮询事件:
- device_fd
- property_set_fd
-signal_recv_fd
-如果有keychord,则注冊keychord_fd
ufds[0].fd = device_fd;
ufds[0].events = POLLIN;
ufds[1].fd = property_set_fd;
ufds[1].events = POLLIN;
ufds[2].fd = signal_recv_fd;
ufds[2].events = POLLIN;
fd_count = 3;
if (keychord_fd > 0) {
ufds[3].fd = keychord_fd;
ufds[3].events = POLLIN;
fd_count++;
}
(22)进入无限循环,确保这个init进程永驻不退出
在这个循环体内,将通过poll模式POLLIN来监视device/property-set/chid-process-exit等事件,
比如,SD卡插入时,init中device_fd将能收到卡插入事件,以便可以创建节点。
另外,所有其他的重要进程都是init的子进程,一旦这些子进程出现意外,init的signal_recv_fd将收到SIGCHLD,系统将可以做后续处理