先根据上图来描述下安卓整个系统的启动流程:
当上电时,系统先执行BootRom, 加载引导程序执行。
然后进入bootloader,在安卓系统中基本上这个bootloader是uboot, 通过uboot引导启动内核,此时运行在kernel空间,这时的idle属于内核中的进程,它的pid = 0,它负责初始化进程、内存、驱动等相关工作,随后由idle启动fork一个为init进程,这个属于用户空间的进程,pid = 1,然后再fork创建pid=2的kthreadd内核进程,这个是内核进程的鼻祖。init进程则是用户空间的鼻祖,应用空间的所有进程要么直接或间接都是由init进程创建的。
比如init会fork()创建zygote, 这个进程则是java进程的所有鼻祖,所有的java app均来自于zygote进程的fork操作,比如安卓非常重要的系统进程服务SystemServer也是由zygote孵化而来,SystemServer是zygote进程的大儿子,SystemServer进程被创建启动之后,将会创建系统所需要的各种Services, 如ActivityManagerService, WindowManagerService, PackageManagerServices等等,安卓系统中一共大约有90+种服务,均由SystemServer创建生成,因此所有的系统Service服务它们都属于SystemServer进程。
而app的启动过程,则是通过AMS通过发送socket消息给zygote进程,由zygote进程fork()创建这个app进程。
init进程的程序可执行源文件位于/system/bin/init中,前面的流程图可知init进程是由内核的idle进程启动的,先来看看内核中启动init进程的部分源码:
/kernel/common/init/main.c -->kernel_init():
-->try_to_run_init_process("/bin/init"); //启动init进程。
-->run_init_process("/bin/init");
-->kernel_execve("/bin/init"); //还是熟悉的味道与配方
init的入口函数是main.cpp文件的main函数,下面是真正的init的启动流程:
main():
//第一阶段重要工作:
//1挂载文件系统,创建文件
//2重定向输入输出,重定向内核日志
//3启动selinux_setup
-->第一阶段:FirstStageMain(argc, argv);
-->mount("tmpfs","dev","tmpfs"); //挂载虚拟文件系统
mount("devpts","/dev/pts", "devpts",0,NULL)
mount("proc", "/proc",..);
mount("sysfs","/sys","sysfs");
mount("selinuxfs",...);
mount("tmpfs","/mnt")
//创建一些设备结点
mknod("/dev/kmsg");
mknod("/dev/null");
SetStdioToDevNULL();
InitKernelLogging(); //日志重定向
DoFirstStageMount(); //挂载一些重要的分区设备
//启动selinux_setup
char* args[]={path, "selinux_setup"};
execv(path, args);//参数传递进去继续执行。
进入第二阶段:main()->SetupSelinux(argv):创建Selinux android强制访问机制
-->SetStdioToDevNull(); //日志重定向
InitKernelLogging();
SelinuxSetupKernelLogging();
SelinuxInitialize(); //linux安全策略初始化
//Android --权限 用selinux最小权限原则来处理。
char* args[]={path, "second_stage"};
execv(path, args);//参数传递进去继续执行,进入第三阶段
进入第三阶段:main()->SecondStageMain(argc, argv);
-->SetStdioToDevNULL();
InitKernelLogging(); //日志重定向
PropertyInit(); //属性域初始化
-->PropertyLoadBootDefaults();
SelinuxSetupKernelLogging();
SelabelInitialize();
SelinuxRestoreContext();//恢复安全上下文
//处理子进程的终止信号--防止僵尸进程
Epoll epoll;
InstallSignalFdHandler(&epoll);
InstallInitNotifier(&epoll)
StartPropertyService(&property_fd);//启动属性服务
GetBuiltinFunctionMap();//命令与函数映射:如将mkdir命令-->mkdir函数匹配
LoadBootScripts(am,sm); //解析init.rc文件
while(1){ //进入while循环
am.ExecuteOneCommand(); //执行解析出来的action里的指令
auto pending_functions = epoll.Wait(epull_time);//等待
}
下面看看LoadBootScripts它是如何进行init.rc文件的解析流程的:
LoadBootScripts(am,sm); //解析init.rc文件
//创建解析器,action_manager结构可以保存所有的action列表
//service_list:保存解析init.rc中的所有服务。
-->Parser parser = CreateParser(action_manager, service_list);
-->parser.AddSectionParser("service"); //service解析器
parser.AddSectionParser("on"); //on解析器
parser.AddSectionParser("import");//import解析器
parser.ParseConfig("/system/etc/init/hw/init.rc");//解析init.rc
-->ParseConfigFile(path);
-->ParseData(path, &config_contents.value());//具体的解析过程在里面,
init进程的重要处理事务:
1 挂载文件
2 设置selinux --安全策略
3 开启属性服务,注册到epoll中
4 解析init.rc文件
5 执行循环处理脚本 --启动ServiceManager zygote等
6 循环等待