`

Android 系统启动分析(转)

阅读更多

Android 系统启动分析(转)

init进程是Android启动后系统执行的第一个名称为init的可执行程序。这个程序以一个守护进程的方式运行,它提供了以下功能:

1、init可执行程序

init 可执行文件是系统运行的第一个用户空间程序,它以守护进程的方式运行。因此这个程序的init.c文件包含main函数的入口,基本分析如下:
int main(int argc, char **argv)
{
   (省略若干。。。)
   
    umask(0);  /*对umask进行清零。*/
    
    mkdir("/dev", 0755);/*为rootfs建立必要的文件夹,并挂载适当的分区。 */
    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和/dev/kmsg节点*/
    open_devnull_stdio();
    log_init();
   
    /*解析/init.rc,将所有服务和操作信息加入链表。*/
    INFO("reading config file\n");
    parse_config_file("/init.rc");

    /*获取内核命令行参数*/
    qemu_init();
    import_kernel_cmdline(0);
    /*先从上一步获得的全局变量中获取信息硬件信息和版本号,如果没有则从/proc/cpuinfo中提取,
     *并保存到全局变量。根据硬件信息选择一个/init.(硬件).rc,并解析,将服务和操作信息加入链表。
     */
    get_hardware_name();
    snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
    parse_config_file(tmp);
    /*执行链表中带有“early-init”触发的的命令。*/
    action_for_each_trigger("early-init", action_add_queue_tail);
    drain_action_queue();
    /*遍历/sys文件夹,是内核产生设备添加事件(为了自动产生设备节点)。
     *初始化属性系统,并导入初始化属性文件。用于在系统运行过程中动态创建设备节点、删除设备节点等操作
     */
    INFO("device init\n");
    device_fd = device_init();

    property_init();
    
    // 从属性系统中得到ro.debuggable,若为1,则初始化keychord监听。
    debuggable = property_get("ro.debuggable");
    if (debuggable && !strcmp(debuggable, "1")) {
        keychord_fd = open_keychord();
    }
    /*打开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);
    /*读取/initlogo.rle(一张位图),如果成功则在/dev/graphics/fb0 显示Logo,如果失败则将/dev/tty0
     *设为TEXT模式并打开/dev/tty0,输出文本ANDROID(本人修改为Zhao Rui Jia做为启动项目的修改)。
     */
    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 ";*/
        "          z h a o R u i J i a";
        write(fd, msg, strlen(msg));
        close(fd);
    }
    }
   /* 判断cmdline 中的參數,并设置属性系统中的参数:
    *  1、 如果 bootmode为
    *     - factory,设置ro.factorytest值为1
    *     - factory2,设置ro.factorytest值为2
    *     - 其他的設ro.factorytest值為0
    *  2、如果有serialno参数,则设置ro.serialno,否则为""
    *  3、如果有bootmod参数,则设置ro.bootmod,否则为"unknown"
    *  4、如果有baseband参数,则设置ro.baseband,否则为"unknown"
    *  5、如果有carrier参数,则设置ro.carrier,否则为"unknown"
    *  6、如果有bootloader参数,则设置ro.bootloader,否则为"unknown"
    *  7、通过全局变量(前面从/proc/cpuinfo中提取的)设置ro.hardware和ro.version。
    */
    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);

    /*执行所有触发标识为init的action。*/
    
    action_for_each_trigger("init", action_add_queue_tail);
    drain_action_queue();
    property_set_fd = start_property_service();

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

    /* 确认所有初始化工作完成
     * device_fd(device init 完成)
     * property_set_fd(property server start 完成)
     * signal_recv_fd (信号机制建立) 
     */
    if ((device_fd < 0) ||
        (property_set_fd < 0) ||
        (signal_recv_fd < 0)) {
        ERROR("init startup failure\n");
        return 1;
    }

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

    /* run all property triggers based on current state of the properties */
    queue_all_property_triggers();
    drain_action_queue();

    /* enable property triggers */   
    property_triggers_enabled = 1;     
  /*
   *    注册轮询事件:
   *   - 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++;
    } else {
        ufds[3].events = 0;
        ufds[3].revents = 0;
    }

/*如果支持BOOTCHART,则初始化BOOTCHART*/

#if BOOTCHART
    bootchart_count = bootchart_init();
    if (bootchart_count < 0) {
        ERROR("bootcharting init failure\n");
    } else if (bootchart_count > 0) {
        NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
    } else {
        NOTICE("bootcharting ignored\n");
    }
#endif
  /*  
   *进入主进程循环:
   *  - 重置轮询事件的接受状态,revents为0
   *  - 查询action队列并执行。
   *  - 重启需要重启的服务
   *  - 轮询注册的事件
   *       - 如果signal_recv_fd的revents为POLLIN,则得到一个信号,获取并处理
   *       - 如果device_fd的revents为POLLIN,调用handle_device_fd
   *       - 如果property_fd的revents为POLLIN,调用handle_property_set_fd
   *       - 如果keychord_fd的revents为POLLIN,调用handle_keychord
   */ 
   for(;;) {
        int nr, i, timeout = -1;

        for (i = 0; i < fd_count; i++)
            ufds[i].revents = 0;

        drain_action_queue();
        restart_processes();

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

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

        if (ufds[2].revents == POLLIN) {
            /* we got a SIGCHLD - reap and restart as needed */
            read(signal_recv_fd, tmp, sizeof(tmp));
            while (!wait_for_one_process(0))
                ;
            continue;
        }

        if (ufds[0].revents == POLLIN)
            handle_device_fd(device_fd);

        if (ufds[1].revents == POLLIN)
            handle_property_set_fd(property_set_fd);
        if (ufds[3].revents == POLLIN)
            handle_keychord(keychord_fd);
    }

    return 0;
}

2、启动脚本init.rc

在 Android中使用启动脚本init.rc,可以在系统的初始化过程中进行一些简单的初始化操作。这个脚本被直接安装到目标系统的根文件系统中,被 init可执行程序解析。 init.rc是在init启动后被执行的启动脚本,其余发主要包含了以下内容:

Commands是一些基本的操作,例如:

    mkdir /sdcard 0000 system system
    mkdir /system
    mkdir /data 0771 system system
    mkdir /cache 0770 system cache
    mkdir /config 0500 root root
    mkdir /sqlite_stmt_journals 01777 root root
    mount tmpfs tmpfs /sqlite_stmt_journals size=4m

这些命令在init可执行程序中被解析,然后调用相关的函数来实现。 Actions(动作)表示一系列的命令,通常在Triggers(触发条件)中调用,动作和触发条件例如:

    on init
    export PATH /sbin:/system/sbin:/system/bin:/system/xbin

init表示一个触发条件,这个触发事件发生后,进行设置环境变量和建立目录的操作称为一个“动作” Services(服务)通常表示启动一个可执行程序,Options(选项)是服务的附加内容,用于配合服务使用。

service vold /system/bin/vold
    socket vold stream 0660 root mount

service bootsound /system/bin/playmp3
    user media
    group audio
    oneshot

vold和bootsound分别是两个服务的名称,/system/bin/vold和/system /bin/playmp3分别是他们所对应的可执行程序。socket、user、group、oneshot就是配合服务使用的选项。 Properties(属性)是系统中使用的一些值,可以进行设置和读取。

    setprop ro.FOREGROUND_APP_MEM 1536
    setprop ro.VISIBLE_APP_MEM 2048
    start adbd

setprop 用于设置属性,on property可以用于判断属性,这里的属性在整个Android系统运行中都是一致的。

综上如果想要修改启动过程只需要修改init.c或者init.rc里的内容即可.

参考资料

《Android 系统原理及开发要点详解》

分享到:
评论
1 楼 lattimore 2011-02-12  
没给一个原文的连接!?

相关推荐

    Android启动流程分析

    在 Android 系统中,默认的 Home 应用程序是 Launcher,它负责将安装好的应用程序展示在桌面上,本文将详细分析 Launcher 应用程序的启动过程。 在 Android 系统中,Launcher 应用程序的启动过程是由 Activity...

    Android系统源代码情景分析 / 罗升阳著

    在内容上,《Android系统源代码情景分析(含CD光盘1张)》结合使用情景,全面、深入、细致地分析了Android系统的源代码,涉及到Linux内核层、硬件抽象层(HAL)、运行时库层(Runtime)、应用程序框架层...

    android init启动分析

    Android系统的启动流程十分复杂,而`init`进程在其中扮演着至关重要的角色。本文将详细解析`init`进程的启动过程,帮助读者深入理解Android系统的核心机制。 #### 二、`init`进程概述 在Linux系统中,`init`通常是...

    Android系统启动分析.pdf

    Android系统的启动过程是一个复杂而有序的序列,涉及多个层次的组件和交互。首先,我们从系统的引导阶段开始。 1. **系统引导 (Bootloader)** Bootloader是系统启动的第一步,它的源码位于`bootable/bootloader/`...

    Android 系统启动流程源码分析

    ### Android系统启动流程源码分析 #### 一、Init 进程启动 **Init 进程**是一个由内核启动的用户级进程。当内核完成自身加载后,接下来的任务便是启动用户空间的第一个进程——`init`。此进程在Android系统中扮演...

    Android系统源代码情景分析 第3版

    《Android系统源代码情景分析 第3版》是深入理解Android操作系统内核与应用程序开发的一本重要参考资料。本书针对Java开发者,详细解读了Android系统的各个方面,包括系统架构、进程管理、内存管理、图形系统、网络...

    Android属性系统分析

    在init进程的初始化过程中,最重要的一项工作是解析init.rc文件,这是一个脚本文件,用于定义系统启动时要执行的动作和服务。此外,init进程还需负责生成设备驱动节点,处理子进程的终止事件,以及提供属性服务。 3...

    Android系统源代码分析.pdf

    7. **系统启动流程**:Android系统的启动涉及bootloader、init进程、Zygote进程等。书中会阐述这个过程中的关键步骤,以及如何调试和优化启动速度。 8. **安全机制**:Android的安全模型基于权限系统,保护用户数据...

    Android_启动过程分析

    Android系统的启动过程是一个复杂而有序的系列步骤,涵盖了硬件初始化、操作系统加载以及应用程序框架的建立。下面是详细的Android启动过程分析: 1. **Bootloader阶段**: Bootloader是设备启动时运行的第一段...

    android系统源代码分析电子书

    《Android系统源代码分析》是一本深度探讨Android操作系统内核及其组件的专业书籍,对于从事Android应用或系统开发的工程师来说,具有极高的学习价值。这本书旨在帮助开发者理解Android系统的内部工作机制,从而提升...

    Android 源码启动分析

    Android系统启动流程 当系统引导程序启动Linux内核,内核会加载各种数据结构,和驱动程序;

    android和Arm启动流程分析工具bootchart(已编译为android版本)

    2. **服务启动**:Android系统的许多服务在启动时自动运行,过度的服务启动可能导致系统资源紧张,影响用户体验。 3. **应用启动**:预置应用或用户自定义的应用启动时间也是评估启动性能的一部分,特别是一些大型...

    Android init 启动过程分析

    2. **解析`/init.rc`和`/init.%hardware%.rc`文件**:`init`进程会解析这两个配置文件,这些文件定义了在系统启动过程中需要执行的各种动作和服务。 3. **执行早期初始化动作**:根据`/init.rc`中的定义,执行一...

    android系统从systemserver开始的launcher启动详细流程.doc

    Android 系统启动流程是一个复杂的过程,从 SystemServer 开始到 Launcher 的启动涉及到多个组件和服务的协作。本文将详细介绍 Android 系统从 SystemServer 开始的 Launcher 启动流程,并对其中的关键组件和服务...

    基于Android系统的取证技术分析.pdf

    本篇文章通过对Android系统的特性的分析,介绍了Android系统漏洞及Root工具的使用,并在证据采集过程中探讨了Root工具的应用,如获取数据、恢复删除的数据、获取系统内存镜像以及绕过启动密码等问题。 首先,需要...

    《Android系统源代码情景分析》

    《Android系统源代码情景分析》随书光盘内容(源代码) 目录如下: 第1篇 初识Android系统 第1章 准备知识 1.1 Linux内核参考书籍 1.2 Android应用程序参考书籍 1.3 下载、编译和运行Android源代码 ...

    Android系统源代码情景分析-源码

    本资源"Android系统源代码情景分析-源码"旨在帮助开发者深入理解Android的工作原理,通过源码级别的学习,提升开发和调试能力。 一、Android系统架构 Android系统主要分为以下几个层次: 1. **Linux内核**:作为...

Global site tag (gtag.js) - Google Analytics