Android Framework-WMS-Window移除

昨天和基友装逼,结果人说你这半拉子,只写addWindow(),removeWindow() 你是一点不写啊。 抓紧补充一下。 主要我之前也没看过这部分,面试没人问啊。

大体流程

java 复制代码
ViewRootImpl.doDie(){
 dispatchDetachedFromWindow();
}

-->mWindowSession.remove(mWindow);
-->Session.remove()
-->WindowManagerService.removeWindow(this, window);
-->WindowState.removeIfPossible();

这里主要看一下WindowState.removeIfPossible()

java 复制代码
    private void removeIfPossible(boolean keepVisibleDeadWindow) {
        mWindowRemovalAllowed = true;
       

      //是启动窗口 去取消动画
        final boolean startingWindow = mAttrs.type == TYPE_APPLICATION_STARTING;
        if (startingWindow) 
            if (mActivityRecord != null) {
                mActivityRecord.forAllWindows(w -> {
                    if (w.isSelfAnimating(0, ANIMATION_TYPE_STARTING_REVEAL)) {
                        w.cancelAnimation();
                        return true;
                    }
                    return false;
                }, true);
            }
        } else if (mAttrs.type == TYPE_BASE_APPLICATION
                && isSelfAnimating(0, ANIMATION_TYPE_STARTING_REVEAL)) {
            //是应用类型 取消动画
            cancelAnimation();
        }



        final DisplayContent displayContent = getDisplayContent();
        final long origId = Binder.clearCallingIdentity();

        try {
          //取消事件
            disposeInputChannel();
            mOnBackInvokedCallbackInfo = null;

            boolean wasVisible = false;
            if (mHasSurface && mToken.okToAnimate()) {
                if (mWillReplaceWindow) {
                    mAnimatingExit = true;
                    mReplacingRemoveRequested = true;
                    return;
                }


                wasVisible = isWinVisibleLw();

              
              //标记死亡
                if (keepVisibleDeadWindow) {


                    mAppDied = true;
                    setDisplayLayoutNeeded();
                    mWmService.mWindowPlacerLocked.performSurfacePlacement();
                    openInputChannel(null);
                    displayContent.getInputMonitor().updateInputWindowsLw(true);
                    return;
                }

  
                final boolean allowExitAnimation = !displayContent.inTransition()

                        && !inRelaunchingActivity();

                if (wasVisible) {
                    final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;

                    if (allowExitAnimation && mWinAnimator.applyAnimationLocked(transit, false)) {
                       
                        mAnimatingExit = true;
                        setDisplayLayoutNeeded();
                        mWmService.requestTraversal();
                    }
                    if (mWmService.mAccessibilityController.hasCallbacks()) {
                        mWmService.mAccessibilityController.onWindowTransition(this, transit);
                    }
                }
                final boolean isAnimating = allowExitAnimation
                        && (mAnimatingExit || isExitAnimationRunningSelfOrParent());
                final boolean lastWindowIsStartingWindow = startingWindow && mActivityRecord != null
                        && mActivityRecord.isLastWindow(this);

              //看是否有动画或者正在执行退出动画 完成后进行移除
                if (mWinAnimator.getShown() && !lastWindowIsStartingWindow && isAnimating) {

                    mAnimatingExit = true;
               
                    //
                    setupWindowForRemoveOnExit();
                    if (mActivityRecord != null) {
                        mActivityRecord.updateReportedVisibilityLocked();
                    }
                    return;
                }
            }


            final boolean windowProvidesNonDecorInsets = providesNonDecorInsets();

          //直接移除
            removeImmediately();
            boolean needToSendNewConfiguration = wasVisible && displayContent.updateOrientation();
            if (windowProvidesNonDecorInsets) {
                needToSendNewConfiguration |=
                        displayContent.getDisplayPolicy().updateDecorInsetsInfo();
            }

            if (needToSendNewConfiguration) {
                displayContent.sendNewConfiguration();
            }
          //更新焦点。
            mWmService.updateFocusedWindowLocked(isFocused()
                            ? UPDATE_FOCUS_REMOVING_FOCUS
                            : UPDATE_FOCUS_NORMAL,
                    true /*updateInputWindows*/);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

这里分2种情况,有动画的需要等待动画执行完成,没动画的直接调用了removeImmediately()

直接删除

removeImmediately()

java 复制代码
//WindowState
 void removeImmediately() {
   //销毁surface
mWinAnimator.destroySurfaceLocked(getSyncTransaction());
   //调用到父类 进入
super.removeImmediately();
   //省略..
   //断开输入
   disposeInputChannel();
   //告知Session 该窗口已经删除
    mSession.windowRemovedLocked();
   //wms进行各种清除,主要是各种缓存,简单理解观察者模式删除观察者
     mWmService.postWindowRemoveCleanupLocked(this);
 }

该方法主要是进行各种销毁,内部调用到了WindowStateAnimator.destroySurfaceLocked()super.removeImmediately() 进入了 WindowContainer.removeImmediately()

先看下 WindowStateAnimator.destroySurfaceLocked()

java 复制代码
void destroySurfaceLocked(SurfaceControl.Transaction t) {
    if (mSurfaceController == null) {
        return;
    }

    mWin.mHidden = true;

    try {
        
        destroySurface(t);
     
        mWallpaperControllerLocked.hideWallpapers(mWin);
    } catch (RuntimeException e) {
       
    }

 
    mWin.setHasSurface(false);
    if (mSurfaceController != null) {
        mSurfaceController.setShown(false);
    }
    mSurfaceController = null;
    mDrawState = NO_SURFACE;
}

WindowStateAnimator.destroySurfaceLocked() 主要是销毁 surface ,然后将状态设置到 NO_SURFACE 状态, mSurfaceController 也设置了 null , 标识当前 WindowState 不存在 surface ,有点类似Message obtain() ,把属性都清空了。

再看下WindowContainer.removeImmediately()

java 复制代码
void removeImmediately() {
    final DisplayContent dc = getDisplayContent();
    if (dc != null) {
        dc.mClosingChangingContainers.remove(this);
        mSurfaceFreezer.unfreeze(getSyncTransaction());
    }
    while (!mChildren.isEmpty()) {
        final E child = mChildren.peekLast();
        child.removeImmediately();
        if (mChildren.remove(child)) {
            onChildRemoved(child);
        }
    }

    if (mSurfaceControl != null) {
        getSyncTransaction().remove(mSurfaceControl);
        setSurfaceControl(null);
        mLastSurfacePosition.set(0, 0);
        mLastDeltaRotation = Surface.ROTATION_0;
        scheduleAnimation();
    }
    if (mOverlayHost != null) {
        mOverlayHost.release();
        mOverlayHost = null;
    }


    if (mParent != null) {
        mParent.removeChild(this);
    }
    for (int i = mListeners.size() - 1; i >= 0; --i) {
        mListeners.get(i).onRemoved();
    }
}

移除当前窗口,删除子窗口,从父亲那删除自己,清理surface ,调用mListeners 通知自己已经被移除。

有动画的时候

# Android Framework-WMS-动画-初步认识中,动画完成后会调用onAnimationFinished

java 复制代码
WindowContainer(WindowManagerService wms) {
    mWmService = wms;
    mTransitionController = mWmService.mAtmService.getTransitionController();
    mPendingTransaction = wms.mTransactionFactory.get();
    mSyncTransaction = wms.mTransactionFactory.get();
    mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms);
    mSurfaceFreezer = new SurfaceFreezer(this, wms);
}


   */
    protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
        doAnimationFinished(type, anim);
        mWmService.onAnimationFinished();
        mNeedsZBoost = false;
    }

这里会进入子类 WindowState

java 复制代码
@Override
protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
    super.onAnimationFinished(type, anim);
    mWinAnimator.onAnimationFinished();
}

调用 WindowStateAnimator.onAnimationFinished(),继续调用到 WindowState.onExitAnimationDone()

java 复制代码
//WindowState
void onExitAnimationDone() {

   //省略///

  //注意该值设置为trye
    mDestroying = true;

    final boolean hasSurface = mWinAnimator.hasSurface();



     //hide
    mWinAnimator.hide(getPendingTransaction(), "onExitAnimationDone");

   
    if (mActivityRecord != null) {
      //如果是app 进入ActivityRecord的destroySurfaces
        if (mAttrs.type == TYPE_BASE_APPLICATION) {
            mActivityRecord.destroySurfaces();
        } else {
            destroySurface(false /* cleanupOnResume */, mActivityRecord.mAppStopped);
        }
    } else {
        if (hasSurface) {
          //
            mWmService.mDestroySurface.add(this);
        }
    }
    mAnimatingExit = false;
 
    getDisplayContent().mWallpaperController.hideWallpapers(this);
}

destroySurface() 有两个判断 分别在onExitAnimationDone()和setupWindowForRemoveOnExit()里面被设置为了true。

java 复制代码
boolean destroySurface(boolean cleanupOnResume, boolean appStopped) {
    boolean destroyedSomething = false;

  //在调用 onExitAnimationDone的时候 设置为true
    if (mDestroying) {
        //省略
      // 在 setupWindowForRemoveOnExit()里面设置为true
        if (mRemoveOnExit) {
            removeImmediately();
        }
        
        mDestroying = false;
        destroyedSomething = true;
//省略
    }

    return destroyedSomething;
}

发现进入removeImmediately()走到了无动画删除的流程。

总结一下

window的删除 从ViewRootImp通过Session,进入到WMSremoveWindow

调用removeIfPossible()

如果没有动画,则直接调用removeImmediately()。 会调用WindowStateAnimator.destroySurfaceLocked() 进行surface的清理,清理WindowState。 调用父类WindowContainer.removeImmediately() 清理surface ,从父亲删除自己,通知自己被移除。

如果有动画,会等待动画完成后,调用到 removeImmediately()。进行对应的清理和回收。

不要死记代码,主要我记不住。

相关推荐
BoomHe1 天前
Android AOSP13 原生 Launcher3 壁纸获取方式
android
Digitally1 天前
如何将联系人从 Android 转移到 Android
android
李小枫1 天前
webflux接收application/x-www-form-urlencoded参数
android·java·开发语言
爱丽_1 天前
MySQL `EXPLAIN`:看懂执行计划、判断索引是否生效与排错套路
android·数据库·mysql
NPE~1 天前
[App逆向]环境搭建下篇 — — 逆向源码+hook实战
android·javascript·python·教程·逆向·hook·逆向分析
yewq-cn1 天前
AOSP 下载
android
cch89181 天前
Laravel vs ThinkPHP:PHP框架终极对决
android·php·laravel
米码收割机1 天前
【Android】基于安卓app的汽车租赁管理系统(源码+部署方式+论文)[独一无二]
android·汽车
流星雨在线1 天前
安卓使用 Startup 管理三方 SDK 初始化
android·startup
jwn9991 天前
Laravel3.x:PHP框架的经典里程碑
android