Android应用程序启动流程(二)
一、前言
在上一篇文章中,我们分析了应用程序进程启动的流程。那么,在应用程序进程已启动的情况下,应用程序又是如何启动的呢?在这篇文章中,我们将从点击应用快捷图标开始,分析应用程序是如何启动的,即根Activity
是如何启动的。
二、根Activity启动流程
2.1 Launcher 请求 AMS 过程
还记得Android系统启动流程中,最后一个阶段是什么嘛?没错,是Launcher
应用程序的启动,也就是手机的桌面。它是Zygote
进程孵化的第一个APP
。在启动过程中,它会请求PackageManagerService
返回系统中已经安装的应用程序的信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上,用户可以通过点击图标来启动相应的应用程序。
当我们点击应用图标时,Launcher
的onClick
方法被调用,该方法如下
1 |
|
如果点击的时应用快捷图标,会调用onClickAppShortcut
方法,进而调用startAppShortcutOrInfoActivity
方法,获取视图对象的Intent
,然后调用startActivitySafely
方法,设置Intent
的Flag
为FLAG_ACTIVITY_NEW_TASK
,指示Android
系统通过创建一个新的任务栈来启动Activity
,之后会调用startActivity
方法,该方法如下
1 |
|
在startActivity
方法中,无论哪个分支,最终都会调用三个参数的startActivityForResult
方法,第二个参数requestCode = -1
表示Launcher
不需要知道Activity
启动的结果,第三个参数则代表Activity
启动的方式。
在三个参数的startActivityForResult
方法中,mParent
是Activity
类型的,表示当前Activity
的父类。很显然,我们要启动的应用程序的第一个Activity
(也就是根Activity
)还没有创建出来,所以调用mInstrumentation
的execStartActivity
方法,mInstrumentation
主要用来监控应用程序和系统的交互。execStartActivity
方法如下
1 |
|
先通过活动监视器检查正在启动的Activity
是否受监视或拦截,如果没有,则调用ActivityManager
的getService
方法获得AMS
的代理对象,接着调用startActivity
方法。
首先看getService
方法做了什么,该方法如下
1 |
|
getService
方法调用了IActivityManagerSingleton
的get
方法,而IActivityManagerSingleton
是一个Singleton
类,这个类中get
方法调用了create
方法。它在创建的时候重写了create
方法,通过getService
方法获取名为 “activity” 的Service
引用,也就是IBinder
类型的AMS
引用,接着将它转换成IActivityManager
类型的对象(采用的是AIDL
,IActivityManager.java
类是由AIDL
工具编译IActivityManager.aidl
时生成的)。AIDL
的作用是实现跨进程通信(IPC
),在这里是建立服务端AMS
和客户端Launcher
之间的通信。
回到Instrumentation.java
,接下来是调用startActivity
方法。
2.2 AMS 到 ApplicationThread 的调用过程
Launcher
请求AMS
后,代码逻辑进入到AMS
中, AMS
的 startActivity
方法如下
1 |
|
与 startActivity
方法相比, startActivityAsUser
方法的参数多了一个UserHandle.getCallingUserId()
,此方法用于获取调用者的UserId
。接着在startActivityAsUser
方法中,检查调用者进程是否被隔离,以及调用者权限,最后调用startActivityMayWait
方法,该方法如下
1 |
|
在startActivityMayWait
方法中,我们主要关注startActivityLocked
方法,该方法先判断了一下启动理由,然后调用startActivity
方法(怎么这么多同名方法啊!)。该方法中,调用了mService.getRecordForAppLocked(caller)
获得代表Launcher
进程的callerApp
对象,它是ProcessRecord
类型的,ProcessRecord
用于描述一个应用程序进程。参数caller
是一路传过来的,指向的是Launcher
所在的应用程序进程的AppliactionThread
对象。
同样地,ActivityRecord
用于描述一个Activity
,记录其所用信息。ActivityRecord
方法创建了用于描述将要启动的Activity
信息的对象r
,并将r
赋值给outActivity[0]
,两者作为startActivity
方法的参数传递下去。
1 |
|
startActivity
方法调用了startActivityUnchecked
方法,该方法主要是处理与Activity
栈管理相关的逻辑。在 2.1 中的 startActivitySafely
方法,里面设置Intent
的Flag
为FLAG_ACTIVITY_NEW_TASK
。所以这里会调用setTaskFromReuseOrCreateNewTask
方法,创建一个新的TaskRecord
用于描述Activity
栈。之后会调用resumeFocusedStackTopActivityLocked
方法,该方法如下
1 |
|
走到这一步,新Activity
栈已经创建好了,但是Activity
还没创建好,所以调用后一个resumeTopActivityUncheckedLocked
方法,该方法如下
1 |
|
在resumeTopActivityUncheckedLocked
方法中,根据mStackSupervisor.inResumeTopActivity
标志来防止递归调用resumeTopActivityInnerLocked
方法,之后调用resumeTopActivityInnerLocked
方法,该方法代码巨多,主要关注startSpecificActivityLocked
方法,该方法如下
1 |
|
在startSpecificActivityLocked
方法中,先通过getProcessRecordLocked
方法获得即将启动的Activity的所在的应用程序进程,接着判断得到的应用程序进程是否已经运行了,如果没有运行,则调用startProcessLocked
方法,沿着此方法继续下去,就是应用程序进程启动流程了。如果运行了,就调用realStartActivityLocked
方法,该方法如下
1 |
|
这里的app
指传入的要启动的Activity
所在的应用程序进程, app.thread
指IApplicationThread
,它的实现是ActivityThread
的内部类AppliactionThread
,这个类又是继承IApplicationThread.Stub
的。
realStartActivityLocked
方法主要是调用scheduleLaunchActivity
方法,将启动Activity
的请求发送给应用程序所在的进程。当前代码逻辑运行在AMS
所在的进程(SystemServer
进程)中,通过ApplicationThread
来与应用程序进程进行Binder
通信,即ApplicationThread
是AMS
所在的进程和应用程序进程的通信桥梁。
2.3 ActivityThread启动Activity的过程
在上一篇文章里讲过,应用程序进程创建后会运行代表主线程的实例ActivityThread
,它管理者当前应用程序进程的主线程。 scheduleLaunchActivity
方法就是在AppliactionThread
类中的,该类又是ActivityThread
的内部类。所以代码逻辑终于进入到应用程序进程中。scheduleLaunchActivity
该方法如下
1 |
|
scheduleLaunchActivity
方法将传入的参数封装成ActivityClientRecord
对象,sendMessage
方法向H
类发送类型为LAUNCH_ACTIVITY
的消息,并将ActivityClientRecord
传递过去。sendMessage
方法有多个重载方法,调用到的如下所示
1 |
|
mH
是H
类,它是ActivityThread
的内部类并继承自Handler
,是应用程序进程中主线程的消息管理类。因为ApplicationThread
是一个Binder
,它的调用逻辑运行在Binder
线程池中,所以这里需要用H
类将代码的逻辑切换到主线程中。
sendMessage
方法将消息添加到消息队列中,消息处理程序会自动从队列中取出消息并调用对应的handleMessage
方法进行处理,该方法在H
类中,如下所示
1 |
|
handleMessage
对 LAUNCH_ACTIVITY
消息的处理为:将参数obj
(也就是在scheduleLaunchActivity
方法中创建的ActivityClientRecord
)转成ActivityClientRecord
对象,通过getPackageInfoNoCheck
的方法获得LoadedApk
类型的对象并赋值给r.packageInfo
。
为什么要获取LoadedApk
呢?因为应用程序进程要启动Activity
时,需要将该Activity
所属的APK
加载进来,而LoadedApk
就是用来描述已加载的APK
文件的。
接下来调用handleLaunchActivity
方法,该方法如下
1 |
|
取消GC
操作,根据profilerInfo
决定是否启动性能分析器,然后更新配置,初始化窗口管理器,调用performLaunchActivity
方法启动Activity
,如果启动成功,则进行相应的处理,包括保存配置信息、报告Activity
尺寸配置、将Activity
的状态设置为Resume
等。如果Activity
启动失败,则通知ActivityManager
停止当前Activity
。
接下来看performLaunchActivity
方法,该方法如下
1 |
|
先做一些准备工作,比如获取Activity
的信息、获取APK
文件描述信息、获取组件名称(ComponentName
)、获取上下文环境(Context
)。然后调用mInstrumentation
的newActivity
方法,通过类加载器创建Activity
实例。
接着是调用makeApplication
方法创建应用程序对象(Application
)的实例。在 Android
中,每个应用程序都有一个全局的 Application
对象,该对象在整个应用程序的生命周期中存在,并且可以用于存储和共享应用程序的全局状态和数据。
之后是对刚创建的Activity
实例进行初始化工作,最后调用callActivityOnCreate
方法启动Activity
。该方法如下
1 |
|
关键是调用了Activity
的performCreate
方法,该方法如下
1 |
|
在performCreate
方法中会调用Activity
的实际的onCreate
方法,其具体的实现是由开发者来重写。到此,根Activity
就启动了,即应用程序启动了。
三、总结
整个流程下来非常长,感觉有点杂乱,这里简单梳理一下整个应用程序启动的流程(假设应用程序进程没有运行):
- 点击桌面的应用图标,
Launcher
进程使用Binder
与SystemServer
进程的AMS
进行跨进程通信(IPC
),发起startActivity
请求。 SystemServer
进程的AMS
接收到请求后,通过zygoteSendArgsAndGetResult
与zygote
进程进行Socket
通信,发送创建进程的请求。Zygote
进程接收请求后,通过forkAndSpecialize
方法创建应用程序进程,然后进行一系列初始化工作。- 启动了应用程序进程后,
AMS
通过ApplicationThread
来与应用程序进程进行Binder
通信,发送scheduleLaunchActivity
请求。 - 应用程序进程的
Binder
线程(ApplicationThread
)接收到请求后,通过sendMessage
方法与主线程ActivityThread
进行Handler
通信,发送LAUNCH_ACTIVITY
的消息。 - 主线程
ActivityThread
接收到消息后,通过反射机制创建目标Activity
,并回调Activity.onCreate()
等方法。到此,应用程序便正式启动,开始进入Activity
生命周期。
参考:
Android深入四大组件(一)应用程序启动过程(前篇) | BATcoder - 刘望舒 (liuwangshu.cn)
Android深入四大组件(一)应用程序启动过程(后篇) | BATcoder - 刘望舒 (liuwangshu.cn)