android启动之init进程详解

来源:互联网 发布:g3网络推广 编辑:程序博客网 时间:2024/05/01 16:02

Android系统的初始化过程是init进程开始的。它在加载linux基本内核后就开始运行。那么系统怎么样知道它应该加载init进程呢?原来是从android加载linux内核时,就设置了下面的参数:

Kernelcommand line: noinitrd root=/dev/nfs console=ttySAC0 init=/initnfsroot=192.168.1.103:/nfsbootip=192.168.1.20:192.168.1.103:192.168.1.1:255.255.255.0::eth0:on

在这行命令里,就是告诉linux内核初始化完成后开始运行init进程,由于init进程就是放在系统根目录下面。而这个进程的代码,就是位于源码的目录system/core/init下面。init是一个进程,确切的说,它是Linux系统中用户空间的第一个进程,由于Android是基于Linux内核的,所以init也是Android系统空间中的第一个进程,它的进程号是1.作为天字第一号进程,它被赋予了很重要的职责。

1.负责创建系统中的几个关键进程,尤其是zygote,它是Java世界的开创者。
2.Android系统中有很多属性,它维护了一个属性空间,那么这个属性空间在何时创建,怎么样管理?这是init提供的property service来完成的。
3.Android中有很多服务,比如adbd、vold、media、dbus等,这些服务如何启动,如何管理,其生存周期是如何的?servicemanager充当了什么角色?这些在init中你会得到些答案。
……
走进init的main函数,你很快会发现,init首先做了一件很重要的,奠定全局基调的事情,就是解析配置文件init.rc,位于system/core/rootdir/init.rc。
parse_config_file("init.rc");

/*..............init.rc...................*/

on init

sysclktz 0

loglevel 3

# setup the global environment
export PATH /sbin:/system/sbin:/system/bin:/system/xbin
export LD_LIBRARY_PATH /system/lib
export ANDROID_BOOTLOGO 1
...
on property:persist.service.adb.enable=1
start adbd

on property:persist.service.adb.enable=0
stop adbd

service servicemanager /system/bin/servicemanager
user system
critical
onrestart restart zygote
onrestart restart media

service vold /system/bin/vold
socket vold stream 0660 root mount
ioprio be 2

service netd /system/bin/netd
socket netd stream 0660 root system
...

/*..................init.rc........................*/

这里不贴解析文件的代码,可是当细细分析代码之后,我不禁对写这个解析文件的程序员心生景仰。
真是解析的太完美了,说不上哪里好,可是就是很折服,只可意会也.......

前面说过解析这个文件是奠定全局基调的,没有它,android一事无成。的确是这样!
先简单说下这个配置文件:

文件中有些行是以on、#或者service开头的,其中#开头的是注释,不多说。以on或service开头的称为一个section,
每个section下面会紧跟一行或者很多行,这些行的开头第一个单词都是这个section的一些command或者option,command或者
options后面的是一些参数。更进一步来说,开头为on的section下面的都是一些command,也就是一些要执行的动作命令。
service section下面的是一些options,这些options是设置这个服务的相关信息的,当然有些options后面的参数可能是一个command

android维护了三个双向链表,分别是action_list、service_list、action_queue.action_list存放的是所有要执行的动作,
service_list存放的是所有待启动的服务,action_queue存放的是即将执行的动作。

解析函数在解析每一个section的时候,如果是on的,就表明是一个action,则把这个action加入action_list中,比如init、boot都是action,而这个action下面会跟着很多的command,解析函数会把这个action下面的所有command链成一个双向链表,保存在action结构体的commands成员中。如果是service,表明是一个服务,则把这个service加入service_list中,这个service下面有很多options,解析函数会根据这些不同的option执行不同的动作,对服务的信息进行设置,其中包括设置环境信息,创建套接字,设置重启标记等等。

解析完init.rc之后,两个链表中已经保存了所有要执行的动作和要启动的服务了。

在讲android什么时候执行这些动作之前得先知道,android的init把这些动作执行的时间分为四个阶段:early-init、init、early-boot、boot。注意,这里说的执行动作仅仅是action,不涉及service(后面会讲到service的启动其实是在这些action中的某一个command中启动的)。

这时候init调用action_for_each_trigger(ACTIONNAME,action_add_queue_tail);把ACTIONNAME阶段的要执行的command添加到action_queue中,以执行。其中ACTIONNAME就是上面所说的四个阶段中的一个,顾名思义,得先执行early-init中的command。这里加个小插曲:分析完整个配置文件后,其实没发现存在early-init和early-boot阶段,可能这是允许在以后的开发中如果需要在init阶段之前添加些动作的话,就直接修改配置文件就行了。这就为我们自由选择启动项或者个性化开机动作提供了接口。

然后调用drain_aciton_queue执行action_queue里面的commands。综观配置文件,这些执行的动作主要有设置环境变量、创建文件目录、挂载文件系统、设置系统属性、设置某些文件目录的属性等。

接下来init得初始化设备文件、属性空间、/dev/keychord设备,然后加载开机动画文件,然后设置一些系统只读属性。

完了之后,init要启动属性服务器,这个属性服务器的作用就是允许客户端通过与之交互来设置属性或者查看属性,这也是唯一的方法。

说了这么多好像还没启动service,其实所有service是在boot阶段中的一个命令中启动的

/* class_start default */

这个命令执行的动作是启动所有classname为default的服务,其实在启动的时候,所有的服务都是default的,这时候就会把service_list中所有classname为default的服务启动,zygote当然也不例外。但是有些服务由于标记了disable性质,所以它不随着这样的类启动而启动,这些服务的启动是另外的时机了。

在所有动作都执行完毕之后,init进入一个死循环,在循环中检测哪些死去的服务需要重启并重启之。
init开始监听来自四方面的消息:监听来自内核的Uevent事、来自属性服务器的事件、来自子进程或者其他进程发来的信号、来自keychord设备事件。对每一种消息调用不同函数处理接收到的消息。

至此,init函数启动完毕,具体init如何处理接收到的各种消息,zygote死后如何重启,android启动完init之后,再执行什么样的动作,启动流程往何处去?且听下回分解。。。。

仅是个人理解,欢迎指正:-D

原创粉丝点击