Android 11平台出现一个随机性问题,灭屏然后亮屏后解锁,界面会闪现一个后台应用的界面,只要出现以后除非清除此后台应用或者重启,否则就一直存在此问题。此问题为概率性问题,故我追踪了很长时间才找到此问题原因。
(1)问题原因:
从抓取的问题log来看,很容易就看出来如下:
Window{fd7df20 u0 com.google.android.gm/com.google.android.gm.welcome.WelcomeTourActivity EXITING}
WelcomeTourActivity的WindowState一直处于EXITING状态,也就是说WindowState的属性mAnimatingExit一直等于true。
(2)问题分析:
WindowState.mAnimatingExit赋值的位置有很多,为了能够定位问题点,我打开了WMS的所有log,然后复现此问题。此过程花费了很长时间精力,不过还是复现看了出现。通过对log的分析,定位在如下位置:
08-06 18:07:02.142999 1282 3643 V WindowManager: applyAnimation: win=WindowStateAnimator{1ee7238 com.google.android.gm/com.google.android.gm.welcome.WelcomeTourActivity}anim=0 attr=0x1 a=null transit=2 type=1 isEntrance=false Callers com.android.server.wm.WindowManagerService.tryStartExitingAnimation:2547 com.android.server.wm.WindowManagerService.relayoutWindow:2341 com.android.server.wm.Session.relayout:213
08-06 18:07:02.144712 1282 3643 V WindowManager: 1ST PASS Window{fd7df20 u0 com.google.android.gm/com.google.android.gm.welcome.WelcomeTourActivity EXITING}: gone=true mHaveFrame=true mLayoutAttached=false config reported=true
如上,通过分析原码把其问题定位到了如下函数中:
private boolean tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator,
boolean focusMayChange) {
// Try starting an animation; if there isn't one, we
// can destroy the surface right away.
int transit = WindowManagerPolicy.TRANSIT_EXIT;
if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = true;
win.mAnimatingExit = true;
} else if (win.isAnimating(TRANSITION | PARENTS)) {
// Currently in a hide animation... turn this into
// an exit.
win.mAnimatingExit = true;
} else if (win.getDisplayContent().mWallpaperController.isWallpaperTarget(win)) {
// If the wallpaper is currently behind this
// window, we need to change both of them inside
// of a transaction to avoid artifacts.
win.mAnimatingExit = true;
} else {
boolean stopped = win.mActivityRecord != null ? win.mActivityRecord.mAppStopped : true;
// We set mDestroying=true so ActivityRecord#notifyAppStopped in-to destroy surfaces
// will later actually destroy the surface if we do not do so here. Normally we leave
// this to the exit animation.
win.mDestroying = true;
win.destroySurface(false, stopped);
}
if (mAccessibilityController != null) {
mAccessibilityController.onWindowTransitionLocked(win, transit);
}
// When we start the exit animation we take the Surface from the client
// so it will stop perturbing it. We need to likewise takeaway the SurfaceFlinger
// side child surfaces, so they will remain preserved in their current state
// (rather than be cleaned up immediately by the app code).
SurfaceControl.openTransaction();
winAnimator.detachChildren();
SurfaceControl.closeTransaction();
return focusMayChange;
}
可以看到tryStartExitingAnimation函数中有多个地方在对WindowState.mAnimatingExit做赋值操作,这和初始的问题原因也有关系,但是找到此问题的正真原因还是要继续分析。
a.对源码分析得出,但是在普通WindowState此自身或者父容器处于isAnimating时会赋值mAnimatingExit=true,但是查看log如下,其自身WindowState和其父容器ActivityRecord刚刚退出了一个动画,且没有新的动画进入:
08-06 18:07:01.664929 1282 1303 V WindowManager: Starting animation on ActivityRecord{a125606 u0 com.google.android.gm/.welcome.WelcomeTourActivity t300}: type=1, anim=com.android.server.wm.LocalAnimationAdapter@4fdb030
08-06 18:07:02.124094 1282 1303 V ActivityTaskManager: Animation done in ActivityRecord{a125606 u0 com.google.android.gm/.welcome.WelcomeTourActivity t300}: reportedVisible=true okToDisplay=true okToAnimate=true startingDisplayed=false
08-06 18:07:02.124120 1282 1303 V WindowManager: onExitAnimationDone in Window{fd7df20 u0 com.google.android.gm/com.google.android.gm.welcome.WelcomeTourActivity}: exiting=false remove=false selfAnimating=false
08-06 18:07:02.124150 1282 1303 V WindowManager: Win Window{fd7df20 u0 com.google.android.gm/com.google.android.gm.welcome.WelcomeTourActivity}: isDrawn=true, animating=true
由以上log看到,ActivityRecord的动画刚运行完,同时WindowState的selfAnimating=false但是WindowState的?animating却为true,查看源码selfAnimating==isSelfAnimating,而animating==isAnimating,以下为其源码:
/**
* Internal method only to be used during {@link #getAnimatingContainer(int, int)}.DO NOT CALL
* FROM OUTSIDE.
*/
protected boolean isSelfAnimating(int flags, int typesToCheck) {
if (mSurfaceAnimator.isAnimating()
&& (mSurfaceAnimator.getAnimationType() & typesToCheck) > 0) {
return true;
}
if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) {
return true;
}
return false;
}
final boolean isAnimating(int flags, int typesToCheck) {
return getAnimatingContainer(flags, typesToCheck) != null;
}
@Nullable
WindowContainer getAnimatingContainer(int flags, int typesToCheck) {
if (isSelfAnimating(flags, typesToCheck)) {
return this;
}
if ((flags & PARENTS) != 0) {
WindowContainer parent = getParent();
while (parent != null) {
if (parent.isSelfAnimating(flags, typesToCheck)) {
return parent;
}
parent = parent.getParent();
}
}
if ((flags & CHILDREN) != 0) {
for (int i = 0; i < mChildren.size(); ++i) {
final WindowContainer wc = mChildren.get(i).getAnimatingContainer(
flags & ~PARENTS, typesToCheck);
if (wc != null) {
return wc;
}
}
}
return null;
}
由以下可以看到isSelfAnimating函数为自身的动画状态判断,而isAnimating为其父容器和子容器的递归的动画状态判断。同时可以确定的为其父容器ActivityRecord.isSelfAnimating=false,其自身的WindowState.isSelfAnimating=false,其自身WindowState没有子容器,那么只能去ActivityRecord的父容器Task看看了,重新查看log,出现以下信息:
08-06 18:07:01.936326 1282 1296 V WindowManager: Starting animation on Task{5ec3041 #300 visible=true type=standard mode=fullscreen translucent=true A=10142:com.google.android.gm U=0 StackId=300 sz=2}: type=8, anim=com.android.server.wm.RecentsAnimationController$TaskAnimationAdapter@98d4c24
08-06 18:07:01.938108 1282 1296 V WindowManager: Starting animation on Task{157ea58 #286 visible=true type=home mode=fullscreen translucent=false I=com.android.launcher3/com.android.searchlauncher.SearchLauncher U=0 StackId=283 sz=1}: type=8, anim=com.android.server.wm.RecentsAnimationController$TaskAnimationAdapter@634938d
08-06 18:07:02.655548 1282 3643 D WindowManager: onAnimationFinished(): controller=com.android.server.wm.RecentsAnimationController@7f9d03e reorderMode=1
08-06 18:07:02.655735 1282 3643 D WindowManager: cleanupAnimation(): Notify animation finished mPendingAnimations=2 reorderMode=1
08-06 18:07:02.657027 1282 3643 D WindowManager: onAnimationFinished(): targetStack=Task{ab75af1 #283 visible=false type=home mode=fullscreen translucent=true I=com.android.launcher3/com.android.searchlauncher.SearchLauncher U=0 StackId=283 sz=1} targetActivity=ActivityRecord{dd35a9d u0 com.android.launcher3/com.android.searchlauncher.SearchLauncher t286} mRestoreTargetBehindStack=Task{5ec3041 #300 visible=true type=standard mode=fullscreen translucent=true A=10142:com.google.android.gm U=0 StackId=300 sz=2}
以下可以看到在WindowManagerService.tryStartExitingAnimation运行时(08-06 18:07:02.142999),WelcomeTourActivity的Task正在进行RecentAnimation的动画,那么这里也就可以定位到问题原因为:
WelcomeTourActivity的Task在运行RecentAnimation的动画,而此时WelcomeTourActivity正处于Visible从true==>false的过程,致使运行到WMS.tryStartExitingAnimation时,WelcomeTourActivity的WindowState的属性mAnimatingExit==ture,但是由于WelcomeTourActivity的Task并没有正在的退出故而RecentsAnimationController是只Finish掉了SearchLauncher的动画,而对WelcomeTourActivity动画没有做Finish,WelcomeTourActivity为欢迎界面,在此之前已经消失,系统对WelcomeTourActivity视为非前台界面,故而就导致WelcomeTourActivity的WindowState一直处于EXITING状态。
|