"Window manager" of GUI system - WMS

Introduction

What does WindowManagerService (hereinafter referred to as WMS) do?

For example, it is like a play involving N actors: SurfaceFlinger is the camera, WMS is the director, and ViewRoot is the individual actor. The role of the camera (SurfaceFlinger) is single and standardized - it is responsible for objectively capturing the current scene and then truly presenting it to the audience; the director (WMS) will take into account the stage effect and visual beauty of the drama, if he needs to base it on the actual situation According to the situation, the sorting position of each actor will be arranged. Who is in front and who is behind will affect the "picture effect" and "plot arrangement" of the performance; and the appearance and expression (ViewRoot) of each actor depend more on them. own conditions and efforts. It is through the "performing of their respective duties" by these three that a wonderful "visual feast" can finally be presented to the audience.

From the perspective of a computer I/O system, WMS must complete at least the following two functions.

  • Global window management (Output)

According to the classification of computer architecture, "window management" belongs to the "output" part - the application's display requests are output to the physical screen or other display devices in an orderly manner with the assistance of SurfaceFlinger and WMS.

  • Global event management dispatch (Input)

Correspondingly, "event management and dispatch" can be regarded as the "input" function of WMS. This is also an important factor that distinguishes WMS from SurfaceFlinger - because the latter only does things related to "display", while WMS also "part-time" dispatches input events.

Startup of WMS

WMS is one of the many system services started by SystemServer. WMS and AMS actually reside in the same process (they are both started by SystemServer) .

/*frameworks/base/services/java/com/android/server/SystemServer.java*/
public void run() {
   ….
   Slog.i(TAG, "Window Manager");
   wm = WindowManagerService.main(context, power, display, inputManager, uiHandler, wmHandler,
         factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,!firstBoot, onlyCore);
   ServiceManager.addService(Context.WINDOW_SERVICE, wm);/*注册到Service Manager中, 其他进程可以利用Context.WINDOW_SERVICE即“window”来获取WMS服务*/ 

It provides a static main function, where the real creation work is done.

IPC communication between WMS, AMS and Activity

Insert image description here

Application access to WMS

Applications must first access WMS services ServiceManagerbecause WMS is a real name Binder Server; in addition, WMS also needs to provide another anonymous implementation for each Activity, that is IWindowSession.
WMS and SurfaceFlinger serve all applications in the system. If any "small requests" from customers need to be processed directly through them, it will undoubtedly increase the burden on both, thus affecting the overall response speed of the system. Therefore, WMS IWindowManager::openSession()opens an open Sessioninterface to the outside world, and then some "trivial" chores on the client can be Sessionsolved. For example, ViewRootthis function will be called during construction:

/*frameworks/base/core/java/android/view/ViewRootImpl.java*/
public ViewRootImpl(Context context) {…
    mWindowSession = WindowManagerGlobal.getWindowSession();//获取一个IWindowSession
    …
}
/*frameworks/base/core/java/android/view/WindowManagerGlobal.java*/
    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {…
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            imm.getClient(), imm.getInputContext());
    …

WMS access application

In the application process, it first openSessionestablishes a "private connection" to the WMS by. Then it will be called IWindowSession::relayout(IWindow window,…)- the first parameter of this function is provided by the application, which is used for WMS to call back the anonymity of the application process Binder Server. IWindowThe implementation in the application process is class W:

static class W extends IWindow.Stub {…

W provides a series of callback interfaces including resized, dispatchAppVisibility, which are used by WMS to notify the application process of changes in the interface in real time (some changes are not the active intention of the application process).dispatchScreenState

Window adding process

The process of adding system windows

Taking the system window StatusBaras an example, StatusBarit is SystemUIan important part of the system, specifically the system status bar, which is used to display information such as time, power, and signals. Let's take a look at the method of StatusBarthe implementation class . This method is responsible for adding , as shown below.PhoneStatusBaraddStatusBarWindowStatusBarWindow

// frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar
private void addStatusBarWindow() {
    makeStatusBarView();//1
    mStatusBarWindowManager = new StatusBarWindowManager(mContext);
    mRemoteInputController = new RemoteInputController(mStatusBarWindowManager,
            mHeadsUpManager);
    mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());//2
}

Comment 1 is used to build StatusBarthe view. StatusBarWindowManagerThe method is called at comment 2 add, and StatusBarthe view ( StatusBarWindowView) and StatusBarare passed in.

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
public void add(View statusBarView, int barHeight) {
    mLp = new WindowManager.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            barHeight,
            WindowManager.LayoutParams.TYPE_STATUS_BAR,//1
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                    | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
            PixelFormat.TRANSLUCENT);
    mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
    mLp.gravity = Gravity.TOP;
    mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
    mLp.setTitle("StatusBar");
    mLp.packageName = mContext.getPackageName();
    mStatusBarView = statusBarView;
    mBarHeight = barHeight;
    mWindowManager.addView(mStatusBarView, mLp);//2
    mLpChanged = new WindowManager.LayoutParams();
    mLpChanged.copyFrom(mLp);
}

First, LayoutParamsconfigure StatusBarthe properties of the view by creating it, including Width、Height、Type、 Flag、Gravity、SoftInputModeetc. The key is in comment 1. It is set TYPE_STATUS_BARto indicate that StatusBarthe window type of the view is the status bar. The method called at comment 2 WindowManageris defined in the parent class interface , and the method is implemented in , as shown below.addViewaddViewWindowManagerViewManageraddViewWindowManagerImpl

frameworks/base/core/java/android/WindowManagerImpl.java
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

In WindowManagerImplthe addViewmethod, the method will then be WindowManagerGlobalcalled addView:

rameworks/base/core/java/android/view/WindowManagerGlobal.java
  public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
      ...//参数检查
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);//1
        } else {
        ...
        }

        ViewRootImpl root;
        View panelParentView = null;
         ...
            root = new ViewRootImpl(view.getContext(), display);//2
            view.setLayoutParams(wparams);
            mViews.add(view);
            mRoots.add(root);//3
            mParams.add(wparams);
        }
        try {
            root.setView(view, wparams, panelParentView);//4
        } catch (RuntimeException e) {
           ...
        }
    }

First, the parameters view, paramsand displayare checked. WindowManager.LayoutParamsNote 1, if the current window is to be used as a child window, the object of the child window type will wparamsbe adjusted accordingly according to the parent window . Note 2 is created ViewRootImpand assigned to , and then root is stored in the type rootat note 3. In addition , and are also types, used to store window objects and type objects respectively. The method called at comment 4 .ArrayList<ViewRootImpl>mRootsmRootsmViewsmParamsArrayListviewWindowManager.LayoutParamswparamsViewRootImplsetView

ViewRootImpl has many responsibilities:

  • The root of the View tree and manages the View tree
  • Trigger the measurement, layout and drawing of View
  • Relay for input events
  • ManageSurface
  • Responsible for inter-process communication with WMS
/*frameworks/base/core/java/android/view/ViewRootImpl.java*/
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;//一个ViewRootImpl对应一棵ViewTree,因而添加到其成员变量中
                …
 requestLayout();//发起layout请求
                …
                try {…
                   res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                          getHostVisibility(), mDisplay.getDisplayId(),
                          mAttachInfo.mContentInsets, mInputChannel);/*调用Session接口*/
                } catch (RemoteException e) {
                   …//出错处理
                } finally {
                   //收尾工作
                }
…

We know that WMS is the window management system. Therefore, when the application adds a new top-level View (the root of ViewTree), WMS must be notified. What should you pay attention to before registering the View tree (from the perspective of WMS, it is a "Window" and managed by WindowState) to WMS? That's right, the first layout must be executed first, that is, requestLayout is called - in addition to window management, WMS is also responsible for the dispatch of various events, so the application must ensure that the View tree has been prepared before "registering" with WMS. Prepare to receive events.

ViewRoot plays the role of an intermediary. As the "manager" of the entire View tree, it is also responsible for IPC communication with WMS. Specifically, it is to establish a bridge between the two parties through IWindowSession.

setViewThere is a lot of logic in the method, only a small part is intercepted here, mainly the method mWindowSessioncalled addToDisplay. mWindowSessionIt is IWindowSessiona type, it is an Binderobject, used for inter-process communication, and IWindowSessionis a client-side proxy. Its server-side implementation is that the code logic Sessionpreviously included ViewRootImplruns in the local process, and Sessionthe addToDisplaymethod runs in WMS The process in which it is located.

In the implementation of the IWindowSession server (Session.java), the function addToDisplay (also directly calls addWindow in WMS:

frameworks/base/services/core/java/com/android/server/wm/Session.java
@Override
 public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
         int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
         Rect outOutsets, InputChannel outInputChannel) {
     return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
             outContentInsets, outStableInsets, outOutsets, outInputChannel);
 }

Carefully analyze the parameters provided by ViewRoot to IWindowSession: The second parameter is IWindow, which is used when WMS calls back ViewRoot. The third parameter is an int value, which is used for status synchronization between WMS and ViewRoot. On the WMS server, this state synchronization value (sequence) is recorded in WindowState::mSeq. When updateStatusBarVisibilityLocked, the sequence value may change, and the ViewRoot is notified to update through the IWindow::dispatchSystemUiVisibilityChanged callback function. The fourth parameter is about properties. The fifth parameter is the visibility of the View, etc.

There are no View objects or "View tree" related variables. why?

Because WMS does not care about the specific UI content expressed by the View tree, it only needs to know the size and "level value" of the display interface of each application process (this information is already included in WindowManager.LayoutParams).

The addToDisplay method calls the addWindow method of WMS and passes itself, the Session, as a parameter. Each application process will correspond to a Session, and WMS will use ArrayList to save these Sessions. In this way, the remaining work is handed over to WMS. In WMS, a Surface will be allocated for the added window and the window display order will be determined. It can be seen that the canvas Surface is responsible for displaying the interface, not the window itself. WMS will hand over the Surface it manages to SurfaceFlinger for processing, and SurfaceFlinger will mix and draw these Surfaces to the screen.

Insert image description here

Activity window addition process

When AMS discovers that an Activity is about to start, it needs to "notify" WMS of relevant information:

/*frameworks/base/services/java/com/android/server/am/ActivityStack.java*/
private final void startActivityLocked(…)
{…
     mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId, r.info.  
     screenOrientation,r.fullscreen, 
                      (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);

WMS will record ActivityRecord into HashMap<IBinder, WindowToken>mTokenMap in WMS.

From startup to final display on the screen, Activity has to go through three state transitions: onCreate->onStart->onResume. Among them, onResume is called when the interface is about to be visible, and then ActivityThread will add the application window to the system through WindowManagerImpl. The specific code is as follows:

/*frameworks/base/core/java/android/app/ActivityThread.java*/
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {…
     ActivityClientRecord r = performResumeActivity(token, clearHide);/*这个函数将导致
                                         Activity的onResume被最终调用*/
     …
     View decor = r.window.getDecorView();/*DecorView是Activity整棵View树的最外围,
                                          可以参见下一章的分析*/
     decor.setVisibility(View.INVISIBLE);//可见性
     ViewManager wm = a.getWindowManager();//得到的实际上是WindowManagerImpl对象
     WindowManager.LayoutParams l = r.window.getAttributes();//获取属性
     a.mDecor = decor;
     l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;//窗口类型
     l.softInputMode |= forwardBit;
     if (a.mVisibleFromClient) {
         a.mWindowAdded = true;
         wm.addView(decor, l);//将窗口添加到WMS中
     }
     …

It is worth mentioning that the function performResumeActivity will eventually call Activity's onResume, but there is still a lot of processing required in the middle. If this Activity is visible, then its UI window needs to be added to WMS.

The outermost part of the View tree corresponding to an Activity is DecorView, which can be obtained by Window.getDecorView(). In other words, the "Content" that developers usually set using setContentView() in onCreate() is actually only the "content" part of the DecorView, not including the "Decor" such as the title bar.

For a general application, its window type (Window Type) is TYPE_BASE_APPLICATION, with a value of 1. This is also the window type with the lowest "level value". The WindowManagerImpl object (ie variable wm) is obtained through Activity.getWindowManager.

Finally, we add DecorView to the system through WindowManagerImpl.addView, which will cause addWindow in WMS to be called - the intermediate process is exactly the same as our analysis of adding a section in the system window.

Guess you like

Origin blog.csdn.net/jxq1994/article/details/132670188