type
status
date
slug
summary
tags
category
icon
password
基于Android 10 源码分析
之前已经大致分析了一下Android系统启动的过程,这里回顾一下:
- 上电,从Boot ROM中执行一段烧录好的代码加载bootloader
- bootloader执行,引导加载并启动linux kernel
- linux kernel启动,并创建第一个用户态的进程
init
init
进程解析init.rc
并启动各种服务,包括通过app_process
程序创建并启动Zygote进程和system server进程,这个阶段已经启动了虚拟机,进入了Java世界
- system server进程会启动各种服务,包括AMS,WMS等
- 启动完成之后,发送广播通知
这里来分析一下
init
进程的一些主要逻辑:强调一点,init就是一个普通的命令行程序,程序位置在/system/core/init
入口:system/core/init/main.cpp
main(int argc, char** argv) ,其中argc是命令行参数的个数,默认为1,argv是传入的参数,argv[0]是程序的全路径名,arg[1]才是实际意义上的第一个参数.
strcmp(s1,s2)则是用来比较字符串的,如果s1 == s2,则返回0basename(path),返回的是文件名,比如 “/system/bin/ueventd”,返回uevened
ueventd
其实就是init
进程的一个软连接,在system/bin
中也可以看到,通过ls -l
可以看到:这个地方根据程序不同的执行方式,有三种入口:
- 默认启动,执行
FirstStageMain(argc, argv)
- 启动
ueventd
程序,执行ueventd_main(argc, argv)
- 带参启动
init
,执行SubcontextMain(argc, argv, &function_map);
SetupSelinux(argv)
SecondStageMain(argc, argv)
中的一个
目前很多文章都说watchdogd进程也是init进程的软连接,但是在新版本的Android中,比如Android 10,watchdogd是一个独立的进程了,并不是init进程.
先来看下
FirstStageMain
第一阶段: FirstStageMain
源码在:
system/core/init/first_stage_init.cpp
setenv():设置环境变量mount():挂载文件系统:mknod():Linux中创建字符设备文件或者块设备文件tmpfs:一个基于内存的文件系统,断电后数据丢失0755:用户具有读/写/执行权限,组用户和其它用户具有读写权限
可以看到这个阶段主要是挂载一些文件系统.并启动SELinux.
启动SELinux
这个过程中会执行:
然后进入到init进程的第二个阶段
第二阶段:SecondStageMain
在第一阶段的源码中有一饿SecondStageMain的方法调用,这个时候会进入第二个执行阶段:
可以看到第二个阶段依次做了这些事:
- 加载init.rc配置文件
- ActionParser
- ServiceParser
- ImportParser
/system/etc/init/
: 核心系统,比如SurfaceFlinger,MediaService,logd/vendor/etc/init/
: SOC需要的核心功能和守护程序/odm/etc/init/
: 设备制造商使用,比如传感器和其他外设功能或者守护程序
这里会根据init.rc中的item类型创建对应的parser:
在加载完init.rc文件之后,会加载/{system,vendor,odm}/etc/init/ 下(Android设备中的目录)的所有rc配置文件:
- 在触发early_int 之前,配置cgroup,kptr_restrict,perf等限制资源使用的工具
Cgroup 抽象层
- 触发early init,创建一些文件目录,挂载一些文件系统等,并启动ueventd
- 触发init,修改权限并挂载binderfs,启动logd.lmkd,servicemanager,hwservicemanager,vndservicemanager等
- 挂载binderfs
- /dev/binder : 框架/应用进程之间的 IPC,使用 AIDL 接口
- /dev/hwbinder : 框架/供应商进程之间的 IPC,使用 HIDL 接口 供应商进程之间的 IPC,使用 HIDL 接口
- /dev/vndbinder : 供应商/供应商进程之间的 IPC,使用 AIDL 接口
- 启动logd,即Android的日志进程
- 启动servicemanager,hwservicemanager,vndservicemanager
- 判断启动模式,如果是充电模式,在调用charger程序
- 正常模式下启动,则挂载文件系统,并启动核心系统服务
- 启动zygote相关进程
低内存终止守护进程 (lmkd)
Android的IPC机制是通过/dev节点从用户空间访问的.一般会分配三个节点:
Android O之前,Binder服务通过servicemanager注册,Android O开始binder节点分成了三种,因此对应的servicemanager也分成了三种.
charger是关机模式下执行的程序,用于显示充电动画,可参考Android运行状况
核心服务,即那些标记
class core
的服务,比如init程序入口的ueventd:还有就是surfaceFlinger等:
late-init中会触发:
zygote_secondary是针对同时支持64位,32位架构的配置:
总结
- init入口中包含5个分支:
- ueventd : 实际上就是init程序的软连接,在init.rc的early-init阶段启动
- selinux_setup : FirstStageMain 中通过
/system/bin/init selinux_setup
启动 - subcontext : SecondStageMain 中启动
- second_stage : 在selinux_setp启动完之后执行
- fisrt_stage : 默认首先执行
- 第二个阶段,首先加载int.rc配置,然后再依次在Android设备中查找以下三种配置,并加载:
- /system/etc/init/
- /vendor/etc/init/
- /odm/etc/init/
- init.rc各个过程中会挂载文件系统,包括binderfs,创建各种文件目录,并分配权限
- 启动servce manager,Android O开始分成三种,对应三种binder节点,给不同的层使用
- 作者:姜康
- 链接:https://jiangkang.tech/article/4e1c6acc-d881-4f93-8e8b-bbe6c7ed78cf
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章