前言
Window底层源码分析(一)中我们只是对Activity从一个组件怎么就管理一个界面的基本的流程去初步了解了一下,其实我们只是知道了一个Window 都是由什么东西组成的,activity是怎么管理的,在什么时候创建的等,那么这篇文章我们就接着上一篇文章继续讨论客户端Window是怎么和服务端WindowManagerService怎么通信的,他们之间的到底是怎么一回事?
WindowManagerService
这里我们就要知道一下WindowManagerService到底只一个什么东西?WindowManagerService和ActivityManagerService一样是一个远程的服务进程,当我们Android系统启动的时候,这些进程都会通过init进程来fork出一个叫zygote的进程,然后他会fork出来一系列的系统服务进程,而WindowManagerService就是其中一个
Window底层源码分析(一)中我们看到了怎么创建初始话界面,但是所有的界面的绘制还是需要交给我们的Android系统去完并且呈现出来的,我们看到每一个窗口其实都是一个surface:
- Surface是一块画布,应用通过canvas或者openGL在上面作画
- 作画后通过SurfaceFlinger将多块Surface的内容按照Z-order进行混合并输出到FrameBuffer,从而将Android的页面显示给用户。
每个窗口都有一块Surface用于显示自己的ui,必然需要一个角色对窗口进行统一管理,WindowManagerService就是这么一个管理者,现在我们对WindowManagerService有一个感性的认识。
由于WindowManagerService是一个远程的服务进程,我们是不能直接去使用它的,所以我们只能通过IPC的进程间通信的方式来通知WindowManagerService应该去怎么干。
客户端做了哪些事
直接通过源码查看
ViewRootImpl
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
...
}
我们会看到一个res的一个int型变量,后面是mWindowSession的方法调用,顾名思义这就是会返回一个一个int的数据然后用于抛出一些异常,其实也就是告诉我们和服务端的操作是不是成功等。下面我们去看看他是如何链接的:
* WindowManagerGlobal*
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) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
通过getWindowManagerService()方法获取到服务端的WindowManagerService的服务
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
if (sWindowManagerService != null) {
ValueAnimator.setDurationScale(
sWindowManagerService.getCurrentAnimatorScale());
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowManagerService;
}
}
可以看到一个很明显的字眼是Stub.asInterface这就是一个进程间通信的标志呀,然后我们就知道了接下来他是通过windowManager.openSession()这个方法去获取服务端的Session,那么下面就进入到了服务端去查看了:
WindowManagerService
@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。。。穿进去了一些参数而已,没有任何的操作,然后通过使用这个session去调用addToDisplay方法。
* Session*
@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);
}
可以看到下面就要去服务端去调用一个addWindow 的方法了。
现在我们知道了每一个客户端Window 都会有一个叫session 的东西从在并且与服务端建立了一个链接(通过这个session和服务端建立链接),通过调用addWindow方法去进入服务端。
服务端做了哪些事
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
...
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
...
}
这个方法传过来了好多的参数,然后通过这些参数去判断是否抛出一些异常,代码就不贴了,然后最主要的一个成员变量的初始化,我们可以看到:WindowState这是保证服务端和客户端的一个通信的主要东西;然后我们可以看到他在openSession的时候传过来了一个callback,他里面其实就是执行了一些通信之间的操作的存根。
总结
到现在我们就可以知道:总的来说,是每个window都会有一个服务端返回的session然后服务端会存在一个WindowState对象,我们可以通过带有session的存根对象去和服务端通信。实现一个IPC的过程。