【Android】Window Mechanism

foreword

Window, that is, window, in Android, it is an abstract thing. In daily development, the thing we directly touch is View, and View is attached to Window. So we can also say that Window is the direct manager of View.

Before understanding the window mechanism, we need to have a general understanding of what is involved in the display part of the Android system.

basic concept

Surface

A Surface is an object that holds a group of pixels that are grouped together to display on the screen. Every Window seen on an Android device has its own Surface, and the Window draws its own content to the Surface. Surface Flinger renders them to the final display according to the order (Z-order) of each Surface on the Z axis.

A Surface usually has two buffers to achieve double-buffered drawing : when the application is drawing its next UI state in one buffer, Surface Flinger can synthesize and display the data in the other buffer to the screen without waiting for the application The drawing is done.

View

A View is an interactive UI element in a Window. Each Window has only one view hierarchy attached to it .

When a Window needs to be redrawn, for example, if a View invalidates itself through the invalidate method, it must enter the Surface of the Window to complete it. First, the Surface of the Window will be locked , and a canvas will be returned at the same time , which can be used to draw content on the Surface. The canvas will be passed to each View along view hierarchythe traversal , so that each View can draw its own UI part. When this process is complete, the Surface will be unlocked and submitted. The purpose of the submission is to exchange the buffer just drawn to the foreground, and then let Surface Flinger use the data in the buffer to refresh the display of the Window.

It is worth mentioning that the SurfaceView I encountered during development is actually a View. Unlike ordinary Views, it has its own dedicated Surface so that applications can draw content directly in it. SurfaceView is independent of other Views . Belongs to the view hierarchy of the Window .

Window

Window has only one Surface to draw its own content. The application creates a Window through the WindowManager, and the WindowManager creates a Surface for each Window, and passes the Surface to the application so that the application can draw on it. Applications can draw arbitrarily on the Surface.

Window's type property:

The type attribute of Window determines the display order of Window.

Window is classified, and different categories have different display height ranges. Window has a variable Z-Order, which determines the height of the Window. The larger the Z-Order, the closer the Window is to the user, and the taller and taller the Window will be displayed. Window with low height will be covered.

Window is divided into three categories:

  • Application Window : Application window, Activity is a typical application window, it is generally located at the bottom, Z-Order is between 1-99
  • Sub Window : A sub-window that cannot exist independently and needs to be attached to other windows, a typical example is PopupWindow, Z-Order between 1000-1999
  • System Window : System windows, Toast, input method windows, system volume windows, and system error windows are all system windows. System-level windows are generally located at the top and will not be covered by other windows. Z-Order is between 2000-2999

The flag parameter of Window:

By setting the flag parameter of Window, we can control the display logic of Window in various scenarios (lock screen, game, etc.) and the processing logic of touch events.

The flag parameter is defined in the inner class LayoutParams of WindowManager.

Add Flag to Window through addFlags method and setFlags method:

window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// or
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

It can also be set through WindowManager.LayoutParams:

val lp = WindowManager.LayoutParams()
lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
val tv = TextView(context)
windowManager.addView(tv, lp)

Window's solfInputMode property:

This part is the processing logic of Window when the software disk pops up, which is often encountered in daily life, such as: when we chat on WeChat, click the input box, when the soft keyboard pops up, the input box will also be closed Go up. If you don't want to be pushed up, you can also set it to be covered by the soft keyboard.

These contents can be set in the properties of Activity in AndroidManifest.xml:

android:windowSoftInputMode

You can also set it through code:

window.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST

Window is an abstract class in Android, its concrete implementation class is PhoneWindow.java, and its responsibility is to manage View.

It is worth noting that each Window has its own unique WindowManager object, and we can set the WindowManager of the Window through setWindowManagerthe method , the code is as follows:

public abstract class Window {
    
    
    // ......
    private WindowManager mWindowManager;
	// ......
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
    
    
        setWindowManager(wm, appToken, appName, false);
    }

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) {
    
    
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated;
        if (wm == null) {
    
    
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
}

The PhoneWindow.java class looks like this:

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    
    
    ......
}

WindowManager

WindowManager is responsible for maintaining the contents of the Window where it is located. In Android, WindowManager is an interface inherited from the ViewManager interface.

public interface WindowManager extends ViewManager {
    
    
    ......
}

In ViewManager, three methods for window management are defined, as follows:

public interface ViewManager {
    
    
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

The implementation class of WindowManager is WindowManagerImpl.java, and WindowManagerImpl will delegate the implementation of specific functions to WindowManagerGlobal.java. WindowManagerGlobal is a singleton, a process has only one instance of WindowManagerGlobal .

public final class WindowManagerImpl implements WindowManager {
    
    
    ......
}

DecorView

DecorView is a View that inherits from FrameLayout:

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
    
    
	......
}

DecorView is the topmost View of the entire view hierarchy.

ViewRootImpl

ViewRootImpl is mainly responsible for communicating with other services and view hierarchyguiding the drawing work.

Note: One Window only corresponds to one ViewRootImpl .

If we want to display it on the interface view hierarchy, we need to notify WMS to handle it, and this notification work is done ViewRootImplin .

For example, we can add a View to the Window WindowManagerthrough the addView method. In the addView method, a ViewRootImpl will be created to operate the view (call the setView method), and finally render the View to the window on the screen.

WMS

WMS, namely WindowManagerService, is an important service in the Android system, and WindowManager is managed by WMS. It is the real manager of Window. All Window creations will eventually go through WindowManagerService. It also determines how all Window on the screen should be displayed, how to distribute click events, etc., so it plays a very important role in the Android system.

The relationship between the nouns involved above can be reflected in this picture:

insert image description here

Window creation

In order to explain the creation of Window, we take the PhoneWindow of Activity as an example,

We know that each Activity has its own Window. When the Activity starts, the ActivityThread will call performLaunchActivity()the method to create an Activity instance:

// ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    
    
   Activity activity = null;
   // ...
   java.lang.ClassLoader cl = appContext.getClassLoader();
   activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
   Application app = r.packageInfo.makeApplication(false, mInstrumentation);
   // ...
   activity.attach(appContext, this, getInstrumentation(), r.token,
            r.ident, app, r.intent, r.activityInfo, title, r.parent,
            r.embeddedID, r.lastNonConfigurationInstances, config,
            r.referrer, r.voiceInteractor, window, r.configCallback,
            r.assistToken);
}

In performLaunchActivitythe method , the Activity's attach()method is called:

// Activity.java
final void attach(Context context, ActivityThread aThread,
    Instrumentation instr, IBinder token, int ident,
    Application application, Intent intent, ActivityInfo info,
    CharSequence title, Activity parent, String id,
    NonConfigurationInstances lastNonConfigurationInstances,
    Configuration config, String referrer, IVoiceInteractor voiceInteractor,
    Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
    
    
  ... 
  // 创建 PhoneWindow 对象
  mWindow = new PhoneWindow(this, window, activityConfigCallback);
  ...
  // 为 PhoneWindow 设置 WindowManager
  mWindow.setWindowManager(
    (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
    mToken, mComponent.flattenToString(),
    (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
 
  mWindowManager = mWindow.getWindowManager();
}

It can be seen from this that the Window (PhoneWindow) object specific to the Activity is created in attachthe method .

We mentioned above that each Window has only one view hierarchy attached to it , view hierarchyso when was it created? Or when was DecorView created?

This point is familiar to most readers. setContentView()When , DecorView will be created.

// Activity.java
public void setContentView(@LayoutRes int layoutResID) {
    
    
  getWindow().setContentView(layoutResID);
  initWindowDecorActionBar();
}

// PhoneWondow.java
@Override
public void setContentView(int layoutResID) {
    
    
  if (mContentParent == null) {
    
    
    // 创建 DecorView
    installDecor();
  } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
    
    
    mContentParent.removeAllViews();
  }
  ...
}
 
private void installDecor() {
    
    
  mForceDecorInstall = false;
  if (mDecor == null) {
    
    
    // 创建 DecorView 并赋值给 PhoneWindow 的成员变量 mDecor
    mDecor = generateDecor(-1);
    ...
  }
  ...
}
 
protected DecorView generateDecor(int featureId) {
    
    
  Context context;
  if (mUseDecorContext) {
    
    
    Context applicationContext = getContext().getApplicationContext();
    if (applicationContext == null) {
    
    
      context = getContext();
    } else {
    
    
      context = new DecorContext(applicationContext, this);
      if (mTheme != -1) {
    
    
        context.setTheme(mTheme);
      }
    }
  } else {
    
    
    context = getContext();
  }
  // 新建 DecorView 对象,并将 PhoneWindow 实例传入其中
  return new DecorView(context, featureId, this, getAttributes());
}

It can be seen from this that when we call setContentView()the method , PhoneWindow also has its own DecorView.

But so far, the Activity at this time still won't display anything on the interface .

To display on the interface view hierarchy, WMS needs to be notified to process, and this notification work is done ViewRootImplin , so another ViewRootImplobject needs to be created.

ViewRootImpl is mainly responsible for communicating with other services and view hierarchyguiding the drawing work.

So, when was ViewRootImpl created and view hierarchyassociated ?

A brief overview in one sentence: When WindowManagerImpl decides to manage the view hierarchy, it associates it with a ViewRootImpl instance . From the code level, it is when WindowManagerImpl calls addView()the method to add the View tree to the View list.

In the startup process of the Activity, ActivityThread.handleResumeActivity()the method :

// ActivityThread.java
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
        String reason) {
    
    
  ...
  // 内部会调用Activity的onResume方法
  final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
 
  final Activity a = r.activity;
 
  final int forwardBit = isForward
          ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

  boolean willBeVisible = !a.mStartedActivity;
  if (!willBeVisible) {
    
    
    try {
    
    
      willBeVisible = ActivityTaskManager.getService().willActivityBeVisible(
              a.getActivityToken());
    } catch (RemoteException e) {
    
    
      throw e.rethrowFromSystemServer();
    }
  }
  // 当窗口没有被添加到 WindowManager 中时 willBeVisible 为 true
  if (r.window == null && !a.mFinished && willBeVisible) {
    
    
    r.window = r.activity.getWindow();
    View decor = r.window.getDecorView();
    decor.setVisibility(View.INVISIBLE);
    ViewManager wm = a.getWindowManager();
    WindowManager.LayoutParams l = r.window.getAttributes();
    a.mDecor = decor;
    // 设置窗口类型
    l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
    if (a.mVisibleFromClient) {
    
    
      if (!a.mWindowAdded) {
    
    
        a.mWindowAdded = true;
        // WindowManagerImpl 将 View 添加到自己的管理队列中
        wm.addView(decor, l);
      } else {
    
    
        a.onWindowAttributesChanged(l);
      }
    }
  }
}	

In ActivityThread.handleResumeActivity()the method , WindowManagerImpl.addView()it is called and the DecorView object is passed in.

So, let's take a look at addView()the method :

// WindowManagerImpl.java

// 持有单例 WindowManagerGlobal
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
 
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    
    
  applyDefaultToken(params);
  mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

As you can see, in WindowManagerImpl.addViewthe method , WindowManagerGlobal.addViewthe method is called, and we enter addView()the method :

// WindowManagerGlobal.java
private static IWindowSession sWindowSession;
 
private final ArrayList<View> mViews = new ArrayList<View>();
@UnsupportedAppUsage
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
@UnsupportedAppUsage
private final ArrayList<WindowManager.LayoutParams> mParams =
      new ArrayList<WindowManager.LayoutParams>();
 
public void addView(View view, ViewGroup.LayoutParams params,
      Display display, Window parentWindow) {
    
    
  ...
  final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
  ...
  ViewRootImpl root;
  View panelParentView = null;
 
  synchronized (mLock) {
    
    
    ...
    // 创建 ViewRootImpl 实例
    root = new ViewRootImpl(view.getContext(), display);
    // 给 View 设置属性
    view.setLayoutParams(wparams);
 
    mViews.add(view);
    mRoots.add(root);
    mParams.add(wparams);
    ...
    // 将 ViewRootImp 于 View 进行绑定
    root.setView(view, wparams, panelParentView);
    ...
  }
}

It can be seen that in addView()the method , ViewRootImplthe object is created, and the ViewRootImpl object is bound to DecorView, that is, ViewRootImpl.setViewthe method . Thus, ViewRootImpl is view hierarchyassociated .

Next, continue to look at ViewRootImpl.setViewthe method :

// ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    
    
    synchronized (this) {
    
    
        ...
        try {
    
    
            mOrigWindowType = mWindowAttributes.type;
            mAttachInfo.mRecomputeGlobalAttributes = true;
            collectViewAttributes();
            // 这里调用了 `mWindowSession.addToDisplay` 方法,其实是调用 WMS 的方法,让 WMS 来处理 View 的显示
            res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                    getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                    mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                    mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                    mTempInsets);
            setFrame(mTmpFrame);
        } 
        ...
    }
}

It can be seen that mWindowSession.addToDisplaythe method , which is actually calling the method of WMS, so that WMS can handle the display of View.

Here we focus on the mWindowSession object, which is created in the constructor of ViewRootImpl:

// ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
    
    
	...
 	mWindowSession = WindowManagerGlobal.getWindowSession();
 	...
}

// WindowManagerGlobal.java
public static IWindowSession getWindowSession() {
    
    
 synchronized (WindowManagerGlobal.class) {
    
    
     if (sWindowSession == null) {
    
    
         try {
    
    
             ...
             sWindowSession = windowManager.openSession(
                     new IWindowSessionCallback.Stub() {
    
    
                         ...
                     });
         } 
         ...
     }
     return sWindowSession;
 }
}

It can be seen that sWindowSession is a singleton here, so we know that an application has only one WindowSession object .

mWindowSession.addToDisplayThe logic of the method is handed over to WMS for processing. The length of this article is limited, so I will not go further.

Windows updates

Update the Window by executing WindowManagerImpl.updateViewLayoutthe method :

// WindowManagerImpl.java:
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    
    
    android.util.SeempLog.record_vg_layout(384,params);
    applyDefaultToken(params);
    mGlobal.updateViewLayout(view, params);
}

The actual call is the method updateViewLayout corresponding to WindowManagerGlobal:

// WindowManagerGlobal.java:
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
    
    
        if (view == null) {
    
    
            throw new IllegalArgumentException("view must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
    
    
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
		// view 设置新的 LayoutParams
        view.setLayoutParams(wparams);

        synchronized (mLock) {
    
    
            int index = findViewLocked(view, true);
            ViewRootImpl root = mRoots.get(index);
            mParams.remove(index);
            mParams.add(index, wparams);
            root.setLayoutParams(wparams, false);
        }
}

Here, the LayoutParams of the parameter view is updated through view.setLayoutParams(wparams)the method ,

Then update the LayoutParams of ViewRootImpl through root.setLayoutParams(wparams, false)the method :

// ViewRootImpl.java:
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
    
    
    scheduleTraversals();
}

In the setLayoutParams method of ViewRootImpl, scheduleTraversalsthe method to re-layout the View, including the three processes of measurement, layout, and redrawing.

In addition to the redrawing of View itself, ViewRootImpl will also update the view of Window through WindowSession. This process is finally implemented by relayoutWindow() of WMS, which is also an IPC process.

Window deletion

The deletion process of Window is carried out through WindowManager.removeViewthe method :

// WindowManagerImpl.java:
@Override
public void removeView(View view) {
    
    
    mGlobal.removeView(view, false);
}

Then call to WindowManagerGlobal.removeViewthe method :

// WindowManagerGlobal.java:
@UnsupportedAppUsage
    public void removeView(View view, boolean immediate) {
    
    
        if (view == null) {
    
    
            throw new IllegalArgumentException("view must not be null");
        }
        synchronized (mLock) {
    
    
			// 查找待删除的 View 的索引
            int index = findViewLocked(view, true);
            // 找出对应的 ViewRootImpl
            View curView = mRoots.get(index).getView();
            // 删除方法
            removeViewLocked(index, immediate);
            if (curView == view) {
    
    
                return;
            }

            throw new IllegalStateException("Calling with view " + view
                    + " but the ViewAncestor is attached to " + curView);
        }
    }

First, get the index of the View to be deleted through findViewLockedthe method view, and then find the corresponding ViewRootImpl from mRoots according to the index.

Then call the removeViewLocked method to delete:

// WindowManagerGlobal.java:
private void removeViewLocked(int index, boolean immediate) {
    
    
        ViewRootImpl root = mRoots.get(index);
    	// 获取 ViewRootImpl 和 View 对象
        View view = root.getView();

        if (view != null) {
    
    
            InputMethodManager imm = view.getContext().getSystemService(InputMethodManager.class);
            if (imm != null) {
    
    
                // 结束该 Window 的输入法相关的逻辑
                imm.windowDismissed(mViews.get(index).getWindowToken());
            }
        }
    	// 执行 die 方法
        boolean deferred = root.die(immediate);
        if (view != null) {
    
    
            view.assignParent(null);
            if (deferred) {
    
    
                mDyingViews.add(view);
            }
        }
    }

First get the ViewRootImpl and view object, if the view object is not null,

Then call InputMethodManager.windowDismissedthe method to end the logic related to the input method of this Window.

Then call diethe method , and continue to follow up root.diethe method:

// ViewRootImpl.java:
boolean die(boolean immediate) {
    
    
    	// 需要立即执行并且此时 ViewRootImpl 不在执行 performTraversals 方法
        if (immediate && !mIsInTraversal) {
    
    
            doDie();
            return false;
        }

        if (!mIsDrawing) {
    
    
            destroyHardwareRenderer();
        } else {
    
    
            Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
                    "  window=" + this + ", title=" + mWindowAttributes.getTitle());
        }
        mHandler.sendEmptyMessage(MSG_DIE);
        return true;
    }

If immediate is true (immediate execution is required), and the value of mIsInTraversal is false, execute doDie()the method ,

mIsInTraversal will be set to true when performTraversalsthe method , and performTraversalswill be set to false when the method is executed.

Continue to follow up the doDie() method:

// ViewRootImpl.java:
void doDie() {
    
    
    	// 检查执行 doDie 方法的线程的正确性
        checkThread();
        if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
        synchronized (this) {
    
    
            if (mRemoved) {
    
    
                return;
            }
            mRemoved = true;
            // Window 有 view 就会调用 dispatchDetachedFromWindow 方法来销毁 view
            if (mAdded) {
    
    
                dispatchDetachedFromWindow();
            }
			// 如果 Window 有 View 并且不是第一次被添加,就会执行后面的代码逻辑
            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);
                            }
                        } catch (RemoteException e) {
    
    
                        }
                    }

                    destroySurface();
                }
            }

            mAdded = false;
        }
    	// 执行 WindowManagerGlobal 的 doRemoveView 方法
        WindowManagerGlobal.getInstance().doRemoveView(this);
    }

In the doDie method, there are the following processes:

1. First check the correctness of the thread that executes the doDie method, that is, judge whether the thread that executes the doDie method is the original thread that created the Window. If not, an exception will be thrown, because only the original thread that created the Window can operate the Window.

2. If the Window has a view, dispatchDetachedFromWindowthe method to destroy the view

3. Execute the doRemoveView method of WindowManagerGlobal

Let's take a look at the doRemoveView method first:

// WindowManagerGlobal.java:
void doRemoveView(ViewRootImpl root) {
    
    
        synchronized (mLock) {
    
    
            final int index = mRoots.indexOf(root);
            if (index >= 0) {
    
    
                mRoots.remove(index);
                mParams.remove(index);
                final View view = mViews.remove(index);
                mDyingViews.remove(view);
            }
        }
        if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
    
    
            doTrimForeground();
        }
    }

Three lists related to Window operations are maintained in WindowManagerGlobal:

  • mRoots: list of ViewRootImpl
  • mParams: list of layout parameters
  • mViews: View list

The doRemoveView method here will clear the elements corresponding to Window from these three lists. First, find the index of ViewRootImpl corresponding to Window, and then delete the elements corresponding to Window from mRoots, mParams and mViews according to this index.

Continuing back to the doDie method, follow up dispatchDetachedFromWindowthe method :

// ViewRootImpl.java:
void dispatchDetachedFromWindow() {
    
    
        // ...
        try {
    
    
            mWindowSession.remove(mWindow);
        } catch (RemoteException e) {
    
    
        }
		// ...
    }

The dispatchDetachedFromWindow method mainly calls the remove method of IWindowSession,

The implementation of IWindowSession on the Server side is Session, located in frameworks/base/services/core/java/com/android/server/wm/Session.java ,

We enter the remove method of Session:

// Session.java:
@Override
public void remove(IWindow window) {
    
    
    mService.removeWindow(this, window);
}

The mService here is WMS, and then check the removeWindow method of WMS:

// WindowManagerService .java
void removeWindow(Session session, IWindow client) {
    
    
    synchronized (mGlobalLock) {
    
    
        // 获取 WindowState 对象
        WindowState win = windowForClientLocked(session, client, false);
        if (win == null) {
    
    
            return;
        }
        // 调用 WindowState.removeIfPossible 方法
        win.removeIfPossible();
    }
}

windowForClientLockedThe method is used to obtain the WindowState object corresponding to the Window .

WindowState is used to save window information, and it is used to describe a window in WMS .

Finally, WindowState.removeIfPossiblethe method , which continues to follow:

// WindowState.java:
@Override
void removeIfPossible() {
    
    
    super.removeIfPossible();
    removeIfPossible(false /*keepVisibleDeadWindow*/);
}

  private void removeIfPossible(boolean keepVisibleDeadWindow) {
    
    
       // ... 条件判断过滤,满足其中一个条件就会return,推迟删除操作
      
       // removeImmediately 立即删除 Window
	   removeImmediately();
	   // ...
}

The removeIfPossible method is the same as its name. It does not directly perform the deletion operation, but performs multiple conditional judgments and filters. If one of the conditions is met, it will return and the deletion operation will be postponed.

For example, Window is performing an animation at this time, and the deletion operation must be postponed until the animation is completed.

Judging and filtering through these conditions will execute the removeImmediately method to delete the Window immediately:

// WindowState.java:
@Override
    void removeImmediately() {
    
    
        super.removeImmediately();
		// 防止重复删除操作
        if (mRemoved) {
    
    
            // Nothing to do.
            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
                    "WS.removeImmediately: " + this + " Already removed...");
            return;
        }
        mRemoved = true;

        mWillReplaceWindow = false;
        if (mReplacementWindow != null) {
    
    
            mReplacementWindow.mSkipEnterAnimationForSeamlessReplacement = false;
        }

        final DisplayContent dc = getDisplayContent();
        if (isInputMethodTarget()) {
    
    
            dc.computeImeTarget(true /* updateImeTarget */);
        }

        final int type = mAttrs.type;
        if (WindowManagerService.excludeWindowTypeFromTapOutTask(type)) {
    
    
            dc.mTapExcludedWindows.remove(this);
        }
        if (mTapExcludeRegionHolder != null) {
    
    
            dc.mTapExcludeProvidingWindows.remove(this);
        }
        dc.getDisplayPolicy().removeWindowLw(this);

        disposeInputChannel();

        mWinAnimator.destroyDeferredSurfaceLocked();
        mWinAnimator.destroySurfaceLocked();
        // 将 Window 对应的 Session 从 WMS 的 ArraySet<Session> mSessions 中删除并清除 Session 对应的 SurfaceSession 资源
        mSession.windowRemovedLocked();
        try {
    
    
            mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
        } catch (RuntimeException e) {
    
    
        }
		// 调用了 WMS 的 postWindowRemoveCleanupLocked 方法用于对 Window 进行一些集中的清理工作
        mWmService.postWindowRemoveCleanupLocked(this);
    }

If mRemoved is true, it means that the Window operation is being deleted. If the deletion is being performed, this method does not need to be executed.

mSession.windowRemovedLocked()The method will delete the Session corresponding to the Window ArraySet<Session> mSessionsfrom and clear the SurfaceSession resource corresponding to the Session.

SurfaceSession is a connection of SurfaceFlinger, through which one or more Surfaces can be created and rendered to the screen

mWmService.postWindowRemoveCleanupLockedThe method is to perform some centralized cleaning work on Window through WMS.

Guess you like

Origin blog.csdn.net/yang553566463/article/details/127656260