这篇博客原创是http://blog.csdn.net/luoshengyang/article/details/8275938,只是更新了一部分比较旧的代码。还有加上自己的理解
Activity在窗口和ViewRootImpl创建后会请求WMS创建一个连接,请求WMS为其创建一个WindowState对象用来描述窗口状态。Activity与WMS的连接分为2方面,
一方面是从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服务三者之间就分别一一地建立了连接。在本文中,我们主要关注Activity组件在应用程序进程和WindowManagerService服务之间以及在WindowManagerService服务和ActivityManagerService服务之间的连接。
W类实现了IWindow接口,它的类实例是一个Binder本地对象。一个Activity组件在启动的过程中,会创建一个关联的ViewRootImpl对象,用来配合WindowManagerService服务来管理该Activity组件的窗口状态。在这个ViewRoot对象内部,有一个类型为W的成员变量mWindow,它是在ViewRootImpl对象的创建过程中创建的。
ViewRootImpl类有一个静态成员变量sWindowSession,它指向了一个实现了IWindowSession接口的Session代理对象。当应用程序进程启动第一个Activity组件的时候,它就会请求WindowManagerService服务发送一个建立连接的Binder进程间通信请求。WindowManagerService服务接收到这个请求之后,就会在内部创建一个类型为Session的Binder本地对象,并且将这个Binder本地对象返回给应用程序进程,后者于是就会得到一个Session代理对象,并且保存在ViewRootImpl类的静态成员变量sWindowSession中。
有了这个Session代理对象之后,应用程序进程就可以在启动Activity组件的时候,调用它的成员函数add来将与该Activity组件所关联的一个W对象传递给WindowManagerService服务,后者于是就会得到一个W代理对象,并且会以这个W代理对象来创建一个WindowState对象,即将这个W代理对象保存在新创建的WindowState对象的成员变量mClient中。
应用程序进程就可以通过保存在ViewRootImpl类的静态成员变量sWindowSession所描述的一个Session代理对象所实现的IWindowSession接口来与WindowManagerService服务通信,例如:
1. 在Activity组件的启动过程中,调用这个IWindowSession接口的成员函数add可以将一个关联的W对象传递到WindowManagerService服务,以便WindowManagerService服务可以为该Activity组件创建一个WindowState对象。
2. 在Activity组件的销毁过程中,调用这个这个IWindowSession接口的成员函数remove来请求WindowManagerService服务之前为该Activity组件所创建的一个WindowState对象。
3. 在Activity组件的运行过程中,调用这个这个IWindowSession接口的成员函数relayout来请求WindowManagerService服务来对该Activity组件的UI进行布局,以便该Activity组件的UI可以正确地显示在屏幕中。
我们再来看W类的作用。W类实现了IWindow接口,因此,WindowManagerService服务就可以通过它在内部所创建的WindowState对象的成员变量mClient来要求运行在应用程序进程这一侧的Activity组件来配合管理窗口的状态,例如:
1. 当一个Activity组件的窗口的大小发生改变后,WindowManagerService服务就会调用这个IWindow接口的成员函数resized来通知该Activity组件,它的大小发生改变了。
2. 当一个Activity组件的窗口的可见性之后,WindowManagerService服务就会调用这个IWindow接口的成员函数dispatchAppVisibility来通知该Activity组件,它的可见性发生改变了。
3. 当一个Activity组件的窗口获得或者失去焦点之后,WindowManagerService服务就会调用这个IWindow接口的成员函数windowFoucusChanged来通知该Activity组件,它的焦点发生改变了。
理解了Activity组件在应用程序进程和WindowManagerService服务之间的连接模型之后,接下来我们再通过简要分析Activity组件在WindowManagerService服务和ActivityManagerService服务之间的连接。
Activity组件在WindowManagerService服务和ActivityManagerService服务之间的连接是通过一个AppWindowToken对象来描述的。AppWindowToken类的实现如图所示:
每一个Activity组件在启动的时候,ActivityManagerService服务都会内部为该Activity组件创建一个ActivityRecord对象,并且会以这个ActivityRecord对象所实现的一个IApplicationToken接口为参数,请求WindowManagerService服务为该Activity组件创建一个AppWindowToken对象,即将这个IApplicationToken接口保存在新创建的AppWindowToken对象的成员变量appToken中。同时,这个ActivityRecord对象还会传递给它所描述的Activity组件所运行在应用程序进程,于是,应用程序进程就可以在启动完成该Activity组件之后,将这个ActivityRecord对象以及一个对应的W对象传递给WindowManagerService服务,后者接着就会做两件事情:
1. 根据获得的ActivityRecord对象的IApplicationToken接口来找到与之对应的一个AppWindowToken对象;
2. 根据获得的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服务之间的连接模型比较抽象,接下来,我们再通过三个过程来分析它们彼此之间的连接模型,如下所示:
1. ActivityManagerService服务请求WindowManagerService服务为一个Activity组件创建一个AppWindowToken对象的过程;
2. 应用程序进程请求WindowManagerService服务创建一个Session对象的过程;
3. 应用程序进程请求WindowManagerService服务为一个Activity组件创建一个WindowState对象的过程。
通过这三个过程的分析,我们就可以对应用程序进程、ActivityManagerService服务和WindowManagerService服务的关系有一个深刻的认识了。
Activity组件在启动的过程中,会调用到ActivityStack类的成员函数startActivityLocked,该函数会请求WindowManagerService服务为当前正在启动的Activity组件创建一个AppWindowToken对象。接下来,我们就从ActivityStack类的成员函数startActivityLocked开始分析一个AppWindowToken对象的创建过程,如图所示:
我们启动一个Activity的时候会调用ActivityStack的startActivityLocked函数,而在这个函数中最后在哪个会调用WMS的addAppToken来创建一个APPWindowToken
final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options) {
TaskRecord rTask = r.task;
final int taskId = rTask.taskId;
// mLaunchTaskBehind tasks get placed at the back of the task stack.
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
// Last activity in task had been removed or ActivityManagerService is reusing task.
// Insert or replace.
// Might not even be in.
insertTaskAtTop(rTask, r);
mWindowManager.moveTaskToTop(taskId);
}
TaskRecord task = null;
if (!newTask) {
// If starting in an existing task, find where that is...
boolean startIt = true;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
task = mTaskHistory.get(taskNdx);
if (task.getTopActivity() == null) {
// All activities in task are finishing.
continue;
}
if (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.
if (!startIt) {
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
+ task, new RuntimeException("here").fillInStackTrace());
task.addActivityToTop(r);
r.putInHistory();
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0,
r.userId, r.info.configChanges, task.voiceSession != null,
r.mLaunchTaskBehind);
我们再来看看WMS的addAppToken函数,在WMS中创建了APPWindowToken然后保存在mTokenMap中。
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {
......
synchronized(mWindowMap) {
AppWindowToken atoken = findAppWindowToken(token.asBinder());//如果已经有了直接退出
if (atoken != null) {
Slog.w(TAG, "Attempted to add existing app token: " + token);
return;
}
atoken = new AppWindowToken(this, token, voiceInteraction);//新建一个APPWindowToken
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
atoken.appFullscreen = fullscreen;
atoken.showForAllUsers = showForAllUsers;
atoken.requestedOrientation = requestedOrientation;
atoken.layoutConfigChanges = (configChanges &
(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
atoken.mLaunchTaskBehind = launchTaskBehind;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
Task task = mTaskIdToTask.get(taskId);
if (task == null) {
task = createTaskLocked(taskId, stackId, userId, atoken);
}
task.addAppToken(addPos, atoken);
mTokenMap.put(token.asBinder(), atoken);//保存在mTokenMap中 token为key(Activity的binder对象)
// Application tokens start out hidden.
atoken.hidden = true;
atoken.hiddenRequested = true;
}
}
再来看看AppWindowToken的构造函数,它是WindowToken的子类,再调用父类构造函数的时候说明了自己是TYPE_APPLICATION类型的。参数_token指向的是一个ActivityRecord对象的IBinder接口,因此,AppWindowToken类的成员变量appToken描述的就是一个ActivityRecord对象。
AppWindowToken(WindowManagerService _service, IApplicationToken _token,
boolean _voiceInteraction) {
super(_service, _token.asBinder(),
WindowManager.LayoutParams.TYPE_APPLICATION, true);
appWindowToken = this;
appToken = _token;
voiceInteraction = _voiceInteraction;
mInputApplicationHandle = new InputApplicationHandle(this);
mAnimator = service.mAnimator;
mAppAnimator = new AppWindowAnimator(this);
}
应用程序进程在启动第一个Activity组件的时候,就会请求与WindowManagerService服务建立一个连接,以便可以配合WindowManagerService服务来管理系统中的所有窗口。具体来说,就是应用程序进程在为它里面启动的第一个Activity组件的视图对象创建一个关联的ViewRootImpl对象的时候,就会向WindowManagerService服务请求返回一个类型为Session的Binder本地对象,这样应用程序进程就可以获得一个类型为Session的Binder代理对象,以后就可以通过这个Binder代理对象来和WindowManagerService服务进行通信了。
之前我们再分析WindowManagerGlobal的时候,先是新建了一个ViewRootImpl,然后才是调用其setView函数。
我们先看下构造函数,先是通过WindowManagerGlobal.getWindowSession获取mWindowSession,然后新建了mWindow对象。
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mDisplayAdjustments = display.getDisplayAdjustments();
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
mWidth = -1;
mHeight = -1;
mDirty = new Rect();
mTempRect = new Rect();
mVisRect = new Rect();
mWinFrame = new Rect();
mWindow = new W(this);
我们来看下WindowManagerGlobal.getWindowSession函数,还是通过WMS获取IWindowSession。
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
Log.e(TAG, "Failed to open window session", e);
}
}
return sWindowSession;
}
}
WMS的openSession函数为每个Activity创建一个Session。
@Override
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
Session session = new Session(this, callback, client, inputContext);
return session;
}
而这个Session也是一个Binder服务,这样每个Activity都能找到属于它的Session和WMS通信。
final class Session extends IWindowSession.Stub
implements IBinder.DeathRecipient {
在Android系统中,WindowManagerService服务负责统一管理系统中的所有窗口,因此,当运行在应用程序进程这一侧的Activity组件在启动完成之后,需要与WindowManagerService服务建立一个连接,以便WindowManagerService服务可以管理它的窗口。具体来说,就是应用程序进程将一个Activitty组件的视图对象设置到与它所关联的一个ViewRootImpl对象的内部的时候,就会将一个实现了IWindow接口的Binder本地对象传递WindowManagerService服务。这个实现了IWindow接口的Binder本地对象唯一地标识了一个Activity组件,WindowManagerService服务接收到了这个Binder本地对象之后,就会将它保存在一个新创建的WindowState对象的内部,这样WindowManagerService服务以后就可以通过它来和Activity组件通信,以便可以要求Activity组件配合来管理系系统中的所有窗口。
应用程序进程将一个Activity组件的视图对象设置到与它所关联的一个ViewRootImpl对象的内部是通过调用ViewRootImpl类的成员函数setView来实现的,因此,接下来我们就从ViewRootImpl类的成员函数setView开始分析Activity组件与WindowManagerService服务的连接过程,即一个WindowState对象的创建过程,如图所示:
下面我们分析下ViewRootImpl的setView函数,在这个函数中调用了IWindowSession的addToDisplay函数
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
然后在实现函数中直接是调用了WMS的addWindow函数。
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
WMS的addWindow我在Activity WMS ViewRootImpl三者关系(Activity创建窗口 按键分发等)的WMS一节中比较详细的分析过了。
在addWindow会新建WindowState对象,下面我们来看下这个对象和它的构造函数。
mSession是WMS对应Activity的一个Binder服务对象
mClient是Activity的IWindow服务对象,用来和Activity通信
mToken指向一个WindowToken对象,通过它唯一的标识一个窗口
mAttrs:指向一个WindowManager.LayoutParams对象,使用参数a来初始化,通过它就可以知道当前当前所创建的WindowState对象所描述的窗口的布局参数。
mViewVisibility:这是一个整型变量,使用参数viewVisibility来初始化,表示当前所创建的WindowState对象所描述的窗口视图的可见性。
mAlpha:这是一个浮点数,使用参数a所描述的一WindowManager.LayoutParams对象的成员变量alpha来初始化,表示当前所创建的WindowState对象所描述的窗口的Alpha通道。
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, final DisplayContent displayContent) {
mService = service;
mSession = s;
mClient = c;
mAppOp = appOp;
mToken = token;
mOwnerUid = s.mUid;
mWindowId = new IWindowId.Stub() {
@Override
public void registerFocusObserver(IWindowFocusObserver observer) {
WindowState.this.registerFocusObserver(observer);
}
@Override
public void unregisterFocusObserver(IWindowFocusObserver observer) {
WindowState.this.unregisterFocusObserver(observer);
}
@Override
public boolean isFocused() {
return WindowState.this.isFocused();
}
};
mAttrs.copyFrom(a);
mViewVisibility = viewVisibility;
我们继续看构造函数:
if ((mAttrs.type >= FIRST_SUB_WINDOW &&
mAttrs.type <= LAST_SUB_WINDOW)) {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.windowTypeToLayerLw(
attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
mAttachedWindow = attachedWindow;
if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + mAttachedWindow);
final WindowList childWindows = mAttachedWindow.mChildWindows;
final int numChildWindows = childWindows.size();
if (numChildWindows == 0) {
childWindows.add(this);
} else {
boolean added = false;
for (int i = 0; i < numChildWindows; i++) {
final int childSubLayer = childWindows.get(i).mSubLayer;
if (mSubLayer < childSubLayer
|| (mSubLayer == childSubLayer && childSubLayer < 0)) {
// We insert the child window into the list ordered by the sub-layer. For
// same sub-layers, the negative one should go below others; the positive
// one should go above others.
childWindows.add(i, this);
added = true;
break;
}
}
if (!added) {
childWindows.add(this);
}
}
mLayoutAttached = mAttrs.type !=
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
|| attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = attachedWindow.mAttrs.type == TYPE_WALLPAPER;
mIsFloatingLayer = mIsImWindow || mIsWallpaper;
} else {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
mSubLayer = 0;
mAttachedWindow = null;
mLayoutAttached = false;
mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
mIsFloatingLayer = mIsImWindow || mIsWallpaper;
}
这段代码初始化WindowState类的以下七个成员变量:
-mBaseLayer:这是一个整型变量,用来描述一个窗口的基础Z轴位置值,这个值是与窗口类型相关的。对于子窗口来说,它的值由父窗口的基础Z轴位置值乘以常量TYPE_LAYER_MULTIPLIER再加固定偏移量TYPE_LAYER_OFFSET得到;对于非子窗口来说,它的值就是由窗口的类型来决定的。一个窗口的基础Z轴位置值是通过调用WindowManagerService类的成员变量mPolicy所描述的一个窗口管理策略器的成员函数windowTypeToLayerLw来获得的,而窗口管理策略器的成员函数windowTypeToLayerLw主要是根据窗口的类型来决定它的基础Z轴位置值的。
-mSubLayer:这是一个整型变量,用来描述一个子窗口相对其父窗口的Z轴偏移值。对于非子窗口来说,这个值固定为0;对于子窗口来说,这个值是由WindowManagerService类的成员变量mPolicy所描述的一个窗口管理策略器的成员函数subWindowTypeToLayerLw来获得的,而窗口管理策略器的成员函数subWindowTypeToLayerLw主要是根据子窗口的类型来决定它相对其父窗口的Z轴偏移值的。
-mAttachedWindow:指向一个WindowState对象,用来描述一个子窗口的父窗口。对于非子窗口来说,这个值固定为null;对于子窗口来说, 这个值使用参数attachedWindow来初始化。如果当前所创建的WindowState对象所描述的窗口是一个子窗口,那么这个子窗口还会被添加用来描述它的父窗口的一WindowState对象的成员变量mChildWindows所描述的一个子窗口列表中去。
-mLayoutAttached:这是一个布尔变量,用来描述一个子窗口的视图是否是嵌入在父窗口的视图里面的。对于非子窗口来说,这个值固定为false;对于子窗口来说,这个值只有子窗口的类型是非对话框时,它的值才会等于true,否则都等于false。
-mIsImWindow:这是一个布尔变量,表示当前所创建的WindowState对象所描述的窗口是否是一个输入法窗口或者一个输入法对话框。
-mIsWallpaper :这是一个布尔变量,表示当前所创建的WindowState对象所描述的窗口是否是一个壁纸窗口。
-mIsFloatingLayer :这是一个布尔变量,表示当前所创建的WindowState对象所描述的窗口是否是一个浮动窗口。当一个窗口是一个输入法窗口、输入法对话框口或者壁纸窗口时,它才是一个浮动窗口。
我们继续向前看代码:
WindowState appWin = this;
while (appWin.mAttachedWindow != null) {
appWin = appWin.mAttachedWindow;
}
WindowToken appToken = appWin.mToken;
while (appToken.appWindowToken == null) {
WindowToken parent = mService.mTokenMap.get(appToken.token);
if (parent == null || appToken == parent) {
break;
}
appToken = parent;
}
mRootToken = appToken;
mAppToken = appToken.appWindowToken;
这段代码主要用来初始化成员变量mRootToken和mAppToken。
成员变量mRootToken的类型为WindowToken,用来描述当前所创建的WindowState对象所描述的窗口的根窗口。如果当前所创建的WindowState对象所描述的窗口是一个子窗口,那么就先找到它的父窗口,然后再找到它的父窗口所属的应用程序窗口,即Activity组件窗口,这时候找到的Activity组件窗口就是一个根窗口。如果当前所创建的WindowState对象所描述的窗口是一个子窗口,但是它不属于任何一个应用程序窗口的,那么它的父窗口就是一个根窗口。如果当前所创建的WindowState对象所描述的窗口不是一个子窗口,并且它也不属于一个应用程序窗口的,那么它本身就是一个根窗口。
成员变量mAppToken的类型为AppWindowToken,只有当成员变量mRootToken所描述的一个根窗口是一个应用程序窗口时,它的值才不等于null。
我们继续向前看最后一段代码:
if (mAppToken != null) {
final DisplayContent appDisplay = getDisplayContent();
mNotOnAppsDisplay = displayContent != appDisplay;
if (mAppToken.showForAllUsers) {
// Windows for apps that can show for all users should also show when the
// device is locked.
mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
}
}
mWinAnimator = new WindowStateAnimator(this);
mWinAnimator.mAlpha = a.alpha;
mRequestedWidth = 0;
mRequestedHeight = 0;
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
mXOffset = 0;
mYOffset = 0;
mLayer = 0;
mInputWindowHandle = new InputWindowHandle(
mAppToken != null ? mAppToken.mInpu
这段代码将以下十个成员变量的值设置为null或者0:
-mSurface:指向一个mSurface对象,用来描述窗口的绘图表面。
-mRequestedWidth:这是一个整型变量,用来描述应用程序进程所请求的窗口宽度。
-mRequestedHeight:这是一个整型变量,用来描述应用程序进程所请求的窗口高度。
-mLastRequestedWidth:这是一个整型变量,用来描述应用程序进程上一次所请求的窗口宽度。
-mLastRequestedHeight:这是一个整型变量,用来描述应用程序进程上一次所请求的窗口高度。
-mXOffset:这是一个整型变量,用来描述壁纸窗口相对屏幕在X轴上的偏移量,对其它类型的窗口为说,这个值等于0。
-mYOffset:这是一个整型变量,用来描述壁纸窗口相对屏幕在Y轴上的偏移量,对其它类型的窗口为说,这个值等于0。
-mLayer:这是一个整型变量,用来描述窗口的Z轴位置值。
-mAnimLayer:这是一个整型变量,用来描述窗口的Z轴位置值,它的值可能等于mLayer的值,但是在以下四种情况中不相等。当一个窗口关联有一个目标窗口的时候,那么它的值就等于mLayer的值加上目标窗口指定的一个动画层调整值;当一个窗口的根窗口是一个应用程序窗口时,那么它的值就等于mLayer的值加上根窗口指定的一个动画层调整值;当一个窗口是一个输入法窗口时,那么它的值就等于mLayer的值加上系统设置的输入法动画层调整值;当一个窗口是壁纸窗口时,那么它的值就等于mLayer的值加上系统设置的壁纸动画层调整值。
-mLastLayer:这是一个整型变量,用描述窗口上一次所使用的mAnimLayer的值。
至此,我们就分析完成WindowState的构造函数的实现了。
返回之前WindowManagerService类的成员函数addWindow中,接下来就会继续调用前面所创建的一个WindowState对象的成员函数attach函数。我们先来看看这个函数在addWindow的调用的地方:
WindowState win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
if (win.mDeathRecipient == null) {
// Client has apparently died, so there is no reason to
// continue.
Slog.w(TAG, "Adding window client " + client.asBinder()
+ " that is dead, aborting.");
return WindowManagerGlobal.ADD_APP_EXITING;
}
if (win.getDisplayContent() == null) {
Slog.w(TAG, "Adding window to Display that has been removed.");
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
mPolicy.adjustWindowParamsLw(win.mAttrs);
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
res = mPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
// From now on, no exceptions or errors allowed!
res = WindowManagerGlobal.ADD_OKAY;
origId = Binder.clearCallingIdentity();
if (addToken) {
mTokenMap.put(attrs.token, token);
}
win.attach();
WindowState的attach函数会创建一个关联的SurfaceSession对象,以便可以用来和SurfaceFlinger服务通信。下面看下这个函数:
void attach() {
if (WindowManagerService.localLOGV) Slog.v(
TAG, "Attaching " + this + " token=" + mToken
+ ", list=" + mToken.windows);
mSession.windowAddedLocked();
}
在Session的windowAddedLocked函数中,直接新建了一个SurfaceSession对象。
void windowAddedLocked() {
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
mService.mSessions.add(this);
if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
mService.dispatchNewAnimatorScaleLocked(this);
}
}
mNumWindow++;
}
Session类的成员变量mSurfaceSession指向的是一个SurfaceSession对象,这个SurfaceSession对象是WindowManagerService服务用来与SurfaceSession服务建立连接的。Session类的成员函数windowAddedLocked首先检查这个成员变量的值是否等于null。如果等于null的话,那么就说明WindowManagerService服务尚未为当前正在请求增加窗口的应用程序进程创建一个用来连接SurfaceSession服务的SurfaceSession对象,因此,Session类的成员函数windowAddedLocked就会创建一个SurfaceSession对象,并且保存在成员变量mSurfaceSession中,并且将正在处理的Session对象添加WindowManagerService类的成员变量mSession所描述的一个HashSet中去,表示WindowManagerService服务又多了一个激活的应用程序进程连接。
Session类的另外一个成员变量mNumWindow是一个整型变量,用来描述当前正在处理的Session对象内部包含有多少个窗口,即运行在引用了当前正在处理的Session对象的应用程序进程的内部的窗口的数量。每当运行在应用程序进程中的窗口销毁时,该应用程序进程就会通知WindowManagerService服务移除用来描述该窗口状态的一个WindowState对象,并且通知它所引用的Session对象减少其成员变量mNumWindow的值。当一个Session对象的成员变量mNumWindow的值减少为0时,就说明该Session对象所描述的应用程序进程连接已经不需要了,因此,该Session对象就可以杀掉其成员变量mSurfaceSession所描述的一个SurfaceSession对象,以便可以断开和SurfaceSession服务的连接。
接下来,我们就继续分析SurfaceSession类的构造函数的实现,以便可以了解一个SurfaceSession对象是如何与SurfaceSession服务建立连接的。
public SurfaceSession() {
mNativeClient = nativeCreate();
}
我们再来看下这个JNI函数,发现这块和surfacefligner相关,SurfaceComposerClient类主要就是用来在应用程序进程和SurfaceFlinger服务之间建立连接的,以便应用程序进程可以为运行在它里面的应用程序窗口请求SurfaceComposerClient创建绘制表面(Surface)的操作等。
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
SurfaceComposerClient* client = new SurfaceComposerClient();
client->incStrong((void*)nativeCreate);
return reinterpret_cast(client);
}
这样,每一个Java层的SurfaceSession对象在C++层就都有一个对应的SurfaceComposerClient对象,因此,Java层的应用程序就可以通过SurfaceSession类来和SurfaceFlinger服务建立连接。
虽然到目前为止,我们已经为Android应用程序窗口创建了很多对象,但是我们仍然还有一个最重要的对象还没有创建,那就是Android应用程序窗口的绘图表面,即用来渲染UI的Surface还没有创建。这个Surface是要请求SurfaceFlinger服务来创建的,我们将在下篇博客中分析。