android init 进程分析

android init 进程分析


 int main(int argc, char **argv)  
 {  
     int device_fd = -1;  
     int property_set_fd = -1;  
     int signal_recv_fd = -1;  
     int keychord_fd = -1;  
     int fd_count;  
     int s[2];  
     int fd;  
     struct sigaction act;  
     char tmp[PROP_VALUE_MAX];  
     struct pollfd ufds[4];  
     char *tmpdev;  
     char* debuggable;  
   
    /** 
    安装SIGCHLD信号。如果父进程不等待子进程结束,子进程将成为僵尸进程, 
    其占用的系统资源将得不到释,必须注册此信号处理。 
    */  
     act.sa_handler = sigchld_handler;  
     act.sa_flags = SA_NOCLDSTOP;  
     sigemptyset(&act.sa_mask);  
     sigaction(SIGCHLD, &act, 0); 


     /** 
     创建文件系统需要的基本目录。mount一些必要的分区 
     */  
     /* clear the umask */  
     umask(0); /* 设置文件的默认权限,umask和chmod的权限刚好反的,umask的0000相当于chmod的0777 */




     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); 


    /*创建/dev/null结点,重定向标准输入,输出以及标准出错。同时为了跟踪系统的行为Android使用kmsg系统。*/
    open_devnull_stdio();
**********************************************************
void open_devnull_stdio(void)
{
    int fd;
    static const char *name = "/dev/__null__";
    if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
        fd = open(name, O_RDWR);
        unlink(name);
        if (fd >= 0) {
            dup2(fd, 0);
            dup2(fd, 1);  //1为标准输出stdout、2为标准错误stderr,这里调用dup2重定向0,1,2文件描述符到/dev/null
            dup2(fd, 2);
            if (fd > 2) {
                close(fd);
            }
            return;
        }
    }


    exit(1);
}


关于mknod系统调用
int mknod(const char *pathname, mode_t mode, dev_t dev)
mknod创建一个设备文件,mode参数指定了文件的类型和访问权限,文件类型必须是S_IFREG, S_IFCHR, S_IFBLK, S_IFIFO or S_IFSOCK
如果文件类型是S_IFCHR or S_IFBLK,那么dev指定了新创建的设备的主次设备号,否则,dev被忽略


************************************************************
    log_init();  //创建/dev/kmsg设备结点,我们可以利用这个设备输出调试信息


    INFO("reading config file\n");  
  //定义在init.h中
  //#define INFO(x...)    log_write(6, "<6>init: " x)
  //6表示Log等级,我们用全局变量LOG_DEFAULT_LEVEL定义默认可输出的Log等级,如果INFO在终端无输出,那么可修改此变量




      /*解析初始化脚本,这里只是parse,将脚本解析到一个链表中,没有执行。 */  
     parse_config_file("/init.rc");    
   
     /*获得内核命令行参数*/  
     /* pull the kernel commandline and ramdisk properties file in */  
     qemu_init();  
     import_kernel_cmdline(0);  
   
     /* 根据上一部获得的hardware参数信息,解析额外的硬件相关init脚本, 一般qemu为init.goldfish.rc */  
     get_hardware_name();  
     snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);  
     parse_config_file(tmp);  
   
     /* 找到init.rc paser链表中为early-init属性的项目,将其添加到action queue中 */  
     action_for_each_trigger("early-init", action_add_queue_tail);  
     /* 执行这些queue中的动作 */  
     drain_action_queue(); 


    INFO("device init\n");
    device_fd = device_init();


*******************************************************************


int device_init(void)
{
    suseconds_t t0, t1;
    int fd;


    fd = open_uevent_socket(); //建立NETLINK的socket,用于内核空间和用户空间的异步通信,
    if(fd < 0)
        return -1;


    fcntl(fd, F_SETFD, FD_CLOEXEC);
    fcntl(fd, F_SETFL, O_NONBLOCK);


    t0 = get_usecs();
    coldboot(fd, "/sys/class"); //递归遍历/sys/devices目录,查找uevent文件,如果存在,则向uevent文件节点写“add”字符串,触发uevent
    //事件,通过socket接收到内核的msg,分析msg字符串,建立相应的设备文件结点
    coldboot(fd, "/sys/block"); //对于subsystem是firmware,action是add的uevent事件,fork一个子进程,调用process_firmware_event
    //处理相应的uevent事件
    coldboot(fd, "/sys/devices");
    t1 = get_usecs();


    log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));


    make_device("/dev/pvrsrvkm", 0, 240, 0);


    make_device("/dev/fb0", 0, 29, 0);
    make_device("/dev/fb1", 0, 29, 1);
    make_device("/dev/fb2", 0, 29, 2);
    make_device("/dev/fb3", 0, 29, 3);
    make_device("/dev/fb4", 0, 29, 4);/*make_device在全局数组qemu_perms,devperms和链表devperms_partners中,查找相匹配的struct   


                       perms,如果存在,则获得相应的uid,gid和mode;否则,uid=gid=0, mode为0600;然后创建设备结点*/


    return fd;
}
*******************************************************************


    property_init();/*初始化属性系统,系统属性是设备文件/dev/ashmem,大小为32Kb的一块区域.用全局变量__system_property_area__引用,
      属性信息存储在这块区域1kb之后,全局变量pa_info_array指向其起始元素;初始化之后,读取根文件系统的/default.prop 


             文件并保存*/


    // only listen for keychords if ro.debuggable is true
    debuggable = property_get("ro.debuggable");
    if (debuggable && !strcmp(debuggable, "1")) {
        keychord_fd = open_keychord();
    } /*遍历service_list中的struct service svc,检测其成员keycodes是否为空
      keycodes是通过/dev/keychord来触发这个service,如果keycodes不为空,那么就添加一个新的keychord到链表keychords中*/


    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);
   /*打开console  ,/dev/console


     /*加载logo图片,格式是rgb565的raw data(/initlogo.rle),如果不存在此文件,则直接在console上打印android文字, 
     注意的是: android在首次加载时,会非常慢, 这个图就是提醒下我们是在加载模式下,此图显示后会被自动删除,因此默认只有烧code完毕后


     看到一次 */
  
    if( load_565rle_image(INIT_IMAGE_FILE) ) {
    fd = open("/dev/tty0", O_WRONLY);
    if (fd >= 0) {
        const char *msg;
            msg = "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"  // console is 40 cols x 30 lines
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "             A N D R O I D ";
        write(fd, msg, strlen(msg));
        close(fd);
    }
    }
 
    if (qemu[0])
        import_kernel_cmdline(1);


 /*设置相关的属性到属性系统中,默认32kb的属性区可以最大存储247个信息
  (8 header words + 247 toc words) = 1020 bytes 
  1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */


     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); 


        /* execute all the boot actions to get us started */
     action_for_each_trigger("init", action_add_queue_tail); /*将action_list中name为init的项添加到action_queue中*/
     drain_action_queue();/*执行init section所有的command,主要是安装全局环境变量,加载动态模块,建立相关的文件结构,挂载mtd分区等*/




    property_set_fd = start_property_service();/*读取/system/build.prop,/system/default.prop,/data/local.prop到系统属性区,
      然后读取目录/data/property,如果有persist.开头的属性文件,则读取值并添加到系统属性 


     区,开启persistent_properties_loaded=1,创建socket /dev/socket/property_service,监  


    听等待连接*/


    /* 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);
    }


    /* make ֝ui
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值