前言
Android 的系统是基于 Linux 的, 因此它的启动与 Linux 是相似的, 主要分为两个阶段
- BIOS 阶段
- BIOS 在主板的 ROM 中存储, 加电之后便会启动
- bootloader 阶段, 读取磁盘上的操作系统
- 0 号进程
- 所有进程的祖先, 这是 Linux 唯一一个没有通过 fork 或者 kernel_thread 产生的进程
- 初始化进程管理、内存管理, 初始化驱动程序 Display, Camera Driver, Binder Driver 等相关工作
- 1 号进程(init 进程)
- 为用户进程, 是所有用户态进程的祖先
- 2 号进程
- 为内核进程, 负责内核态所有进程的管理和调度, 是所有 Linux 内核进程的祖先
- 0 号进程
一. init 进程
从 Init 进程的启动主要的职责如下
- 挂载文件系统, 创建驱动目录和驱动设备文件
- 解析启动脚本
- 执行脚本指令
- 启动服务管理进程
- 启动图像渲染进程
- 启动 Zygote 进程
二. ServiceManager
ServiceManager 为服务管理进程, 我们系统的服务的 Binder 代理对象都会注册到 ServiceManager 中, 由它统一对应用进程提供
- 打开 Binder 驱动
- open: 打开 Binder 设备文件
- mmap: 初始化一个 128 kb 的缓冲区
- 注册为当前进程为 Binder 上下文的管理者
- binder_node 对象通过静态变量 binder_context_mgr_node 保存
- 将当前线程注册为 Binder Loop 线程
- 死循环通过 ioctl 从 Binder 驱动中读取数据
- 没有任务, 则阻塞在 binder_thread_read 的 wait_event_freezable_exclusive 函数上, 等待任务到来了再唤醒
- 读到任务之后, 通过 binder_parse 处理任务数据
- 死循环通过 ioctl 从 Binder 驱动中读取数据
三. SurfaceFlinger
SurfaceFlinger 进程主要负责 VSYNC 信号的分发和图层的合成
- main 函数初始化 Binder 驱动
- 启动 Binder 的 Loop 线程
- SurfaceFlinger 的创建
- DispSyncThread: 用于将 DispSync 处理好的 SW-VSYNC 分发给监听者 DisplaySyncSource
- EventThread-app: 维护了与 App 进程的 Connection 连接, 用于接收 DispSyncThread 发送的信号, 并且发送给 App 端, 会触发 Choreographer 执行 View 的绘制流程
- EventThread-sf: 维护了与 SurfaceFlinger 的 Connection, 接收到 VSYNC 后, 会调用 cb_eventReceiver 执行图层的合成操作
- EventControlThread: 用于控制硬件 Vsync 的开关
- StartPropertySetThread: 执行属性列表, 会启动 BootAnimation 进程展示开机启动动画
四. Zygote
Zygote 是在 init 进程启动过程中启动的, 主要负责进程的孵化
- SystemServer 进程
- 应用进程
启动之后会调用 app_main.cpp 的 main 函数, 主要有两个方面的初始化
- Native 层调用 AndroidRuntime::start
- 启动 ART 虚拟机
- Java 层调用 ZygoteInit 的 main 方法
- 预加载资源
- 创建 Socket
- 用于后续监听是否有 fork 请求
- 创建 SystemService 系统服务进程
- 启动死循环
- 监听 Socket 端口, 响应进程创建请求
一) SystemServer
系统服务进程是由 Zygote 进程孵化的第一个进程, 它的初始化和启动流程如下
- 创建
- 通过 Zygote.fork 创建
- 初始化
- Native 初始化
- startThreadPool 启动 Binder 驱动线程池的主线程
- 主线程的 run 方法会执行 joinThreadPool 进入一个 loop 不断的与 Binder 驱动交互
- 内核中阻塞在 binder_thread_read 上, 有工作项时唤醒
- Java 初始化
- 找到 SystemServer 的 main 函数
- Native 初始化
- 启动
- 引导服务
- 启动 ActivityManagerService
- 启动 PackageManagerService
- 核心服务
- 其他服务
- 启动 InputManagerService
- 启动 WindowManagerService
- 回调 AMS 的 systemReady
- 启动 SystemUi 服务进程, 为 App 提供通用的 UI 组件
- 状态栏 StatusBar, 通知 NotificationChannels, 最近任务列表 Recents…
- 启动 Launcher 进程
- 启动 SystemUi 服务进程, 为 App 提供通用的 UI 组件
- 进入 Looper 死循环, 保证 SystemServer 进程长久存活
- 引导服务
PKMS
1) PKMS 的启动
- 解析应用程序备份信息 package.xml/package-backup.xml
- 为应用程序分配 UserID
- 扫描应用程序安装目录
- PKMS 使用 Package 对象来描述一个已经安装的应用程序, 它会从 base.apk 中解析 AndroidManifest.xml 中四大组件的信息, 将它封装到 Pacakge 中
- 发布应用数据
- 将安装包内的 Android 四大组件发布到 PMS 的 mActivity, mServices… 集合中
2) PKMS 安装应用
我们 Android 端, 整个应用程序的安装主要有两种方式:
- 通过 Session 发起(adb, 手动点击安装)
- 提前将安装包拷贝到 “data/app/vmdl${sessionId}.tmp/” 目录下
- 再通过 Session commit, 通知 PKMS 的 PKMS.installStage 进行安装
- 通过系统的软件商店自动发起
- 直接通过 PKMS 的 PKMS.installStage 进行安装
通过 Session 拷贝安装包
- 获取 SessionId 描述一个安装任务
- 分配 SessionId
- 创建临时目录 stageDir
- “data/app/vmdl{sessionId}.tmp”
- 创建服务进程的 PackageInstallerSession 对象
- 将安装包拷贝到 “data/app/vmdl${sessionId}.tmp/PackageInstaller” 位置下暂存
- 提交安装任务
- 调用 sealAndValidateLocked 对拷贝过来的安装包进行验证
- 将 “data/app/vmdl${sessionId}.tmp/PackageInstaller” 重命名为 “data/app/vmdl${sessionId}.tmp/base.apk”
- 解压 Native 库
- 调用 PKMS.installStage 发起这次应用安装的请求
- 调用 sealAndValidateLocked 对拷贝过来的安装包进行验证
PKMS 安装应用程序
- 连接远程应用安装服务 DefaultContainerService
- 获取 IMediaContainerService 的 Binder 代理对象
- 安装应用
- 拷贝安装包
- 若是已经通过 Session 拷贝过了, 跳过拷贝的过程
- 若未拷贝, 调用了 IMediaContainerService 的 copyPackage, 在远程服务中执行 apk 拷贝操作
- 拷贝到 “data/app/vmdl${sessionId}.tmp/base.apk” 中
- 解压 Native 库文件
- 安装应用程序
- 调用了 PackageParser.Package 解析 base.apk 安装包文件
- 即将 apk 中的信息发布到 PKMS
- 解析 apk 的 dex 文件
- 调用 InstallArgs.doRename 更换目录名称
- 更名前: “data/app/vmdl${sessionId}.tmp/”
- 更名后: “data/app/${PackageName}${Base64 随机码}/”
- 优化 dex 文件
- 调用了 PackageParser.Package 解析 base.apk 安装包文件
- 拷贝安装包
IMS
IMS 的初始化
- 创建线程 InputReaderThread, 使用 InputReader 读取输入设备产生事件到 QueuedInputListener
- 创建线程 InputDispatcherThread, 使用 InputDispatcher 分发数据
IMS 与应用进程的交互
- 当应用进程通知 WMS 创建了一个窗体时, 会创建 InputChannel 输入通道组
- 创建最大缓冲为 32 kb 的 Socket
- 服务端的 InputChannel 保留 Socket 服务端的文件描述符
- 客户端的 InputChannel 保留 Socket 客户端的文件描述符
- 将服务端的新建的 WindowState 和 InputChannel 注册到 IMS 中
- InputDipatcher 将 WindowState 和 InputChannel 封装到 Connection 中用于后续的事件分发
- 客户端监听 InputChannel
- 应用进程拿到 WMS 传递过来的 InputChannel 后便会构建一个 InputChannelReceived
- InputChannelReceived 在 Native 层通过 Looper 的 epoll 监听了 InputChannel 的 Socket 端口
- 有数据写入便会通过 JNI 调用 dispatchInputEvent 分发到 Java 层
WMS
WMS 的启动流程如下
- WMS 的创建
- 在 DisplayThread 执行创建操作
- WMS.onInitReady
- 执行了 PhoneWindowManager 的初始化
- WMS.displayReady
- 初始化 RootWindowContainer 子窗体
- WMS.systemReady
- 执行了 PhoneWindowManager 的初始化
当这些服务都启动完毕之后, 会回调 AMS 的 systemReady 启动 Launcher 这个 App
二) 应用进程
1. Activity 启动
- 准备阶段
- 获取目标 Activity 的 ActivityRecord
- 不存在则创建一个
- 获取目标 Activity 所在的任务栈 ActivityStack
- 不存在则创建一个
- 获取目标 Activity 的 ActivityRecord
- 若发起方 Activity 未暂停, 则通知发起方的应用进程处理请求 Activity 的暂停
- 暂停成功之后, 通知 AMS, 继续进行目标 Activity 的启动操作
- 若目标 Activity 的进程未启动, 则先通过 Socket 请求 Zygote fork 应用进程
- 应用进程初始化阶段会启动 Binder 的 loop 线程
- ActivityThread.main 中会回调 AMS.attachApplication 继续执行后续操作
- AMS 发送请求到应用进程, 执行目标 Activity 的启动
- 构建 App 的资源包
- 优先从缓存中获取 LoadedApk
- 不存在, 则构建一个对象, 添加到缓存 mPackages 中
- 创建一个 Activity 的 Context
- 创建 ContextImpl
- 注入 Resource 资源信息
- 构建 Activity 实例
- 创建进程唯一的 Application 对象
- 创建 Resource, 并注入 Application
- 创建 ContextImpl
- 注入 Resource 资源信息
- 创建进程唯一的 Application 对象
- 让 appContext 绑定 Activity
- 为 Activity.attach 绑定参数
- 绑定 ContextImpl
- 创建 Window 和 WindowManager
- 回调 onCreate
- 构建 App 的资源包
2. Service
start
- 未启动
- 未创建进程, 则先创建进程
- 回调 onCreate, 启动服务
- 回调 onStartCommand
- 已经启动
- 直接回调 onStartCommand
- 结束服务
- 回调 onDestroy
bind
- 未启动
- 未创建进程, 则先创建进程
- 回调 onCreate, 启动服务
- AMS 调用 onBind, 获取一个 Binder 实体对象
- AMS 将 Binder 实体对象通过 Binder 驱动发送给请求方的 ServiceConnection
- 已经启动
- 直接回调 onRebind
- 结束服务
- 回调 onUnbind
- 回调 onDestroy