接着第二篇:https://www.jianshu.com/p/861fb070fed0?v=1698131713139
2.服务端
2.1 窗口添加
WMS通过Session接受客户端添加窗口的请求,因此WMS会新建WindowState、将WindowState加入到WindowToken,并更新WindowToken下所有WindowState的z-order。
客户端通过Binder通信调用WMS端的Session.addToDisplayAsUser进入addWindow的流程。
主要做了这三件事:
1.接收客户端请求
2.WindowState初始化
3.WindowState加入到WIndowToken
2.1.1 接收客户端请求
客户端传递给Session的参数
IWindow window:是WMS与客户端通信的句柄。
WindowManager.LayoutParams arrts:窗口布局参数。
viewVisibility:附着在窗口的rootView的可见性。
displayId:顾名思义,display id表示的是DisplayContent即屏幕的id。
InsetsVisibilities requestedVisibilities:当前对象的mVisibilities记录了insets的可见性。
InputChannel outInputChannel:InputDispatcher接收InputReader读取到的事件,分发给对应窗口,InputDispatcher属于system_server进程和各个应用不在同一进程,它们之间的联系靠的就是InputChannel。
InsetsState outInsetsState:用来保存系统中所有Insets的状态,该对象只是在客户端创建,内部属性需要在WMS端赋值。
InsetsSourceControl[] outActiveControls:InSetsSourceControl数组。该对象也是只在客户端创建,内部属性需要在WMS端赋值。
Session调用WMS.addWindow 将客户端传入的参数传递给WMS。
代码路径:framework/services/core/java/com/android/server/wm/Session.java
@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
requestedVisibilities, outInputChannel, outInsetsState, outActiveControls);
}
2.1.2 addWindow
添加窗口的主要逻辑均在WMS.addWindow执行,该方法主要实现以下功能:
1.首先进行权限验证以及各种条件判断。
2.根据客户端传来的token获取windowToken。
3.借助客户端传来的参数,创建WindowState实例,并将其加入到WMS. mWindowMap中。
4.将新建的WindowState加入到相应的WindowToken,并为每个窗口赋值一个z-order。
代码路径:framework/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, int requestUserId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
......
/*1.进行权限验证以及各种条件判断*/
//判断调用者是否有权限add window
int res = mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName,
appOp);
if (res != ADD_OKAY) {
return res;
}
WindowState parentWindow = null;
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
//获取将要添加的窗口类型
final int type = attrs.type;
synchronized (mGlobalLock) {
......
//根据displayId以及客户端传过来的token获取相应的displayContent
final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
......
//判断mWindowMap中是否已经存在当前客户端的key,如果有则已经将当前客户端的window添加了,无需重复添加
if (mWindowMap.containsKey(client.asBinder())) {
ProtoLog.w(WM_ERROR, "Window %s is already added", client);
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
//判断是否是子窗口
if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
parentWindow = windowForClientLocked(null, attrs.token, false);
if (parentWindow == null) {
ProtoLog.w(WM_ERROR, "Attempted to add window with token that is not a window: "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
ProtoLog.w(WM_ERROR, "Attempted to add window with token that is a sub-window: "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
}
//判断当前DisplayContent是否是私有的,只拥有该display或者display已经的应用才可以在其上创建
if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
ProtoLog.w(WM_ERROR,
"Attempted to add private presentation window to a non-private display. "
+ "Aborting.");
return WindowManagerGlobal.ADD_PERMISSION_DENIED;
}
......
ActivityRecord activity = null;
//设置是否有父窗口的标志位
final boolean hasParent = parentWindow != null;
// Use existing parent window token for child windows since they go in the same token
// as there parent window so we can apply the same policy on them.
/*2.根据客户端传来的token获取windowToken*/
//attrs.token去DisplayContent.mTokenMap中去取WindowToken
//那么WindowToken是什么时候加入到mTokenMap中的呢
//这就要追溯到Activity的启动时,加入到DisplayContent中
//在ActivityStarter.startActivityInner中调用addOrReparentStartingActivity通过addChild一步步调用到WindowContainert中。
//在调用setParent,最终通过onDisplayChanged将ActivityRecord加入到DisplayContent.mTokenMap中
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
// If this is a child window, we want to apply the same type checking rules as the
// parent window type.
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
boolean addToastWindowRequiresToken = false;
final IBinder windowContextToken = attrs.mWindowContextToken;
if (token == null) {
......
}else if (rootType >= FIRST_APPLICATION_WINDOW
&& rootType <= LAST_APPLICATION_WINDOW) {
//当前窗口为应用窗口,通过token,获取ActivityRecord
activity = token.asActivityRecord();
......
} else if (token.asActivityRecord() != null) {
ProtoLog.w(WM_ERROR, "Non-null activity for system window of rootType=%d",
rootType);
// It is not valid to use an app token with other system types; we will
// instead make a new token for it (as if null had been passed in for the token).
attrs.token = null;
token = new WindowToken.Builder(this, client.asBinder(), type)
.setDisplayContent(displayContent)
.setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
.build();
}
/*3.创建WindowState*/
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
//将客户端传过来的Insets可见性赋值给WindowState的requestedVisibilities
win.setRequestedVisibilities(requestedVisibilities);
//验证当前窗口是否可以添加到WMS
res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
if (res != ADD_OKAY) {
return res;
}
//调用openInputChannel,初始化input相关通路
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
//创建SufaceSession用于SurfaceFlinger通信
win.attach();
//将客户端与WindowState加入到mWindowMap中
mWindowMap.put(client.asBinder(), win);
win.initAppOpsState();
......
/*4.将WindowState加入到WindowToken*/
win.mToken.addWindow(win);
......
return res;
}
mWindowMap保存了每个WindowState和客户端窗口的映射关系,客户端应用请求窗口操作时,通过mWindowMap查询到对应的WindowState
2.1.3 WindowToken的创建
token = new WindowToken.Builder(this, client.asBinder(), type)
.setDisplayContent(displayContent)
.setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
.build();
这里调用的是其WindowToken自身的build方法创建
代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowToken.java
WindowToken build() {
return new WindowToken(mService, mToken, mType, mPersistOnEmpty, mDisplayContent,
mOwnerCanManageAppTokens, mRoundedCornerOverlay, mFromClientToken, mOptions);
}
protected WindowToken(WindowManagerService service, IBinder _token, int type,
boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens,
boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
super(service);
token = _token;
windowType = type;
mOptions = options;
mPersistOnEmpty = persistOnEmpty;
mOwnerCanManageAppTokens = ownerCanManageAppTokens;
mRoundedCornerOverlay = roundedCornerOverlay;
mFromClientToken = fromClientToken;
if (dc != null) {
dc.addWindowToken(token, this);
}
}
dc.addWindowToken(token, this);在WindowToken构造方法中,调用DisplayContent.addWindowToken将WindowToken添加到以DisplayContent为根节点的WindowContainer层级结构中。
代码路径:frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
void addWindowToken(IBinder binder, WindowToken token) {
final DisplayContent dc = mWmService.mRoot.getWindowTokenDisplay(token);
if (dc != null) {
// We currently don't support adding a window token to the display if the display
// already has the binder mapped to another token. If there is a use case for supporting
// this moving forward we will either need to merge the WindowTokens some how or have
// the binder map to a list of window tokens.
throw new IllegalArgumentException("Can't map token=" + token + " to display="
+ getName() + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
}
if (binder == null) {
throw new IllegalArgumentException("Can't map token=" + token + " to display="
+ getName() + " binder is null");
}
if (token == null) {
throw new IllegalArgumentException("Can't map null token to display="
+ getName() + " binder=" + binder);
}
mTokenMap.put(binder, token);
if (token.asActivityRecord() == null) {
// Set displayContent for non-app token to prevent same token will add twice after
// onDisplayChanged.
// TODO: Check if it's fine that super.onDisplayChanged of WindowToken
// (WindowsContainer#onDisplayChanged) may skipped when token.mDisplayContent assigned.
token.mDisplayContent = this;
// Add non-app token to container hierarchy on the display. App tokens are added through
// the parent container managing them (e.g. Tasks).
//1.调用DisplayContent.findAreaForToken为当前WindowToken寻找一个合适的父容器,DisplayArea.Tokens对象。
final DisplayArea.Tokens da = findAreaForToken(token).asTokens();
//2.将WindowToken添加到父容器中。
da.addChild(token);
}
}
这里我们分两步看
1.final DisplayArea.Tokens da = findAreaForToken(token).asTokens();调用DisplayContent.findAreaForToken为当前WindowToken寻找一个合适的父容器,DisplayArea.Tokens对象。
/**
* Finds the {@link DisplayArea} for the {@link WindowToken} to attach to.
* <p>
* Note that the differences between this API and
* {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} is that this API finds a
* {@link DisplayArea} in {@link DisplayContent} level, which may find a {@link DisplayArea}
* from multiple {@link RootDisplayArea RootDisplayAreas} under this {@link DisplayContent}'s
* hierarchy, while {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} finds a
* {@link DisplayArea.Tokens} from a {@link DisplayArea.Tokens} list mapped to window layers.
* </p>
*
* @see DisplayContent#findAreaForTokenInLayer(WindowToken)
*/
DisplayArea findAreaForToken(WindowToken windowToken) {
return findAreaForWindowType(windowToken.getWindowType(), windowToken.mOptions,
windowToken.mOwnerCanManageAppTokens, windowToken.mRoundedCornerOverlay);
}
为传入的WindowToken找到一个DisplayArea对象来添加进去。
DisplayArea findAreaForWindowType(int windowType, Bundle options,
boolean ownerCanManageAppToken, boolean roundedCornerOverlay) {
// TODO(b/159767464): figure out how to find an appropriate TDA.
//1.如果是App窗口,那么返回默认的TaskDisplayArea对象。
if (windowType >= FIRST_APPLICATION_WINDOW && windowType <= LAST_APPLICATION_WINDOW) {
return getDefaultTaskDisplayArea();
}
// Return IME container here because it could be in one of sub RootDisplayAreas depending on
// the focused edit text. Also, the RootDisplayArea choosing strategy is implemented by
// the server side, but not mSelectRootForWindowFunc customized by OEM.
//2.如果是输入法窗口,那么返回ImeContainer。
if (windowType == TYPE_INPUT_METHOD || windowType == TYPE_INPUT_METHOD_DIALOG) {
return getImeContainer();
}
//3.如果是其他类型,继续寻找。
return mDisplayAreaPolicy.findAreaForWindowType(windowType, options,
ownerCanManageAppToken, roundedCornerOverlay);
}
如果是App窗口,那么返回默认的TaskDisplayArea对象。
如果是输入法窗口,那么返回ImeContainer。
如果是其他类型,继续寻找。
mDisplayAreaPolicy.findAreaForWindowType(windowType, options, ownerCanManageAppToken, roundedCornerOverlay);调用的是DisplayAreaPolicy中的findAreaForWindowType方法,DisplayAreaPolicy为抽象类,DisplayAreaPolicyBuilder中的Result继承了该类
代码路径:frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
static class Result extends DisplayAreaPolicy {
......
@Override
public DisplayArea.Tokens findAreaForWindowType(int type, Bundle options,
boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
return mSelectRootForWindowFunc.apply(type, options).findAreaForWindowTypeInLayer(type,
ownerCanManageAppTokens, roundedCornerOverlay);
}
......
代码路径:frameworks/base/services/core/java/com/android/server/wm/RootDisplayArea.java
DisplayArea.Tokens findAreaForWindowTypeInLayer(int windowType, boolean ownerCanManageAppTokens,
boolean roundedCornerOverlay) {
//通过getWindowLayerFromTypeLw方法获取对应的窗口类型
int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType,
ownerCanManageAppTokens, roundedCornerOverlay);
if (windowLayerFromType == APPLICATION_LAYER) {
throw new IllegalArgumentException(
"There shouldn't be WindowToken on APPLICATION_LAYER");
}
return mAreaForLayer[windowLayerFromType];
}
通过getWindowLayerFromTypeLw方法计算出该窗口的类型对应的层级值windowLayerFromType,然后从mAreaForLayer数组中,找到windowLayerFromType对应的那个DisplayArea.Tokens对象。
- da.addChild(token);将WindowToken添加到父容器(叶子节点)中。
代码路径:frameworks/base/services/core/java/com/android/server/wm/DisplayArea.java
/**
* DisplayArea that contains WindowTokens, and orders them according to their type.
*/
public static class Tokens extends DisplayArea<WindowToken> {
......
void addChild(WindowToken token) {
addChild(token, mWindowComparator);
}
......
addChild(token, mWindowComparator);最终调用到WindowContainer.addChild方法添加WindowToken到叶子节点
2.1.4 WindowState初始化
在addWindow中初始化WindowState
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
下面我们看一下在WindowState的实例化过程中,都做了什么。
1.根据客户端传过来的参数,对相关属性进行赋值。
2.根据当前窗口的类型获取mBaseLayer,当将WindowState加入到WindowToken时,该值用来确定加入窗口在WindowToken数组中的位置。
3.实例化WindowStateAnimator,该类会跟踪当前WIndowState的动画以及surface操作。
代码路径:framework/services/core/java/com/android/server/wm/WindowState.java
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
PowerManagerWrapper powerManagerWrapper) {
/*1.根据客户端传递过来的参数,对相关属性进行赋值*/
//调用WindowState的父类WindowContainer构造方法,将WMS赋值给其父类属性mWmService
super(service);
//获取事务
mTmpTransaction = service.mTransactionFactory.get();
//将Session赋值给mSession
mSession = s;
//将与客户端通信的Binder赋值给mClient
mClient = c;
mAppOp = appOp;
//将当前activity的token赋值给mToken
mToken = token;
//通过token,获取当前窗口对的ActivityRecord
mActivityRecord = mToken.asActivityRecord();
//赋值id
mOwnerUid = ownerId;
mShowUserId = showUserId;
//是否可以添加系统窗口的标志位
mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
mWindowId = new WindowId(this);
//布局参数赋值给mAttrs
mAttrs.copyFrom(a);
//将surfaceInsets赋值给mLastSurfaceInsets
mLastSurfaceInsets.set(mAttrs.surfaceInsets);
//将窗口可见性赋值给mViewVisibility
mViewVisibility = viewVisibility;
//将窗口WindowManagerPolicy赋值给mPolicy
mPolicy = mWmService.mPolicy;
mContext = mWmService.mContext;
......
/*2.获取当前窗口的BaseLayer*/
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
......
} else {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
//当前为应用窗口所以mPolicy.getWindowLayerLw(this)获取值为2,即应用层级
//TYPE_LAYER_MULTIPLIER为同一类型的多窗口保留空间
//TYPE_LAYER_OFFSET将同一组窗口移动到同一层中其他窗口的上方或者下方
mBaseLayer = mPolicy.getWindowLayerLw(this)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = 0;
mIsChildWindow = false;
mLayoutAttached = false;
mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
}
......
/*3.新建windowStateAnimator,该类会跟踪当前WindowState的动画以及surface操作*/
mWinAnimator = new WindowStateAnimator(this);
//将透明度alpha赋值给mAlpha
mWinAnimator.mAlpha = a.alpha;
......
}
2.1.5 将WindowState加入到WindowToken
在addWindow中将WindowState加入到WindowToken
win.mToken.addWindow(win);
WindowState加入到WindowToken中的具体过程:
1.将要加入的WindowState.mBaseLayer与WindowToken中现有的WindowState.mBaseLayer相比,按照mBaseLayer有小到大存放到数组中,若mBaseLayer相等,则后加入的WindowState放在数组后面。
代码路径:framework/services/core/java/com/android/server/wm/WindowToken.java
void addWindow(final WindowState win) {
ProtoLog.d(WM_DEBUG_FOCUS,
"addWindow: win=%s Callers=%s", win, Debug.getCallers(5));
if (win.isChildWindow()) {
// Child windows are added to their parent windows.
//如果是子窗口直接返回
return;
}
// This token is created from WindowContext and the client requests to addView now, create a
// surface for this token.
if (mSurfaceControl == null) {
createSurfaceControl(true /* force */);
// Layers could have been assigned before the surface was created, update them again
reassignLayer(getSyncTransaction());
}
if (!mChildren.contains(win)) {
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", win, this);
//调用WindowContainer.addChild方法
addChild(win, mWindowComparator);
mWmService.mWindowsChanged = true;
// TODO: Should we also be setting layout needed here and other places?
}
}
/**
* Compares two child window of this token and returns -1 if the first is lesser than the
* second in terms of z-order and 1 otherwise.
*/
private final Comparator<WindowState> mWindowComparator =
(WindowState newWindow, WindowState existingWindow) -> {
final WindowToken token = WindowToken.this;
......
//如果新窗口的mBaseLayer 不小于(大于等于)已经存在的WindowState的BaseLayer,则返回1,否则返回-1
return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1;
};
/**
* Returns true if the new window is considered greater than the existing window in terms of
* z-order.
*/
protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
WindowState existingWindow) {
// New window is considered greater if it has a higher or equal base layer.
//此处可以发现比较的是两个窗口的mBaseLayer
return newWindow.mBaseLayer >= existingWindow.mBaseLayer;
}
我们看看WindowContainer.addChild方法
代码路径:framework/services/core/java/com/android/server/wm/WindowContainer.java
/**
* Adds the input window container has a child of this container in order based on the input
* comparator.
* @param child The window container to add as a child of this window container.
* @param comparator Comparator to use in determining the position the child should be added to.
* If null, the child will be added to the top.
*/
@CallSuper
protected void addChild(E child, Comparator<E> comparator) {
......
//记录插入数组的位置,若为-1则将windowState加入到后面
int positionToAdd = -1;
if (comparator != null) {
//判断当前WindowToken中WindowState的数量
//依次比较将要加入的窗口与已经存在的WindowState的BaseLayer
//mChildren越大放到数组最前面WindowToken
final int count = mChildren.size();
for (int i = 0; i < count; i++) {
//比较baseLayer,如果child大于列表中已经存在的,则需要返回1,否则返回-1
//新加入的的child大于mChildren.get(i)则返回1,小于则返回-1
//注:comparator比较器的逻辑见上面代码的mWindowComparator
if (comparator.compare(child, mChildren.get(i)) < 0) {
//记录当前要插入的位置
positionToAdd = i;
break;
}
}
}
//如果新加入的窗口大于现在所有窗口
if (positionToAdd == -1) {
//将该窗口加入到列表最后
mChildren.add(child);
} else {
mChildren.add(positionToAdd, child);
}
// Set the parent after we've actually added a child in case a subclass depends on this.
//此处将child的mParent设置为this
child.setParent(this);
}
2.将WindowState的mParent置为刚才的WindowToken,并更新其Parent的mTreeWeight。mTreeWeight记录了其子节点的数量。
继续查看WindowState的父类WindowContainer.setParent
final protected void setParent(WindowContainer<WindowContainer> parent) {
//将当前WindowState的mParent设置为相应的WindowToken
final WindowContainer oldParent = mParent;
mParent = parent;
if (mParent != null) {
//更新parent中的mTreeWeight属性
//mTreeWeight代表以parent的根节点的子树中的元素的数量
mParent.onChildAdded(this);
} else if (mSurfaceAnimator.hasLeash()) {
mSurfaceAnimator.cancelAnimation();
}
if (!mReparenting) {
onSyncReparent(oldParent, mParent);
if (mParent != null && mParent.mDisplayContent != null
&& mDisplayContent != mParent.mDisplayContent) {
onDisplayChanged(mParent.mDisplayContent);
}
//计算显示layer
onParentChanged(mParent, oldParent);
}
}
3.将WindowState加入到WindowToken之后,调用parent的assignChildLayers方法,调整其所有child的z-order。主要经历以下步骤:
初始化layer=0,代表着z-order。
遍历mChildren数组,判断Children是否需要提高到顶部(判断标志位mNeedsZBoost)。如果不需要则调用Children的assignLayer方法调整其z-order为layer,并将layer++。如果需要则执行下一遍循环。
再次遍历mChildren数组,判断Children是否需要提高到顶部。如果需要则则调用Children的assignLayer方法调整其z-order为layer,并将layer++。如果不需要则执行下一次循环。
继续看onParentChanged方法
/**
* Callback that is triggered when @link WindowContainer#setParent(WindowContainer)} was called.
* Supposed to be overridden and contain actions that should be executed after parent was set.
*/
@Override
void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
onParentChanged(newParent, oldParent, null);
}
void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent,
PreAssignChildLayersCallback callback) {
......
if (mSurfaceControl == null) {
// If we don't yet have a surface, but we now have a parent, we should
// build a surface.
//创建一个SurfaceControl来调整窗口的z-order
createSurfaceControl(false /*force*/);
} else {
......
}
......
// Either way we need to ask the parent to assign us a Z-order.
//进入WindowToken的父类WindowContainer中,调整窗口的z-order
mParent.assignChildLayers();
scheduleAnimation();
}
void assignChildLayers() {
assignChildLayers(getSyncTransaction());
scheduleAnimation();
}
void assignChildLayers(Transaction t) {
//分配给当前窗口的z-order,初始化为0
int layer = 0;
// We use two passes as a way to promote children which
// need Z-boosting to the end of the list.
//此处会以parent为根节点向下遍历到子节点,再从下到上依次进行处理
for (int j = 0; j < mChildren.size(); ++j) {
final WindowContainer wc = mChildren.get(j);
wc.assignChildLayers(t);
//needsZBoot是用来判断当前窗口是否应该提升到容器的顶部
//若不需要提升到容器的顶部
if (!wc.needsZBoost()) {
//调用WindowState的父类WindowContainer中的assignLayer
wc.assignLayer(t, layer++);
}
}
//处理需要提升到容器顶部的窗口
for (int j = 0; j < mChildren.size(); ++j) {
final WindowContainer wc = mChildren.get(j);
if (wc.needsZBoost()) {
wc.assignLayer(t, layer++);
}
}
if (mOverlayHost != null) {
mOverlayHost.setLayer(t, layer++);
}
}
4.在Children的assignLayer中会首先判断此次要调整的layer与自己上次layer是否相等,不相等则最终会调用nativeSetLayer来调整自己的z-order。
void assignLayer(Transaction t, int layer) {
// Don't assign layers while a transition animation is playing
// TODO(b/173528115): establish robust best-practices around z-order fighting.
//如果正在执行Transaction,则不需要进行assignLayer
if (mTransitionController.isPlaying()) return;
//layer为此次要调整的z-order
final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
//如果需要调整
if (mSurfaceControl != null && changed) {
//调用setLayer调整窗口的z-order
setLayer(t, layer);
//将mLastLayer调整为新的z-order
mLastLayer = layer;
mLastRelativeToLayer = null;
}
}
protected void setLayer(Transaction t, int layer) {
if (mSurfaceFreezer.hasLeash()) {
......
} else {
// Route through surface animator to accommodate that our surface control might be
// attached to the leash, and leash is attached to parent container.
//调用SurfaceAnimator中的setLayer
mSurfaceAnimator.setLayer(t, layer);
}
}
代码路径:framework/services/core/java/com/android/server/wm/SurfaceAnimator.java
/**
* Sets the layer of the surface.
* <p>
* When the layer of the surface needs to be adjusted, we need to set it on the leash if the
* surface is reparented to the leash. This method takes care of that.
*/
void setLayer(Transaction t, int layer) {
//调用SurfaceControl中的setlayer方法
t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), layer);
}
代码路径:framework/core/java/android/view/SurfaceControl.java
/**
* Set the Z-order for a given SurfaceControl, relative to it's siblings.
* If two siblings share the same Z order the ordering is undefined. Surfaces
* with a negative Z will be placed below the parent surface.
*
* @param sc The SurfaceControl to set the Z order on
* @param z The Z-order
* @return This Transaction.
*/
@NonNull
public Transaction setLayer(@NonNull SurfaceControl sc,
@IntRange(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE) int z) {
//调用调整layer
checkPreconditions(sc);
nativeSetLayer(mNativeObject, sc.mNativeObject, z);
return this;
}
————————————————
版权声明:本文为CSDN博主「yi诺千金」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yimelancholy/article/details/130339779