Android14 WMS-窗口添加流程(一)-Client端-CSDN博客
Android14 WMS-窗口添加流程(二)-Server端-CSDN博客
经过上述两个流程后,窗口的信息都已经传入了WMS端。
1. ViewRootImpl#setView
在窗口添加流程(一)中,有这个方法:
http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/view/ViewRootImpl.java#1314
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
...
}
2. ViewRootImpl#requestLayout
requestLayout中的scheduleTraversals是一个异步方法
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
//异步方法
scheduleTraversals();
}
}
3. ViewRootImpl#scheduleTraversals
scheduleTraversals中有一个Runnable方法
关于Choreographer编舞者,这里也不重点介绍。
final class TraversalRunnable implements Runnable {
@Override
public void run() {
//执行view遍历操作,进行measure,layout,draw操作
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//Choreographer Posts a callback to run on the next frame.
// The callback runs once then is automatically removed.
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
4. ViewRootImpl#doTraversal
来看看Runnable中的方法
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
...
//要执行到了真正的遍历操作,这就要对view执行measure,layout, draw流程了
performTraversals();
...
}
}
5. ViewRootImpl#performTraversals
private void performTraversals() {
...
// cache mView since it is used so much below...
//这个mView是通过setView方法传进来的,也就是Activity的根布局DecorView,使用final修饰,以防在遍历过程中被修改
final View host = mView;
...
//mAdded指DecorView是否被成功加入到window中,在setView()中被赋值为true
if (host == null || !mAdded) {
mLastPerformTraversalsSkipDrawReason = host == null ? "no_host" : "not_added";
return;
}
...
mIsInTraversal = true;//是否正在遍历
mWillDrawSoon = true;//是否需要马上绘制
boolean cancelDraw = false;
String cancelReason = null;
boolean isSyncRequest = false;
boolean windowSizeMayChange = false;
WindowManager.LayoutParams lp = mWindowAttributes;
//顶层视图DecorView窗口的期望宽高
int desiredWindowWidth;
int desiredWindowHeight;
//DecorView是否可见
final int viewVisibility = getHostVisibility();
//视图可见性改变
final boolean viewVisibilityChanged = !mFirst
&& (mViewVisibility != viewVisibility || mNewSurfaceNeeded
// Also check for possible double visibility update, which will make current
// viewVisibility value equal to mViewVisibility and we may miss it.
|| mAppVisibilityChanged);
...
WindowManager.LayoutParams params = null;
...
boolean windowShouldResize = layoutRequested && windowSizeMayChange
&& ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
|| (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
frame.width() < desiredWindowWidth && frame.width() != mWidth)
|| (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
frame.height() < desiredWindowHeight && frame.height() != mHeight));
windowShouldResize |= mDragResizing && mPendingDragResizing;
...
//第一次执行测量布局绘制操作||Activity窗口大小需要改变||View的可见性发生了变化||窗口属性发生了变化||ViewRootHandler接收到消息MSG_RESIZED_REPORT,即size改变了
if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
|| mForceNextWindowRelayout) {
...
//如果此窗口为窗口管理器提供内部insets,那么我们首先要在布局期间使提供的insets保持不变。
//这样可以避免它短暂地导致其他窗口根据窗口的原始框架调整大小/移动,
//等到我们完成此窗口的布局并返回窗口管理器,并最终计算出插图。
insetsPending = computesInternalInsets;
...
//判断是否有surface
boolean hadSurface = mSurface.isValid();
try {
...
if (mFirst || viewVisibilityChanged) {
mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
}
//params,窗口属性变化内容
//请求WMS计算Activity窗口大小及边衬区域大小
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
...
// Ask host how big it wants to be
//绘制三部曲之measure
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
//绘制三部曲之layout
performLayout(lp, mWidth, mHeight);
...
//绘制三部曲之draw
performDraw();
...
6. ViewRootImpl#relayoutWindow
我们主要是来看看ViewRootImpl如何向WMS申请布局的
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
...
//window申请的宽
final int requestedWidth = (int) (measuredWidth * appScale + 0.5f);
//window申请的高
final int requestedHeight = (int) (measuredHeight * appScale + 0.5f);
int relayoutResult = 0;
mRelayoutSeq++;
if (relayoutAsync) {
mWindowSession.relayoutAsync(mWindow, params,
requestedWidth, requestedHeight, viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
mLastSyncSeqId);
} else {
//请求重新布局
relayoutResult = mWindowSession.relayout(mWindow, params,
requestedWidth, requestedHeight, viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
mTempInsets, mTempControls, mRelayoutBundle);
...
这里就又用到了AIDL,WindowSession,WindowSession是APP和WMS沟通的桥梁
final IWindowSession mWindowSession;
可以看下这篇文章加强理解
Android14 WMS-IWindowSession介绍-CSDN博客
7. Session #relayout
//Session继承了IWindowSession.Stub
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
...
@Override
public int relayout(IWindow window, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
int lastSyncSeqId, ClientWindowFrames outFrames,
MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl,
InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
Bundle outSyncSeqIdBundle) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
//调用到了Server端
int res = mService.relayoutWindow(this, window, attrs,
requestedWidth, requestedHeight, viewFlags, flags, seq,
lastSyncSeqId, outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
outActiveControls, outSyncSeqIdBundle);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
return res;
}
8. WindowManagerService #relayoutWindow
Server端流程太多了,另起一篇文章分析。