概述

Android本质上是一个基于Linux内核的开源操作系统,与我现在用的Ubuntu系统类似,但是所有的Android设备都是运行在ARM处理器(ARM源自进阶精简指令集机器,源自ARM架构)上,而像Ubuntu操作系统是x86(x86是一系列的基于intel 8086 CPU计算机微处理器指令集架构)系统。不过既然Android也是基于Linux内核的系统,那么基本的启动过程也应该符合Linux的规则。下图基本描述了当你按下电源开关后Android设备的执行步骤: Android init进程——源码分析_第1张图片
一个完整的Linux系统首先会将一个Linux内核装载到内存,也就是编译Linux内核源代码生产的bzImage文件,对于为Android优化的LInux内核源代码会生成zImage文件。该文件就是Linux内核的二进制版本。由于zImage在内核空间运行,而我们平常使用的软件都是在应用空间运行,内核空间和应用空间是不能直接通过内存地址级别访问的,所以就需要建立某种通讯机制。目前Linux有很多通讯机制可以在用户空间和内核空间之间交互,例如设备驱动文件(位于/dev目录中)、内存文件(/proc、/sys目录等)。Linux的重要特征之一就是一切都是以文件的形式存在,例如,一个设备通常与一个或多个设备文件对应。这些与内核空间交互的文件都在用户空间,所以在Linux内核装载完,需要首先建立这些文件所在的目录,而完成这些工作的程序就是init进程。在分析init的核心代码之前,可以初步了解init的主要做了如下工作:
  1. Android系统有很多属性,init提供了一个property_service(属性服务)来管理它们。
  2. 处理配置文件的命令(主要是init.rc文件),包括处理各种Action。

init进程源码

源码位于:system/core/init/目录,本文将基于Android4.4.4_r1版本进行分析。其中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));    // 将标准输入、输出、错误输出重定向到/dev/__null__。    open_devnull_stdio();    // 将init的日志输出设备设置为/dev/__kmsg__。    klog_init();    // 初始化和属性相关的资源    property_init();    get_hardware_name(hardware, &revision);        // 处理内核命令行    process_kernel_cmdline();    union selinux_callback cb;    cb.func_log = klog_write;    selinux_set_callback(SELINUX_CB_LOG, cb);    cb.func_audit = audit_callback;    selinux_set_callback(SELINUX_CB_AUDIT, cb);    selinux_initialize();    /* These directories were necessarily created before initial policy load     * and therefore need their security context restored to the proper value.     * This must happen before /dev is populated by ueventd.     */    restorecon("/dev");    restorecon("/dev/socket");    restorecon("/dev/__properties__");    restorecon_recursive("/sys");    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");        // 解析完init.rc配置文件后,会得到一系列的Action动作。    // init将动作的执行时间划分为四个阶段:early-init,init,early-boot,boot    action_for_each_trigger("early-init", action_add_queue_tail);    queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");    queue_builtin_action(keychord_init_action, "keychord_init");    queue_builtin_action(console_init_action, "console_init");    /* execute all the boot actions to get us started */    action_for_each_trigger("init", action_add_queue_tail);    /* skip mounting filesystems in charger mode */    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);    }    /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random     * wasn't ready immediately after wait_for_coldboot_done     */    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");    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;#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;}


推荐阅读链接

经过了一段时间对Android系统的学习,我发现init进程主要完成了两大块任务:

  • 解析init.rc配置文件。
  • 属性服务。


针对这两大块任务,我花费精力用Markdown语法重写了两篇文章,建议阅读:

1.Android init进程——属性服务

2.Android init进程——解析配置文件


更多相关文章

  1. Android 上传头像(文件)到服务器
  2. Android 进程保活
  3. Android代码混淆配置(Proguard文件解析)
  4. 升级Android SDK后ADT找不到adb.exe文件的解决办法
  5. 浅入浅出 Android 安全:第二章 Android Linux 内核层安全
  6. android 文件系统分析
  7. android下解析xml文件遇到中文问题
  8. Android开发5――文件读写
  9. android 获取uri的正确文件路径的办法

随机推荐

  1. Android预制APP第一次打开时不弹权限提示
  2. Android中WebView如何加载JavaScript脚本
  3. android手机两种方式获取IP地址
  4. Android(安卓)SDK下载和更新失败的解决方
  5. AndroidのUI布局之layout weight
  6. android debug
  7. include merge的使用
  8. android 设置时区
  9. Android:android studio提示adb: ADB ser
  10. 2011.08.12(2)——— android MediaPlayer