Android init源代码分析(1)概要分析

本文详细介绍了Android系统的/init进程,包括其功能概述和代码分析。内容涉及初始化Android属性系统,处理子进程,以及解析init.rc。重点解析了open_devnull_stdio(), klog_init(), property_init()等函数,同时介绍了sysfs, proc和devpts等虚拟文件系统的作用。" 136998016,8753399,C#代码判断电脑网络连接状态,"['C#', '开发语言', '网络编程']
摘要由CSDN通过智能技术生成

功能概述

init进程是Android内核启动的第一个进程,其进程号(pid)为1,是Android系统所有进程的祖先,因此它肩负着系统启动的重要责任。Android的init源代码位于system/core/init/目录下,伴随Android系统多个版本的迭代,init源代码也几经重构。
目前Android4.4源代码中,init目录编译后生成如下Android系统的三个文件,分别是
  • /init
  • /sbin/ueventd-->/init
  • /sbin/watchdogd-->/init
其中ueventd与wathdogd均是指向/init的软链接。(具体实现请阅读init/Android.mk)。
在Android系统早期版本(2.2之前)只有init进程,Android2.2中将创建设备驱动节点文件功能独立到ueventd进程完成,在Android4.1中则添加了watchdogd。

/init主要完成三大功能:
  1. 解析init.rc初始化Android属性系统,并维护属性服务
  2. 初始化Android属性系统,并维护属性服务
  3. 处理子进程启动、停止、重启动
/ueventd用于创建设备驱动节点。
/watchdogd 是看门狗服务进程。

代码分析

分析代码当先抓住主干,了解其大致结构与流程,再逐块深入,分析其实现细节。这样先大局再细节的方法可以让我们在阅读代码时保持头脑的清醒,切忌不可在没有对整体流程了解的情况下深入细节,那很容易导致我们迷失在代码森林中。
接下来分析init.c的main函数。为了方便分析,将main函数代码做了精简,代码如下。
int main(int argc, char **argv)
{
    //<part 1>
    if (!strcmp(basename(argv[0]), "ueventd"))
        return ueventd_main(argc, argv);
    if (!strcmp(basename(argv[0]), "watchdogd"))
        return watchdogd_main(argc, argv);
   
    //<part2>
    umask(0);
    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);
    ....
    open_devnull_stdio();
    klog_init();
    property_init();
    ....
    //<part3>
    INFO("reading config file\n");
    init_parse_config_file("/init.rc");
    ...
    action_for_each_trigger("early-init", action_add_queue_tail);
    ....
    queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
   
    //<part4>
    for(;;) {
        ...
        execute_one_command();
        restart_processes();
        ....
        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;
}
将main函数分为上述4个部分,对应part1到part4,下面分别做具体说明。

代码<part1>

通过命令行判断argv[0]的字符串内容,来区分当前程序是init,ueventd或是watchdogd。
C程序的main函数原型为 main(int argc, char* argv[]), ueventd以及watchdogd的启动都在init.rc中描述,由init进程解析后执行fork、exec启动,因此其入口参数的构造在init代码中,将在init.rc解析时分析。此时我们只需要直到argv[0]中将存储可执行文件的名字。

代码<part2>

umaks(0)用于设定当前进程(即/init)的文件模型创建掩码(file mode creation mask),注意这里的文件是广泛意义上的文件,包括普通文件、目录、链接文件、设备节点等。
PS. 以上解释摘自umask的mannual,可在linux系统中执行man 3 umask查看。
Linux C库中mkdir与open的函数运行如下。
int mkdir(const char *pathname, mode_t mode);
int open(const char *pathname, int flags, mode_t mode);
Linux内核给每一个进程都设定了一个掩码,当程序调用op
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值