Android WMS窗口管理(二)

       接着上篇文章分析,Android WMS窗口管理,接下来看一下窗口显示流程:

五.窗口显示

       窗口从最初创建到显示在屏幕上会有五个mDrawState状态的变迁,分别为:NO_SURFACE、DRAWING_PENDING、COMMIT_DRAW_PENDING、READY_TO_SHOW、HAS_DRAWN;结合代码实现来一起看一下:

1.NO_SURFACE

       当一个窗口刚刚被WMS执行addWindow()方法创建的时候,WindowStateAnimator在WindowState的构造函数中一起被创建,在relayoutWindow之前,窗口是没有Surface的,所以不可能被显示出来,此时状态就是NO_SURFACE。

2.DRAWING_PENDING

       客户端调用了relayoutWindow(),这个时候通过WindowManagerServcice的createSurfaceControl()创建了SurfaceControl,然后为窗口创建了一块空白的Surface,此时需要客户端在Surface上作画,但由于Surface为空白状态,所以还是不能显示出;看一下具体的代码逻辑实现:

2.1.relayoutWindow()

public int relayoutWindow(Session session, IWindow client, int seq,WindowManager.LayoutParams attrs, xx,xx, Surface outSurface) {
    ............................
    ...........................
    try {
        result = createSurfaceControl(outSurface, result, win, winAnimator);
    }
    .................
    .................
}

       在relayoutWindow()内部会执行createSurfaceControl(),看一下该方法实现:

2.2.createSurfaceControl()

private int createSurfaceControl(Surface outSurface, int result, WindowState win,
            WindowStateAnimator winAnimator) {
    ................
    WindowSurfaceController surfaceController;
    try {
        surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
    } finally {
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
    if (surfaceController != null) {
        surfaceController.getSurface(outSurface);
     } else {
        outSurface.release();
     }

    return result;
}

       在createSurfaceControl()内部主要做了两件事:
       1.通过WindowStateAnimator的createSurfaceLocked()获取WindowSurfaceController实例;
       2.通过WindowSurfaceController的getSurface()来对outSurface进行赋值,该outSurface对应ViewRootImpl内部的Surface,最终在该surface进行绘制显示;

2.3.createSurfaceLocked()

WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
    final WindowState w = mWin;
    ............................ 
    w.setHasSurface(false);
    resetDrawState();

    final WindowManager.LayoutParams attrs = w.mAttrs;

    if (mService.isSecureLocked(w)) {
        flags |= SurfaceControl.SECURE;
    }

    ...............................
    try {
        ......................
        mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
                    attrs.getTitle().toString(),width, height, format, flags, this, windowType, ownerUid);
        mSurfaceFormat = format;
        w.setHasSurface(true);
    }
        ..................................
    mService.openSurfaceTransaction();
    try {
        mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, false);
        mSurfaceController.setLayerStackInTransaction(getLayerStack());
        mSurfaceController.setLayer(mAnimLayer);
    } finally {
        mService.closeSurfaceTransaction();
    }
    mLastHidden = true;
    return mSurfaceController;
}

       该方法比较重要,一起看一下主要做了什么事情:
       1.执行setHasSurface(false),表示此时还未创建Surface;
       2.执行resetDrawState(),将mDrawState设置为DRAW_PENDING,此时状态变为DRAW_PENDING;
       3.创建WindowSurfaceController对象,在构造方法内部会创建SurfaceControl,每个WindowState对应一个SurfaceControl,SurfaceControl与底层的SurfaceFlinger进行交互;
       4.执行setHasSurface(true),表示Surface已经创建完毕;
       5.执行setPositionInTransaction()来设置WindowState显示的位置;
       6.执行setLayerStackInTransaction()来表示该WindowState显示在对应的LayerStack,通过SurfaceControll通知到SurfaceFlinger,一个Display对应一个LayerStack,即显示在对应的Display上;
       7.执行setLayer()来设置WindowState显示的layer,通过SurfaceControll通知到SurfaceFlinger,上篇文章讲到,对App窗口来说,mAnimLayer跟mLayer是相同的;

2.4.getSurface()

       接着上面relayoutWindow()实现分析,在创建完WindowSurfaceController后,会执行getSurface()来获取要绘制内容的Surface;

void getSurface(Surface outSurface) {
    outSurface.copyFrom(mSurfaceControl);
}

public void copyFrom(SurfaceControl other) {
    .............

    long surfaceControlPtr = other.mNativeObject;
    
    long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);

    synchronized (mLock) {
         if (mNativeObject != 0) {
             nativeRelease(mNativeObject);
         }
         setNativeObjectLocked(newNativeObject);
    }
}

       通过copyFrom()方法可以看到,将刚才创建的SurfaceControl的信息赋值给要展示的Surface,由于Surface、SurfaceControl跟底层SurfaceFlinger打交道,所以直接通过native方法来进操作;

3.COMMIT_DRAW_PENDING

       在获取到要绘制的Surface时,ViewRootImpl就通过Canvas在Surface上进行绘制,绘制完成之后会调用Session的finishDrawing()方法,调用到WMS的finishDrawingWindow()方法,看一下实现:

3.1.finishDrawingWindow()

void finishDrawingWindow(Session session, IWindow client) {
    try {
        synchronized (mWindowMap) {
            WindowState win = windowForClientLocked(session, client, false);
            if (win != null && win.mWinAnimator.finishDrawingLocked()) {
                win.setDisplayLayoutNeeded();
                mWindowPlacerLocked.requestTraversal();
            }
        }
    }
 }

       调用到WindowState的finishDrawingLocked()方法:

3.2.finishDrawingLocked()

boolean finishDrawingLocked() {
    ....................

    if (mDrawState == DRAW_PENDING) {
        mDrawState = COMMIT_DRAW_PENDING;
        layoutNeeded = true;
    }

    return layoutNeeded;
}

       在该方法内部将mDrawState设置为COMMIT_DRAW_PENDING,此时状态切换到COMMIT_DRAW_PENDING,表示窗口已经绘制完成,正在等待布局系统进行提交。

4.READY_TO_SHOW

       在WMS内部的findDrawingWindow()在设置完状态后,接着执行了mWindowPlacerLocked.requestTraversal()来请求刷新窗口,跟着调用关系,最终会调用到DIsplayContent的applySurfaceChangesTransaction()方法:

4.1.applySurfaceChangesTransaction()

boolean applySurfaceChangesTransaction(boolean recoveringMemory)
   .........................
   ........................
   forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
   ...................
}

private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
    ...........................
    ...........................
    if (w.mHasSurface) {
       final boolean committed = winAnimator.commitFinishDrawingLocked();
       .................
    }
    .............
}

       在mApplySurfaceChangesTransaction内部会遍历WindowState,前面在createSurfaceLocked()时,已经将mHasSurface设为了true,所以此时执行commitFinishDrawingLocked():

4.2.commitFinishDrawingLocked()

boolean commitFinishDrawingLocked() {
    if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
        return false;
    }
    mDrawState = READY_TO_SHOW;
    boolean result = false;
    final AppWindowToken atoken = mWin.mAppToken;
    if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
        result = mWin.performShowLocked();
    }
    return result;
}

       1.设置mDrawState = READY_TO_SHOW,把状态切换到READY_TO_SHOW;
       2.然后做如下检查:
          a.atoken == null,表示不是App窗口;
          b.atoken.allDrawn,表示 AppWindowToken 的对应的所有窗口都已经是 allDrawn,AppWindowToken通常只有一个WindowState,也可能存在 子窗口的情况,保证所有的窗口已经绘制完成了;
          c.mWin.mAttrs.type ==TYPE_APPLICATION_STARTING,表示该窗口是启动窗口;
       3.如果满足以上任何一个条件就会执行 WindowState 的 performShowLocked();

5.HAS_DRAWN

       前面讲到,在满足条件后,会执行WindowState的performShowLocked(),一起看一下:

5.1.performShowLocked()

boolean performShowLocked() {
    ......................
    final int drawState = mWinAnimator.mDrawState;
    if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW)
            && mAttrs.type != TYPE_APPLICATION_STARTING && mAppToken != null) {
        mAppToken.onFirstWindowDrawn(this, mWinAnimator);
    }

    if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
        return false;
    }

    logPerformShow("Showing ");

    mService.enableScreenIfNeededLocked();
    mWinAnimator.applyEnterAnimationLocked();

    mWinAnimator.mLastAlpha = -1;
       
    mWinAnimator.mDrawState = HAS_DRAWN;
    mService.scheduleAnimationLocked();

    if (mHidden) {
        mHidden = false;
        final DisplayContent displayContent = getDisplayContent();

        for (int i = mChildren.size() - 1; i >= 0; --i) {
            final WindowState c = mChildren.get(i);
            if (c.mWinAnimator.mSurfaceController != null) {
                c.performShowLocked();
                if (displayContent != null) {
                    displayContent.setLayoutNeeded();
                }
            }
        }
    }
   ...................
    return true;
}

       1.窗口要显示了,执行mAppToken.onFirstWindowDrawn(this, mWinAnimator)来移除STARTING_WINDOW;
       2.执行mWinAnimator.applyEnterAnimationLocked(),来加载窗口动画;
       3.设置mDrawState = HAS_DRAWN,此时窗口显示状态更新为HAS_DRWAN;
       4.执行mService.scheduleAnimationLocked()来执行窗口动画;
       5.如果有子WindowState时,执行子WindowState的performShowLocked()方法来显示窗口;

6.总结

       用一种流程图总结一下状态的变迁过程:


image.png

六.Task动画

       Task动画分为两种:STARTING_WINDOW_TYPE_SNAPSHOT和STARTING_WINDOW_TYPE_SPLASH_SCREEN,发生在一个Activity启动伴随着一次Task的切换, 要启动的窗口还没有Ready的情况下,为了体现流畅性,显示的一种窗口;
       既然是在启动的窗口还没有ready情况下显示的一种窗口,那么启动时机就应该比较早,Activity启动过程就不赘述了,直接从入口开始,在ActivityStarter内部的startActivityUnchecked()内部会调用以下逻辑:

mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,mOptions)

       在该方法内部,会执行:

r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity))

       跟着调用逻辑继续看:

void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
            boolean fromRecents) {
    ...............................
    final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
                compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
                prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
                allowTaskSnapshot(),
                state.ordinal() >= RESUMED.ordinal() && state.ordinal() <= STOPPED.ordinal(),
                fromRecents);
    if (shown) {
        mStartingWindowState = STARTING_WINDOW_SHOWN;
    }
}

       调用到AppWindowContainerController的addStartingWindow(),上篇文章中讲到,AppWindowContainerController是在创建ActivityRecord时就创建了,看一下addStartingWindow()方法:

public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
            CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
            IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
            boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
    synchronized(mWindowMap) {
        .....................................
        final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
                    mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
                    false /* restoreFromDisk */, false /* reducedResolution */);
        final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
                    allowTaskSnapshot, activityCreated, fromRecents, snapshot);
        if (type == STARTING_WINDOW_TYPE_SNAPSHOT ) {
            return createSnapshot(snapshot);
        }
        ..............................
        mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
                    compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
                    mContainer.getMergedOverrideConfiguration(), false);
        scheduleAddStartingWindow();
    }
    return true;
}

       1.通过getSnapshot()来获取该TaskRecord对应的截图;
       2.根据getStartingWindowType()来获取对应的启动type;
       3.应用非首次启动时,会走createSnapshot(snapshot)分支;首次启动时,会执行SplashScreenStartingData分支;
       先从STARTING_WINDOW_TYPE_SPLASH_SCREEN开始看:

1.STARTING_WINDOW_TYPE_SPLASH_SCREEN

       先创建SplashScreenStartingData对象赋值给mContainer.startingData,即赋值给AppWindowToken的startingData变量,接着执行scheduleAddStartingWindow()来开始staring window,先看一下SplashScreenStartingData:

1.1.SplashScreenStartingData

class SplashScreenStartingData extends StartingData {
    .....................
    SplashScreenStartingData(WindowManagerService service, String pkg, int theme,
            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
            int logo, int windowFlags, Configuration mergedOverrideConfiguration,boolean isForUIMode) {
        super(service);
        ...................
    }

    @Override
    StartingSurface createStartingSurface(AppWindowToken atoken) {
        return mService.mPolicy.addSplashScreen(atoken.token, mPkg, mTheme, mCompatInfo,
                mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags,
                mMergedOverrideConfiguration, atoken.getDisplayContent().getDisplayId(),mIsForUIMode);
    }

       继承StartingData,实现了createStartingSurface()方法来返回StartingSurface;

1.2.scheduleAddStartingWindow()

void scheduleAddStartingWindow() {
    mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
}

       发送消息到消息队列的头部,优先执行,看一下mAddStartingWindow:

private final Runnable mAddStartingWindow = () -> {
    final StartingData startingData;
    final AppWindowToken container;

    synchronized (mWindowMap) {
        if (mContainer == null) {
            return;
        }
        startingData = mContainer.startingData;
        container = mContainer;
    }
    .........................

    StartingSurface surface = null;
    try {
        surface = startingData.createStartingSurface(container);
    }
    if (surface != null) {
        boolean abort = false;
        synchronized(mWindowMap) {
            ............................
            container.startingSurface = surface;
            .......................
        }
    }
};

       1.将mContainer的startingData赋值给startingData变量;
       2.通过startingData的createStartingSurface()来获取StartingSurface实例,赋值给container的startingSurface变量;
       前面已经讲到,在createStartingSurface()内部会执行到PhoneWindowManager的addSplashScreen()来获取StartingSurface对象;

1.3.addSplashScreen()

public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
            int logo, int windowFlags, Configuration overrideConfig, int displayId,boolean forUIMode) {
    //可以设置该Flag不让显示splash screen;
    if (!SHOW_SPLASH_SCREENS) {
        return null;
    }
    WindowManager wm = null;
    View view = null;

    try {
        Context context = mContext;
        final Context displayContext = getDisplayContext(context, displayId);
        context = displayContext;
        .......................................
        final PhoneWindow win = new PhoneWindow(context);
        win.setIsStartingWindow(true);
        ............................
        win.setType(WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
        ..................................
        final WindowManager.LayoutParams params = win.getAttributes();
        params.token = appToken;
        ...........................
        params.setTitle("Splash Screen " + packageName);
        if (forUIMode){
            addSplashscreenContentForUIMode(win, context);
        } else {
            addSplashscreenContent(win, context);
        }

        wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
        view = win.getDecorView();
        wm.addView(view, params);
        return view.getParent() != null ? new SplashScreenSurface(view, appToken) : null;
    }
}

       1.获取对应Display的Context,来获取不同的资源;
       2.创建PhoneWindow实例win,设置属性mIsStartingWindow为true;
       3.设置type为TYPE_APPLICATION_STARTING,跟App窗口是不一样的,后续会根据该type来进行相应的逻辑处理;
       4.将Spashscreen窗口对应的appToken设置为params.token;
       5.设置title为"Splash Screen " + packageName;
       6.addSplashscreenContent()来创建View(),设备backgroud,并执行PhoneWindow.setContentView()来创建DecorView;
       7.通过WindowManager的addView()来显示View(SplashScreen);
       8.最后创建SplashScreenSurface对象作为返回值,为了后面来移除SplashScreen窗口;

class SplashScreenSurface implements StartingSurface {
    private final View mView;
    private final IBinder mAppToken;
    SplashScreenSurface(View view, IBinder appToken) {
        mView = view;
        mAppToken = appToken;
    }

    @Override
    public void remove() {
        final WindowManager wm = mView.getContext().getSystemService(WindowManager.class);
        wm.removeView(mView);
    }
}

1.4.onFirstWindowDrawn()

       前面讲到,在WindowState执行performShowLocked()进行最后的显示时,如果mAttrs.type != TYPE_APPLICATION_STARTING,即当App窗口要显示时会执行mAppToken.onFirstWindowDrawn(this, mWinAnimator),在该方法内部会移除SplashScreen,一起看一下逻辑实现:

void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
    firstWindowDrawn = true;
    removeDeadWindows();

    if (startingWindow != null) {
        winAnimator.clearAnimation();
        if (getController() != null) {
            getController().removeStartingWindow();
        }
    }
    updateReportedVisibilityLocked();
}

       可以看到,如果AppWindowToken对应的startingWindow不为null时,会通过AppWindowContainerController的removeStartingWindow()来进行移除:

1.5.removeStatingWindow()

public void removeStartingWindow() {
    synchronized (mWindowMap) {
        final StartingSurface surface;
        if (mContainer.startingData != null) {
            surface = mContainer.startingSurface;
            mContainer.startingData = null;
            mContainer.startingSurface = null;
            mContainer.startingWindow = null;
            mContainer.startingDisplayed = false;
        } 
        ............................
        mService.mAnimationHandler.post(() -> {
            try {
                surface.remove();
            }
        });
    }
}

       从mContainer获取StartingSurface,执行remove(),在内部通过removeView()来移除SplashScreen窗口;

2.STARTING_WINDOW_TYPE_SNAPSHOT

       从AppWindowContainerController的addStartingWindow()内部,如果返回的type为STARTING_WINDOW_TYPE_SNAPSHOT时,表示TaskRecord已经启动过,用snapshot来作为Task动画窗口,从createSnapshot()开始:

2.1.createSnapshot()

private boolean createSnapshot(TaskSnapshot snapshot) {
     if (snapshot == null) {
         return false;
     }

     mContainer.startingData = new SnapshotStartingData(mService, snapshot);
     scheduleAddStartingWindow();
     return true;
}

       创建SnapshotStartingData对象赋值给AppWindowToken的变量startingData,然后执行scheduleAddStartingWindow();

2.2.SnapshotStartingData

class SnapshotStartingData extends StartingData {

    private final WindowManagerService mService;
    private final TaskSnapshot mSnapshot;

    SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot) {
        super(service);
        mService = service;
        mSnapshot = snapshot;
    }

    @Override
    StartingSurface createStartingSurface(AppWindowToken atoken) {
        return mService.mTaskSnapshotController.createStartingSurface(atoken, mSnapshot);
    }
}

       也是继承StartingData,实现了createStartingSurface()方法内部通过TaskSnapshotController的createStartingSurface来获取StartingSurface;
       scheduleAddStartingWindow()实现前面在SplashScreen已经分析了,就不赘述了,直接看TaskSnapshotController的createStartingSurface()方法:

2.3.createStartingSurface()

StartingSurface createStartingSurface(AppWindowToken token,TaskSnapshot snapshot) {
    return TaskSnapshotSurface.create(mService, token, snapshot);
}

       调用TaskSnapshotSurface的create()方法来返回StartingSurface;

2.4.TaskSnapshotSurface

static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
            TaskSnapshot snapshot) {
    final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
    final Window window = new Window();
    final IWindowSession session = WindowManagerGlobal.getWindowSession();
    window.setSession(session);
    final Surface surface = new Surface();
    ......................
    int backgroundColor = WHITE;
    ................
    synchronized (service.mWindowMap) {
        .............................
        layoutParams.type = TYPE_APPLICATION_STARTING;
        layoutParams.token = token.token;
        layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId))
        .........................
    }
    try {
        final int res = session.addToDisplay(window, window.mSeq, layoutParams,
                View.VISIBLE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect, tmpRect, null);
    } 
    final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
                surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
                navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds,
                currentOrientation);
    window.setOuter(snapshotSurface);
    try {
        session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
                    tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
                    tmpMergedConfiguration, surface);
    }
    snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
    snapshotSurface.drawSnapshot();
    return snapshotSurface;
}

       跟SplashScreen实现类似也是设置了type及token、title、backgroudColor等参数,直接通过addToDisplay及relayout()、drawSnapshot()来显示窗口,最后返回snapshotSurface;
       最后在onFirstWindowDrawn()内不removeStartingWindow(),调用mSession.remove(mWindow)来移除snapshot窗口;

3.总结

       用一张逻辑执行流程图来总结一下:


image.png

七.窗口移除

       一个应用在启动后,下次再进入该应用时会特别快,是因为上次启动的窗口没有删除,下次再启动时不会重新执行addWindow(),那么什么时候去移除窗口呢?
       拿Activity来说,从当前Activity切换到别的Activity时,该Activity对应的窗口是不会删除的,只有当该Activity执行finish()时,比如:主动finish()、back键等,此时会执行handleDestroyActivity(),从以下三方面来看一下:

1.Activity执行finish()开启

       当Activity执行了finish()时,会对该activity进行销毁,即会执行onDestroy(),直接从ActivityThread的handleDestroy()方法看起:

private void handleDestroyActivity(IBinder token, boolean finishing,
            int configChanges, boolean getNonConfigInstance) {
    ActivityClientRecord r = performDestroyActivity(token, finishing,configChanges, getNonConfigInstance);
    WindowManager wm = r.activity.getWindowManager();
    View v = r.activity.mDecor;'
    wm.removeViewImmediate(v)
    ..............
    ActivityManager.getService().activityDestroyed(token);
}

       1.执行performDestroyActivity(),在该方法内部会通过token获取到ActivityClientRecord,然后执行activity的onDestroy(),最后从mActivities内部删除该ActivityClientRecord,最后返回ActivityClientRecord;
       2.获取到WindowManage及Activity对应的DecorView,最后调用removeViewImmediate()来移除该view;
       3.最后通知ActivityManagerService执行activityDestroyed()进行后续工作;
       先看一下removeViewImmediate()的执行过程:

1.1.removeViewImmediate()

public void removeViewImmediate(View view) {
    mGlobal.removeView(view, true);
}

       调用到WindowManagerGlobal的removeView():

1.2.removeView()

public void removeView(View view, boolean immediate) {
    synchronized (mLock) {
        int index = findViewLocked(view, true);
        View curView = mRoots.get(index).getView();
        removeViewLocked(index, immediate);
        if (curView == view) {
            return;
        }
    }
}

private void removeViewLocked(int index, boolean immediate) {
    ViewRootImpl root = mRoots.get(index);
    View view = root.getView();
    ....................
    boolean deferred = root.die(immediate);
    .....................
}

       通过index找到该view对应的ViewRootImpl,调用到ViewRootImpl的die()方法;

1.3.die()

boolean die(boolean immediate) {
    if (immediate && !mIsInTraversal) {
        doDie();
        return false;
    }
    .................
}

       在die()内调用了doDie()方法:

1.4.doDie()

void doDie() {
    checkThread();
    synchronized (this) {
        ..............
        mRemoved = true;
        if (mAdded) {
            dispatchDetachedFromWindow();
        }

        if (mAdded && !mFirst) {
            destroyHardwareRenderer();

            if (mView != null) {
                int viewVisibility = mView.getVisibility();
                boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
                if (mWindowAttributesChanged || viewVisibilityChanged) {
                    try {
                        if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
                                    & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                            mWindowSession.finishDrawing(mWindow);
                        }
                    }
                mSurface.release();
            }
        }
        mAdded = false;
    }
    WindowManagerGlobal.getInstance().doRemoveView(this);
}

       1.执行dispatchDetachedFromWindow();
       2.执行destroyHardwareRenderer(),释放跟绘制渲染相关的逻辑;
       3.执行WindowManagerGlobal.getInstance().doRemoveView(this)通知WindowManagerGlobal将该ViewRootImpl从mRoots中删除;

1.5.dispatchDetachedFromWindow()

void dispatchDetachedFromWindow() {
    if (mView != null && mView.mAttachInfo != null) {
        mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
        mView.dispatchDetachedFromWindow();
    }
    .............
    mView.assignParent(null);
    mView = null;
    mAttachInfo.mRootView = null;
    mSurface.release();
    .......................
    if (mInputEventReceiver != null) {
        mInputEventReceiver.dispose();
        mInputEventReceiver = null;
    }
    try {
        mWindowSession.remove(mWindow);
    }
    if (mInputChannel != null) {
        mInputChannel.dispose();
        mInputChannel = null;
    }

   mDisplayManager.unregisterDisplayListener(mDisplayListener);
   unscheduleTraversals();
}

       1.通过mView.dispatchDetachedFromWindow()通知Activity执行onDetachedFromWindow();
       2.进行置空和mSurface.release();
       3.执行mInputEventReceiver.dispose来取消Input事件监听;
       4.执行 mWindowSession.remove(mWindow)来移除window;
       5.执行mInputChannel.dispose()来销毁Input事件监听通道;
       6.反注册mDisplayListener;
       7.执行unscheduleTraversals()来移除消息屏障,表示不需要处理绘制优先消息了;

2.SurfaceFlinger移除对应layer

       前面讲到,执行mWindowSession的remove(),会调用到WMS的removeWindow(),一步一步执行,最终通知SurfaceFlinger来移除WindowState对应的layer,跟着调用逻辑一起看一下执行过程:

2.1.removeWindow()

void removeWindow(Session session, IWindow client) {
    synchronized(mWindowMap) {
        WindowState win = windowForClientLocked(session, client, false);
        win.removeIfPossible();
    }
}

       通过windowForClientLocked根据client找到对应的WindowState,执行removeIfPossible(),跟着调用关系,执行到removeImmediately():

2.2.removeImmediately()

void removeImmediately() {
    .......................
    mPolicy.removeWindowLw(this);
    disposeInputChannel();
    mWinAnimator.destroyDeferredSurfaceLocked();
    mWinAnimator.destroySurfaceLocked();
    mSession.windowRemovedLocked();
    mService.postWindowRemoveCleanupLocked(this);
}

       1.执行PhoneWindowManager的removeWindowLw(this) 做特殊窗口的处理,比如状态栏、导航栏等;
       2.执行disposeInputChannel()来移除Input事件监听通道;
       3.执行mWinAnimator.destroySurfaceLocked()来销毁Surface,最终会通知到SurfaceFlinger进行销毁,接下来看;
       4.执行mSession.windowRemovedLocked()来从WMS的mSessions内移除该WindowState对应的Session;
       5.执行mService.postWindowRemoveCleanupLocked(this)来从WMS的mWindowMap内移除该WindowState;

2.3.destroySurfaceLocked()

void destroyDeferredSurfaceLocked() {
    .................
    mSurfaceDestroyDeferred = false;
    mPendingDestroySurface = null;
}

       在WindowState执行removeImmediately()时,会先执行destroyDeferredSurfaceLocked(),进行一些变量的设置,再执行destroySurfaceLocked(),只列出了执行的代码逻辑:

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

void destroySurface() {
    try {
        if (mSurfaceController != null) {
            mSurfaceController.destroyInTransaction();
        }
    } finally {
        mWin.setHasSurface(false);
        mSurfaceController = null;
        mDrawState = NO_SURFACE;
    }
}

       1.执行destroySuface()来执行SurfaceController的destroyInTransaction();
       2.设置WindowState的mHasSurface为false;
       3.将mDrawState设置为NO_SURFACE;

2.4.destroyInTransaction()

void destroyInTransaction() {
    try {
        if (mSurfaceControl != null) {
            mSurfaceControl.destroy();
        } finally {
            setShown(false);
            mSurfaceControl = null;
        }
    }
}

       在destroyInTransaction()执行SurfaceControl的destroy():

2.5.destroy()

public void destroy() {
    if (mNativeObject != 0) {
        nativeDestroy(mNativeObject);
        mNativeObject = 0;
    }
    mCloseGuard.close();
}

       在destroy()内部执行nativeDestroy(mNativeObject)通知SurfaceFlinger将该WindowState对应的Layer从mCurrentState中移除;

3.WMS管理

       前面讲到,在Activity执行完onDestroy()后,会通知AMS执行activityDestroyed()方法,一起看一下:

3.1.activityDestroyedLocked()

final void activityDestroyedLocked(IBinder token, String reason) {
    try {
        ActivityRecord r = ActivityRecord.forTokenLocked(token);
        if (r != null) {
            mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
        }
        if (isInStackLocked(r) != null) {
            if (r.state == ActivityState.DESTROYING) {
                cleanUpActivityLocked(r, true, false);
                removeActivityFromHistoryLocked(r, reason);
            }
        }
    }
}

3.2.removeActivityFromHistoryLocked()

private void removeActivityFromHistoryLocked(ActivityRecord r, String reason) {
    ......................................
    r.removeWindowContainer();
    final TaskRecord task = r.getTask();
    final boolean lastActivity = task != null ? task.removeActivity(r) : false;
    ..........................
    if (lastActivity) {
        removeTask(task, reason, REMOVE_TASK_MODE_DESTROYING);
    }
}

       只分析跟WMS窗口管理相关的逻辑:
       1.调用ActivityRecord的removeWindowContainer()方法移除该ActivityRecord对应的AppWindowToken;
       2.如果是最后的activity,那么会通或removeTask()执行到Task.removeWindowContainer()来移除该TaskRecord对应的Task;

3.3.removeWindowContainer()

void removeWindowContainer() {
    mWindowContainerController.removeContainer(getDisplayId());
    mWindowContainerController = null;
}

       通过AppWindowContainerController的removeContainer()来移除,传入了displayId参数;

3.4.removeContainer()

public void removeContainer(int displayId) {
    synchronized(mWindowMap) {
        final DisplayContent dc = mRoot.getDisplayContent(displayId);
        dc.removeAppToken(mToken.asBinder());
        super.removeContainer();
    }
}

       找到displayId对应的DisplayContent,,然后执行removeAppToken():

3.5.removeAppToken()

void removeAppToken(IBinder binder) {
    final WindowToken token = removeWindowToken(binder);
    ..........................
    final AppWindowToken appToken = token.asAppWindowToken();
    ...................
    appToken.onRemovedFromDisplay();
}

WindowToken removeWindowToken(IBinder binder) {
    final WindowToken token = mTokenMap.remove(binder);
    if (token != null && token.asAppWindowToken() == null) {
        oken.setExiting();
    }
    return token;
}

       1.执行removeWindowToken()将该AppWindowToken从DisplayContent的mTokenMap中移除;
       2.执行AppWindowToken的onRemovedFromDisplay()来处理其他逻辑;

3.6.onRemovedFromDisplay()

void onRemovedFromDisplay() {
    ............................
    mRemovingFromDisplay = true;
    //从mOpeningApps中移除
    mService.mOpeningApps.remove(this);
    //从对应的snapshot从mCache中移除
    mService.mTaskSnapshotController.onAppRemoved(this);
    .....................................
    //有必要的话,移除StartingWindow
    if (startingData != null && getController() != null) {
         getController().removeStartingWindow();
    }
    ...............................
    final TaskStack stack = getStack();
    .............................
    mAppAnimator.clearAnimation();
    mAppAnimator.animating = false;
    if (stack != null) {
        //从TaskStack中的mExitingAppTokens移除
        stack.mExitingAppTokens.remove(this);
    }
   removeIfPossible();

   removed = true;
   stopFreezingScreen(true, true);
   if (mService.mFocusedApp == this) {
        mService.mFocusedApp = null;
        mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
        mService.mInputMonitor.setFocusedAppLw(null);
    }

     mRemovingFromDisplay = false;
}

       主要是做了一些清理工作,在看一下removeIfPossible()方法:

3.7.removeIfPossible()

void removeIfPossible() {
    mIsExiting = false;
    removeAllWindowsIfPossible();
    removeImmediately();
}

       调用super方法,最终调用到WindowContainer内的removeImmediately()方法:

3.8.removeImmediately()

void removeImmediately() {
    while (!mChildren.isEmpty()) {
        final WindowContainer child = mChildren.peekLast();
        child.removeImmediately();
        mChildren.remove(child);
    }

    if (mParent != null) {
        mParent.removeChild(this);
    }

    if (mController != null) {
        setController(null);
    }
}

       AppWindowToken对应的mParent为Task,调用mParent.removeChild(this)把AppWindowToken从Task中移除,然后执行setController(null)将 AppWindowContainerController置空;

4.总结

       1.窗口移除从App端发起,当Activity执行destroy()后执行wm.removeViewImmediate()开启;
       2.通过WindowManagerGlobal-->ViewRootImpl-->Session-->WindowManagerService的removeWindow(),调用到WindowState的removeImediately(),接着通过WindowStateAnimator-->WindowSurfaceController的destroyInTransaction()最终调用到SurfaceControl的destroy()来通知SurfaceFlinger来移除layer;
       3.在Acticity执行onDestroy()后会通知AMS,来执行ActivityRecord的removeWindowContainer()来从DisplayContent、taskStack、Task删除对应的AppWindowToken,并把AppWindowContainerController置空;
       4.如果该ActivityRecord的TaskRecord的最后一个ActivityRecord,那么TaskRecord也没有存在的必要了,也会跟删除AppWindowToken逻辑一样,将TaskRecord对应的Task从DisplayContent及TaskStack中删除,并把TaskWindowContainerController置空;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容