因为我以前接触APP层的视图绘制相关业务比较多,对View的显示相关源码相对来说更感兴趣,所以想写WMS相关的源码解析很久了,但是一直迟迟没有开始写。主要是因为WMS的确是属于Android系统中最复杂的组件之一,知识点涉及从Activity生命周期、Binder、JNI、Native再到SurfaceFlinger等方方面面,分析起来容易陷入无形的大网中迷失方向
之前我有分析过View视图的测量、布局、绘制与Activity的联系,也分析过ViewRootImpl在App客户端的地位,其实就是为了这篇做准备,现在感觉基础的知识点已经具备了。但是一篇博客的内容实在是太难覆盖WMS相关的知识点了, 所以我对其中的代码进行了一定的删减,避免陷入阅读源码细节的囧境
我的目的本身是为了理解WMS在视图绘制的角色,本文中尽量多画图,少列举代码,方便快速的理解App, WMS与SurfaceFlinger的交互模式与流程
视图绘制流程:
frameworks/base/core/java/android/app/ActivityThread.java
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
...
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
...
}
关于窗口的新建与添加,我直接跳过了Activity的启动流程,直接从AMS调用scheduleResumeActivity到App端后讲起,当Activity可见时,回调用对应Activity的makeVisible方法进行可视化
frameworks/base/core/java/android/app/Activity.java
void makeVisible() {
// 如果窗口之前并没有被添加,那么先获取WindowManager服务进行添加
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
// App端视图相关的大管家是ViewRootImpl,一个窗口会对应一个,这里进行新建
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
// 保存在列表中
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// 这里进行视图设置相关操作
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
...
}
}
和ViewRootImpl的控制器角色类似,WindowManagerGlobal是窗口相关的控制器,专门用来协调窗口相关的操作
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
...
}
ViewRootImpl并没有和WindowManagerService直接进行通信,而是通过运行在system_server的WindowSession服务进行了中转
frameworks/base/services/core/java/com/android/server/wm/Session.java
@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进行处理
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
...
// 尝试获取token
WindowToken token = mTokenMap.get(attrs.token);
if (token == null) {
// 如果为空,那么会新建一个WindowToken
token = new WindowToken(this, attrs.token, -1, false);
}
...
// 新创建一个WindowState
WindowState win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
...
// 进行保存
mWindowMap.put(client.asBinder(), win);
...
}
至此,创建视图的大概操作已经完成,addWindow的操作主要在于初始化WindowToken, WindowState这两个数据结构,WMS正是主要凭借着它们来组织视图的系统层级结构的
frameworks/base/core/java/android/view/ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
...
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
}
窗口的刷新是由VSYNC进行控制的,主要是通过调用scheduleTraversals方法进行实现,这里可以看到,主要是通过mChoreographer发送了一个Message进行实现的
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
...
performTraversals();
...
}
}
private void performTraversals() {
...
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
...
}
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending) throws RemoteException {
...
int relayoutResult = mWindowSession.relayout(
mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
mSurface);
...
}
TraversalRunnable这个类中,主要是进行doTraversal的调用,最终同样是通过mWindowSession binder call到system_server进行处理
frameworks/base/services/core/java/com/android/server/wm/Session.java
public int relayout(IWindow window, int seq...) {
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
outStableInsets, outsets, outBackdropFrame, outConfig, outSurface);
return res;
}
Session的调用仅仅是起到了中转的作用
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int relayoutWindow(Session session, IWindow client...) {
...
// 首先获取到对应的WindowState
WindowState win = windowForClientLocked(session, client, false);
...
WindowStateAnimator winAnimator = win.mWinAnimator;
// 随后创建Surface
result = createSurfaceControl(outSurface, result, win, winAnimator);
}
private int createSurfaceControl(Surface outSurface, int result, WindowState win, WindowStateAnimator winAnimator) {
...
// 创建Surface
WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked();
if (surfaceController != null) {
// 进行拷贝
surfaceController.getSurface(outSurface);
} else {
// For some reason there isn't a surface. Clear the
// caller's object so they see the same state.
outSurface.release();
}
return result;
}
Surface的创建其实是层层委托,最终交给了SurfaceControl去创建Surface
frameworks/base/services/core/java/com/android/server/wm/WindowSurfaceController.java
public WindowSurfaceController(SurfaceSession s,
String name, int w, int h, int format, int flags, WindowStateAnimator animator) {
...
if (animator.mWin.isChildWindow() &&
animator.mWin.mSubLayer < 0 &&
animator.mWin.mAppToken != null) {
...
} else if (DEBUG_SURFACE_TRACE) {
...
} else {
mSurfaceControl = new SurfaceControl(
s, name, w, h, format, flags);
}
}
frameworks/base/core/java/android/view/SurfaceControl.java
public SurfaceControl(SurfaceSession session,
String name, int w, int h, int format, int flags)
throws OutOfResourcesException {
...
mNativeObject = nativeCreate(session, name, w, h, format, flags);
...
}