preface

Why is this article about Windows Manager in the first place rather than looking directly at Windows ManagerService? What is the relationship between them? This is because in order to understand WMS, you need to understand WindowManager first, and WindowManager is the class most closely associated with WMS, so it kind of lays the groundwork for WMS. This article will cover Windows Manager in more detail. To recap, we’ve looked at SystemServer, the four major components, and AMS startup analysis. After an Activity starts, you need to parse XML into a View and add a View to the Window. How does Windows relate to Windows Manager? Let’s take a look at why. If you haven’t read this series, you are advised to read it first. Otherwise, it will not be easy to understand the process of adding or binding WMS to Windows directly.

Android 8.0 source code analysis (a) SystemServer process started

Android 8.0 source code analysis (ii) Launcher

Android 8.0 source code analysis (three) application process creation to the application startup process

Android 8.0 source code analysis (four) Activity start

Android 8.0 source code analysis (5) Service startup

Android 8.0 source code analysis (6) BroadcastReceiver launch

Android 8.0 source code analysis (seven) ContentProvider start

ActivityManagerService

Android 8.0 source code analysis (nine) WindowManager

Android 8.0 source code analysis (ten) WindowManagerService window management

The relationship between Windows, WindowManager, and WMS

  • Window: Window is an abstract class that implements PhoneWindow and manages views.

    //Window.java
    public abstract class Window {... }//PhoneWindow.java
    public class PhoneWindow extends Window implements MenuBuilder.Callback {... }Copy the code
  • WindowManager is an interface class, inherited from the interface ViewManager, from its name know that it is used to manage Windows, its implementation class is WindowManagerImpl.

    //ViewManager.java
    public interface ViewManager
    {
      / / add the View
        public void addView(View view, ViewGroup.LayoutParams params);
      / / update
        public void updateViewLayout(View view, ViewGroup.LayoutParams params);
      / / delete
        public void removeView(View view);
    }
    
    //WindowManager.java
    public interface WindowManager extends ViewManager {... }//WindowManagerImpl
    public final class WindowManagerImpl implements WindowManager {... }Copy the code

    If you want to add, update, or delete Windows, you can use the WindowManager class. WindowManager hands over the work to WMS, which communicates with its Binder. This is the same with ActivityManager and AMS.

Let’s use a diagram of their relationship to illustrate their connection

Windows contains the View and manages the View, WindowManager manages the Window, and the functionality provided by WindowManager is ultimately handled by WMS.

WindowManager’s associated class

Next, we will analyze the WindowManager associated classes from the source point of view, from which we can better understand the relationship between Windows and WindowManager.

As we learned in the previous section, WindowManager is an interface that inherits from ViewManager, which defines three abstract methods for adding, updating, and deleting views. WindowManager inherits the method of the parent class, indicating that it also has the ability of the parent class. From the first parameter in the parent class method, we know that all the parameters passed in are View type parameters, so we can indicate that the Window is in View mode. In addition to inheriting the features of the parent class, WindowManager has added many features, such as Window types and hierarchical constants, inner classes, and methods, two of which were added according to the features of Window. As follows:

//interface-->WindowManager.java
public interface WindowManager extends ViewManager {.../** * The Window has been added to the screen@return* /
    public Display getDefaultDisplay(a);


    / * * * rules to be executed immediately before this method returns the onDetachedFromWindow () to complete the incoming View relevant logic destruction of *@param view
     */
    public void removeViewImmediate(View view); . }Copy the code

PhoneWindow is an abstract class, and its only subclass is PhoneWindow. When was PhoneWindow created? The handleLaunchActivity -> performLaunchActivity method of class H is used to start an Activity The Attach method, where the PhoneWindow is created, lets just look at the code:

//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) {.../** * 1. Instantiate the unique subclass of Window PhoneWindow */
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this); ./** * 2. Bind WindowManager */mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) ! =0);
        if(mParent ! =null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;

        mWindow.setColorMode(info.colorMode);
    }
Copy the code

The code above mainly two meanings, one Window abstract class instantiation of subclasses PhonWindow, secondly is PhoneWindow associated with WindowManager want to, we see setWindowManager method, the code is as follows:

//Window.java
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
          	/ / 1.
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
      / / 2.
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
Copy the code

If the WindowManager of wm type is null, the method McOntext. getSystemService is used to retrieve the WindowManager object, where mContext is of Context type. Its implementation class is the ContentImp object, also instantiated in the performLaunchActivity method. ContentImp getSystemService (ContentImp getSystemService)

//ContextImpl.java
    @Override
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }



Copy the code

We see the static method getSystemService in the SystemServiceRegistry class as follows:

//SystemServiceRegistry.java
final class SystemServiceRegistry {.../ / 1.
  private static finalHashMap<String, ServiceFetcher<? >> SYSTEM_SERVICE_FETCHERS =newHashMap<String, ServiceFetcher<? > > (); .static{.../ / 2.
    registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher<WindowManager>() {
            @Override
            public WindowManager createService(ContextImpl ctx) {
                return newWindowManagerImpl(ctx); }}); . }private static <T> void registerService(String serviceName, Class
       
         serviceClass, ServiceFetcher
        
          serviceFetcher)
        
        {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }
  
  public static Object getSystemService(ContextImpl ctx, String name) { ServiceFetcher<? > fetcher = SYSTEM_SERVICE_FETCHERS.get(name);returnfetcher ! =null ? fetcher.getService(ctx) : null;
    }

Copy the code

SYSTEM_SERVICE_FETCHERS is a container singleton class that registers services of type context. XXX in a static block of SystemServiceRegistry. Finally, the register success is stored in the singleton container.

Then look at note 2 and call createLocalWindowManager to create the WindowManager implementation class as follows:

//WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {...public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    		// Instantiate the WindowManager implementation class object
        return new WindowManagerImpl(mContext, parentWindow);
    }
  
      private WindowManagerImpl(Context context, Window parentWindow) { mContext = context; mParentWindow = parentWindow; }... }Copy the code

Both comment 1 and comment 2 create a WindowManagerImpl. The difference is that comment 2 also passes in the instance that created Window, so that WindowManagerImpl has a reference to PhoneWindow, You can then do something to the Window, such as call WindowManagerImp addView, as follows:

//WindowManagerImpl.java
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        /** * delegate to Windows ManagerGlobal to handle addView */
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
Copy the code

As you can see from the above code, the addView method is called in the WindowManagerImp class, but the internal method is not implemented. Instead, the addView logic is delegated to the WindowManagerGlobal. Windows ManagerGlobal will be covered in a later section. Let’s first look at how it is created in Windows Manager IMP. The code is as follows:

//WindowManagerImp.java
public final class WindowManagerImpl implements WindowManager {
  	//1. Get Windows ManagerGlobal objects via thread-safe singletons
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
			/ * * 2. * /
      private final Window mParentWindow;
  
      private WindowManagerImpl(Context context, Window parentWindow) {
        mContext = context;
        / / 3mParentWindow = parentWindow; }}//WindowManagerGlobal.java
    public static WindowManagerGlobal getInstance(a) {
        synchronized (WindowManagerGlobal.class) {
            if (sDefaultWindowManager == null) {
                sDefaultWindowManager = new WindowManagerGlobal();
            }
            returnsDefaultWindowManager; }}Copy the code

You can see in the code in comment 1 that we get the address of WindowManagerGlobal through a thread-safe singleton, and then comments 2 and 3 are passed along when the Activity creates the PhoneWindow, This represents which Window instance WindowManagerImpl will be used as a child Window. Using the source code described in this section, I have drawn a WindowManager association diagram, as shown in the following figure.

As can be seen from the figure, PhoneWindow inherits from Window, and PhoneWindow is associated with WindowManager through setWindowManager. WindowManager inherits from the ViewManager interface. WindowManagerImpl is the implementation class of the WindowManager interface, but the internal functions are delegated to WindowManagerGlobal.

The attribute of the Window

In the previous section, we explained the relationship between Windows, WindowManager and WMS, and we also know that WMS is the executor who finally deals with Windows. Window is like an employee, and WMS is like a boss. In order to facilitate the boss to manage employees, a set of “rules and regulations” should be defined. These rules are equivalent to the properties of Window, which are defined in the WindowManager inner class LayoutParams. Understanding the properties of Window will help you better understand the inner workings of WMS. There are many kinds of Window attributes, and the three most closely related to application development are Type(Window Type), Flag(Window Flag) and SoftInputMode(soft keyboard related mode). The following three attributes are introduced respectively.

The type of the Window

There are many types of Windows, such as application Window, system error Window, input method Window, PopWindow, Toast, Dialog, etc. Generally speaking, Windows can be divided into three types, namely Application Window, Sub Window and System Window. Each large type contains many types. They are all defined in the Static inner class LayoutParams of WindowManager, and we’ll look at each of the three types.

  1. Application window

    An Activity is a typical application window. Application Windows contain the following types:

    //WindowManager.java
            /** * indicates the application window type initial value */
            public static final int FIRST_APPLICATION_WINDOW = 1;
            /** * window base value, other window values are greater than this value */
            public static final int TYPE_BASE_APPLICATION   = 1;
    
    
            /** * Normal application window ** /
            public static final int TYPE_APPLICATION        = 2;
    
    
            /** * The type of application launch window that the system displays before the application window starts */
            public static final int TYPE_APPLICATION_STARTING = 3;
    
    
            public static final int TYPE_DRAWN_APPLICATION = 4;
    
    
            /** * indicates the end value of the application window type. The value ranges from 1 to 99 */
            public static final int LAST_APPLICATION_WINDOW = 99;
    Copy the code

    From the above constants, we know that the Type value of the application window ranges from 1 to 99. This value is related to the window hierarchy, which we will learn more about later.

  2. Child window

    Child window, as its name implies, is a fragment that must be attached to other Windows. The subwindow types are defined as follows:

    //WindowManager.java
            /** * Subclass window initializes the value */
            public static final int FIRST_SUB_WINDOW = 1000;
    
            public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
    
            public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
    
            public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
    
            public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
            public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4;
    
            public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
            /** * Subclass window type end value */
            public static final int LAST_SUB_WINDOW = 1999;
    
    Copy the code

    It can be seen that the Type value of the sub-window ranges from 1000 to 1999

  3. The system window

    For example, Toast, input method Window, system volume bar Window and system error Window in Android are all system-level Windows. System-level window types are defined as follows:

    //WindowManager.java
            /** * System type window type initial value */
            public static final int FIRST_SYSTEM_WINDOW     = 2000;
    
            /** * System status bar window */
            public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
    
            /** * Search bar window */
            public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;
    
            /** * Call window */
            @Deprecated
            public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;
    
            /** * system aleat window */
            @Deprecated
            public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;
    
            /** * System lock window */
            public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;
    
            /** * Toast window */
            @Deprecated
            public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5; ./** * End value of system window type */
            public static final int LAST_SYSTEM_WINDOW      = 2999;
    Copy the code

    There are nearly more than 40 system window Type values, only part of which are listed here. The system window Type values range from 2000 to 2999.

A sign of the Window

Window Flag, also known as Flag, is used to control the reality of Window. It is also defined in the inner class LayoutParams of WindowManager. There are more than 20 of them.

Window Flag instructions
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON Lock the screen on the open screen as long as the window is visible
FLAG_NOT_FOCUSABLE Windows do not get input focus. FLAG_NOT_TOUCH_MODAL is also set when this flag is set
FLAG_NOT_TOUCHABLE The window does not receive any touch events
FLAG_NOT_TOUCH_MODAL Passes touch events outside the Window area to other Windows, and only handles touch events inside the Window area itself
FLAG_KEEP_SCREEN_NO The screen is always on as long as the window is visible
FLAG_LAYOUT_NO_LIMITS Allows Windows to go beyond the screen
FLAG_FULISCREEN Hide all screen decoration Windows, such as full-screen displays in games and players
FLAG_SHOW_WHEN_LOCKED Windows can be displayed on top of Windows on the lock screen
FLAG_IGNORE_CHEEK_PRESSES When the user’s face is close to the screen (for example, making a phone call), it does not respond to events
FLAG_TURN_SCREEN_NO Light up the screen when the window is displayed

There are three ways to set the Flag of a Window

  1. The Window addFlag method is used

    Window mWindow = getWindow();
    mWindow.addFlay(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    Copy the code
  2. Through the Window setFlags method

    Window mWindow = getWindow();
    mWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN)
    Copy the code
  3. Set flags for LayoutParams and add them through the addView method of Windows Manager

    WindowManager.LayoutParams mWindowLayoutParams = new WindowManager.LayoutParams();
    mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN;
    WindowManager mWindowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
    Text mText = new Text(this);
    mWindowManager.addView(mTextView,mWindowLayoutParams);
    Copy the code

Software disk related mode

The overlay of Windows is a very common scenario, but if the window is the window of the software disk, there may be some problems, for example, a typical user login page, the default pop-up window of the software disk may block the button below the input box, so that the user experience is very bad. In order to make the soft keyboard window display as expected, Windows Manager static inner class LayoutParams defines the software disk related mode, here are some commonly used:

SoftInputMode describe
SOFT_INPUT_STATE_UNSPECIFIED If no state is set, the system selects an appropriate state or subject-dependent setting
SOFT_INPUT_STATE_UNCHANGED Does not change the soft keyboard state
SOFT_INPUT_STATE_ALWAYS_HIDDEN The soft keyboard is always hidden when the window gets focus
SOFT_INPUT_ADJUST_RESIZE When the soft keyboard pops up, the window resizes
SOFT_INPUT_ADJUST_PAN The window does not need to be resized when the soft keyboard pops up, making sure the input focus is visible
SOFT_INPUT_STATE_HIDDEN The soft keyboard is hidden by default when the user enters the window

From SoftInputMode given above, can be found, they and AndroidManifest. Activity in the XML attribute android: windowsoftInputMode is corresponding. Therefore, in addition to configuring an Activity in androidmanifest.xml, you can also configure it dynamically with code, as shown below:

geWindow().setSoftInputMode(MindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
Copy the code

The operation of the Window

WindowManager manages Windows. When it comes to managing Windows, it cannot do without a series of operations such as Add, Update and remove. For these operations, WMS is the last one to handle them. Windows can be divided into three categories: ApplicationWindow, SubWindow and SystemWindow. The process of adding Windows varies according to different types. But it is the same for WMS processing. Here is a schematic diagram to help you understand:

The process of adding system Windows

According to the introduction of the above article, we know that Window is divided into three types, and the adding process of different Window types is different. This section will analyze the process of adding system Windows. Here Toast is used to analyze the process of adding the SystemWindow. Instead of introducing the four major components to start the analysis, we will mainly focus on the main point. After all, the main character is still the process of adding the SystemWindow. Toast makeText: Toast makeText: Toast makeText: Toast makeText: Toast makeText

  //Toast  
	public static Toast makeText(@NonNull Context context, @Nullable Looper looper,
            @NonNull CharSequence text, @Duration int duration) {
       //1. Instantiate Toast objects
    		Toast result = new Toast(context, looper);
				
        LayoutInflater inflate = (LayoutInflater)
                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    		//2. Internal parsing of XML as a View
        View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
        TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
        tv.setText(text);
				//3. Remember mNextView which is the object we will add later
        result.mNextView = v;
        result.mDuration = duration;

        return result;
    }


    final TN mTN;
    int mDuration;
    View mNextView;

    public Toast(@NonNull Context context, @Nullable Looper looper) {
        mContext = context;
        mTN = new TN(context.getPackageName(), looper);
        mTN.mY = context.getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.toast_y_offset);
        mTN.mGravity = context.getResources().getInteger(
                com.android.internal.R.integer.config_toastDefaultGravity);
    }
Copy the code

From makeText, we know that Toast mainly creates a View with a default layout, and then assigns the View to the mNextView variable of Toast. Let’s look at the Toast show method, with the code as follows:

//Toast.java
    public void show(a) {
        if (mNextView == null) {
            throw new RuntimeException("setView must have been called");
        }
				//1. Get the NMS agent class
        INotificationManager service = getService();
        String pkg = mContext.getOpPackageName();
      	2. TN receives the NMS message
        TN tn = mTN;
        tn.mNextView = mNextView;

        try {
          //3. Notify NMS to call the enqueueToast method
            service.enqueueToast(pkg, tn, mDuration);
        } catch (RemoteException e) {
            // Empty}}private static class TN extends ITransientNotification.Stub {... }Copy the code

By the above code we know get INotificationManager first, and then will create good mTN assigned to TN object, it inherits from ITransientNotification. The Stub Binder object that has the function of receiving interprocess communication, Last call INotificationManager enqueueToast method to notify NotificationManagerService, let’s take a look at below NMS enqueueToast concrete implementation, the code is as follows:

//NotificationManagerService.java
public class NotificationManagerService extends SystemService {...private final IBinder mService = new INotificationManager.Stub() {
        @Override
        public void enqueueToast(String pkg, ITransientNotification callback, int duration)
        {...synchronized (mToastQueue) {
                int callingPid = Binder.getCallingPid();
                long callingId = Binder.clearCallingIdentity();
                try{ ToastRecord record; ./ / 1.
                    record = new ToastRecord(callingPid, pkg, callback, duration, token);
                        
                    if (index == 0) {
                      / / 2.showNextToastLocked(); }}finally {
                    Binder.restoreCallingIdentity(callingId);
                }
            }
        }  
  }
  ....
  
}

    void showNextToastLocked(a) {
        ToastRecord record = mToastQueue.get(0);
        while(record ! =null) {
            try {
              	/ / 3.
                record.callback.show(record.token);
                scheduleTimeoutLocked(record);
                return;
            } catch(RemoteException e) { .... }}Copy the code

Call ToastRecord (PKG, callback, etc.); call record.callback.show (); The callback is defined to receive the NMS message in Toast. Let’s go back to the Toast show(Binder Binder) method, with the following code:

//Toast.java
        @Override
        public void show(IBinder windowToken) {
            / / 1.
            mHandler.obtainMessage(SHOW, windowToken).sendToTarget();
        }


            mHandler = new Handler(looper, null) {
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what) {
                        case SHOW: {
                            IBinder token = (IBinder) msg.obj;
                          / / 2.
                            handleShow(token);
                            break; }... }}}};Copy the code

The above is a simple inter-thread communication operation, we directly look at the concrete implementation of note 2, the code is as follows:

//Toast.java

        public void handleShow(IBinder windowToken) {...if(mView ! = mNextView) { .../** * 1. The added object */
                mView = mNextView;
                Context context = mView.getContext().getApplicationContext();
                String packageName = mView.getContext().getOpPackageName();
                if (context == null) {
                    context = mView.getContext();
                }
                /** * 1. Get WindowManager */mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); .try {
                    /** * 3. Call WindowManager addView to add */
                    mWM.addView(mView, mParams);
                    trySendAccessibilityEvent();
                } catch (WindowManager.BadTokenException e) {
                    /* ignore */}}}Copy the code

We directly look at the above most important code note 3, call WindowManager addView method, through the above introduction, we know that the implementation of WindowManager is in WindowManagerImpl, the specific implementation code is as follows:

//WindowManagerImpl.java

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        /** * delegate to Windows ManagerGlobal to handle addView */
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
Copy the code

The first parameter of addView is of type View, indicating that Windows exist in the form of View. AddView calls the addView method of WindowManagerGlobal. The code is as follows:

//
    public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {...final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if(parentWindow ! =null) {
            / * * * 1. According to the WindowManager. LayoutParams parameters to adjust to add the child window * /
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else{... } ViewRootImpl root; View panelParentView =null;

        synchronized (mLock) {
            ...
            /** * 2. Instantiate the ViewRootImpl object and assign it to root */
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            /** * 3. Add view to mViews list */
            mViews.add(view);
            /** * 4. Store root in ViewRootImp */
            mRoots.add(root);
            /** * 5. Save the window parameters to the layout parameter list. * /
            mParams.add(wparams);

            try {
                /**
                 * 6. 将窗口和窗口的参数通过 setView 方法设置到 ViewRootImpl 中
                 */
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throwe; }}}Copy the code

From the above code, we can know that six things are done as follows:

  1. According to the WindowManager. LayoutParams parameters to adjust to add the child window.
  2. Instantiate the ViewRootImpl object and assign it to the root variable
  3. Add view to mViews list
  4. Store root in the ViewRootImp list
  5. Save the window’s parameters to the layout parameter list
  6. Set the window and its parameters to the View wrootimpl using the setView method

Finally, after a series of steps to step 6, you can see that we added the window using the View wrootimpl. ViewRootImpl has many responsibilities, mainly the following:

  1. View tree root and manage the View tree
  2. Trigger View measurement, layout, and drawing
  3. A relay station for input events
  4. Management of surface
  5. Responsible for inter-system communication with WMS

Now that we know what the ViewRootImpl does, let’s look at the ViewRootImpl setView method:

//ViewRootImpl.java
 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {...try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch(RemoteException e) { ... }... }}Copy the code

There’s a lot of logic in the setView method, and I’m just going to grab the important code, which is basically the addToDisplay method that calls WindowSession of type mWindowSession, which is a Binder object, and its server implementation is the Session class, Let’s take a look at the diagram to see the relationship between view wrotimpl, IWindowSession, WMS and Session, as follows:

Let’s look at its implementation in detail, the code is as follows:

//Session.java
public class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
  
  finalWindowManagerService mService; .@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); }... }Copy the code

We know from the above code that the local process viewrotimpl needs to go through a Session to communicate with the WMS, so why is the Session included in the WMS? If we look at the code above, the addToDisplay method inside the Session is actually calling the addWindow method of WMS. Each application process will have a Session, and WMS will call ArrayList to hold those sessions. This is why WMS wraps sessions. WMS assigns the Surface to the added Window, so the Surface is responsible for displaying the interface, not the Window. WMS assigns the Surface it manages to SurfaceFlinger. SurfaceFlinger mixes and draws these surfaces onto the screen.

The WMS Window addition section will be examined separately in the next article. The process of adding system Windows Toast will be examined here. Let’s look at the process of adding Windows to the application.

The process of adding an Activity

No matter what kind of window it is, the process of adding it is basically similar in the WMS processing part, but it is different in the WindowManager processing part. Here is a typical example of an Activity. If the Activity is in a process that doesn’t already exist, a new process is created. After the new process is created, an instance of ActivityThread, representing the main thread, runs. ActivityThread manages the threads of the current application process. This is evident during the Activity startup process, when the interface interacts with the user, the ActivityThread’s handleResumeActivity method is called, as shown below:

//ActivityThread.java
    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {.../** * 1. The Activity onResume lifecycle function is eventually called */
        r = performResumeActivity(token, clearHide, reason);

        if(r ! =null) {...if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                /** * 2. Get the ViewManager object */
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if(impl ! =null) { impl.notifyChildRebuilt(); }}if (a.mVisibleFromClient) {
                    if(! a.mWindowAdded) { a.mWindowAdded =true;
                        /** * 3. Call the addView method of ViewManager */
                        wm.addView(decor, l);
                    } else{ a.onWindowAttributesChanged(l); }}... }}Copy the code

We get three important pieces of information from the code above, one, through the comment one, the Activity’s onResume lifecycle function is executed, and two, we get the ViewManager object, which we introduced earlier, It is an interface inherited by WindowManager and finally implemented in WindowManagerImpl, so three, comment three is the addView method that calls WindowManagerImpl, and the rest of the call is the same as Toast’s execution flow, I won’t repeat it here. Let’s examine the Window update process

Windows update process

Updating a Window is similar to adding a Window. You call the ViewManager updateViewlayout method, which is implemented in WindowmanagerImpl. WindowManagerImpl’s updateViewLayout method calls WindowManagerGlobal’s updateViewLayout method as follows:

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

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;

        /**
         * 1. 将更新的参数设置到 View 中
         */
        view.setLayoutParams(wparams);

        synchronized (mLock) {
            /** * 2. Get the index of the window to be updated in the View list */
            int index = findViewLocked(view, true);
            /** * 3. Get the window's ViewRootImpl */ according to the index
            ViewRootImpl root = mRoots.get(index);
            /** * 4. Delete the old parameter */
            mParams.remove(index);
            /** * 5. Add a new parameter */
            mParams.add(index, wparams);
            /** * 6. Set the updated parameters to ViewRootImpl */
            root.setLayoutParams(wparams, false); }}Copy the code

Get the ViewRootImpl that needs to be updated and call its setLayoutParams to pass in the parameters. Let’s look at the code implementation of comment 6:

//ViewRootImpl.java
  void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {... scheduleTraversals(); }Copy the code
//ViewRootImpl.java
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

final class TraversalRunnable implements Runnable {... }void scheduleTraversals(a) {
        if(! mTraversalScheduled) { mTraversalScheduled =true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            /** * mChoreographer: For receiving VSync signals from the display system, for controlling the execution of operations on the next frame of render, * for issuing add callbacks within the Run of mTraversalRunnable */
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
Copy the code

TraversalRunnable TraversalRunnable TraversalRunnable TraversalRunnable

//ViewRootImpl.java
    final class TraversalRunnable implements Runnable {
        @Override
        public void run(a) {
          // Call the internal doTraversal methoddoTraversal(); }}Copy the code
//ViewRootImpl.java

    void doTraversal(a) {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false; }}}Copy the code

In doTraversal the performTraversals method is called again, and so on:

//ViewRootImpl.java
private void performTraversals(a) {
  /** * 1. The relayout method of IWindowSession is called internally to update the Window view */relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); ./** * 2. Call the View measure method */performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); ./** * 3. The View layout is called internally */performLayout(lp, mWidth, mHeight); ./** * 4. Draw the View by calling the View draw method. * /performDraw(); . }Copy the code

Through the above performTraversals function, internal View measure, layout and draw are performed to complete the View drawing process. The Window is updated by updating the Window view in the performTraversals method.

conclusion

The article learned WindowManager related knowledge points, including WindowManager associated classes, Window properties and Window operations, the next article will bring home WindowManagerService source code analysis, please look forward to!

Thank you for reading, I hope to help you!

reference

  • Android Advanced Decryption