转载自 牛晓伟
ActivityClientRecord
App进程内Activity的记录者
为了把ActivityRecord与ActivityClientRecord之间的关系展示的更清楚,我特意绘制了一幅图:
图解
ActivityRecord是存在于systemserver进程,它是归ATMS管理,Android系统中每一个被启动的Activity都会被ActivityRecord记录下来。而ActivityClientRecord是存在于每一个App进程内,它的作用是记录App进程内启动的Activity,App进程内启动的Activity是存放在ArrayMap数据结构中,它的key值是类型为IBinder的token对象,它的value值就是ActivityClientRecord对象,ActivityClientRecord的属性中activity指向真正的启动Activity实例。
下面表格是ActivityClientRecord的主要属性。”
属性 | 说明 |
---|---|
token:IBinder | 正如它的名字令牌,它可是ActivityRecord与ActivityClientRecord之间的连接器 |
intent:Intent | 启动一个Activity是需要把启动信息放入Intent中的,而这个intent就是它了 |
state:Bundle | 若该Activity保存了数据,则ATMS会把保存的数据下发给state |
activity:Activity | 真正启动的Activity实例 |
window:Window | 每个Activity都有一个Window对象,而它的类型是PhoneWindow,window就是指向PhoneWindow实例 |
paused:boolean | activity是否进入paused状态 |
stopped:boolean | activity是否进入stopped状态 |
activityInfo:ActivityInfo | 该信息是ATMS下发下来的,代表了在AndroidManifest文件中配置的Activity信息 |
mLifecycleState:int | activity的状态对应activity执行了哪些生命周期方法,它的值有PRE_ON_CREATE、ON_CREATE、ON_START、ON_RESUME、ON_PAUSE、ON_STOP、ON_DESTROY |
App进程内所有启动的Activity
App进程内所有启动的Activity是存储在ActivityThread的属性中的,如下代码:
//ActivityThread
//保存了所有启动的Activity
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
如上代码,mActivities保存了所有启动的Activity,其中IBinder作为key值,它是从ATMS传递过来的,每个Activity都对应自己的IBinder对象,ActivityClientRecord对象则保存了Activity的相关信息。关于IBinder在后面知识点中会介绍,它可是ActivityRecord和ActivityClientRecord一一映射的关键。
ActivityClientRecord何时初始化
我同样也绘制了一幅启动Activity的流程图,如下
图解
上图展示了App1进程启动App2进程中的Activity的流程,这个过程中要经过两次binder通信:
- App1进程调用startActivity方法,启动Activity的信息是在Intent对象中存储着
- ATMS收到启动Activity的信息,经过各种处理后,给App2进程发送启动Activity的信息
- App2进程收到Activity的启动信息intent:Intent、info:ActivityInfo、state:Bundle等
而ActivityClientRecord初始化的时机就是在App进程收到ATMS发送的启动Activity的信息后,ATMS会把启动Activity的各种信息都传递过来初始化ActivityClientRecord对象,开始App进程内Activity的启动过程。
总结
ActivityClientRecord的作用是记录App进程内启动的Activity,它与位于systemserver进程内的ActivityRecord是一一对应关系,而这个对应关系的关键连接器是类型为IBinder的token。
Activity与ActivityRecord“互认”
“Activity与ActivityRecord之间“互认”可是ATMS管理控制Activity的关键,这也是我上一篇文章留下的一个知识点,那咱们这节就把它消化了,先从IBinder对象特性说起吧。”
注:ATMS是ActivityTaskManagerService的简称
IBinder对象特性
我绘制了一幅图,来展示IBinder对象在进程之间的传递过程:
image
图注:Binder和BinderProxy类都是IBinder类的子类,A进程和B进程都是App类型进程,Binder-A对象和BinderProxy-B对象代表任意的Binder和BinderProxy对象。
结合上图来介绍下IBinder对象的特性:
- A进程中的一个Binder-A对象被传递给B进程时,该Binder对象在binder驱动层会被转换,因此B进程收到的是BinderProxy-B对象。
- Binder-A对象从A进程传递到B进程传递多次,B进程获取的依然是Binder-B对象。即一个进程中的同一Binder对象被多次传递给相同的其他进程,则其他进程获取的BinderProxy对象是不变的。
- B进程的BinderProxy-B对象被传递给A进程,A进程得到的是Binder-A对象。即可以通过BinderProxy对象反解出原先的Binder对象。
大牛:“IBinder对象特性可是实现“互认”的基础,既然介绍完毕IBinder对象特性,那咱们进入正题。”
类型为IBinder的token从何而来
token是ATMS下发的,看到token这个单词有没有想到在进行网络请求之前,需要从服务器取token信息,而后的网络请求客户端都需要拼接上token信息,以供服务器验证使用者的信息。
而ATMS下发的token也有类似的作用,每一个ActivityRecord对象的类型为IBinder的token属性,而该token属性就是被下发的token,那该token对象到达是什么类型呢?
请看如下代码:
//ActivityRecord类
//Token就是保证它们连接的类
private static class Token extends Binder {
@NonNull WeakReference<ActivityRecord> mActivityRef;
@Override
public String toString() {
return "Token{" + Integer.toHexString(System.identityHashCode(this)) + " "
+ mActivityRef.get() + "}";
}
}
上面的Token类就是token的类型,Token类是不是非常简单啊,它只是继承了Binder了,并且它的mActivityRef属性指向ActivityRecord。
何时下发IBinder类型的token
当需要启动App进程中的Activity时,ATMS就会下发Activity的各种信息,其中就包含了类型为Token类的token对象,
如下相关代码:
//ActivityTaskSupervisor
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
省略代码······
//使用IApplicationThread和token来创建ClientTransaction,它可是会被传递到App进程
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.token);
省略代码······
}
App进程收到IBinder类型的token
在一分钟掌握一个知识点--Activity系列之ActivityClientRecord一文中介绍了ActivityClientRecord,从ATMS下发下来的Activity包括token信息都会被存放在ActivityClientRecord对象中,依据上面介绍的IBinder对象特性,这时候的token的类型已经不是Token了,而是BinderProxy类型。
在如下方法中,会把App进程内的Activity实例及token进行存放:
//ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
省略代码······
synchronized (mResourcesManager) {
//这时候App进程内的Activity实例已经初始化完成,并且存放在ActivityClientRecord对象中。 key值为token,r为ActivityClientRecord,mActivities存放了所有App进程内启动的Activity
mActivities.put(r.token, r);
}
省略代码······
}
App进程会把类型为BinderProxy的token作为key值,ActivityClientRecord对象作为value值存放在mActivities属性中,以这种方式来存放App进程内所有启动的Activity。
Activity发送消息给ActivityRecord
有了上面的基础后,如果Activity要想发送消息给ActivityRecord,比如发送pause、stop消息,相关的代码如下:
//ActivityClient
//发送pause消息给ActivityRecord,其中参数token就是保存在ActivityClientRecord对象中的token
public void activityPaused(IBinder token) {
try {
getActivityClientController().activityPaused(token);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
ATMS收到以上消息会调用以下方法,对token转换为ActivityRecord:
//ActivityRecord类
//该方法从IBinder中找到ActivityRecord
static @Nullable ActivityRecord forTokenLocked(IBinder token) {
if (token == null) return null;
final Token activityToken;
try {
activityToken = (Token) token;
} catch (ClassCastException e) {
Slog.w(TAG, "Bad activity token: " + token, e);
return null;
}
final ActivityRecord r = activityToken.mActivityRef.get();
return r == null || r.getRootTask() == null ? null : r;
}
凡是Activity有消息发送给ActivityRecord,都需要携带上token,根据IBinder对象特性,该token到达systemserver进程后会被转换为Token类型,而调用上面的forTokenLocked方法可以把token转换为ActivityRecord。
ActivityRecord发送消息给Activity
ActivityRecord发送消息给Activity也会携带token,如下例子:
//ActivityRecord
boolean makeActiveIfNeeded(ActivityRecord activeActivity) {
省略代码······
//其中token就是要发送给App进程的,下面方法通知Activity调用它的onPause方法
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
PauseActivityItem.obtain(finishing, false /* userLeaving */,
configChangeFlags, false /* dontReport */));
省略代码······
}
App进程收到上面的消息,会从getActivityClient方法中根据token获取到对应的ActivityClientRecord,而ActivityClientRecord中包含了Activity实例,进而就可以调用Activity实例的相应方法了,getActivityClient方法如下:
//ActivityThread
public ActivityClientRecord getActivityClient(IBinder token) {
//根据token,从mActivities中获取ActivityClientRecord
return mActivities.get(token);
}
总结
ActivityRecord中定义的Token类是实现Activity与ActivityRecord“互认”核心类,它是一个Binder子类,充分使用IBinder对象的特性就可以做到ActivityRecord与App进程中的Activity“互认”的目的。