Android 应用启动流程
一、前言
最近开始接触 Android APP 加固,涉及到 Android APP 启动流程,之前也没有较为系统的了解过,故记录一下。
二、开始
源自看雪的一篇文章,但篇文章中并没有文字解释。
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
第一阶段:Launcher 处理
Launcher.startActivity()
↓
ActivityTaskManager.startActivity()
↓ (Binder 跨进程)
ActivityManagerService.startActivity()
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
↓
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
第二阶段:进程创建
Process.start()
↓
ZygoteProcess.start()
↓
Zygote.fork()
↓
ActivityThread.main()
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
↓
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
第三阶段:SO 加载
LoadedApk.loadLibrary()
↓
System.loadLibrary()
↓
Runtime.loadLibrary0()
↓
DexPathList.findLibrary()
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
↓
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
第四阶段:DEX 加载
PathClassLoader.loadClass()
↓
BaseDexClassLoader.loadClass()
↓
DexPathList.findClass()
↓
DexFile.loadClassBinaryName()
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
↓
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
第五阶段:Application 创建
LoadedApk.makeApplication()
↓
Instrumentation.newApplication()
↓
Application.attach()
↓
Application.onCreate()
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
↓
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
第六阶段:Activity 启动
ActivityThread.handleLaunchActivity()
↓
ActivityThread.performLaunchActivity()
↓
Instrumentation.newActivity()
↓
Activity.onCreate()
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
↓
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
第七阶段:视图绘制
Activity.setContentView()
↓
PhoneWindow.setContentView()
↓
LayoutInflater.inflate()
↓
ViewRootImpl.performTraversals()
↓
measure() → layout() → draw()
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
下面是文字解释:
第一阶段:Launcher 处理
- 当用户点击桌面图标时,Launcher 调用
startActivity()
。 - 经过
ActivityTaskManager.startActivity()
,最终跨进程调用到系统服务ActivityManagerService.startActivity()
(AMS)。 - AMS 是 Android 应用组件的调度中心,负责决定是否需要新建进程、是否复用已有进程,并开始应用的启动流程。
第二阶段:进程创建
- 如果应用进程尚未存在,AMS 会调用
Process.start()
。 - 内部通过
ZygoteProcess.start()
与 Zygote 进程通信,请求孵化新进程。 - Zygote 作为系统中预加载了运行时和框架类的进程,会调用
fork()
复制出一个新的应用进程。 - 新进程启动后执行
ActivityThread.main()
,这是应用 Java 世界的入口点,启动主线程(UI 线程)的 Looper 消息循环。 - 通过
ActivityManagerService.attachApplication()
把自己注册到 AMS,告诉系统“我进程起来了,可以调度应用逻辑了”。
第三阶段:SO 库加载
- 在应用初始化过程中,如果代码里调用了
System.loadLibrary()
来使用 JNI,本阶段负责加载本地.so
动态库。 - 调用链路是:
LoadedApk.loadLibrary()
→System.loadLibrary()
→Runtime.loadLibrary0()
→DexPathList.findLibrary()
。 - 最终会定位到 APK 内的
lib/
目录或系统库路径,将目标.so
文件映射到进程空间。
第四阶段:DEX 加载
- 应用的 Java 代码存在于
classes.dex
中,需要被类加载器解析。 - 加载流程是:
PathClassLoader.loadClass()
→BaseDexClassLoader.loadClass()
→DexPathList.findClass()
→DexFile.loadClassBinaryName()
。 - 这一步负责把
.dex
文件里的字节码转换为虚拟机可执行的类对象(Class),并缓存到内存中。
第五阶段:Application 创建
- 系统通过
LoadedApk.makeApplication()
创建应用的Application
实例。 - 流程:
Instrumentation.newApplication()
→ 调用Application.attach()
→ 调用Application.onCreate()
。 - 注意:
Application.attachBaseContext()
会在onCreate()
之前调用,这是应用最早可以执行自定义代码的时机。很多“壳代码”或框架初始化逻辑都插在这里。
第六阶段:Activity 启动
- AMS 调用
ActivityThread.handleLaunchActivity()
,通知应用进程启动目标 Activity。 - 内部调用
performLaunchActivity()
:
通过 Instrumentation.newActivity()
创建 Activity 实例。
调用 Activity.attach()
绑定上下文和 Window。
调用生命周期方法 Activity.onCreate()
,开始执行开发者写的逻辑。
第七阶段:视图绘制
- 在 Activity 的
onCreate()
中调用setContentView()
设置布局。 - 流程:
Activity.setContentView()
→PhoneWindow.setContentView()
→LayoutInflater.inflate()
解析 XML → 生成 View 树。 - 之后由
ViewRootImpl.performTraversals()
触发三大绘制流程:
- measure() → 测量每个 View 的尺寸。
- layout() → 确定每个 View 的位置。
- draw() → 绘制到屏幕。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1621925986@qq.com