Android R WindowManagerService模块(4) Window的定位过程


// 对win应用Policy
mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);

}

applyKeyguardPolicyLw()方法中,将根据当前是否锁屏和WindowState是否能在锁屏上显示,对WindowState设置相应的可见标记:

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

public void applyKeyguardPolicyLw(WindowState win, WindowState imeTarget) {
// 该win是否能被keyguard隐藏
if (canBeHiddenByKeyguardLw(win)) {
// 是否当前应该进行隐藏
if (shouldBeHiddenByKeyguard(win, imeTarget)) {
win.hideLw(false);
} else {
win.showLw(false);
}
}
}

首先会判断当前WindowState是否能够被keyguard隐藏,这将直接影响到窗口的显示。如果能够被隐藏,则接下来会判断是否应该进行隐藏,如果需要进行隐藏,则调用WindowState#hideLw()进行隐藏,否则调用WindowState#showLw()进行显示。下面依次看下这个过程。

1.WindowState是否能够被keyguard隐藏

先来看如何确认WindowState是否能被Keyguard隐藏:

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

public boolean canBeHiddenByKeyguardLw(WindowState win) {
// 如果是Activity类型的WindowState,是否可见由ActivityRecord决定,不会被keyguard覆盖
if (win.getAppToken() != null) {
return false;
}
// 以下四个窗口类型,不会被Keyguard覆盖
switch (win.getAttrs().type) {
case TYPE_NOTIFICATION_SHADE:
case TYPE_STATUS_BAR:
case TYPE_NAVIGATION_BAR:
case TYPE_WALLPAPER:
return false;
default:
// 当前Win的layer是否小于
return getWindowLayerLw(win) < getWindowLayerFromTypeLw(TYPE_NOTIFICATION_SHADE);
}
}

以上流程说明,对于Activity窗口、四类系统窗口、以及窗口类型对应的Layer值大于TYPE_NOTIFICATION_SHADE类型窗口的Layer值的窗口,Keyguard是不会进行覆盖,除此之外的窗口,都会进行覆盖。

2.当前WindowState是否应该被覆盖

如果能够被覆盖,接下来会确认是否应该被覆盖:

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

private boolean shouldBeHiddenByKeyguard(WindowState win, WindowState imeTarget) {
final LayoutParams attrs = win.getAttrs();

// 如果当前窗口为IME窗口,且处于AOD状态,则对IME窗口进行隐藏
final boolean hideIme = win.isInputMethodWindow()
&& (mAodShowing || !mDefaultDisplayPolicy.isWindowManagerDrawComplete());
if (hideIme) {
return true;
}
//如果当前IME Target窗口存在且可见,且该IME Target能在锁屏上显示
final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleLw()
&& (imeTarget.canShowWhenLocked() || !canBeHiddenByKeyguardLw(imeTarget));

// 锁屏时显示IME窗口
boolean allowWhenLocked = win.isInputMethodWindow() && showImeOverKeyguard;
// 判断是否处于锁屏状态
final boolean isKeyguardShowing = mKeyguardDelegate.isShowing();
// 如果处于锁屏状态但锁屏被遮挡
if (isKeyguardShowing && isKeyguardOccluded()) {
allowWhenLocked |= win.canShowWhenLocked()
|| (attrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
}
// 返回"当前是否处于锁屏状态且不允许在锁屏上显示"
return isKeyguardShowing && !allowWhenLocked && win.getDisplayId() == DEFAULT_DISPLAY;
}

这个方法中,如果确定当前系统处于锁屏状态,且当前WindowState不允许在锁屏上显示,那么就说明需要被隐藏。

3.WindowState的隐藏和显示

如果满足条件,则通过hideLw()和showLw()方法,对WindowState进行隐藏操作,这里直接通过对WindowState#mPolicyVisibility属性设置标记来实现:

// frameworks/base/services/core/java/com/android/server/wm/WindowState.java

boolean hideLw(boolean doAnimation, boolean requestAnim) {

if (!doAnimation) {
// 清除LEGACY_POLICY_VISIBILITY标记
clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
}
return true;
}

boolean showLw(boolean doAnimation, boolean requestAnim) {
// 添加LEGACY_POLICY_VISIBILITY标记
setPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
return true;
}

WindowState最终的显示与否,取决于许多影响其可见的变量。这里通过policy的方式,无论客户端和WMS状态是否让其显示,都会对窗口进行隐藏。

3.3.mApplySurfaceChangesTransaction

mApplyPostLayoutPolicy接口执行完毕后,接下来执行mApplySurfaceChangesTransaction函数接口,在该接口中,会遍历各个WindowState,根据携带参数确定是否修改逻辑屏显示参数,并且对WindowState状态进行由COMMIT_DRAW_PENDINGREADY_TO_SHOW的转变:

// frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

private final Consumer mApplySurfaceChangesTransaction = w -> {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
// 确定当前WindowState是否被上面的WindowState遮挡
w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;

// 当前没有遮挡其他窗口的WindowState,会获取win中设置的逻辑屏显示相关属性
if (!mTmpApplySurfaceChangesTransactionState.obscured) {
final boolean isDisplayed = w.isDisplayedLw();

// 确定是否会遮挡之后进行遍历的WindowState
if (isDisplayed && w.isObscuringDisplay()) {
root.mObscuringWindow = w;
mTmpApplySurfaceChangesTransactionState.obscured = true;
}
// 逻辑屏上是否有内容显示,用于控制多屏镜像
final boolean displayHasContent = root.handleNotObscuredLocked(w,
mTmpApplySurfaceChangesTransactionState.obscured,
mTmpApplySurfaceChangesTransactionState.syswin);
if (!mTmpApplySurfaceChangesTransactionState.displayHasContent
&& !getDisplayPolicy().isWindowExcludedFromContent(w)) {
mTmpApplySurfaceChangesTransactionState.displayHasContent |= displayHasContent;
}

// 确定WindowState是否携带了preferredRefreshRate、preferredDisplayModeId等属性
if (w.mHasSurface && isDisplayed) {
final int type = w.mAttrs.type;

if (mTmpApplySurfaceChangesTransactionState.preferredRefreshRate == 0
&& w.mAttrs.preferredRefreshRate != 0) {
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate
= w.mAttrs.preferredRefreshRate;
}

}
}
// Surface状态的转换
if (w.mHasSurface) {
final boolean committed = winAnimator.commitFinishDrawingLocked();

}


};

这个方法中,主要做了三件事:

  1. 设置WindowState#mObscured属性值;
  2. 将窗口所携带控制逻辑屏显示相关参数填充给mTmpApplySurfaceChangesTransactionState对象属性;
  3. 对已经画好的窗口进行commit操作。

1.设置WindowState#mObscured属性

WindowState#mObscured表示该窗口是否被其他窗口遮挡。在此次遍历过程中,只要一个窗口已经显示且全屏显示,那么之后遍历的WindowState的mObscured属性将设置为true,表示将会被遮挡。同时将mTmpApplySurfaceChangesTransactionState.obscured设置为true。

mTmpApplySurfaceChangesTransactionState对象用来在遍历过程中保存对所有窗口遍历的结果,之所以以"temp"命名,是因为每次进行窗口遍历时,都会重置该对象。

2.填充mTmpApplySurfaceChangesTransactionState对象

在确定完WindowState#mObscured属性后,如果没有存在遮挡其他WindowState的窗口,接下来将会获取窗口属性中携带的用于控制逻辑屏显示参数的一些属性,主要有:

  • w.mAttrs.preferredRefreshRate、w.mAttrs.preferredDisplayModeId携带的刷新率;
  • w.mAttrs.screenBrightness携带的窗口亮度;
  • w.mAttrs.userActivityTimeout携带的自动休眠时间;

同时,会通过RootWindowContainer#handleNotObscuredLocked()方法,确定displayHasContent变量,表示对应窗口是否需要镜像给其他display:

// frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

boolean handleNotObscuredLocked(WindowState w, boolean obscured, boolean syswin) {

if (w.mHasSurface && canBeSeen) {

final int type = attrs.type;
final DisplayContent displayContent = w.getDisplayContent();
if (displayContent != null && displayContent.isDefaultDisplay) {
// 对于Dream类型窗口或锁屏显示时,副屏上需要不进行显示
if (w.isDreamWindow() || mWmService.mPolicy.isKeyguardShowing()) {
mObscureApplicationContentOnSecondaryDisplays = true;
}
// 默认屏幕永远为true
displayHasContent = true;
} else if (displayContent != null &&
(!mObscureApplicationContentOnSecondaryDisplays
|| (obscured && type == TYPE_KEYGUARD_DIALOG))) {
// 满足该条件的窗口在副屏上也会进行显示
displayHasContent = true;
}

}
return displayHasContent;
}

最终遍历完成后,将值保存在mTmpApplySurfaceChangesTransactionState中,并在最后向DMS发出请求,为顶层window设置显示参数,如刷新率、宽高、是否镜像…

// frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

void applySurfaceChangesTransaction() {

mTmpApplySurfaceChangesTransactionState.reset();

mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
mLastHasContent,
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredModeId,
mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
true /* inTraversal, must call performTraversalInTrans… below */);
}

3. 对绘制完成的SurfaceControl进行提交

最后一个操作是执行WindowStateAnimator#commitFinishDrawingLocked()方法,通过这个方法,会将已经绘制完成的窗口进行提交:

// frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
boolean commitFinishDrawingLocked() {

// 绘制状态变为READY_TO_SHOW
mDrawState = READY_TO_SHOW;
boolean result = false;
final ActivityRecord activity = mWin.mActivityRecord;
// 如果该WindowState的WindowToken管理的所有WindowState都完成绘制,则直接进行show操作
if (activity == null || activity.canShowWindows()
|| mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
result = mWin.performShowLocked();
}
return result;
}

经过这个方法,窗口的绘制状态将由COMMIT_DRAW_PENDING变为READY_TO_SHOW状态,进入这个状态,表示窗口已经绘制完成并且完成提交,接下来将等待同一WindowToken的窗口完成绘制后,进行最终的show操作。

窗口的显示过程共有五个状态:

  • NO_SURFACE:在创建WindowState后的默认状态,表示当前窗口还创没有执行relayout()方法创建Surface;
  • DRAW_PENDING:执行relayout()方法后,创建完成Surface后的状态,表示等待绘制;
  • COMMIT_DRAW_PENDING:窗口Surface上完成绘制后的状态,执行WindowStateAnimator#finishDrawingLocked()方法设置,表示已经完成绘制,等待下次刷帧进行提交;
  • READY_TO_SHOW:表示窗口已经绘制完成并且完成提交,此时如果该窗口的兄弟窗口全部完成绘制且满足显示要求,则直接进行HAS_DRAWN的转变完成显示,否则等待其他兄弟窗口完成绘制后,再进行HAS_DRAWN转变;
  • HAS_DRAWN:表示该窗口正式显示;

至此,mApplySurfaceChangesTransaction中的内容全部完毕。

回到DisplayContent#app()方法中,接下来将会执行prepareSurface()方法。

3.4.prepareSurfaces()对所有SurfaceControl进行最后的准备

prepareSurfaces()方法将会对每个WindowContainer的Surface做最后的准备工作,各个Surface位置、大小、是否显示在屏幕上等,都将通过这个方法来进行设置,并在关闭事务后,提交给SurfaceFlinger进行显示。

相比前面几个函数接口都是针对WindowState进行遍历,该方法则针对所有的WindowContainer进行遍历,遍历方式是由父容器→ 子容器进行,遍历路径如下图:

Android R WindowManagerService模块(4) Window的定位过程_第1张图片

黄色加深的都是实现了WindowContainer#prepareSurfaces()方法的类,下面就按照次序,看下几个重要类中的prepareSurfaces()方法。

1.DisplayContent#prepareSurfaces()

在DisplayContent#prepareSurfaces()中,主要作用是获取一个Transaction对象mPendingTransaction,并继续遍历子容器:

// frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

void prepareSurfaces() {
try {
// 获取mPendingTransaction
final Transaction transaction = getPendingTransaction();
// 执行WindowContainer#prepareSurfaces()
super.prepareSurfaces();
// 将mPendingTransaction合并到sGlobalTransaction
SurfaceControl.mergeToGlobalTransaction(transaction);
} finally {
}
}

后面可以看到,所有的prepareSurfaces()都是将SurfaceControl提交在了mPendingTransaction上。然后完成遍历后,将mPendingTransaction合并到全局Transaction对象上提交给SurfaceFlinger。

2.WindowContainer#prepareSurfaces()

在WindowContainer中,主要是提供了统一的遍历子容器的逻辑:

// frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
void prepareSurfaces() {

// 遍历子容器
for (int i = 0; i < mChildren.size(); i++) {
mChildren.get(i).prepareSurfaces();
}
}

因此,接下来DisplayContent的子容器的对应方法将会执行,依次类推…下面我们着重看下ActivityRecord和WindowState中的实现

3.ActivityRecord#prepareSurfaces()

在ActivityRecord中,将会根据其mVisible属性,对它的mSurfaceControl进行show或hide操作,同时遍历子容器prepareSurfaces操作:

// frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java

void prepareSurfaces() {
// 该ActivityRecord管理的Window是否要可见
final boolean show = isVisible() || isAnimatingExcluding(PARENTS,
ANIMATION_TYPE_SCREEN_ROTATION);

if (mSurfaceControl != null) {
// 对该SurfaceControl进行show
if (show && !mLastSurfaceShowing) {
getSyncTransaction().show(mSurfaceControl);
} else if (!show && mLastSurfaceShowing) {
// 对该SurfaceControl进行show
getSyncTransaction().hide(mSurfaceControl);
}
}

// 表示最近一次prepareSurfaces操作
mLastSurfaceShowing = show;
super.prepareSurfaces(); //继续遍历子容器
}

在这个方法中,通过getSyncTransaction()方法得到Transaction对象,并在该Transaction上对该容器的mSurfaceControl进行show或hide的操作。这个Transaction对象其实就是DisplayContent#mPendingTransaction对象。

对于所有DisplayContent以下的WindowContainer来说,它的mSurfaceControl对象并非是直接进行内容显示的Surface载体,真正的载体是在relayout()过程中由WindowSurfaceController管理并创建的对于由ActivityRecord管理的mSurfaceControl对象,而且WindowContainer#mSurfaceControl作为WindowSurfaceController#mSurfaceControl的父SurfaceControl。对于SurfaceFlinger来说,WindowContainer#mSurfaceControl是一个ContainerLayer,WindowSurfaceController#mSurfaceControl才真正进行绘制的BufferQueueLayer。

这也是为何对于由ActivityRecord来管理的WindowState而言,其可见状态由ActivityRecord控制(canBeHiddenByKeyguardLw()第一个return false)。

4.WindState#prepareSurfaces()

WindowState#prepareSurfaces()方法,是所有prepareSurfaces()方法中最重要的,在这个方法中,将会设置SurfaceControl的位置、Alpha值、Matrix、Crop等各种属性,下面来看这个方法:

// frameworks/base/services/core/java/com/android/server/wm/WindowState.java

void prepareSurfaces() {
mIsDimming = false;
// 应用Dim Layer
applyDims();
// 更新Surface的位置
updateSurfacePosition();
updateFrameRateSelectionPriorityIfNeeded();
// 进入WindowStateAnimator中进行实际Surface的准备工作
mWinAnimator.prepareSurfaceLocked(true);
notifyBlastSyncTransaction();
super.prepareSurfaces(); // 继续处理子WindowState
}

1.updateSurfacePosition()设置position

首先,通过updateSurfacePosition()设置SurfaceControl的position,这里用的Transaction对象还是mPendingTransaction:

// frameworks/base/services/core/java/com/android/server/wm/WindowState.java

void updateSurfacePosition(Transaction t) {
// 将WindowState#mWindowFrames转换成Position
transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top,
mSurfacePosition);

if (!mSurfaceAnimator.hasLeash() && mPendingSeamlessRotate == null
&& !mLastSurfacePosition.equals(mSurfacePosition)) {
// 设置position
t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);

}
}

在这个方法中,首先会使用WindowState的mWindowFrames.mFrame获得SurfaceControl的位置坐标点,然后通过Transaction#setPosition()方法完成设置。因此,每个窗口的WindowFrame对象的mFrame属性,就决定了该窗口要具体显示的位置。

2.WindowStateAnimator#prepareSurfaceLocked()

接下来进入到WindowStateAnimator#prepareSurfaceLocked()方法中

// frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java

设计模式学习笔记

Android R WindowManagerService模块(4) Window的定位过程_第2张图片

设计模式系列学习视频

Android R WindowManagerService模块(4) Window的定位过程_第3张图片

  • 以上进阶BATJ大厂学习资料可以免费分享给大家,需要完整版的朋友,【点这里可以看到全部内容】。

/server/wm/WindowStateAnimator.java

设计模式学习笔记

[外链图片转存中…(img-0ctssXwg-1643775306915)]

设计模式系列学习视频

[外链图片转存中…(img-rUcbJp7e-1643775306915)]

  • 以上进阶BATJ大厂学习资料可以免费分享给大家,需要完整版的朋友,【点这里可以看到全部内容】。

你可能感兴趣的:(程序员,架构,移动开发,android)