先根据上图来描述下安卓整个系统的启动流程:
当上电时,系统先执行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进程的启动
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_setupchar* 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 循环等待