Android 12 addWindow过程分析
1 背景
分析过Window层级结构之后,以addWindow为切入点看一下系统是怎么使用的。而且addWindow也是系统非常重要的一个环节,无论是Activity(PhoneWindow)还是各种系统窗口,都会走到这里。
addView举例:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
attach方法。
2 时序分析
2.1 client端(WMS之前)
WindowManager.addView()
WindowManagerImpl.addView()
WindowManagerGlobal.addView()
WindowManagerGlobal.getWindowSession()
WindowManagerService.openSession()
new Session()
new ViewRootImpl()
ViewRootImpl.setView()
Session.addToDisplayAsUser()
- 如果没有创建过Session(Aidl是IWindowSession,每个进程一个),则向WMS申请创建一个Session
- 然后在ViewRootImpl中调用Session的
addToDisplayAsUser
方法。
2.2 WMS端
Session.addToDisplayAsUser()
WindowManagerService.addWindow()
WindowManagerService.getDisplayContentOrCreate()
RootWindowContainer.getWindowToken(IBinder binder)
WindowToken.getDisplayContent() or RootWindowContainer.getDisplayContentOrCreate()
new WindowToken() // 并且设置DisplayContent(setDisplayContent())
new WindowState()
WindowState.attach()
Session.windowAddedLocked()
new SurfaceSession()
new SurfaceComposerClient() // jni
WindowToken.addWindow()
WindowToken.createSurfaceControl()
WindowContainer.createSurfaceControl()
WindowToken.makeSurface()
WindowContainer.makeSurface()
DisplayContent.makeChildSurface()
setInitialSurfaceControlProperties()
WindowContainer.setInitialSurfaceControlProperties() // SurfaceControl.Builder.build()
WindowContainer.setSurfaceControl()
WindowContainer.updateSurfacePositionNonOrganized
WindowManagerService.updateFocusedWindowLocked()
RootWindowContainer.updateFocusedWindowLocked()
- 找到添加Window的DisplayContent
- 先后创建WindowToken(令牌)和WindowState(实际对象)
- 调用WindowState.attach()方法,内部会创建SurfaceSession,native层对应创建SurfaceComposerClient
- 调用WindowToken.addWindow()方法,内部创建SurfaceControl,native层对应创建SurfaceControl
3 token的传递
这里分析一下Server端怎么区分不同的client。
3.1 client创建自己的token
// ViewRootImpl.java
public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
token是IBinder类型的。
以StatusBar的添加为例,ViewRootImpl中的mWindowAttributes的token就是addView的时候new的。
3.2 server中怎么使用client的token
WMS在addWindow的时候会通过token找到一个DisplayContent对象:
// 1 WMS.addWindow()中
final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
这个寻找DisplayContent的过程如上图。
4 Session和IWindow接口
这里分析一下WMS.addWindow函数的前两个入参:
// WMS
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, int requestUserId, InsetsState requestedVisibility,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls)
- 第一个入参
Session
和client对应,一个client对应一个Session - 第二个入参
IWindow client
和client的IWindow的实现W类对应,WMS用client唯一标识一个WindowState
简单概括:addWindow时,Session负责client和Server间的通信,而IWindow
参数是WindowState在client的代理。
看一下IWindow是怎么实现和初始化对象的。
// ViewRootImpl.java
final W mWindow;
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
boolean useSfChoreographer) {
mWindow = new W(this);
}
static class W extends IWindow.Stub {
private final IWindowSession mWindowSession;
W(ViewRootImpl viewAncestor) {
...
mWindowSession = viewAncestor.mWindowSession;
}
}
// ViewRootImpl.setView()方法中,mWindow最为参数请求Session去addWindow。
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,
mTempControls);