Activity组件在其窗口对象和视图对象创建完成之后,就会请求与WindowManagerService建立一个连接,即请求WindowManagerService为其增加一个WindowState对象,用来描述它的窗口状态。
我们从两方面来看Activity组件与WindowManagerService服务之间的连接。一方面是从Activity组件到WindowManagerService服务的连接,另一方面是从WindowManagerService服务到Activity组件的连接。
从Activity组件到WindowManagerService服务的连接是以Activity组件所在的应用程序进程为单位来进行的。当一个应用程序进程在启动第一个Activity组件的时候,它便会打开一个到WindowManagerService服务的连接,这个连接以应用程序进程从WindowManagerService服务处获得一个实现了IWindowSession接口的Session代理对象来标志。
从WindowManagerService服务到Activity组件的连接是以Activity组件为单位来进行的。在应用程序进程这一侧,每一个Activity组件都关联一个实现了IWindow接口的W对象,这个W对象在Activity组件的视图对象创建完成之后,就会通过前面所获得一个Session代理对象来传递给WindowManagerService服务,而WindowManagerService服务接收到这个W对象之后,就会在内部创建一个WindowState对象来描述与该W对象所关联的Activity组件的窗口状态,并且以后就通过这个W对象来控制对应的Activity组件的窗口状态。
上述Activity组件与WindowManagerService服务之间的连接模型如图所示:
每一个Activity组件在ActivityManagerService服务内部,都对应有一个ActivityRecord对象,这个ActivityRecord对象是Activity组件启动的过程中创建的,用来描述Activity组件的运行状态。这样,每一个Activity组件在应用程序进程、WindowManagerService服务和ActivityManagerService服务三者之间就分别一一地建立了连接。
W类的实现:
Session类和WindowState类的实现:
W类实现了IWindow接口,它的类实例是一个Binder本地对象。一个Activity组件在启动的过程中,会创建一个关联的ViewRoot对象,用来配合WindowManagerService服务来管理该Activity组件的窗口状态。在这个ViewRoot对象内部,有一个类型为W的成员变量mWindow,它是在ViewRoot对象的创建过程中创建的。ViewRoot类有一个静态成员变量sWindowSession,它指向了一个实现了IWindowSession接口的Session代理对象。
当应用程序进程启动第一个Activity组件的时候,它就会请求WindowManagerService服务发送一个建立连接的Binder进程间通信请求。WindowManagerService服务接收到这个请求之后,就会在内部创建一个类型为Session的Binder本地对象,并且将这个Binder本地对象返回给应用程序进程,后者于是就会得到一个Session代理对象,并且保存在ViewRoot类的静态成员变量sWindowSession中。
有了这个Session代理对象之后,应用程序进程就可以在启动Activity组件的时候,调用它的成员函数add来将与该Activity组件所关联的一个W对象传递给WindowManagerService服务,后者于是就会得到一个W代理对象,并且会以这个W代理对象来创建一个WindowState对象,即将这个W代理对象保存在新创建的WindowState对象的成员变量mClient中。
Session类实现了IWindowSession接口,因此,应用程序进程就可以通过保存在ViewRoot类的静态成员变量sWindowSession所描述的一个Session代理对象所实现的IWindowSession接口来与WindowManagerService服务通信,例如:
- 在Activity组件的启动过程中,调用这个IWindowSession接口的成员函数add可以将一个关联的W对象传递到WindowManagerService服务,以便WindowManagerService服务可以为该Activity组件创建一个WindowState对象。
- 在Activity组件的销毁过程中,调用这个这个IWindowSession接口的成员函数remove来请求WindowManagerService服务之前为该Activity组件所创建的一个WindowState对象。
- 在Activity组件的运行过程中,调用这个这个IWindowSession接口的成员函数relayout来请求WindowManagerService服务来对该Activity组件的UI进行布局,以便该Activity组件的UI可以正确地显示在屏幕中。
W类实现了IWindow接口,因此,WindowManagerService服务就可以通过它在内部所创建的WindowState对象的成员变量mClient来要求运行在应用程序进程这一侧的Activity组件来配合管理窗口的状态,例如:
- 当一个Activity组件的窗口的大小发生改变后,WindowManagerService服务就会调用这个IWindow接口的成员函数resized来通知该Activity组件,它的大小发生改变了。
- 当一个Activity组件的窗口的可见性之后,WindowManagerService服务就会调用这个IWindow接口的成员函数dispatchAppVisibility来通知该Activity组件,它的可见性发生改变了。
- 当一个Activity组件的窗口获得或者失去焦点之后,WindowManagerService服务就会调用这个IWindow接口的成员函数windowFoucusChanged来通知该Activity组件,它的焦点发生改变了。
Activity组件在WindowManagerService服务和ActivityManagerService服务之间的连接是通过一个AppWindowToken对象来描述的。
每一个Activity组件在启动的时候,ActivityManagerService服务都会内部为该Activity组件创建一个ActivityRecord对象,并且会以这个ActivityRecord对象所实现的一个IApplicationToken接口为参数,请求WindowManagerService服务为该Activity组件创建一个AppWindowToken对象,即将这个IApplicationToken接口保存在新创建的AppWindowToken对象的成员变量appToken中。
同时,这个ActivityRecord对象还会传递给它所描述的Activity组件所运行在应用程序进程,于是,应用程序进程就可以在启动完成该Activity组件之后,将这个ActivityRecord对象以及一个对应的W对象传递给WindowManagerService服务,后者接着就会做两件事情:
- 根据获得的ActivityRecord对象的IApplicationToken接口来找到与之对应的一个AppWindowToken对象;
- 根据获得的AppWindowToken对象以及前面传递过来的W代理对象来为正在启动的Activity组件创建一个WindowState对象,并且将该AppWindowToken对象保存在新创建的WindowState对象的成员变量mAppToken中。
AppWindowToken类是从WindowToken类继续下来的。WindowToken类也是用来标志一个窗口的,不过这个窗口类型除了是应用程序窗口,即Activity组件窗口之外,还可以是其它的,例如,输入法窗口或者壁纸窗口类型等,而AppWindowToken类只是用来描述Activity组件窗口。当WindowToken类是用来描述Activity组件窗口的时候,它的成员变量token指向的就是用来描述该Activity组件的一个ActivityRecord对象所实现的一个IBinder接口,而成员变量appWindowToken指向的就是其子类AppWindowToken对象。当另一方面,当WindowToken类是用来描述非Activity组件窗口的时候,它的成员变量appWindowToken的值就会等于null。这样,我们就可以通过WindowToken类的成员变量appWindowToken的值来判断一个WindowToken对象是否是用来描述一个Activity组件窗口的,即是否是用来描述一个应用程序窗口的。
上面所描述的Activity组件在ActivityManagerService服务和WindowManagerService服务之间以及应用程序进程和WindowManagerService服务之间的连接模型比较抽象,接下来,我们再通过三个过程来分析它们彼此之间的连接模型,如下所示:
- ActivityManagerService服务请求WindowManagerService服务为一个Activity组件创建一个AppWindowToken对象的过程;
- 应用程序进程请求WindowManagerService服务创建一个Session对象的过程;
- 应用程序进程请求WindowManagerService服务为一个Activity组件创建一个WindowState对象的过程。
一. AppWindowToken对象的创建过程
Activity组件在启动的过程中,会调用到ActivityStack类的成员函数startActivityLocked,该函数会请求WindowManagerService服务为当前正在启动的Activity组件创建一个AppWindowToken对象。
Step 1. ActivityStack.startActivityLocked
public class ActivityStack {
......
final ActivityManagerService mService;
......
final ArrayList mHistory = new ArrayList();
......
private final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume) {
final int NH = mHistory.size();
int addPos = -1;
if (!newTask) {
// If starting in an existing task, find where that is...
boolean startIt = true;
for (int i = NH-1; i >= 0; i--) {
ActivityRecord p = (ActivityRecord)mHistory.get(i);
if (p.finishing) {
continue;
}
if (p.task == r.task) {
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
addPos = i+1;
if (!startIt) {
mHistory.add(addPos, r);
......
mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
......
return;
}
break;
}
if (p.fullscreen) {
startIt = false;
}
}
}
// Place a new activity at top of stack, so it is next to interact
// with the user.
if (addPos < 0) {
addPos = NH;
}
......
// Slot the activity into the history stack and proceed
mHistory.add(addPos, r);
......
if (NH > 0) {
......
mService.mWindowManager.addAppToken(
addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
.....
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
}
......
if (doResume) {
resumeTopActivityLocked(null);
}
}
......
}
参数r是一个ActivityRecord对象,用来描述的是要启动的Activity组件,参数newTask是一个布尔变量,用来描述要启动的Activity组件是否是在新任务中启动的,参数doResume也是一个布尔变量,用来描述是否需要马上将Activity组件启动起来。
ActivityStack类的成员变量mService指向的是系统的ActivityManagerService,另外一个成员变量mHistory是一个数组列表,用来描述系统的Activity组件堆栈。
当参数newTask的值等于false时,就说明参数r所描述的Activity组件是在已有的一个任务中启动的,因此,这时候ActivityStack类的成员函数startActivityLocked就会从上到下遍历保存成员变量mHistory,找到一个已有的Activity组件,它与参数r所描述的Activity组件是属于同一个任务的,即它们的成员变量task的值相等。找到这样的一个Activity组件之后,如果位于它上面的其它Activity组件的窗口至少有一个全屏的,即变量startIt的值等于true,那么ActivityStack类的成员函数startActivityLocked就只是将参数r所描述的Activity组件加入到成员变量mHistory所描述的一个Activity组件堆栈中,以及调用成员变量mService所描述的ActivityManagerService服务的成员变量mWindowManager所描述的WindowManagerService服务的成员函数addAppToken来为它创建一个AppWindowToken对象,然后就返回了。这相当于是延迟到参数r所描述的Activity组件可见时,才将它启动起来。
当参数newTask的值等于true时,就说明参数r所描述的Activity组件是在一个任务中启动的,这时候ActivityStack类的成员函数startActivityLocked就会首先将它添加到成员变量mHistory所描述的一个Activity组件堆栈,接着再判断它是否是系统中第一个启动的Activity组件。如果是系统中第一个启动的Activity组件,那么ActivityStack类的成员函数startActivityLocked就只是简单地调用WindowManagerService服务的成员函数addAppToken来为它创建一个AppWindowToken对象就完事了。如果不是系统系统中第一个启动的Activity组件,那么ActivityStack类的成员函数startActivityLocked除了会调用WindowManagerService服务的成员函数addAppToken来为它创建一个AppWindowToken对象之外,还会为它创建一些启动动画等,我们忽略这些代码。
无论如何,ActivityStack类的成员函数startActivityLocked都会调用WindowManagerService服务的成员函数addAppToken为正在启动的Activity组件创建一个AppWindowToken对象。创建完成这个AppWindowToken对象之后,如果参数doResume的值等于true,那么ActivityStack类的成员函数startActivityLocked就会继续调用另外一个成员函数resumeTopActivityLocked来继续执行启动参数r所描述的一个Activity组件。
Step 2. WindowManagerService.addAppToken
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor {
......
/**
* Mapping from a token IBinder to a WindowToken object.
*/
final HashMap<IBinder, WindowToken> mTokenMap =
new HashMap<IBinder, WindowToken>();
/**
* The same tokens as mTokenMap, stored in a list for efficient iteration
* over them.
*/
final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();
......
/**
* Z-ordered (bottom-most first) list of all application tokens, for
* controlling the ordering of windows in different applications. This
* contains WindowToken objects.
*/
final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
......
public void addAppToken(int addPos, IApplicationToken token,
int groupId, int requestedOrientation, boolean fullscreen) {
......
long inputDispatchingTimeoutNanos;
try {
inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L;
} catch (RemoteException ex) {
......
inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
}
synchronized(mWindowMap) {
AppWindowToken wtoken = findAppWindowToken(token.asBinder());
if (wtoken != null) {
......
return;
}
wtoken = new AppWindowToken(token);
wtoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
wtoken.groupId = groupId;
wtoken.appFullscreen = fullscreen;
wtoken.requestedOrientation = requestedOrientation;
mAppTokens.add(addPos, wtoken);
......
mTokenMap.put(token.asBinder(), wtoken);
mTokenList.add(wtoken);
// Application tokens start out hidden.
wtoken.hidden = true;
wtoken.hiddenRequested = true;
//dump();
}
}