Window的添加-流程简单梳理版本

140 阅读2分钟

Window的添加-流程简单梳理版本

前言

当activity生命周期走到onstart,onresume时,activity可见,但是window还不可见,window的绘制在onResume之后,从此处开始进行分析

handleResumeActivity-addView

 @Override
    public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            boolean isForward, boolean shouldSendCompatFakeFocus, String reason) {
... ...
        if (r.window == null && !a.mFinished && willBeVisible) {
... ...
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    // 进入addView方法
                    wm.addView(decor, l);
                } else {
                    // The activity will get a callback for this {@link LayoutParams} change
                    // earlier. However, at that time the decor will not be set (this is set
                    // in this method), so no action will be taken. This call ensures the
                    // callback occurs with the decor set.
                    a.onWindowAttributesChanged(l);
                }
            }
 ... ...


        mNewActivities.add(r);
        if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
        Looper.myQueue().addIdleHandler(new Idler());
    }

addview方法会调用到WindowManagerImpl,随后调用到WindowManagerGlobal的同名addView方法

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyTokens(params);
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }

WMSImpl-WMSGlobal-addView

在wmsGlobal的addView方法中,new出VRI,然后调用VRI的setView方法

  public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
  ... ...
      // new出关键对象ViewRootImpl
        if (windowlessSession == null) {
            root = new ViewRootImpl(view.getContext(), display);
        } else {
            root = new ViewRootImpl(view.getContext(), display,
                    windowlessSession, new WindowlessWindowLayout());
        }

        view.setLayoutParams(wparams);

        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
	// 关键方法,VRI的setView
        // do this last because it fires off messages to start doing things
        try {
            root.setView(view, wparams, panelParentView, userId);
        } catch (RuntimeException e) {
            final int viewIndex = (index >= 0) ? index : (mViews.size() - 1);
            // BadTokenException or InvalidDisplayException, clean up.
            if (viewIndex >= 0) {
                removeViewLocked(viewIndex, true);
            }
            throw e;
        }

VRI-setView

此处兵分两路,一路添加窗口,一路绘制窗口

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
        synchronized (this) {
... ...
	// 关键方法,主要进行绘制
                requestLayout();
                

                try {
... ...
    //关键方法, 添加窗口
                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
                            mTempControls, attachedFrame, compatScale);
... ... 
                } catch (RemoteException | RuntimeException e) {
 
                    
                    ... ...
                }
            }
        }
    }

addToDisplayAsUser

或许你会好奇,为什么先绘制窗口,后添加窗口,是不是反了,其实执行顺序上,和代码相对位置是相反的,requestLayout内部是一个异步方法,post出去了,

requestLayout

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
scheduleTraversals
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            // 注意此处同步屏障的使用,阻塞住同步信息,让异步信息的处理被提前
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            // 此处将会异步执行mTraversalRunnable.run
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
doTraversal
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }

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

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

            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }
performTraversals

在performTraverslas中进行测绘三部曲,measure-layout-draw

  • relayoutWindow
  • performMeasure
  • performLayout
  • performDraw
  • createSyncIfNeeded
    private void performTraversals() {
... ...
    relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
... ...
        if (!mStopped || mReportNextDraw) {
           ... ...
           performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
           ... ...
        }
    ... ...
         performLayout(lp, mWidth, mHeight);
    ... ...
        if (!performDraw(mActiveSurfaceSyncGroup)) {
            handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
                    mPendingTransaction, mLastPerformDrawSkippedReason);
            mHasPendingTransactions = false;
        }
    ... ...
        if (!cancelAndRedraw) {
			... ...
        	createSyncIfNeeded();
            ... ...
        }
    ... ...

总结

在ActivityThread的handleResumeActivity中,activity处于resume之后,开始了window的绘制,调用addView

然后层层调用到WMSImpl和WMSGlobal的addView方法,该方法new出了VRI,随后去调用VRI的setVIew方法

在VRI的setView方法中

同步执行addToDisplayAsUer添加了窗口,

异步执行了requestLayout准备去测绘->经过schedule/do/perform-Traversals

最终在performTraversals方法中进行了测绘三部曲,measure-layout-draw,绘制完毕

handleResumeActivity

=>performResumeActivity-performResume-执行activity生命周期回调onResume

=>addview(new 出VRI,然后准备调用VRI的setview)

=>setview

异步=>requestLayout();

	=>scheduleTraversals

	=>doTraversal

	=>performTraversals

			=>relayoutWindow(方法内调用->relayoutWindowInner->createSurfaceControl-createSurfaceLocked-resetDrawState)对应DRAW_PENDING

			=>performMeasure=>performLayout=>performDraw

			=>createSyncIfNeeded(方法内调用->reportDrawFinished-finishDrawing-finishDrawingWindow-finishDrawingLocked)对应COMMIT_DRAW_PENDING

同步=>addToDisplayAsUser