type
status
date
slug
summary
tags
category
icon
password
之前也写过Application启动流程之类的文章,但是总感觉这个程度不够,再来总结下.
先把脑子里那一堆忘掉,想一想要启动一个Application需要干什么:
- 需要知道app可执行文件的位置
即apk中的dex文件,或者经过dexopt优化过后的dex文件,在APK安装的时候信息已经被记录在了手机上.
- 创建app进程
Android是基于Linux的,创建进程的方式一般有两种,fork和exec,在Android中应用进程都是从zygote进程fork的.
- 进程创建了得执行一个main()入口方法,把应用跑起来
main()入口在
ActivityThread
中- Android还比较特殊,需要启动一个主界面,即Launch Activity
APK安装时已经把Activity的各种信息保存了,因此找到对应APP的Launch Activity即可
再把流程走一遍吧!
点击桌面上的App Icon
Launcher 应用中 点击APP Icon之后会调用:
Launcher中有:
最终还是会调用到
startActivity()
Activity#startActivity()
这里的
mMainThread
即是ActivityThread
,不过不是目标应用的ActivityThread.后面依次经历如下类的调用:
- Instrumentation#execStartActivity()
- ActivityTaskManagerService#startActivityAsUser()
- ActivityStartController#obtainStarter()
- ActivityStarter#startActivity() -> ActivityStarter#startActivityUnchecked()
- RootActivityContainer#resumeFocusedStacksTopActivities()
- ActivityStack#resumeTopActivityUncheckedLocked() -> ActivityStack#resumeTopActivityInnerLocked()
- ActivityStackSupervisor#startSpecificActivityLocked()
- 目标app如果有线程正在运行,则ActivityStackSupervisor#realStartActivityLocked()
- 目标app如果没有线程在运行,则会发送一个Handler Message,调用ActivityManagerInternal#startProcess()
启动app进程
从
ActivityManagerInternal#startProcess()
方法开始看:在
ActivityManagerService
中有一个内部类LocalService
就是继承的ActivityManagerInternal
,因此看一下startProcess的实现方法:到
ProcessList
中看下:这里默认是异步的方式启动进程,即在一个单独的线程中启动进程:
其实这个方法里有一个判断,即regular_zygote,app_zygote,webview_zygote.其实这三个判断,在HostingRecord中可以简单的看出来区别:
- regular_zygote,一般是各种Activity的启动时候用的
- app_zygote,一般是各种Service启动的时候用的
- webview_zygote,当然是webview用的
后面就进入了
Process
中了:这里的
USAP
就是unspecialized app process 的意思.这里分两步:
- 打开zygote 的socket 连接
对于Android而言,这里首先会尝试打开64位的zygote socket,如果失败才会尝试32位的zygote.然后返回一个连接状态ZygoteState.
不管是64位还是32位的zygote socket,过程都是一样的:
具体的连接过程看下面:
到这里已经建立起了和zygote的local socket连接.
- 通过建立的local socket 连接发送命令并且返回结果
这里发送的命令都在前面组装的
argsForZygote
中,在这里其实就是使用zygote 启动(fork) 指定的进程的命令.经历了这些步骤之后,app 进程也就创建成功了,再来看下zygote具体是如何响应fork请求的.
Zygote fork app进程
ZygoteServer和ZygoteConnection中会收到socket请求,并做对应的处理:
到Zygote中看看:
到
frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
中看看:进程fork之后,会执行下面的逻辑(ZygoteConnection.java中):
再来看一下
ZygoteInit
:这个方法里干了很多重要的事情:
- 设置异常处理的逻辑和一些崩溃日志的输出逻辑
具体的异常捕获话题就不在这里写了,偏题了.
- 找到ActivityThread的入口方法,并反射调用
到这里ActivityThread.main()就被成功执行了.
那么实际上这个返回的Runnable是谁运行的,在什么线程里运行的呢?
答案是在
ZygoteServer
的runSelectLoop
方法中会再处理一下,最后交由ZygoteInit去执行.ActivityThread.main()
最为关键的调用就是attach方法:
然后会调用到
ApplicationThread
中的bindApplication()
方法:这里会发送一个
BIND_APPLICATION
消息,Handler接收到之后会进行处理:这个过程中做了很多事,但是主要就以下这些:
- 告诉ART虚拟机一些信息,比如应用的包名,数据目录等
- 各种调试功能,Profile功能判断与设置
- 告诉虚拟机当前UI线程是敏感线程
- 硬件加速的支持
- 创建LoadedApk对象
- 创建Context对象
- 在创建Application之前,创建Instrumentation,用于监视app与系统的交互
- 创建Application对象
- 安装ContentProvider
- 利用Instrumentation执行Application#onCreate()回调
Application对象的创建
上面已经说过,会调用
LoadedAPk#makeApplication()
方法去创建Application对象:可以看到其实还是调用的Instrumentation去创建Application对象:
最后会进入到
AppComponentFactory
中利用ClassLoader去创建Application对象:到这里Application对象就创建成功了,并且调用了Application的
attach(context)
方法.attach
方法子类是不可以重写的,但是attachBaseContext
可以,这里可以看到Application还持有了LoadedApk对象.Application#onCreate()执行
在application对象
attach(context)
之后,Instrumentation会中会调用Application#onCreate()
方法:其实在调用
Application#onCreate()
之前,可以在Instrumentation
中插入一些钩子逻辑,这个在前面的代码中可以看到端倪:Instrumentation
的onCreate()
是一个空方法,可以实现自己的Instrumentation
以插入一些逻辑,以在应用代码执行前做一些特殊的处理.到这里Application就已经创建完成,并且执行了onCreate了.剩下的就是其中Launcher Activity的流程了,这篇文章源码流程已经够多了,后面单独写一篇文章梳理下Activity的启动流程吧!
总结
- Application其实也是通过ClassLoader加载的
- zygote fork出了进程,但是并不代表执行了ActivityThread的main方法
- zygote是java世界的进程,fork出 app进程之后,app进程也拥有一份拷贝数据
- Instrumentation和LoadedApk在Application的启动过程中很重要,可以利用它做很多事情
- 全局的异常捕获与处理也是在这个阶段设置的
- 堆内存的使用上限也是这个过程设置的
- Context的创建,主线程Looper等都是在这个过程中进行的
- Debug模式,Profile模式的逻辑判断也是在这个过程进行的
- zygote的通信机制:local socket + file descriptor
- 作者:姜康
- 链接:https://jiangkang.tech/article/0c62e7e9-d9fe-4dac-84bd-24e77ee5f7b0
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。