写点什么

Android 应用启动流程分析 (1),android 应用开发实战项目

用户头像
Android架构
关注
发布于: 刚刚

在 Android 系统中,任何一个 Activity 的启动都是由 AMS 和 App 进程(主要是 ActivityThread)相互配合来完成的。AMS 服务统一调度系统中所有进程的 Activity 启动,而每个 Activity 的启动过程则由其所属的进程具体来完成。

3.4 Android Binder 机制

我们知道 AMS 与 ActivityThread 的交互主要是通过进程间通信 (IPC) 。跨进程通信的机制就是将方法调用及其数据分解至操作系统可识别的程度,并将其从本地进程和地址空间传输至远程进程和地址空间,然后在远程进程中重新组装并执行该调用。 Android 提供了执行这些 IPC 事务的方案——Binder 机制,因此我们只需关心接口定义和实现 RPC 编程接口。


而 App 进程与 SystemServer 进程也是通过 Binder 机制进行进程间通信,Android 为此设计了两个 Binder 接口:


  1. IApplicationThread: 作为系统进程请求应用进程的接口;

  2. IActivityManager: 作为应用进程请求系统进程的接口。


对于一个 Binder 接口,在客户端和服务端各有一个实现:Proxy 和 Native,它们之间的通信主要是通过 transact 和 onTransact 触发。一般从命名上可以区分:xxxNative 是在本进程内的 Binder 代理类,xxxProxy 是在对方进程的 Binder 代理类。


多说一句,这些 Binder 都由 ServiceManager 统一管理:

  1. ServiceManager 管理所有的 Android 系统服务,有人把 ServiceManager 比喻成 Binder 机制中的 DNS 服务器,client 端应用如果要使用系统服务,调用 getSystemService 接口,ServiceManager 就会通过字符串形式的 Binder 名称找到并返回对应的服务的 Binder 对象。

  2. 它是一个系统服务进程,在 native 层启动,它在 system/core/rootdir/init.rc 脚本中描述并由 init 进程启动。

  3. ServiceManager 启动后,会通过循环等待来处理 Client 进程的通信请求。


App 进程与 SystemServer 进程的 Binder 接口如下图:


3.4.1 服务端 IActivityManager——ActivityManagerNative——ActivityManagerService

  1. ActivityManagerNative 作为服务端的“桩(Stub)”,其主要职责就是对远程传递过来的数据进行”反序列化(unparcel)”;

  2. Act


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


ivityManagerProxy 作为服务的“代理(Proxy)”,运行在客户端,其主要职责就是将数据进行“序列化(parcel)”,再传递给远程的“桩(Stub)”,App 使用 AMS 提供的功能,比如 startActivity,是通过 AMS 在客户端的代理 ActivityManagerProxy 发起的。3. 最下面一层是桩(Stub)的具体实现——AMS(ActivityManagerService),负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,非常复杂。


AMS 是一个系统服务,在 SystemServer 进程启动后完成初始化。在应用启动流程中,充当着服务端的角色。 App 中 Activity 的生命周期由 AMS 管理,它决定着什么时候该调用 onCreate、onResume 这些生命周期函数,把 Activity 放在哪个栈里,上下文之间的关系是怎样的等等。


比如:


  1. startActivity 最终调用了 AMS 的 startActivity 系列方法,实现了 Activity 的启动;Activity 的生命周期回调,也在 AMS 中完成;

  2. startService,bindService 最终调用到 AMS 的 startService 和 bindService 方法;

  3. 动态广播的注册和接收在 AMS 中完成(静态广播在 PMS 中完成)

  4. getContentResolver 最终从 AMS 的 getContentProvider 获取到 ContentProvider

3.4.2 客户端 IApplicationThread——ApplicationThreadNative——ActivityThread

  1. 桩(Stub):ApplicationThreadNative

  2. 代理(Proxy):ApplicationThreadProxy,App 在客户端进程中实现了实例化 Activity、调用 onCreate 等生命周期函数的功能,因为跨进程也不能被 AMS 直接调用,而是 AMS 通过客户端的代理 ApplicationThreadProxy 来处理。

  3. 最下面一层是桩(Stub)的具体实现——ApplicationThread,它是 ActivityThread 的一个内部类,ApplicationThread 负责响应系统进程发起的请求,而实际触发的业务逻辑是在 ActivityThread 中。与一般的代理模式不同,它不是直接持有 ActivityThead 的一个引用,而是把处理的请求发到 ActivityThread 内部的一个 Handler 上。


和服务端的 AMS 相对应,ActivityThread 在应用启动的 Client/Server 模式中,是作为客户端那一边的具体实现。它并不是一个线程,但它包含了一个应用进程的主线程运作的全部机制:


  1. 启动应用的主线程,并开启消息循环

  2. 提供了一个 IActivityThread 接口作为与 AMS 的通讯接口,通过该接口 AMS 可以将 Activity 的状态变化传递到客户端的 Activity 对象

3.5 启动一个 Activity 的通信过程

我们已经知道应用进程创建以后,App 进程的 ActivityThread 与 SystemServer 进程的 AMS 通过 Binder 进行通信。 在文章前面【2 应用启动流程】提到,在 ActivityThread 的 main 方法中,调用 ActivityThread#attach(false)方法进行 Binder 通信,通知 system_server 进程执行 ActivityManagerService#attachApplication(mAppThread)方法,用于初始化 Application 和 Activity。


可以结合源码流程,稍微总结一下这个通信过程。

3.5.1 Application 的初始化

从应用进程到系统进程

在 ActivityThread 创建的时候,会将自己的 ApplicationThread 绑定到 AMS 中:


ActivityThread.main()└── ActivityThread.attach()└── IActivityManager.attachApplication(mAppThread)└── Binder.transact()


应用进程作为客户端,通过 IAcitivtyManager 接口发起了跨进程调用,跨进程传递的参数 mAppThread 就是 IApplicationThread 的实例,执行流程从应用进程进入到系统进程:


ActivityManagerService.onTransact()└── ActivityManagerService.attachApplication(IApplicationThread thread)


AMS 作为 IActivityManager 接口的服务端实现,会响应客户端的请求,最终 AMS.attachApplication()函数会被执行,该函数接收跨进程传递过来的 IApplicationThread 实例,将存在系统进程维护的 ProcessRecord 中。 具体细节可以看 AMS 的源码,我们只需要知道 AMS 中维护了所有进程运行时的信息(ProcessRecord),一旦发生了应用进程的绑定请求,ProcessRecord.thread 就被赋值成应用进程的 IApplicationThread 实例,这样一来,在 AMS 中就能通过该 IApplicationThread 实例发起向应用进程的调用

从系统进程到应用进程

在 AMS.attachApplication()的过程中,会有一些信息要传递给应用进程,以便应用进程的初始化,系统进程会发起如下函数调用:


ActivityManagerService.attachApplication()└── ActivityManagerService.attachApplicationLocked()└── IApplicationThread.bindApplication(processName, appInfo ...)└── Binder.transact()


此时,AMS 会反转角色,即系统进程作为客户端,通过 IApplicationThread 接口向应用进程发起调用。


  1. AMS 通过 ProcessRecord 来维护进程运行时的状态信息,需要将应用进程绑定到 ProcessRecord 才能开始一个 Application 的构建;

  2. AMS 维护的 ProcessRecord 这个数据结构,包含了进程运行时的信息,譬如应用进程的名称 processName、解析 AndroidManifest.xml 得到的数据结构 ApplicationInfo 等,其中,要传递给应用进程的数据都是 Parcelable 类型的实例。


应用进程响应请求的调用关系如下所示:


ApplicationThread.onTransact()└── ApplicationThread.bindApplication()└── ActivityThread.H.handleMessage(BIND_APPLICATION)└── ActivityThread.handleBindApplication()└── Application.onCreate()


ApplicationThread 作为 IApplicationThread 接口的服务端实现,运行在应用进程中,然后 ApplicationThread.bindApplication()会被执行,完成一些简单的数据封装(AppBindData)后,通过 Handler 抛出 BIND_APPLICATION 消息。这一抛,就抛到了主线程上,ActivityThread.handleBindApplication()会被执行,终于创建了 Application 对象,然后调用 Application#attach(context) 来绑定 Context,并调用 Application.onCreate()函数。历经应用进程和系统进程之间的一个来回,总算是创建了一个应用程序。


Android 源码里有较统一的函数命名方式,在 AMS 中与 Activity 管理相关很多函数都会带有 Locked 后缀,表示这些函数的调用都需要多线程同步操作(synchronized),它们会读/写一些多线程共享的数据

3.5.2 Activity 的初始化

前面提到在 system_server 进程中,ActivityManagerService#attachApplication(mAppThread)里依次初始化了 Application 和 Activity,其中的mStackSupervisor#attachApplicationLocked(ProcessRecord)里进行了 Activity 的初始化。


  1. AMS 通过 ActivityRecord 来维护 Activity 运行时的状态信息,需要将 Activity 绑定到 AMS 中的 ActivityRecord 能开始 Activity 的生命周期。

  2. 在 Activity 类中有一个 IBinder 类型的属性:private IBinder mToken;,IBinder 类型表示这个属性是一个远程对象的引用,Token 持有了一个 ActivityRecord 实例的弱引用。在创建一个 ActivityRecord 的时候,就会创建了一个 Token 类型的对象。


在启动一个新的 Activity 时,AMS 会将 ActivityRecord 的 Token 传递给应用进程,调用关系如下所示:


ActivityStackSupervisor.realStartActivityLocked(ActivityRecord, ...)└── IApplicationThread.scheduleLaunchActivity(...token, ...)// 将 ActivityRecord 的 Token 跨进程传递给应用进程└── Binder.transact()


ActivityStackSupervisor.realStartActivityLocked()表示要启动一个 Activity 实例,ActivityRecord 作为参数。从 ActivityRecord 中提取出 Token 对象,作为跨进程调用的参数,通过 IApplicationThread.scheduleLaunchActivity()传递到应用进程。


在应用进程这一侧,会收到启动 Activity 的跨进程调用,触发以下函数的调用:


ApplicationThread.onTransact()└── ApplicationThread.scheduleLaunchActivity(...token, ...)// token 将被封装进 ActivityClientRecord 这个数据结构中└── ActivityThread.H.handleMessage()└── ActivityThread.handleLaunchActivity(LAUNCH_ACTIVITY)└── ActivityThread.performLaunchActivity(ActivityClientRecord, ...)// 从 ActivityRecord 取出 token└── Activity.attch(...token, ...)


标准的 Binder 服务端处理流程,收到 AMS 传递过来的 Token 对象,进行一下数据封装(ActivityClientRecord),然后通过 Handler 抛出一个 LAUNCH_ACTIVITY 消息。这个消息显然也是抛到了应用进程的主线程去执行,所以 ActivityThread.performLaunchActivity()函数会在主线程上执行,该函数从封装的数据结构 ActivityClientRecord 中取出 Token 对象,调用 Activity.attach()函数,将其绑定到 Activity 上,如此一来,就建立应用进程的 Activity 与系统进程中 ActivityRecord 的关联。


系统进程维护的是 ActivityRecord,应用进程维护的是 Activity,两者之间的映射关系就是利用 Token 来维系的。应用进程的 Activity 在创建的时候,就被赋予了一个 Token,拿着这个 Token 才能完成后续与系统进程的通信。在发生 Activity 切换时,应用进程会将上一个 Activity 的 Token(AMS.startActivity()的输入参数 resultTo)传递给系统进程,系统进程会根据这个 Token 找到 ActivityRecord,对其完成调度后,再通知应用进程:Activity 状态发生了变化。

3.5.3 Instrumentation

每个 Activity 都持有 Instrumentation 对象的一个引用,但是整个应用程序进程只会存在一个 Instrumentation 对象。 Instrumentation 可以理解为应用进程的管家,ActivityThread 要创建或暂停某个 Activity 时,都需要通过 Instrumentation 来进行具体的操作。


Instrumentation 这个类就是完成对 Application 和 Activity 初始化和生命周期的工具类。


前面提到,App 和 AMS 是通过 Binder 传递信息的,ActivityThread 接受 AMS 的命令,然后就是通过 Instrumentation 真正地创建 Activity 以及调用 Activity 的生命周期函数。 比如 ApplicationThread 接受 AMS 命令创建 Acitivity,最后执行到 ActivityThread,通过 Instrumentation 创建 Activity 并调用 onCreate()生命周期。


//ActivityThread.performLaunchActivity()└── mInstrumentation.newActivity(appContext.getClassLoader(), component.getClassName(), activityClientRecord.intent)└── return (Activity)cl.loadClass(className).newInstance()


└── mInstrumentation.callActivityOnCreate(activity, r.state)└── activity.performCreate()└── activity.onCreate(Bundle)

4 Activity 的管理方式

前面知道应用启动以及 Activity 启动是一个跨进程通信的过程,这是因为: 每个应用都是一个独立的进程,Activity 的生命周期本来就会在不同进程之间互相影响,所以需要一个系统进程对所有 Activity 进行统一管理。 在一个应用程序安装时,系统会解析出 APK 中所有 Activity 的信息,当显示 APK 中的用户界面时,就需要调度 Activity 的生命周期函数了。 系统进程(SystemServer)中维护了所有 Activity 的状态,管理中枢就是 ActivityManagerService。

系统进程怎么管理 Activity?

在应用进程这边,Activity 的生命周期都是发生在本进程的主线程里,由 ActivityThread 调用 Instrumentation 完成。 而在系统进程(SystemServer)这头,则是由 AMS 维护 ActivityRecord 等数据结构来进行调度。 Activity 管理的数据结构包括: ActivityRecord TaskRecord ActivityStack ActivityDisplay ActivityStackSupervisor ProcessRecord 这些数据结构都属于 JAVA 实体类,它们的构建和销毁都在系统进程中完成。


它们之间的联系可以参考下图:



图中的方框可以理解为一个包含关系:譬如一个 TaskRecord 中包含多个 ActivityRecord; 图中的连接线可以理解为等价关系,譬如同一个 ActivityRecord 会被 TaskRecord 和 ProcessRecord 引用,两者是从不同维度来管理 ActivityRecord。


  1. ActivityRecord 是 Activity 管理的最小单位,它对应着应用进程的一个 Activity;

  2. TaskRecord 也是一个栈式管理结构,每一个 TaskRecord 都可能存在一个或多个 ActivityRecord,栈顶的 ActivityRecord 表示当前可见的界面;

  3. ActivityStack 是一个栈式管理结构,每一个 ActivityStack 都可能存在一个或多个 TaskRecord,栈顶的 TaskRecord 表示当前可见的任务;

  4. ActivityStackSupervisor 管理着多个 ActivityStack,但当前只会有一个获取焦点(Focused)的 ActivityStack;

  5. ProcessRecord 记录着属于一个进程的所有 ActivityRecord,运行在不同 TaskRecord 中的 ActivityRecord 可能是属于同一个 ProcessRecord。


每种数据结构的属性和行为

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android应用启动流程分析(1),android应用开发实战项目