Android - Activity 启动过程
概述
从点击桌面应用图标到应用显示的过程我们再熟悉不过了,下面我们来分析下这个过程都做了什么。
本文主要对以下问题分析:
- ActivityThread 是什么,它是一个线程吗,如何被启动的?
- ActivityClientRecord 与 ActivityRecord 是什么?
- Context 是什么,ContextImpl,ContextWapper 是什么?
- Instrumentation 是什么?
- Application 是什么,什么时候创建的,每个应用程序有几个 Application?
- 点击 Launcher 启动 Activity 和应用内部启动 Activity 的区别?
- Activity 启动过程,onCreate(),onResume() 回调时机及具体作用?
Launcher
如不了解 Android 是如何从开机到 Launcher 启动的过程,请先阅读Android - 系统启动过程。
我们知道 Android 系统启动后已经启动了 Zygote,ServiceManager,SystemServer 等系统进程;ServiceManager 进程中完成了 Binder 初始化;SystemServer 进程中 ActivityManagerService,WindowManagerService,PackageManagerService 等系统服务在 ServiceManager 中已经注册;最后启动了 Launcher 桌面应用。
其实 Launcher 本身就是一个应用程序,运行在自己的进程中,我们看到的桌面就是 Launcher 中的一个 Activity。
应用安装的时候,通过 PackageManagerService 解析 apk 的 AndroidManifest.xml 文件,提取出这个 apk 的信息写入到 packages.xml 文件中,这些信息包括:权限、应用包名、icon、apk 的安装位置、版本、userID 等等。packages.xml 文件位于系统目录下/data/system/packages.xml。
同时桌面 Launcher 会为安装过的应用生成不同的应用入口,对应桌面上的应用图标,下面分析点击应用图标的到应用启动的过程。
点击 Launcher 中应用图标
点击 Launcher 中应用图标将会执行以下方法
1 | Launcher.startActivitySafely() |
在 system_server 进程中的服务端 ActivityManagerService 收到 START_ACTIVITY_TRANSACTION 命令后进行处理,调用 startActivity() 方法。
1 | ActivityManagerService.startActivity() -> startActivityAsUser(intent, requestCode, userId) |
fork 新进程
从 Launcher 点击图标,如果应用没有启动过,则会 fork 一个新进程。创建新进程的时候,ActivityManagerService 会保存一个 ProcessRecord 信息,Activity 应用程序中的AndroidManifest.xml 配置文件中,我们没有指定 Application 标签的 process 属性,系统就会默认使用 package 的名称。每一个应用程序都有自己的 uid,因此,这里 uid + process 的组合就可以为每一个应用程序创建一个 ProcessRecord。每次在新建新进程前的时候会先判断这个 ProcessRecord 是否已存在,如果已经存在就不会新建进程了,这就属于应用内打开 Activity 的过程了。
1 | ActivityManagerService.startProcessLocked() |
进程创建成功切换至 App 进程,进入 app 进程后将 ActivityThread 类加载到新进程,并调用 ActivityThread.main() 方法
1 | ActivityThread.main() |
此时只创建了应用程序的 ActivityThread 和 ApplicationThread,和开启了 Handler 消息循环机制,其他的都还未创建, ActivityThread.attach(false) 又会最终到 ActivityMangerService 的 attachApplication,这个工程其实是将本地的 ApplicationThread 传递到 ActivityMangerService。然后 ActivityMangerService 就可以通过 ApplicationThread 的代理 ApplicationThreadProxy 来调用应用程序 ApplicationThread.bindApplication,通知应用程序的 ApplicationThread 已和 ActivityMangerService 绑定,可以不借助其他进程帮助直接通信了。此时 Launcher 的任务也算是完成了。
在 system_server 进程中的服务端 ActivityManagerService 收到 ATTACH_APPLICATION_TRANSACTION 命令后进行处理,调用 attachApplication()。
1 | ActivityMangerService.attachApplication() -> attachApplicationLocked() |
- Activity: 检查最顶层可见的 Activity 是否等待在该进程中运行,调用 ActivityStackSupervisor.attachApplicationLocked()。
- Service:寻找所有需要在该进程中运行的服务,调用 ActiveServices.attachApplicationLocked()。
- Broadcast:检查是否在这个进程中有下一个广播接收者,调用 sendPendingBroadcastsLocked()。
此处讨论 Activity 的启动过程,只讨论 ActivityStackSupervisor.attachApplicationLocked() 方法。
1 | ActivityStackSupervisor.attachApplicationLocked() -> realStartActivityLocked() |
发送送完 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令,还会发送 BIND_APPLICATION_TRANSACTION 命令来创建 Application。
1 | ApplicationThreadProxy.bindApplication() |
App 进程初始化
在 app 进程中,收到 BIND_APPLICATION_TRANSACTION 命令后调用 ActivityThread.bindApplication()。
1 | ActivityThread.bindApplication() |
ApplicationThreadProxy.bindApplication(…) 会传来这个应用的一些信息,如ApplicationInfo,Configuration 等,在 ApplicationThread.bindApplication 里会待信息封装成A ppBindData,通过
1 | sendMessage(H.BIND_APPLICATION, data) |
将信息放到应用里的消息队列里,通过 Handler 消息机制,在 ActivityThread.handleMeaasge 里处理 H.BIND_APPLICATION 的信息,调用 AplicationThread.handleBindApplication。
1 | handleBindApplication(AppBindData data) { |
Instrumentation:
1 | public Application newApplication(ClassLoader cl, String className, Context context) { |
这时 Application 就创建好了,这点很重要,很多资料里说 Application 是在performLaunchActivity() 里创建的,因为 performLaunchActivity() 也有mInstrumentation.newApplication 这个调用,newApplication() 函数中可看出会先判断是否以及创建了 Application,如果之前已经创建,就返回已创建的 Application 对象。
Activity 启动
上面 fork 进程时会发送 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令,在 app 进程中,收到 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令后调用 ApplicationThread.scheduleLaunchActivity()。
1 | ApplicationThread.scheduleLaunchActivity() |
与 Window 进行关联,具体过程详见:Activity,Window,View 之间的关系
总结
Activity 的整体启动流程如图所示:
- ActivityThread 是什么,它是一个线程吗,如何被启动的?
它不是一个线程,它是运行在 App 进程中的主线程中的一个方法中。当 App 进程创建时会执行 ActivityThread.main(),ActivityThread.main() 首先会创建 Looper 执行 Looper.prepareMainLooper();然后创建 ActivityThread 并调用 ActivityThread.attach() 方法告诉 ActivityManagerService 我们创建了一个应用 并将 ApplicationThread 传给 ActivityManagerService;最后调用 Looper.loop()。
- ActivityClientRecord 与 ActivityRecord 是什么?
记录 Activity 相关信息,比如:Window,configuration,ActivityInfo 等。
ActivityClientRecord 是客户端的,ActivityRecord 是 ActivityManagerService 服务端的。
- Context 是什么,ContextImpl,ContextWapper 是什么?
Context 定义了 App 进程的相关环境,Context 是一个接口,ContextImpl 是子类,ContextWapper 是具体实现。
应用资源是在 Application 初始化的时候,也就是创建 Application,ContextImpl 的时候,ContextImpl 就包含这个路径,主要就是对就是 ResourcesManager 这个单例的引用。
可以看出每次创建 Application 和 Acitvity 以及 Service 时就会有一个 ContextImpl 实例,ContentProvider 和B roadcastReceiver 的 Context 是其他地方传入的。
所以 Context 数量 = Application 数量 + Activity 数量 + Service 数量,单进程情况下 Application 数量就是 1。
- Instrumentation 是什么?
管理着组件 Application,Activity,Service 等的创建,生命周期调用。
- Application 是什么,什么时候创建的,每个应用程序有几个 Application?
Application 是在 ActivityThread.handleBindApplication() 中创建的,一个进程只会创建一个 Application,但是一个应用如果有多个进程就会创建多个 Application 对象。
- 点击 Launcher 启动 Activity 和应用内部启动 Activity 的区别?
点击 Launcher 时会创建一个新进程来开启 Activity,而应用内打开 Activity,如果 Activity 不指定新进程,将在原来进程打开,是否开启新进程实在 ActivityManagerService 进行控制的,上面分析得到,每次开启新进程时会保存进程信息,默认为 应用包名 + 应用UID,打开 Activity 时会检查请求方的信息来判断是否需要新开进程。Launcher 打开 Activity 默认 ACTIVITY_NEW_TASK,新开一个 Activity 栈来保存 Activity 的信息。
- Activity 启动过程,onCreate(),onResume() 回调时机及具体作用?
Activity.onCreate() 完成了 App 进程,Application,Activity 的创建,调用 setContentView() 给 Activity 设置了 layout 布局。
Activity.onResume() 完成了 Activity 中 Window 与 WindowManager 的关联,并对所有子 View 进行渲染并显示。
参考资料
- startActivity启动过程分析
- Android应用程序的Activity启动过程简要介绍和学习计划
- Android 应用点击图标到Activity界面显示的过程分析
- 《深入理解 Android 内核设计思想》