Android的init过程详解(一)init的初始化

本文使用的软件版本

Android:4.2.2

Linux内核:3.1.10

本文及后续几篇文章将对Android的初始化(init)过程进行详细地、剥丝抽茧式地分析,并且在其中穿插了大量的知识,希望对读者了解Android的启动过程又所帮助。本章主要介绍了与硬件相关初始化文件名的确定以及属性服务的原理和实现。

Android本质上就是一个基于Linux内核的操作系统。与Ubuntu Linux、Fedora Linux类似。只是Android在应用层专门为移动设备添加了一些特有的支持。既然Android是Linux内核的系统,那么基本的启动过程也应符 合Linux的规则。如果研究过其他Linux系统应该了解,一个完整的Linux系统首先会将一个Linux内核装载到内存,也就是编译Linux内核 源代码生成的bzImage文件,对于为Android优化的Linux内核源代码会生成zImage文件。该文件就是Linux内核的二进制版本。由于 zImage在内核空间运行,而我们平常使用的软件都是在应用空间运行(关于内核空间和应用空间的详细描述,可以参考《Android深度探索(卷1):HAL与驱动开发》一书的内容,在后续的各卷中将会对Android的整体体系进行全方位的剖析)。内核空间和应用空间是不能直接通过内存地址级别访问的,所以就需要建立某种通讯机制。

目前Linux有很多通讯机制可以在用户空间和内核空间之间交互,例如设备驱动文件(位于/dev目录中)、内存文件(/proc、/sys目录等)。了 解Linux的同学都应该知道Linux的重要特征之一就是一切都是以文件的形式存在的,例如,一个设备通常与一个或多个设备文件对应。这些与内核空间交 互的文件都在用户空间,所以在Linux内核装载完,需要首先建立这些文件所在的目录。而完成这些工作的程序就是本文要介绍的init。Init是一个命 令行程序。其主要工作之一就是建立这些与内核空间交互的文件所在的目录。当Linux内核加载完后,要做的第一件事就是调用init程序,也就是 说,init是用户空间执行的第一个程序。

在分析init的核心代码之前,还需要初步了解init除了建立一些目录外,还做了如下的工作

1. 初始化属性

2. 处理配置文件的命令(主要是init.rc文件),包括处理各种Action。

3. 性能分析(使用bootchart工具)。

4. 无限循环执行command(启动其他的进程)。

尽管init完成的工作不算很多,不过代码还是非常复杂的。Init程序并不是由一个源代码文件组成的,而是由一组源代码文件的目标文件链接而成的。这些文件位于如下的目录。

<Android源代码本目录>/system/core/init

其中init.c是init的主文件,现在打开该文件,看看其中的内容。由于init是命令行程序,所以分析init.c首先应从main函数开始,现在好到main函数,代码如下:

int main(int argc, char **argv)
{
    int fd_count = 0;
    struct pollfd ufds[4];
    char *tmpdev;
    char* debuggable;
    char tmp[32];
    int property_set_fd_init = 0;
    int signal_fd_init = 0;
    int keychord_fd_init = 0;
    bool is_charger = false; 

    if (!strcmp(basename(argv[0]), "ueventd"))
        return ueventd_main(argc, argv); 

    if (!strcmp(basename(argv[0]), "watchdogd"))
        return watchdogd_main(argc, argv); 

    /* clear the umask */
    umask(0);
    //  下面的代码开始建立各种用户空间的目录,如/dev、/proc、/sys等
    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/.booting文件是否可读写和创建*/
    close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000)); 

    open_devnull_stdio();
    klog_init();
    //  初始化属性
    property_init(); 

    get_hardware_name(hardware, &revision);
    //  处理内核命令行
    process_kernel_cmdline();
    … … 

    is_charger = !strcmp(bootmode, "charger"); 

    INFO("property init\n");
    if (!is_charger)
        property_load_boot_defaults(); 

    INFO("reading config file\n");
    //  分析/init.rc文件的内容
    init_parse_config_file("/init.rc");
    … …//  执行初始化文件中的动作
    action_for_each_trigger("init", action_add_queue_tail);
    //  在charger模式下略过mount文件系统的工作
    if (!is_charger) {
        action_for_each_trigger("early-fs", action_add_queue_tail);
        action_for_each_trigger("fs", action_add_queue_tail);
        action_for_each_trigger("post-fs", action_add_queue_tail);
        action_for_each_trigger("post-fs-data", action_add_queue_tail);
    } 

    queue_builtin_action(property_service_init_action, "property_service_init");
    queue_builtin_action(signal_init_action, "signal_init");
    queue_builtin_action(check_startup_action, "check_startup"); 

    if (is_charger) {
        action_for_each_trigger("charger", action_add_queue_tail);
    } else {
        action_for_each_trigger("early-boot", action_add_queue_tail);
        action_for_each_trigger("boot", action_add_queue_tail);
    } 

        /* run all property triggers based on current state of the properties */
    queue_builtin_action(queue_property_triggers_action, "queue_property_triggers"); 

#if BOOTCHART
    queue_builtin_action(bootchart_init_action, "bootchart_init");
#endif
    //  进入无限循环,建立init的子进程(init是所有进程的父进程)
    for(;;) {
        int nr, i, timeout = -1;
        //  执行命令(子进程对应的命令)
        execute_one_command();
        restart_processes(); 

        if (!property_set_fd_init && get_property_set_fd() > 0) {
            ufds[fd_count].fd = get_property_set_fd();
            ufds[fd_count].events = POLLIN;
            ufds[fd_count].revents = 0;
            fd_count++;
            property_set_fd_init = 1;
        }
        if (!signal_fd_init && get_signal_fd() > 0) {
            ufds[fd_count].fd = get_signal_fd();
            ufds[fd_count].events = POLLIN;
            ufds[fd_count].revents = 0;
            fd_count++;
            signal_fd_init = 1;
        }
        if (!keychord_fd_init && get_keychord_fd() > 0) {
            ufds[fd_count].fd = get_keychord_fd();
            ufds[fd_count].events = POLLIN;
            ufds[fd_count].revents = 0;
            fd_count++;
            keychord_fd_init = 1;
        } 

        if (process_needs_restart) {
            timeout = (process_needs_restart - gettime()) * 1000;
            if (timeout < 0)
                timeout = 0;
        } 

        if (!action_queue_empty() || cur_action)
            timeout = 0;
//  bootchart是一个性能统计工具,用于搜集硬件和系统的信息,并将其写入磁盘,以便其
//  他程序使用
#if BOOTCHART
        if (bootchart_count > 0) {
            if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
                timeout = BOOTCHART_POLLING_MS;
            if (bootchart_step() < 0 || --bootchart_count == 0) {
                bootchart_finish();
                bootchart_count = 0;
            }
        }
#endif
        //  等待下一个命令的提交
        nr = poll(ufds, fd_count, timeout);
        if (nr <= 0)
            continue; 

        for (i = 0; i < fd_count; i++) {
            if (ufds[i].revents == POLLIN) {
                if (ufds[i].fd == get_property_set_fd())
                    handle_property_set_fd();
                else if (ufds[i].fd == get_keychord_fd())
                    handle_keychord();
                else if (ufds[i].fd == get_signal_fd())
                    handle_signal();
            }
        }
    } 

    return 0;
}

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索linux
, android
, 文件
, 内核
, android、初始化
, init
, 空间
, android properties
, creat 文件属性 0755
, 不能循环读sysfs文件
, 内核android
, init.rc
, init.rc文件详解
init.rc简介
android编译过程详解、android 启动过程详解、nlpir init初始化失败、mui init初始化参数、init方法初始化,以便于您获取更多的相关知识。

时间: 2024-09-06 13:07:46

Android的init过程详解(一)init的初始化的相关文章

Android的init过程详解(一)(转)

  本文使用的软件版本 Android:4.2.2 Linux内核:3.1.10      本文及后续几篇文章将对Android的初始化(init)过程进行详细地.剥丝抽茧式地分析,并且在其中穿插了大量的知识,希望对读者了解Android的启动过程又所帮助.本章主要介绍了与硬件相关初始化文件名的确定以及属性服务的原理和实现.      Android本质上就是一个基于Linux内核的操作系统.与Ubuntu Linux.Fedora Linux类似.只是Android在应用层专门为移动设备添加了

Android的init过程详解(一)

Android的init过程(二):初始化语言(init.rc)解析 本文使用的软件版本 Android:4.2.2 Linux内核:3.1.10      本文及后续几篇文章将对Android的初始化(init)过程进行详细地.剥丝抽茧式地分析,并且在其中穿插了大量的知识,希望对读者了解Android的启动过程又所帮助.本章主要介绍了与硬件相关初始化文件名的确定以及属性服务的原理和实现.      Android本质上就是一个基于Linux内核的操作系统.与Ubuntu Linux.Fedor

转[Android]APK打包过程详解(一)

原文地址:http://jojol-zhou.iteye.com/blog/729271 如作者要求,请留言,博主可删除此博文.  这篇文章对android打包过程的每个步骤做了详细的解释,这里我给一个Maven简单版本作为概括  第一步, aapt,如果pom依赖中有apklib,将会先解压,与原文件一起产生aidl r等文件. 第二步, aidl,javac,编译, 和传统maven编译一样, 需要解决依赖, 包冲突等还有scope. 第三步, proguard,混淆,发布包需要,会把所有依

转[Android]APK打包过程详解(二)

此博文是引用自:http://jojol-zhou.iteye.com/blog/729254 jojol-zhou给予大家实际使用命令的具体例子,对于想深入研究APK是怎么打包出来的同学很有帮助,特转载在此.  [详细步骤]:  1使用aapt生成R.java类文件: 例: F:\explorer\android-sdk-windows2.2\tools>f:\explorer\android-sdk-windows2.2\platforms\android-3\tools\aapt.exe

android上传图片到PHP的过程详解_php实例

今天在做上传头像的时候,总是提交连接超时错误,报错信息如下:XXXXXXSokcetTimeOutXXXXXXXX 然后自己设置HTTP的超时时间: 复制代码 代码如下: [java] view plaincopyprint? //设置超时时间  httpclient.setTimeout(20000);  再building,runing,还是不行....这就怪了,明明好好的,怎么会突然就变成连接超时了呢!又折腾了一阵子后,也跟后台那边的朋友沟通过,他也测试了上传接口,发现没什么问题,就让我自

Android 定时任务过程详解_Android

在Android开发中,通过以下三种方法定时执行任务: 一.采用Handler与线程的sleep(long)方法(不建议使用,java的实现方式) 二.采用Handler的postDelayed(Runnable, long)方法(最简单的android实现) 三.采用Handler与timer及TimerTask结合的方法(比较多的任务时建议使用) android里有时需要定时循环执行某段代码,或者需要在某个时间点执行某段代码,这个需求大家第一时间会想到Timer对象,没错,不过我们还有更好的

基于Android实现百度地图定位过程详解_Android

一.问题描述 LBS位置服务是android应用中重要的功能,应用越来越广泛,下面我们逐步学习和实现lbs相关的应用如定位.地图.导航等,首先我们看如何基于百度地图实现定位功能 二.配置环境 1.注册密钥:地址http://developer.baidu.com/map/ 2.下载定位SDK,并导入SDK如图所示:   三.编写MyApplication类 编写MyApplication类,为了使用方便我们可以将实现定位的方法封装的Application组件中 封装下列方法 1.  获取定位信息

Android 定时任务过程详解

在Android开发中,通过以下三种方法定时执行任务: 一.采用Handler与线程的sleep(long)方法(不建议使用,java的实现方式) 二.采用Handler的postDelayed(Runnable, long)方法(最简单的android实现) 三.采用Handler与timer及TimerTask结合的方法(比较多的任务时建议使用) android里有时需要定时循环执行某段代码,或者需要在某个时间点执行某段代码,这个需求大家第一时间会想到Timer对象,没错,不过我们还有更好的

.NET配置文件解析过程详解

过程|详解 在我看来,WEB project的开发与WINFORM的开发最大的区别在于web的运行是在Framework上更高一层框架上运行,即ASP.NET框架,程序员在web下的开发可以说是黑盒开发,不是让你去定义程序入口和执行顺序,而是asp.net来调用你的各个方法,程序员做的一切都是一种受控的舞蹈.就像我们调用nunit之类的工具来测试一个dll一样,nunit是容器,是框架,执行哪个方法是由nunt来决定的.因此,也就有了页面执行周期各状态等令刚入门的程序员困惑不已的事,其实,究其根