Android 8.1 FreeForm切换显示异常

简介: Android 8.1 FreeForm切换显示异常

平台


RK3399 + Android 8.1

调试应用: com.android.documentsui


问题


切换后显示异常, 如下图所示, 窗口明显被拉伸了:

image.png

正确的显示效果:

image.png


调试


dumpsys window


显示异常

Window #5 Window{82f86c3 u0 com.android.documentsui/com.android.documentsui.files.FilesActivity}:
    mDisplayId=0 stackId=2 mSession=Session{8e3c127 1593:u0a10012} mClient=android.os.BinderProxy@4d7d272
    mOwnerUid=10012 mShowToOwnerOnly=true package=com.android.documentsui appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#10 ty=1 fl=#81810100 pfl=0x20000 fmt=-3 wanim=0x10302f6 vsysui=0x600 surfaceInsets=Rect(40, 40 - 40, 40) (manual) (!preservePreviousSurfaceInsets) needsMenuKey=2 colorMode=0}
    Requested w=960 h=512 mLayoutSeq=577
    mHasSurface=true mShownPosition=[484,90] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{a17f258 com.android.documentsui/com.android.documentsui.files.FilesActivity}:
      mAnimating=true mLocalAnimating=false mAnimationIsEntrance=false mAnimation=null mStackClip=1
      XForm: has=true hasLocal=false {alpha=1.0 matrix=[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
      Surface: shown=true layer=21010 alpha=1.0 rect=(444.0,50.0) 1040.0 x 592.0 transform=(0.99166936, 0.0, 1.5310801, 0.0)
      mGlobalScale=1.0 mDsDx=0.99166936 mDtDx=0.0 mDtDy=0.0 mDsDy=1.5310801
    isOnScreen=true
    isVisible=true


正常显示

Window #5 Window{82f86c3 u0 com.android.documentsui/com.android.documentsui.files.FilesActivity}:
    mDisplayId=0 stackId=2 mSession=Session{8e3c127 1593:u0a10012} mClient=android.os.BinderProxy@4d7d272
    mOwnerUid=10012 mShowToOwnerOnly=true package=com.android.documentsui appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#10 ty=1 fl=#81810100 pfl=0x20000 fmt=-3 wanim=0x10302f6 vsysui=0x600 surfaceInsets=Rect(40, 40 - 40, 40) (manual) (!preservePreviousSurfaceInsets) needsMenuKey=2 colorMode=0}
    Requested w=960 h=512 mLayoutSeq=595
    mHasSurface=true mShownPosition=[480,256] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{a17f258 com.android.documentsui/com.android.documentsui.files.FilesActivity}:
      Surface: shown=true layer=21010 alpha=1.0 rect=(440.0,216.0) 1040.0 x 592.0 transform=(1.0, 0.0, 1.0, 0.0)
    isOnScreen=true
    isVisible=true


从近期任务切换为FreeForm模式:


com.android.server.am.ActivityManagerService.startActivityFromRecents(ActivityManagerService.java:4935)
com.android.server.am.ActivityStackSupervisor.startActivityFromRecentsInner(ActivityStackSupervisor.java:4882)
com.android.server.wm.WindowManagerService.continueSurfaceLayout(WindowManagerService.java:2979)
com.android.server.wm.WindowSurfacePlacer.continueLayout(WindowSurfacePlacer.java:126)
com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:135)
com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:145)
com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:197)
com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:608)
com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:865)
com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:2784)
com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:633)
com.android.server.wm.DisplayContent.forAllWindows(DisplayContent.java:1533)
com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:616)
com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:616)
com.android.server.wm.WindowState.forAllWindows(WindowState.java:4034)
com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4127)
com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:777)
com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:779)


AppWindowAnimator.java

com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:623)
com.android.server.wm.WindowSurfacePlacer.handleAppTransitionReadyLocked(WindowSurfacePlacer.java:344)
com.android.server.wm.WindowSurfacePlacer.handleOpeningApps(WindowSurfacePlacer.java:404)
com.android.server.wm.AppWindowToken.setVisibility(AppWindowToken.java:372)
com.android.server.wm.WindowManagerService.applyAnimationLocked(WindowManagerService.java:2435)
com.android.server.wm.AppWindowAnimator.setAnimation(AppWindowAnimator.java:127)


在APP切换动画启动后,

image.png


WindowStateAnimator中计算并重新设置上面dump出来的相关变量: mShownPosition 和 transform


问题的根源在于 startProlongAnimation 调用了, 但 endProlongedAnimation 却迟迟未调用, 导致动画被无限推后, mShownPosition 和 transform 也一直无变化:


AppWindowAnimator

/**
     * Sometimes we need to synchronize the first frame of animation with some external event, e.g.
     * Recents hiding some of its content. To achieve this, we prolong the start of the animaiton
     * and keep producing the first frame of the animation.
     */
    private long getAnimationFrameTime(Animation animation, long currentTime) {
        if (mProlongAnimation == PROLONG_ANIMATION_AT_START) {
            animation.setStartTime(currentTime);
            return currentTime + 1;
        }
        return currentTime;
    }
    private boolean stepAnimation(long currentTime) {
        if (animation == null) {
            return false;
        }
        transformation.clear();
        final long animationFrameTime = getAnimationFrameTime(animation, currentTime);
  ...
  }
  void startProlongAnimation(int prolongType) {
        if(!ffNoCaption)mProlongAnimation = prolongType;
        mClearProlongedAnimation = false;
    }
    void endProlongedAnimation() {
        mProlongAnimation = PROLONG_ANIMATION_DISABLED;
    }

image.png

WindowManagerService.java

@Override
    public void endProlongedAnimations() {
        synchronized (mWindowMap) {
            for (final WindowState win : mWindowMap.values()) {
                final AppWindowToken appToken = win.mAppToken;
                if (appToken != null && appToken.mAppAnimator != null) {
                    appToken.mAppAnimator.endProlongedAnimation();
                }
            }
            mAppTransition.notifyProlongedAnimationsEnded();
        }
    }


加上调试LOG后输出:


//开始切换:
05-30 05:13:25.287 D/AppWindowAnimator      497): startProlongAnimation 80261794
05-30 05:13:25.298 D/RecentsActivity(       670): addOnPreDrawListener 2
05-30 05:13:25.301 D/RecentsActivity(       670): onPreDraw
//从mWindowMap 中删除 com.android.documentsui
05-30 05:13:25.309 D/WindowManagerService(  497): postWindowRemoveCleanupLocked remove com.android.documentsui/com.android.documentsui.files.FilesActivity
05-30 05:13:25.336 D/RecentsActivity(       670): Recents.getSystemServices().endProlongedAnimations();
//开始遍历并调用 AppWindowAnimator.endProlongedAnimation
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=com.android.systemui/com.android.systemui.recents.RecentsActivity
05-30 05:13:25.337 D/AppWindowAnimator(     497): endProlongedAnimation 43221400
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=NavigationBar
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=NavigationBar mAppAnimator is NULL
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=AssistPreviewPanel
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=AssistPreviewPanel mAppAnimator is NULL
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=DockedStackDivider
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=DockedStackDivider mAppAnimator is NULL
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=com.android.launcher3/com.android.launcher3.Launcher
05-30 05:13:25.337 D/AppWindowAnimator(     497): endProlongedAnimation 73295989
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=StatusBar
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=StatusBar mAppAnimator is NULL
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=com.android.systemui.ImageWallpaper
05-30 05:13:25.337 D/WindowManagerService(  497): endProlongedAnimations win.mAppToken.stringName=com.android.systemui.ImageWallpaper mAppAnimator is NULL
//重新将 com.android.documentsui 加入 mWindowMap 中
05-30 05:13:25.404 D/WindowManagerService(  497): addWindow com.android.documentsui/com.android.documentsui.files.FilesActivity


从调试的LOG看, 对应com.android.documentsui的Window在循环调用 AppWindowAnimator.endProlongedAnimation时, 完美地错过了…


解决:


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) {
        int[] appOp = new int[1];
        int res = mPolicy.checkAddPermission(attrs, appOp);
//...省略代码...
            } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                atoken = token.asAppWindowToken();
    //增加代码
    if(atoken != null && atoken.mAppAnimator != null){atoken.mAppAnimator.endProlongedAnimation();}
//....省略代码....


相关文章
|
18天前
|
Android开发
jack-server导致 Android 编译 出现异常
jack-server导致 Android 编译 出现异常
23 6
|
20天前
|
Android开发
android捕获全局异常,并对异常做出处理
android捕获全局异常,并对异常做出处理
20 4
|
20天前
|
Android开发
android 12 U盘 /mnt/media_rw 下读取文件异常 没有权限
android 12 U盘 /mnt/media_rw 下读取文件异常 没有权限
68 0
|
20天前
|
存储 安全 文件存储
Android OTA升级后输入法异常和应用丢失的分析
Android OTA升级后输入法异常和应用丢失的分析
25 1
|
10月前
|
数据库 Android开发 数据库管理
java.lang.NullPointerException: Attempt to invoke virtual method ‘int android.database.sqlite异常
java.lang.NullPointerException: Attempt to invoke virtual method ‘int android.database.sqlite异常
257 0
|
10月前
|
Android开发
Android > Project with path ‘:audiovisualize‘ could not be found in project ‘:app‘. 异常解决方案
Android > Project with path ‘:audiovisualize‘ could not be found in project ‘:app‘. 异常解决方案
47 0
|
JSON Android开发 数据格式
Android:解析Json异常 Expected a string but was BEGIN_OBJECT at
今天解析后端数据时,发现了这个报错:Expected BEGIN_OBJECT but was STRING at 看来是自己哪儿解析错误了。 因为数据的特殊性,后端返回的Json串里面可能还会有Json数据,可能嵌套了三次层,
|
Android开发
Android oppo手机显示安装包异常(Bug6)
Android oppo手机显示安装包异常(Bug6)
|
Java Android开发
RK3188 Android5.1 双屏异显副屏显示异常
RK3188 Android5.1 双屏异显副屏显示异常
287 0
|
Java Android开发
Android 7.1 FreeForm 多窗口模式
Android 7.1 FreeForm 多窗口模式
659 0
Android 7.1 FreeForm 多窗口模式