#############################################
本文为极度寒冰原创,转载请注明出处
#############################################
前面讲到了,我们init进程执行的话,首先执行的会是init的main函数。
那我们就先来看看init的main函数做了什么事情。
首先,我们看到init最先做的事情是创建一些文件夹,并且挂载设备,这些函数都是linux的常见函数:
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);这里,我们正好介绍一些这里涉及到的两个目录在linux系统中的作用:
/dev:dev这个目录非常的重要,这个目录里面存放了linux的所有外部设备的节点,提供了访问外部设备的接口
/proc: 用户和应用程序可以通过proc来得到系统的信息,并可以改变内核的某些参数。常用的命令比如我们前面介绍过的cat /proc/kmsg等
mount函数的作用也一起介绍一下吧:
比如这个:
mount("devpts", "/dev/pts", "devpts", 0, NULL);这个的意思就是说:将devpts挂载到/dev/pts,文件系统的类型是devpts,指定文件的读写类型是0,文件系统没有特殊的参数即为NULL,
在执行了一些根文件系统的创建和挂载之后,有一个重要的函数出现在了我们的眼前。而这个,就是我们提到的cat /proc/kmsg
来看一下:
open_devnull_stdio(); klog_init(); property_init();open_devnull_stdio()是将标准输入,标准输出以及错误输出都重定向到了/dev/_null_的设备节点。
也就是说,在android启动的这个过程中,屏蔽了stdin,stdout,stderror的操作。在这个过程中,禁止读取文件向屏幕输出等操作。
klog_init就是我们说的init的输出设备为kmsg了,我们来看一下klog_init的实现:
首先,klog_init的实现位于:system/core/libcutils/klog.c
39void klog_init(void)40{41 static const char *name = "/dev/__kmsg__";4243 if (klog_fd >= 0) return; /* Already initialized */4445 if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {46 klog_fd = open(name, O_WRONLY);47 if (klog_fd < 0)48 return;49 fcntl(klog_fd, F_SETFD, FD_CLOEXEC);50 unlink(name);51 }52}我们可以看到,这边打开了一个/dev/__kmsg__的节点,
然后调用fcntl设定init的输出设备为/dev/__kmsg__
然后会去进行如下的操作:
get_hardware_name(hardware, &revision); process_kernel_cmdline(); union selinux_callback cb; cb.func_log = log_callback; 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"); property_load_boot_defaults();这里,进行的都是linux的一些系统操作。
比如get_hardware_name,是从/proc/cpuinfo里面读取的
可以简单看一下cat /cpuinfo里面的内容:
445 hw = strstr(data, "\nHardware");446 rev = strstr(data, "\nRevision");而 cpuinfo的显示的为(笔者为nexus机器):
[email protected]:/ # cat /proc/cpuinfo Processor : ARMv7 Processor rev 2 (v7l)processor : 0BogoMIPS : 13.53processor : 1BogoMIPS : 13.53processor : 2BogoMIPS : 13.53processor : 3BogoMIPS : 13.53Features : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 CPU implementer : 0x51CPU architecture: 7CPU variant : 0x0CPU part : 0x06fCPU revision : 2Hardware : QCT APQ8064 MAKORevision : 000bSerial : 0000000000000000读取的Hardware即为MAKO的hardware
SELINUX这个,比较复杂。是美国国家安全局研究的增强型的linux,主要为了保护信息安全。
这里,自动忽略掉这个模块,因为并不阻碍我们的分析。
在执行完这些之后,接下来的函数映入眼帘估计大家会眼前一亮。因为我们看到了一个熟悉的名字,init.rc
INFO("reading config file\n"); init_parse_config_file("/init.rc");
init.rc的文件是如何被解析的呢?
我们接下来慢慢分析