In Android system, WindowManager(hereinafter referred to as WMS) is responsible for the management of all Windows. Windows can be understood as various display areas on the screen, such as status bar, Activity, lock screen…… For WMS, is a concrete window instance. Starting with this article, you’ll summarize the Windows Manager module.

1. The WMS architecture

In WindowManager, Windows are managed in the form of a container + tree structure. The top container is ConfigurationContainer, which is the parent of all containers. The inheritance relationship of each container is as follows:

The figure above contains all containers in the WMS. The meanings of each sub-container are as follows:

  1. ConfigurationContainer: A top-level container that defines multiple Configuration objects and provides common logic for organizing each container level.
  2. WindowProcessController: used to communicate with ProcessRecord in AMS. When ProcessRecord adjusts the application process, it communicates with WM through WindowProcessController.
  3. WindowContainer: As the parent of the save window class, it defines all the public methods used to manipulate the window.
  4. RootWindowContainer: The root node of the window container in the tree.
  5. DisplayContent: As a child of RootWindowContainer, used to manage Windows on the same logical screen;
  6. DisplayChildWindowContainer: DisplayContent all child nodes of the parent class;
  7. NonAppWindowContainers: inheritance in DisplayChildWindowContainer, the main save not WindowToken from application;
  8. WindowContainers: contains only one child node — displayArea.root, in which large sections of Windows are stored;
  9. DisplayArea: used for group management of nodes in DisplayContent, mainly divided into three categories;
  10. Root: subclass of DisplayArea. The container is the top-level DisplayArea of DisplayContent to hold Tokens, TaskDisplayArea, and ImeContainer containers.
  11. TaskDisplayArea: a subclass of DisplayArea used to manage tasks;
  12. Tokens: A subclass of DisplayArea that holds WindowTokens for normal Windows;
  13. ImeContainer: a subclass of Tokens. This container holds windowTokens for IME Windows.
  14. Task: Used to save ActivityRecord, which is often called “Task”;
  15. ActivityStack: subclass of Task, used to manage activities in the same stack, special stack can hold tasks;
  16. WindowToken: Used to manage Windows, multiple Windows can be managed by a WindowToken;
  17. ActivityRecord: Inherits from Windows Token and represents an Activity instance in ActivityStack;
  18. WallpaperWindowToken: Inherits from WindowToken. The wallpaper window is special, so it is managed by WallpaperWindowToken.
  19. WindowState: window object instance;

DisplayArea is a new container added to Android R to simplify and decouple complex window hierarchies.

In the tree structure, each container structure is as follows:

As you can see, in the tree structure, the root node is RootWindowContainer and the leaf node is WindowState. It is through this structure that WMS manages all window displays in the system in order, and sends all Windows to SurfacaFlinger in the form of Surface for synthesis and display.

2.WMS startup process

Let’s take a look at the WMS startup process. WindowManagerService does not inherit from SystemService, but directly inherits the iWindowManager. Stub interface. Therefore, the startup process is different from that of SytemService. In system_server, WMS is started by doing the following:

// frameworks/base/services/java/com/android/server/SystemServer.java

    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
	    / / create the WMSwm = WindowManagerService.main(context, inputManager, ! mFirstBoot, mOnlyCore,new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
            // Initialize
            wm.onInitReady();
            // Set the InputCallback interface
            inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
            // Update the Display configuration
            wm.displayReady();
            // The system is started
            wm.systemReady();
            / / calculate the Configuration
        final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY);
        DisplayMetrics metrics = new DisplayMetrics();
        context.getDisplay().getMetrics(metrics);
        context.getResources().updateConfiguration(config, metrics);
	}
Copy the code

The above operations are analyzed respectively below.

1.1.wms #main() creates a WMS object

After executing the main() method, an instance of WMS is eventually created on the Android.display thread:

// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    private WindowManagerService(Context context, InputManagerService inputManager,
            boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,
            Supplier<Surface> surfaceFactory,
            Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {.../ / Tranaction object
        mTransaction = mTransactionFactory.get();

	// Create WindowAnimator objects
        mAnimator = new WindowAnimator(this);
	// Create RootWindowContainer object
        mRoot = new RootWindowContainer(this);
	Create a WindowSurfacePlacer object
        mWindowPlacerLocked = new WindowSurfacePlacer(this);
	// Create a TaskSnapshotController object
        mTaskSnapshotController = new TaskSnapshotController(this);
	/ / create DisplayWindowListenerController object
        mDisplayNotificationController = new DisplayWindowListenerController(this); .// Create the SurfaceAnimationRunner object
        mSurfaceAnimationRunner = new SurfaceAnimationRunner(mTransactionFactory,
                mPowerManagerInternal);
        / / create TaskPositioningController
        mTaskPositioningController = new TaskPositioningController(
                this, mInputManager, mActivityTaskManager, mH.getLooper());
        // Create the DragDropController object
        mDragDropController = new DragDropController(this, mH.getLooper());
        / / create EmbeddedWindowController
        mEmbeddedWindowController = new EmbeddedWindowController(mAtmService);
        / / create DisplayAreaPolicy. The Provider objectmDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources( mContext.getResources()); . }Copy the code

In the constructor, you create multiple objects used by WMS.

2.2.WMS#onInitReady() initializes the Policy

The onInitReady() method is then used to initialize, in which the WindowManagerPolicy#init() method is called in the android.ui thread:

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

    public void init(Context context, IWindowManager windowManager, WindowManagerFuncs windowManagerFuncs) { mContext = context; mWindowManager = windowManager; mWindowManagerFuncs = windowManagerFuncs; . }Copy the code

A lot of initialization is done in this method. Inheriting from WindowManagerPolicy, PhoneWindowManager is a policy class in the process of managing Windows in WMS. The display of Windows and the distribution of events are affected by the policies in PhoneWindowManager. MWindowManager and mWindowManagerFuncs are WMS objects themselves.

2.3. IMS# setWindowManagerCallbacks () sets the InputCallback callback

This method is used to set the InputManagerCallback callback to the IMS:

// frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

    public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
        mWindowManagerCallbacks = callbacks;
    }
Copy the code

The InputManagerCallback object is created when THE WMS is loaded:

// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    // Create InputManagerCallback
    final InputManagerCallback mInputManagerCallback = new InputManagerCallback(this);
    
    public InputManagerCallback getInputManagerCallback(a) {
        return mInputManagerCallback;
    }
Copy the code

The InputManagerCallback interface is used to receive IMS callbacks, such as ANR during input event distribution, and transmit them to WMS through this interface.

2.4.WMS#displayReady() updates the DisplayContent configuration

This method is used to perform the first update of the Display configuration:

// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    public void displayReady(a) {
        synchronized (mGlobalLock) {
            ......
            // Tell WindowAnimator that initialization is complete
            mAnimator.ready();
            // Indicates that Display is ready to complete
            mDisplayReady = true;
            / / update the Configuration
            mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
        }

        try {
            / / update the Configuration
            mActivityTaskManager.updateConfiguration(null);
        } catch (RemoteException e) {
        }
    }
Copy the code

Here we update the DisplayContent configuration with DisplayContent#reconfigureDisplayLocked().

2.5. WMS# systemReady () method

WMS will execute the systemReady() method of other components separately:

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

    public void systemReady(a) {
        / / system
        mSystemReady = true;
        // PhoneWindowManager
        mPolicy.systemReady();
        / / execution DisplayPolicy# systemReadymRoot.forAllDisplayPolicies(DisplayPolicy::systemReady); mTaskSnapshotController.systemReady(); mHasWideColorGamutSupport = queryWideColorGamutSupport(); mHasHdrSupport = queryHdrSupport(); UiThread.getHandler().post(mSettingsObserver::loadSettings); . }Copy the code

2.6. WMS# computeNewConfiguration ()

This method is the last method executed during startup to update the global configuration status:

// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    private Configuration computeNewConfigurationLocked(int displayId) {
        if(! mDisplayReady) {return null;
        }
        final Configuration config = new Configuration();
        final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
        displayContent.computeScreenConfiguration(config);
        return config;
    }
Copy the code

In this method, it obtains the corresponding DisplayContent object based on the logical screen ID to update the configuration. After the update, it sets the configuration to the Resource object of the corresponding Context. The update configuration update process in DisplayContent will be explained in detail in future articles in combination with specific scenarios.

After the above steps, the WMS startup is complete.