Analyzing the internal mechanism of Window from the source code

Posted by LiamOReilly on Mon, 06 Jan 2020 23:26:20 +0100

1. Window adding process

1.1 start from the source

To add a small floating window, you need to use addView of WindowManager,

And we checked the official documents and found that WindowManager is an interface

public interface WindowManager implements ViewManager

Its real implementation is WindowManagerImpl, which has the following code

   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);
    }

    @Override
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.updateViewLayout(view, params);
    }

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

1.2 explore WindowManagerGlobal

As you can see, all the operations to implement Window are handed over to WindowManagerGlobal,

It provides its own instance in the form of factory. addView mainly performs the following work:

1.2.1 check the validity of parameters and adjust parameters
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    if (display == null) {
        throw new IllegalArgumentException("display must not be null");
    }
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }
    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    if (parentWindow != null) {
        parentWindow.adjustLayoutParamsForSubWindow(wparams);
    } 
1.2.2 create the ViewRootImpl and add the View to the list

First, focus on several parameters in WindowManagerGlobal

    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
    private final ArraySet<View> mDyingViews = new ArraySet<View>();

Where mView stores the View corresponding to all windows, mRoot stores the ViewRootImpl corresponding to all windows, mParams stores the layout parameters corresponding to all windows, mDyingViews stores the View object being deleted, or the Window that has called removeView but the deletion operation has not been completed.

In addView, add a series of Window objects to the list by the following methods:

    root = new ViewRootImpl(view.getContext(), display);
    view.setLayoutParams(wparams);
    mViews.add(view);
    mRoots.add(root);
    mParams.add(wparams);
1.2.3 update the interface and complete the Window adding process through ViewRootImpl

First, through the setView method of ViewRootImpl:



setView Pass through requestLayout Complete asynchronous refresh:

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

Where scheduleTraversals is actually the entry point for View rendering.

Next,

        final IWindowSession mWindowSession;        
        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) {
            mAdded = false;
            mView = null;
            mAttachInfo.mRootView = null;
            mInputChannel = null;
            mFallbackEventHandler.setView(null);
            unscheduleTraversals();
            setAccessibilityFocus(null, null);
            throw new RuntimeException("Adding window failed", e);
        }

Here mWindowSession type is IWindowSession, which is a Binder object. The real implementation class is Session.

That is to say, Window adding is an IPC call.

The internal Session will add windows through WindowManagerService.

It's not over. I'll write it tomorrow

Topics: Windows Session