Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1412839
  • 博文数量: 1334
  • 博客积分: 645
  • 博客等级: 上士
  • 技术积分: 5762
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-25 16:56
文章分类

全部博文(1334)

文章存档

2014年(108)

2013年(1059)

2012年(169)

分类: 嵌入式

2013-02-28 10:55:48

转自:http://blog.csdn.net/fu_shuwu/article/details/6017403

 

Linux kernel起来后android 之init详解

分类: Android 880人阅读 评论(0)  举报

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)执行所有触发标识为initaction
    /* 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-bootbootaction
/* 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状态,执行所有触发标识为propertyaction
     /* 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卡插入时,initdevice_fd将能收到卡插入事件,以便可以创建节点。

 另外,所有其他的重要进程都是init的子进程,一旦这些子进程出现意外,initsignal_recv_fd将收到SIGCHLD,系统将可以做后续处理。

 

阅读(587) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~