一个专注音视频领域问答的小圈子

在如下三篇文章中过了一遍 Launcher 启动 Activity 的代码流程。

然而, 即使看过了多遍代码流程依旧有点云里雾里的感觉。不从整体上来把握,光抓住细节代码会始终不得要领。

由于是从 Launcher 组件启动一个 Activity 组件,其中还需要与 ActivityManagerService 通信,而这三个部分都是位于不同的进程内,涉及进程间通信,因此可以将整个过程划分为三个不同的部分来分析,在 Launcher 进程内的操作,在 ActivityManagerService 进程内的操作,在创建的应用程序进程内的操作。

Launcher 进程内的操作

在 Launcher 进程内执行函数:

  • Launcher . startActivitySafely(View v, Intent intent, Object tag)

  • Launcher . startActivity(View v, Intent intent, Object tag)

  • Activity . startActivity(Intent intent, @Nullable Bundle options)

  • Activity . startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options)

  • Instrumentation . execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options)

  • ActivityManagerProxy . startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options)

Launcher 进程这部分执行的操作主要就是 委托ActivityManagerService 去启动一个 Activity 组件,把这个 Activity 组件的 Intent信息传递过去,把自己的包名信息传递过去,还把自己的本地 Binder 对象 ApplicationThread传递过去,以便 ActivityManagerService 可以通过它来联系到 Launcher 组件。

毕竟,当 ActivityManagerService 要去创建新的 Activity 组件时,首先得让之前的 Activity 组件进入 Paused状态。

Launcher 组件的运行流程从startActivitySafelystartActivity,再从 Activity 类的startActivitystartActivityForResult,最后通过 Instrumentation类的execStartActivity方法得到 ActivityManagerService 的代理对象 ActivityManagerProxy来执行startActivity。成功地把 Activity 组件启动的任务交给了 ActivityManagerService 去完成。

ActivityManagerService 进程

在 Launcher 进程内执行函数:

  • ActivityManagerService . startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options)

  • ActivityManagerService . startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId)

  • ActivityStackSupervisor . startActivityMayWait(…)

  • ActivityStackSupervisor . startActivityLocked( …)

  • ActivityStackSupervisor . startActivityUncheckedLocked( …)

  • ActivityStack . startActivityLocked(ActivityRecord r, boolean newTask, boolean doResume, boolean keepCurTransition, Bundle options)

  • ActivityStackSupervisor . resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, Bundle targetOptions)

  • ActivityStack . resumeTopActivityLocked(ActivityRecord prev, Bundle options)

  • ActivityStack . resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options)

  • ActivityStackSupervisor . startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig)

ActivityManagerService 响应跨进程调用执行startActivity方法,方法内执行startActivityAsUser方法。

接着执行startActivityMayWait方法,首先通过 PackageManager解析待启动 Activity 的 Intent 信息,得到了包含更多信息的 ActivityInfo对象。

接着开始执行startActivityLocked方法,创建一个待启动的 Activity 组件的 ActivityRecord对象,里面包含了相关信息。在接下来的方法startActivityUncheckedLocked中为待启动的 Activity 组件找到它的 Task 任务,由于是新建的 Activity,则直接创建了一个新的 Task。而这个 Task也是 ActivityRecord的成员变量task。由这个 TaskRecord得到它的成员变量ActivityStack ,管理 Activity 的堆栈。

接下来便执行 ActivityStack类的startActivityLocked方法, 首先将待启动的 ActivityRecord 位于栈顶,然后执行 resumeTopActivitiesLocked方法,将所有 ActivityStack 栈顶的 ActivityRecord 运行至 Resumed 状态,其中都是调用的resumeTopActivityLocked方法,而该方法内部又是调用的resumeTopActivityInnerLocked方法,该方法会做一系列的判断,判断当年能够将 ActivityStack 栈顶的 Activity 运行至 Resumed状态,比如:当有 Activity 没有进入 Paused 状态时,便会通过跨进程通信来通知它进入 Paused 状态。当所有的状态都满足了,准备就绪了,就会去检查应用程序进程是否启动了,如果没有则去创建进程,否则让 Activity 组件运行至 Resumed 状态。

ActivityManagerService 创建应用程序进程

  • ActivityStackSupervisor . startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig)

  • ActivityManagerService . startProcessLocked(…)

  • ActivityManagerService . newProcessRecordLocked(ApplicationInfo info, String customProcess, boolean isolated, int isolatedUid)

  • ActivityManagerService . startProcessLocked(…)

startSpecificActivityLocked方法会创建应用程序进程,在 startProcessLocked方法内部根据进程名称和用户 ID 检查应用程序是否存在,不存在,则调用了newProcessRecordLocked方法创建了一个ProcessRecord对象,它包含了进程的基本信息,根据这个 ProcessRecord对象,在startProcessLocked函数的另一形式中去创建了应用程序进程。

当应用程序进程创建成功后,会得到一个大于 0 的进程 ID ,而 ActivityManagerService 就以这个 ID 为关键字将这个进程对应的 ProcessRecord 保存在变量mPidsSelfLocked中,以便 ActivityManagerService 可以根据这个 ID 找到该进程的记录信息。

当进程创建成功后,便会开始运行了,而 Java 程序的入口就是 main函数了。

Activity 应用程序进程启动

  • ActivityThread . main(…)

  • ActivityThread . attach(boolean system)

  • ActivityManagerService . attachApplication(IApplicationThread thread)

  • ActivityManagerService . attachApplicationLocked(IApplicationThread thread, int pid)

  • ApplicationThread . bindApplication(…)

  • ActivityThread . handleBindApplication(AppBindData data)

  • StackSupervisor . attachApplicationLocked(ProcessRecord app)

  • StackSupervisor . realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig)

  • ApplicationThread . scheduleLaunchActivity(…)

  • ActivityThread . handleLaunchActivity(ActivityClientRecord r, Intent customIntent)

  • ActivityThread . performLaunchActivity(ActivityClientRecord r, Intent customIntent)

  • ActivityThread . handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume)

  • ActivityThread . performResumeActivity(IBinder token, boolean clearHide)

由于 Process 类的 start 方法指定了 ActivityThread 类的 main 方法作为一个进程的开始点,跟进 main 方法,初始化线程消息循环,并且在 attach方法中向 ActivityManagerService 跨进程发送请求,要求 ActivityManagerService 将当前进程添加 Application ,毕竟这还是个单纯的进程,并不是 Android 进程。

于是 ActivityManagerService 执行了 attachApplication方法响应这个跨进程请求,接着又继续调用了 attachApplicationLocked方法,从mPidsSelfLocked变量中根据 PID 找到 Activity 应用程序进程对应的 ProcessRecord 。然后将ProcessRecord绑定到应用进程,将ApplicationThread赋值给ProcessRecord的成员变量thread,这样就能 ActivityManagerService 就能通过它来和 Activity 通信了。

接下来 ActivityManagerService 又发起跨进程调用,通过 ApplicationThreadbindApplication方法。ActivityThread 主线程消息循环收到 Handler 发送的消息,响应方法为handleBindApplication。在此方法内,创建了Application 运行环境上下文Context、监控程序与系统交互的Instrumentation、应用程序的Application、并且调用了Application的 onCreate 方法。

当 ActivityManagerService 将 Activity 的 Application 创建完成后,又开始调度 Activity 的生命周期了。通过 StackSupervisor 类的 attachApplicationLocked方法,找到位于栈顶的 ActivityRecord对象,检查这个 Activity 组件的用户 ID 和进程名是否与 ProcessRecord 对象所描述的一致,如果一致,则调用realStartActivityLocked真正的开启一个 Activity 组件了。

开启一个 Activity 组件的生命周期当然是在应用程序进程内了,此时又是 ActivityManagerService 的跨进程通信,执行 ApplicationThread 的 scheduleLaunchActivity,ActivityThread 的消息循环响应方法为 handleLaunchActivity。在该方法内又继续执行 performLaunchActivity将 Activity 组件启动起来。通过反射创建了一个 Activity 对象,并且创建了 Activity 的运行环境上下文,通过 Instrumentation 执行了 Activity 的 onCreate 方法、onStart 方法。接着又执行了handleResumeActivity方法让 Activity 运行到 Resumed状态,真正执行操作的是performResumeActivity方法,而最终还是调用 Instrumentation类的callActivityOnResume方法。

至此,一个 Activity 组件就已经创建成功了,里面具体的代码细节暂不深入讨论了,比如 Activity 的加载之类的。

知识星球

一个专注音视频领域问答的小圈子

公众号音视频开发进阶对应的知识星球,一个编程开发领域的专业圈子,贩卖知识和技巧!

※ 入群须知:了解该星球能提供的价值和帮助,在提问时务必阐述好背景,附带相关的信息。

iOS 用户可以加我微信 ezglumes 邀请你进星球,有疑问也可以加我微信咨询。

※ 星球内容:

基础教程:

在知识星球连载的干货教程,可以在专栏中找到,随着时间的推移,教程也会越来越多:

- 音视频基础概念
- WebRTC 入门教程及源码实践
- 播放器教程及源码实践
- OpenGL 和特效开发教程
- Vulkan 入门教程

部分内容可以在博客 https://glumes.com 中检索到,后面会在星球里持续更新.

干货分享:

涵盖了移动开发和音视频工程领域的绝大部分,从项目实战角度出发,提升能力,包括但不限于以下领域:

- Android/iOS 移动开发
- Camera 开发
- 短视频编辑 SDK 项目实践
- 在线直播和推流
- WebRTC 开发
- 播放器基础和提高
- OpenGL 图像渲染及特效开发
- C++ 基础和提高
- FFmpeg 使用和分析
- 干货资源和书籍分享

不止于技术方面的,各种 IT 新闻、茶余饭后、生活趣事也欢迎大家分享!!!

技术答疑解惑:

针对上述基础教程和干货分享的答疑,另外还有音视频和 IT 开发中的各种交流讨论。

- 基础知识点答疑
- 工业项目实践答疑
- 问题排查思路分析

一个 BUG 排查很久,不如来星球里提个问题,效率提升百倍。

求职和面试辅导:

一站式职场服务,每份工作都值得用心对待!!!

- 面试题和面试经验分享
- 简历修改和模拟面试
- 大厂内推和信息同步
- 职场经验分享
- 职业规划和发展分析

※ 星主和合伙人介绍

星主是公众号音视频开发进阶的作者,也是网站 https://glumes.com 的作者,曾参与过抖音、剪映等头部音视频 APP 底层 SDK 的开发。

合伙人也是在头条、快手从事音视频架构师的职位,具有多年的音视频开发经验,能力圈覆盖了音视频的绝大多数领域,资深音视频从业人员为你保驾护航。

微信公众号

扫描下面的二维码关注我的微信公众号《音视频开发进阶》,推送更多精彩内容!

添加我的微信 ezglumes 拉你入音视频与图形图像技术群一起交流学习~

wechat-account-qrcode

原创文章,转载请注明来源:    Android 6.0 Launcher 启动 Activity 过程分析小结(四)