应用进程创建二三事

前言

"Zygote进程创建并通过ZygoteInit类初始化内部功能时,创建了ZygoteServer对象."

"然后呢?"

"runSelectLoop开启Socket循环,等待并处理消息,如ActivityManagerService要求创建应用进程命令"

  • Zygote进程交给谁轮询啊,具体怎么轮询的呀
  • 为什么runSelectLoop里有两个循环
  • 怎么取出消息呀,为什么都是从peer.get拿到的ZygoteConnection去processCommand呀,为什么不是从别的判断执行啊
  • 那外部需要创建进程时发的报文是怎么发的,是什么内容呀
  • 进程创建后为什么能到了Application#onCreate了呀

一个个来!

ZygoteServer轮询

Zygote进程创建并通过ZygoteInit类初始化内部功能时,创建了ZygoteServer对象,由该对象的runSelectLoop开启Socket循环,监听请求

while里做了什么

1. 重置状态

一定时间间隔获取USAP池相关系统属性,重置USAP池重填动作为无操作.

2. poll数据结构准备

创建poll结构数组,大小根据是否启用USAP池决定.如果USAP池启用,还获取USAP管道文件描述符

3. 填充poll数据结构

将pollIndex作为递增的数组索引,用于填充pollFDs数组,每填充一个元素后递增。这确保了所有需要监听的套接字文件描述符被正确添加到 poll结构中

填充完所有套接字描述符后,其值被保存为usapPoolEventFDIndex。这是一个重要的分界点,它标记了USAP池事件文件描述符在pollFDs数组中的位置

当USAP池启用时,pollIndex继续用于添加USAP池事件描述符和USAP管道描述符到pollFDs数组.

4. 计算poll超时时间

  • 如果没有设置触发时间戳,则返回-1,代表无限期阻塞,直到有事件发生(如收到新连接请求)
  • 如果超过延迟时间,返回0,代表不阻塞,并标记延迟重填,
  • 如果时间戳异常(时钟回调),重新设置完整延迟时间
  • 否则计算剩余等待时间,代表最多阻塞指定的毫秒数

5. 执行系统poll调用

调用底层OS的poll函数,等待文件描述符就绪.使用计算好的超时值调用系统的poll函数,这控制了Zygote进程在select循环中的阻塞行为.

6. 处理poll结果

  • 返回值为0表示超时发生,则此时标记USAP池需要延迟重填
  • 否则从后向前遍历poll结构数组,并检查USAP池状态并决定是否重填

遍历poll结构数组

处理poll结果时,pollIndex变成了一个反向迭代器。--pollIndex 使索引从数组末尾开始向前遍历

  • 优先处理新添加的事件:在数组后面的通常是最近添加的 USAP 相关文件描述符,这些可能需要优先处理
  • 安全移除元素:在处理过程中可能需要从 socketFDs 和 peers 数组中移除元素,从后向前遍历使得在移除过程中不会影响到尚未处理的元素的索引
  • 分层处理逻辑:通过判断 pollIndex 与 usapPoolEventFDIndex 的关系,可以区分是套接字事件还是 USAP 相关事件

会跳过没有POLLIN事件的描述符

  • pollIndex==0,代表Zygote服务的Socket,会接受新连接并添加到peers和socketFDs列表
  • pollIndex < usapPoolEventFDIndex,接收从ZygoteServer来的Socket内容
  • 其他值则代表是读取USAP相关文件描述符事件
接收从ZygoteServer来的Socket内容里

处理来自客户端的命令

  • 如果是子进程(fork后),这里就触发了ZygoteConnection#processCommand,并返回应该运行的命令.
  • 如果仍在服务器进程,清理已关闭的连接
  • 处理异常情况
  • 重置子进程标志

检查USAP池状态并决定是否重填

如果读取了USAP相关事件,检查当前USAP池大小:

  • 如果低于最小值,标记需要立即重填
  • 如果低于阈值,设置延迟重填触发时间戳

7. 执行USAP池重填

如果需要重填USAP池,收集所有会话套接字的原始文件描述符,根据重填类型(立即或延迟)调用fillUsapPool

  • 如果返回命令(成为USAP子进程),则返回该命令
  • 如果是优先重填但未完成,设置延迟重填时间戳继续填充

ZygoteCommand#processCommand内容

循环内容核心就是ZygoteConnection的processCommand方法,取出Socket内容后fork子进程

fork以后:

  • 父进程调用handleParentProc,通过套接字发送回PID信息

  • 子进程调用handleChildProc方法进行初始化

场景触发,创建进程

当用户点击桌面应用图标,创建Intent,最终走到ContextImpl.startActivity,请求经ActivityTaskManagerService调用ActivitManagerService的startProcessLocked.

最终在方法里判断调用Process.start方法(用于与Zygote进程通信以请求创建一个新的应用进程).

和zygote通信阶段

Process.start其实最后就是ZygoteProcess.start方法.如图:

startViaZygote方法具体步骤包括:

1. 拼接命令和参数准备发送给 Zygote

指定了targetSdkVersion,appdata文件夹等参数

2. 检测开启合适的Zygote进程打开和Zygote进程的连接

根据ABI选择合适的Zygote进程(32位或64位),检查ABI兼容性并返回适当的ZygoteState,必要时连接到次要的Zygote服务

3.发送参数并获取结果

与Zygote进程实际通信的核心部分.

携带参数通过zygoteState交互,前面提到新建进程,即子进程从Zygote进程fork出来后,会将结果告知父进程,所以能通过zygoteInputStream的readInt获取到pid.而子进程执行后续内容,就会执行到RuntimeInit的applicationInit,这就开始执行到ActivityThread.main阶段.

ActivityThread.main阶段

1. 从ActivityThread到ActivityManagerService

ActivityThread#main方法内触发ActivityThread#attach方法,并传入ActivityThread的ApplicationThread字段给到ActivityManagerService,让ActivityManagerService能操作ApplicationThread.

2. 从ActivityManagerService到ApplicationThread

ActivityManagerService将结果告知给ActivityThread

3. 从ApplicationThread到ActivityThread

ActivityManagerService将结果告知给ActivityThread的(内部H类型字段,再通过消息机制转发调用)handleBindApplication方法,创建Application对象,并触发onCreate声明周期方法.

结论

  • ZygoteServer开启了循环,使用poll阻塞的形式监听文字描述符
  • 使用了USAP池进行优化
  • 一层循环是阻塞轮询,二层是倒序pollIndex接收从ZygoteServer来的Socket内容,就会调用到ZygoteConnection#processCommand,并返回command
  • 外部发送报文在ZygoteProcess#startViaZygote方法内完成
  • Runtime#application内触发ActivityThread#main方法跟attach方法,最终创建Application对象并执行onCreate生命周期方法.

引用

xrefandroid.com/android-15....

xrefandroid.com/android-15....

xrefandroid.com/android-15....

xrefandroid.com/android-15....

xrefandroid.com/android-15....

xrefandroid.com/android-15....

xrefandroid.com/android-15....

xrefandroid.com/android-15....

xrefandroid.com/android-15....

xrefandroid.com/android-15....

xrefandroid.com/android-15....

相关推荐
阿华的代码王国几秒前
【Android】内外部存储的读写
android·内外存储的读写
inmK14 小时前
蓝奏云官方版不好用?蓝云最后一版实测:轻量化 + 不限速(避更新坑) 蓝云、蓝奏云第三方安卓版、蓝云最后一版、蓝奏云无广告管理工具、安卓网盘轻量化 APP
android·工具·网盘工具
giaoho4 小时前
Android 热点开发的相关api总结
android
咖啡の猫5 小时前
Android开发-常用布局
android·gitee
程序员老刘6 小时前
Google突然“变脸“,2026年要给全球开发者上“紧箍咒“?
android·flutter·客户端
Tans56 小时前
Androidx Lifecycle 源码阅读笔记
android·android jetpack·源码阅读
雨白6 小时前
实现双向滑动的 ScalableImageView(下)
android
峥嵘life6 小时前
Android Studio新版本编译release版本apk实现
android·ide·android studio
studyForMokey9 小时前
【Android 消息机制】Handler
android
敲代码的鱼哇9 小时前
跳转原生系统设置插件 支持安卓/iOS/鸿蒙UTS组件
android·ios·harmonyos