WMS 窗口添加流程

news2024/5/18 14:48:11

WMS 系统窗口添加流程

文章目录

  • WMS 系统窗口添加流程
        • 一. addView
        • 二. addView代码分析
          • 2.1 应用端调用WindowManager的addView
          • 2.2 WindowManager的实现类是WindowManagerImpl
          • 2.3 WindowManagerGlobal
          • 2.4 setView
          • 2.4 addToDisplayAsUser(Session.java)
          • 2.5 addWindow(WindowManagerService.java)
          • 2.6 WindowToken的创建
        • 三. relayout
          • 3.1 TraversalRunnable
          • 3.2 doTraversal
          • 3.3 performTraversals
          • 3.4 relayoutWindow
            • 3.4.1 relayout(Session)
            • 3.4.1.1 relayoutWindow(WindowManagerService)
            • 3.4.1.2 createSurfaceControl
          • 3.4.2 performSurfacePlacement 强制布局
        • 四. finishDraw
            • 4.1 reportDrawFinished
            • 4.2 finishDrawing(Session.java)
            • 4.3 finishDrawingWindow(WindowManagerService.java)
            • 4.4 WindowState.finishDraw
            • 4.5 finishDrawingLocked(WindowStateAnimation.java)
            • 4.6 requestTraversal(Windowurfaceplacer.java)
            • 4.7 mPerformSurfacePlacement
            • 4.8. performSurfacePlacement(WindowSurfacePlacer.java)
            • 4.9 performSurfacePlacement
            • 4.10 performSurfacePlacementLoop
            • 4.11 mRoot.performSurfacePlacement
            • 4.12 performSurfacePlacementNoTrace
            • 4.13 applySurfaceChangesTransaction
            • 4.14 applySurfaceChangesTransaction(DisplayContent)
            • 4.15 mApplySurfaceChangesTransaction
            • 4.16 commitFinishDrawingLocked(WindowAnimator)
            • 4.17 performShowLocked
        • 五. prepareSurface
            • 5.1 prepareSurfaces
            • 5.1.1 prepareSurfaces
            • 5.1.2 prepareSurfaces(WindowContainer)
            • 5.1.3 prepareSurfaces(WindowState)
            • 5.1.4 mWinAnimator.prepareSurfaceLocked
            • 5.1.5 showSurfaceRobustlyLocked
            • 5.1.6 showRobustly
            • 5.1.7 closeSurfaceTransaction
        • 六. 高清大图

千里马framework学习笔记

环境: android 13
分析系统窗口添加流程,以悬浮窗为例
整体步骤分为四个,如下:

  1. addView
  2. relayout
  3. finishraw
  4. prepareurfaces

一. addView

主要流程如下:
addView
先说结论:addView主要做了什么?

addView 创建了WindowToken以及WindowState
其中也包括InputChannel的创建(事件相关)

二. addView代码分析

2.1 应用端调用WindowManager的addView
WindowManager mWindowManager;
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
mWindowManager.addView(mLayout, mLayoutParams);
2.2 WindowManager的实现类是WindowManagerImpl
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyTokens(params);
        // 这里又调用了WindowManagerGlobal的addview
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }
2.3 WindowManagerGlobal
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
       	// ... 省略若干容错代码

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
        // 一些参数调整
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } 
		// ... 省略一些代码
        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
			// ... 仅保留主要代码
            IWindowSession windowlessSession = null;
        
				
            if (windowlessSession == null) {
            	// 创建ViewRootImpl
                root = new ViewRootImpl(view.getContext(), display);
            }
			// 设置View的参数
            view.setLayoutParams(wparams);
			// 将view保存到一个集合中    ArrayList<View> mViews = new ArrayList<View>();
            mViews.add(view);
            // 将 root 也添加到集合中  ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
            mRoots.add(root);
            // 将参数也添加到集合中  ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
            	// TODO 重点,这里就是将view添加到WMS中的入口
                root.setView(view, wparams, panelParentView, userId);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }
2.4 setView
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
        synchronized (this) {
        // 这里view是不为null的一般
            if (mView == null) {
                mView = view;
				// ... 省略部分非主体代码
				// 下面就是InputChannel的创建了,这个和事件相关,不在这里分析
                InputChannel inputChannel = null;
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    inputChannel = new InputChannel();
                }

                try {
					// 调用session的addToDisplayAsUser将window添加到wms
                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
                            mTempControls);
                   }catch (RemoteException e) {
                    mAdded = false;
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    throw new RuntimeException("Adding window failed", e);
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
                // ... 省略非主体代码
   
2.4 addToDisplayAsUser(Session.java)
    public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls) {
            // 这里直接调用了WMS的addWindow,Session只是一个代理罢了(binder通信)
        return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
                requestedVisibilities, outInputChannel, outInsetsState, outActiveControls);
    }
2.5 addWindow(WindowManagerService.java)
    public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
            int displayId, int requestUserId, InsetsVisibilities requestedVisibilities,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls) {
		
        WindowState parentWindow = null;
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        final int type = attrs.type;

        synchronized (mGlobalLock) {
			// 根据displayId获取displayContent,一般为0,手机一般一个屏幕
            final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
			// ... 省略容错代码
            ActivityRecord activity = null;
            final boolean hasParent = parentWindow != null;
           	// 窗口不存在的时候这里是获取不到的
            WindowToken token = displayContent.getWindowToken(
                    hasParent ? parentWindow.mAttrs.token : attrs.token);
            // If this is a child window, we want to apply the same type checking rules as the
            // parent window type.
            final int rootType = hasParent ? parentWindow.mAttrs.type : type;
			
            boolean addToastWindowRequiresToken = false;

            final IBinder windowContextToken = attrs.mWindowContextToken;
			// 这里一般为null
            if (token == null) {
                // token的创建,在创建的时候就将它挂载到层级结构树上了
               token = new WindowToken.Builder(this, binder, type)
                            .setDisplayContent(displayContent)
                            .setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
                            .setRoundedCornerOverlay(isRoundedCornerOverlay)
                            .build();
            }
            
			// windowState的创建
            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], attrs, viewVisibility, session.mUid, userId,
                    session.mCanAddInternalSystemWindow);

            res = ADD_OKAY;

            win.attach();
            // 保存window 方便查找 StateHashMap<IBinder, WindowState> mWindowMap = new HashMap<>();
            mWindowMap.put(client.asBinder(), win);
			// 将windowState添加到windowToken下面
            win.mToken.addWindow(win);
		}
		// ... 省略非主体部分

        return res;
    }
2.6 WindowToken的创建
    protected WindowToken(WindowManagerService service, IBinder _token, int type,
            boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens,
            boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
        super(service);
        token = _token;
        windowType = type;
        mOptions = options;
        mPersistOnEmpty = persistOnEmpty;
        mOwnerCanManageAppTokens = ownerCanManageAppTokens;
        mRoundedCornerOverlay = roundedCornerOverlay;
        mFromClientToken = fromClientToken;
        if (dc != null) {
        	// 这里,将windowToken添加到层级结构树上
            dc.addWindowToken(token, this);
        }
    }

到此为止,addView部分,流程结束

三. relayout

主要流程如下图:
relayout
在收到Vsync信号时会执行ViewRootImpl中的TraversalRunnable方法

3.1 TraversalRunnable
	// 这是一个runnable,会执行其中的run方法
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
        	// 如上图,执行doTraversal
            doTraversal();
        }
    }
3.2 doTraversal
    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = fals;
            // 紧接着执行performTraversals,这些方法都是一路调下去的,也没啥好解释的
            performTraversals();
        }
    }
3.3 performTraversals
// 这个方法太长,删除了部分不重要的
private void performTraversals() {
     			// ... 省略部分代码
     			// 对window进行布局
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
                final boolean dragResizing = mPendingDragResizing;
                if (mSyncSeqId > mLastSyncSeqId) {
                    mLastSyncSeqId = mSyncSeqId;
                    if (DEBUG_BLAST) {
                        Log.d(mTag, "Relayout called with blastSync");
                    }
                    reportNextDraw();
                    mSyncBuffer = true;
                }
                // ... 省略部分代码
    }
3.4 relayoutWindow
    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {

        int relayoutResult = 0;
        // 获取窗口配置
        WindowConfiguration winConfig = getConfiguration().windowConfiguration;
    		// 根据参数对window布局
            relayoutResult = mWindowSession.relayout(mWindow, params,
                    requestedWidth, requestedHeight, viewVisibility,
                    insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
                    mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
                    mTempControls, mRelayoutBundle);
            final int maybeSyncSeqId = mRelayoutBundle.getInt("seqid");
            if (maybeSyncSeqId > 0) {
                mSyncSeqId = maybeSyncSeqId;
            }

            if (mTranslator != null) {
                mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);
                mTranslator.translateRectInScreenToAppWindow(mTmpFrames.displayFrame);
                mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
                mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
            }
            mInsetsController.onStateChanged(mTempInsets);
            mInsetsController.onControlsChanged(mTempControls);
		
            mPendingAlwaysConsumeSystemBars =
                    (relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;

        final int transformHint = SurfaceControl.rotationToBufferTransform(
                (mDisplayInstallOrientation + mDisplay.getRotation()) % 4);
        return relayoutResult;
    }
3.4.1 relayout(Session)
    public int relayout(IWindow window, WindowManager.LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewFlags, int flags,
            ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
		// 这里又调用到了WMS中的relayoutWindow
        int res = mService.relayoutWindow(this, window, attrs,
                requestedWidth, requestedHeight, viewFlags, flags,
                outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
                outActiveControls, outSyncSeqIdBundle);
        return res;
    }
3.4.1.1 relayoutWindow(WindowManagerService)
    public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewVisibility, int flags,
            ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls, Bundle outSyncIdBundle) {
   	
        synchronized (mGlobalLock) {
            // 获取windowState,这就是前面保存起来的windowState
            final WindowState win = windowForClientLocked(session, client, false);
            final DisplayContent displayContent = win.getDisplayContent();
            final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();

            WindowStateAnimator winAnimator = win.mWinAnimator;
            
            if (shouldRelayout) {
            // TODO: 重点,创建SrufaceControl
               result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
            }
            // 强制布局
		   mWindowPlacerLocked.performSurfacePlacement(true /* force */);
        return result;
    }
3.4.1.2 createSurfaceControl
    private int createSurfaceControl(SurfaceControl outSurfaceControl, int result,
            WindowState win, WindowStateAnimator winAnimator) {
		// 声明一个本地的变量
        WindowSurfaceController surfaceController;
        // 开始创建
        surfaceController = winAnimator.createSurfaceLocked();
     	// 如果不为null则创建成功
        if (surfaceController != null) {
        	// 赋值给outSurfaceControl,这个是传出参数,传进来是空的,这里就将重新指向了新创建的surfaceControl
            surfaceController.getSurfaceControl(outSurfaceControl);
            ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);
        } 
        return result;
    }

这个函数执行完,SurfaceControl就创建好了,接着我们往回退

3.4.2 performSurfacePlacement 强制布局
    final void performSurfacePlacement(boolean force) {
        int loopCount = 6;
        do {
            mTraversalScheduled = false;
            // 这里调用栈很深,可以跟着上面的流程图走一遍
            performSurfacePlacementLoop();
            mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
            loopCount--;
        } while (mTraversalScheduled && loopCount > 0);
        mService.mRoot.mWallpaperActionPending = false;
    }

到此,relayout也结束了

四. finishDraw

主流程图如下:
finishDraw
当layout完成之后,wms会通知应用开始绘制,应用端绘制完成之后会告知wms已经绘制完成,wms会将根据状态将surface提交给surfaceflinger进行合成。
其中,绘制状态如下:
绘制状态
没有surface的时候,处于NO_SURFACE状态,经过relayout后,创建了surfaceControl,就变成了DRAW_PENDING

上面的流程图,其中reportDrawFinished是回调方法,当绘制完成之后会回调到这里,看流程图的时候需要注意,并不是顺序往下调用的。
回调方法
这段代码着重说明一下, 通过 mSurfaceSyncer.setupSync() 方法将transaction添加到 mSurfaceSyncer 中进行同步。还会设置一个回调函数,该回调函数会在 SurfaceSync 对象完成同步后被调用。

在回调函数中,首先将当前的绘制操作合并到 mSurfaceChangedTransaction 中,然后调用 reportDrawFinished() 方法通知主线程界面绘制完成。最后,在创建 SurfaceSync 对象后,还会将其添加到 mSyncTarget 中,以进行同步。

这段代码的作用是为界面绘制操作创建一个 SurfaceSync 对象,并将其添加到同步队列中进行同步,以保证多个 Surface 的同步更新。

TODO: 这里容易忽略这个回调。就会认为没有绘制就走了finishDraw的流程,所以一定记得是绘制完成了才走的这里

4.1 reportDrawFinished
    private void reportDrawFinished(int seqId) {
    	// 调用session的finishDrawing
       mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, seqId);
    }
4.2 finishDrawing(Session.java)
    public void finishDrawing(IWindow window,
            @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
     	// 这里又直接调用了wms的finishDrawingWindow,和上面一样,其实就可以看出来了,Session其实就是应用端和WMS沟通的代理
        mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
    }
4.3 finishDrawingWindow(WindowManagerService.java)
    void finishDrawingWindow(Session session, IWindow client,
            @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
            synchronized (mGlobalLock) {
            	// 获得windowstate
                WindowState win = windowForClientLocked(session, client, false);
                // 调用windowState的finishDrawing
                if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
                    win.setDisplayLayoutNeeded();
                    mWindowPlacerLocked.requestTraversal();
                }
            }
    }

4.4 WindowState.finishDraw
    boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
        if (mOrientationChangeRedrawRequestTime > 0) {
         // ... 省略
        final boolean layoutNeeded =
                mWinAnimator.finishDrawingLocked(postDrawTransaction, mClientWasDrawingForSync);
        mClientWasDrawingForSync = false;
        // We always want to force a traversal after a finish draw for blast sync.
        return !skipLayout && (hasSyncHandlers || layoutNeeded);
    }
4.5 finishDrawingLocked(WindowStateAnimation.java)
    boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction,
            boolean forceApplyNow) {
            // 前面就知道,当创建完成SurfaceControl之后,DrawState就会变成DRAW_PENDING,这里符合条件
        if (mDrawState == DRAW_PENDING) {
            ProtoLog.v(WM_DEBUG_DRAW,
                    "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s", mWin,
                    mSurfaceController);
            if (startingWindow) {
                ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Draw state now committed in %s", mWin);
            }
            // 这里直接赋值为COMMIT_DRAW_PENDING
            mDrawState = COMMIT_DRAW_PENDING;
            layoutNeeded = true;
        }
        return layoutNeeded;
    }

根据流程图,回到wms

4.6 requestTraversal(Windowurfaceplacer.java)
    void requestTraversal() {
		
		// 接下来执行mPerformSurfacePlacement
        mService.mAnimationHandler.post(mPerformSurfacePlacement);
    }

源码就是这样的,一层一层的,我们只需要关注重点就行,主体流程不需要记忆,这里仅仅是按照源码分析,因为不同的版本,源码会有不同的差异,但主体思想一般不会有大改动。

4.7 mPerformSurfacePlacement
    private class Traverser implements Runnable {
        @Override
        public void run() {
            synchronized (mService.mGlobalLock) {
            // 执行这个方法
                performSurfacePlacement();
            }
        }
    }
4.8. performSurfacePlacement(WindowSurfacePlacer.java)
    final void performSurfacePlacement() {
        performSurfacePlacement(false /* force */);
    }
4.9 performSurfacePlacement
    final void performSurfacePlacement(boolean force) {
        if (mDeferDepth > 0 && !force) {
            mDeferredRequests++;
            return;
        }
        int loopCount = 6;
        do {
            mTraversalScheduled = false;
            // 执行这个,其实和前面都一样了
            performSurfacePlacementLoop();
            mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
            loopCount--;
        } while (mTraversalScheduled && loopCount > 0);
        mService.mRoot.mWallpaperActionPending = false;
    }
4.10 performSurfacePlacementLoop
    private void performSurfacePlacementLoop() {

        mService.mRoot.performSurfacePlacement();

    }
4.11 mRoot.performSurfacePlacement
    void performSurfacePlacement() {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
        try {
        // 继续执行这里
            performSurfacePlacementNoTrace();
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }
4.12 performSurfacePlacementNoTrace
    void performSurfacePlacementNoTrace() {
 
		// 打开一个事物
        mWmService.openSurfaceTransaction();
        try {
        	// 执行这个函数
            applySurfaceChangesTransaction();
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
        } finally {
        	// 关闭一个事物
            mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
          
        }
    }
4.13 applySurfaceChangesTransaction
    private void applySurfaceChangesTransaction() {
   
        final int count = mChildren.size();
        for (int j = 0; j < count; ++j) {
            final DisplayContent dc = mChildren.get(j);
            // 执行这里
            dc.applySurfaceChangesTransaction();
        }
    }
4.14 applySurfaceChangesTransaction(DisplayContent)
    void applySurfaceChangesTransaction() {
       		// 执行 mApplySurfaceChangesTransaction
            forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */)}
4.15 mApplySurfaceChangesTransaction
    private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
     
			// 执行这里
            final boolean committed = winAnimator.commitFinishDrawingLocked();
     
    };
4.16 commitFinishDrawingLocked(WindowAnimator)
    boolean commitFinishDrawingLocked() {
   
        // TODO 这里将状态修改为READY_TO_SHOW
        mDrawState = READY_TO_SHOW;
        boolean result = false;
        final ActivityRecord activity = mWin.mActivityRecord;
        if (activity == null || activity.canShowWindows()
                || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
                // 对于系统窗口来讲,会走这里
            result = mWin.performShowLocked();
        }
        return result;
    }
4.17 performShowLocked
boolean performShowLocked() {
		// 赋值状态为HAS_DRAWN
        mWinAnimator.mDrawState = HAS_DRAWN;
        return true;
    }

其中,在上面的分析中,有一点需要注意,commitfinishDrawing之后,会将mdrawState设置为READY_TO_SHOW,然后就又设置为HAS_DRAW,这个时候HAS_DRAW并非代表已经显示出来了,窗口内容仅仅是被绘制到了表面缓冲区,只有prepareSurface执行完成之后,才会告知系统surface缓冲区可以进行后续操作。

五. prepareSurface

主流程如下图:
prepareurface

5.1 prepareSurfaces

在HAS_DRAW之后,回到前面的commitfinishDrawing之后的逻辑

    void prepareSurfaces() {
        try {
            final Transaction transaction = getPendingTransaction();
            // 执行父类的prepareSurfaces
            super.prepareSurfaces();

            // TODO: Once we totally eliminate global transaction we will pass transaction in here
            //       rather than merging to global.
            SurfaceControl.mergeToGlobalTransaction(transaction);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }
5.1.1 prepareSurfaces
        void prepareSurfaces() {
            mDimmer.resetDimStates();
            // 继续prepareSurfaces
            super.prepareSurfaces();
    
        }
5.1.2 prepareSurfaces(WindowContainer)
    void prepareSurfaces() {
        // If a leash has been set when the transaction was committed, then the leash reparent has
        // been committed.
        mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash();
        for (int i = 0; i < mChildren.size(); i++) {
        	// 执行mChildren的prepareSurfaces
            mChildren.get(i).prepareSurfaces();
        }
    }
5.1.3 prepareSurfaces(WindowState)
    void prepareSurfaces() {
	
		// 执行这里	
        mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
        super.prepareSurfaces();
    }
5.1.4 mWinAnimator.prepareSurfaceLocked
    void prepareSurfaceLocked(SurfaceControl.Transaction t) {
        final WindowState w = mWin;
        if (!hasSurface()) {

            // There is no need to wait for an animation change if our window is gone for layout
            // already as we'll never be visible.
            if (w.getOrientationChanging() && w.isGoneForLayout()) {
                ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change skips hidden %s", w);
                w.setOrientationChanging(false);
            }
            return;
        }

        computeShownFrameLocked();

        if (w.isParentWindowHidden() || !w.isOnScreen()) {
            hide(t, "prepareSurfaceLocked");
            mWallpaperControllerLocked.hideWallpapers(w);

            // If we are waiting for this window to handle an orientation change. If this window is
            // really hidden (gone for layout), there is no point in still waiting for it.
            // Note that this does introduce a potential glitch if the window becomes unhidden
            // before it has drawn for the new orientation.
            if (w.getOrientationChanging() && w.isGoneForLayout()) {
                w.setOrientationChanging(false);
                ProtoLog.v(WM_DEBUG_ORIENTATION,
                        "Orientation change skips hidden %s", w);
            }
        } else if (mLastAlpha != mShownAlpha
                || mLastHidden) {       // 窗口在没有显示之前都是隐藏的,创建surface的时候置位true
            mLastAlpha = mShownAlpha;
            ProtoLog.i(WM_SHOW_TRANSACTIONS,
                    "SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s",
                    mSurfaceController, mShownAlpha, w.mHScale, w.mVScale, w);

            boolean prepared =
                mSurfaceController.prepareToShowInTransaction(t, mShownAlpha);    // 设置一下alpha

            if (prepared && mDrawState == HAS_DRAWN) {
                if (mLastHidden) {
                // 执行这里
                    if (showSurfaceRobustlyLocked(t)) 
                       
               
            }
        } 

    
    }
5.1.5 showSurfaceRobustlyLocked
    private boolean showSurfaceRobustlyLocked(SurfaceControl.Transaction t) {
    	// 执行showRobustly
        boolean shown = mSurfaceController.showRobustly(t);
    }
5.1.6 showRobustly
    boolean showRobustly(SurfaceControl.Transaction t) {
		
		// 这里就告诉系统我们已经可以显示了
        t.show(mSurfaceControl);
        return true;
    }
5.1.7 closeSurfaceTransaction

关闭事物

六. 高清大图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/531146.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

韦东山Linux驱动入门实验班(2)hello驱动---驱动层与应用层通讯,以及自动产生设备节点

前言 &#xff08;1&#xff09;学习韦东山老师的Linux&#xff0c;因为他讲的很精简&#xff0c;以至于很多人听不懂。接下来我讲介绍韦东山老师的驱动实验班的第二个Hello程序。 &#xff08;2&#xff09;注意&#xff0c;请先学习完视频再来看这个教程&#xff01;本文仅供…

Oracle数据库实现limit功能

Oracle数据库不支持mysql中limit功能&#xff0c;但可以通过rownum来限制返回的结果集的行数&#xff0c;rownum并不是用户添加的字段&#xff0c;而是oracle系统自动添加的。 #1、使查询结果最多返回前100行&#xff1a; SELECT * FROM TESTSDK WHERE rownum<10; #2、查询结…

跟庄买股票得新技巧(2023.05.16)(绝密资料,只发一次)

昨天学了一个跟庄买卖股票的得新技能 统计昨天庄家异动的情况&#xff0c;按照行业分类&#xff08;板块&#xff09;板块对涨幅进行排序&#xff0c;涨幅排名分前三的是&#xff0c;龙头一&#xff0c;龙头二&#xff0c;龙头三买卖规则&#xff1a;看龙一&#xff0c;玩龙二…

如何使用Sentinel做流量控制?此文将附代码详细介绍Sentinel几种限流模式

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;在一家满意的公司实习。本篇文章将详细介绍Sentinel的两种限流模式&#xff0c;由于篇幅原因&#xff0c;后续文章将详细介绍Sentinel的其他三种。 如果文章有什么需要改进的地方还请大佬不吝赐教…

SCS【25】单细胞细胞间通信第一部分细胞通讯可视化(CellChat)

桓峰基因公众号推出单细胞生信分析教程并配有视频在线教程&#xff0c;目前整理出来的相关教程目录如下&#xff1a; Topic 6. 克隆进化之 Canopy Topic 7. 克隆进化之 Cardelino Topic 8. 克隆进化之 RobustClone SCS【1】今天开启单细胞之旅&#xff0c;述说单细胞测序的前世…

Servlet进阶API、监听器与过滤器

过滤器和监听器是Servlet规范里的两个高级特性&#xff0c; 过滤器的作用是通过对request、response 的修改实现特定的功能&#xff0c;例如请求数据字符编码、IP地址过滤、异常过滤、用户身份认证等。监听器的作用是用于监听Web程序中正在执行的程序&#xff0c; 根据发生的事…

罗德与施瓦茨Rohde Schwarz FSW8 2HZ-8GHZ信号分析仪FSW13收购

罗德与施瓦茨Rohde & Schwarz FSW8 2HZ-8GHZ信号分析仪 附加功能&#xff1a; 10 kHz 偏移&#xff08;1 GHz 载波&#xff09;时的低相位噪声为 –137 dBc (1 Hz) 用于 WCDMA ACLR 测量的 –88 dBc 动态范围&#xff08;带噪声消除&#xff09; 高达 2 GHz 的分析带宽 &…

Camtasia2023.0.1CS电脑录制屏幕动作工具新功能介绍

Camtasia Studio是一款专门录制屏幕动作的工具&#xff0c;它能在任何颜色模式下轻松地记录 屏幕动作&#xff0c;包括影像、音效、鼠标移动轨迹、解说声音等等&#xff0c;另外&#xff0c;它还具有即时播放和编 辑压缩的功能&#xff0c;可对视频片段进行剪接、添加转场效果。…

云原生背景下如何配置 JVM 内存

image.png 背景 前段时间业务研发反馈说是他的应用内存使用率很高&#xff0c;导致频繁的重启&#xff0c;让我排查下是怎么回事&#xff1b; 在这之前我也没怎么在意过这个问题&#xff0c;正好这次排查分析的过程做一个记录。 首先我查看了监控面板里的 Pod 监控&#xff1a;…

指令的运行原理及Linux权限解读

目录 一. 指令的运行原理 二. Linux下的用户 2.1 Linux的用户分类 2.2 用户之间的切换 三. 文件权限的概念 3.1 文件类型 3.2 文件的权限 3.3 ls -l 打印文件全部信息的解读 四. 权限的修改 五. 拥有者和所属组的修改 六. 起始权限问题和权限掩码umask 七. 目录文件…

ArcGIS之克里金插值教学

本文来自&#xff1a;GIS科研实验室 基本概念 1.什么是克里金插值&#xff1f; 克里金插值又称空间局部插值法&#xff0c;是以半变异函数理论和结构分析为基础&#xff0c;在有限区域内对区域化变量进行无偏最优估计的一种方法&#xff0c;是地统计学的主要内容之一。南非矿产…

【消息中间件】RocketMQ消息重复消费场景及解决办法

文章目录 前言那么在什么情况下会发生RocketMQ的消息重复消费呢&#xff1f;消息重复消费的场景大概可以分为生产者端重复消费和消费者端重复消费&#xff0c;那么如何来解决消息的重复消费呢&#xff1f;既然在生产者做幂等性的方案都不是特别靠谱&#xff0c;那就再在消费者端…

信创办公–基于WPS的EXCEL最佳实践系列 (宏的录制)

信创办公–基于WPS的EXCEL最佳实践系列 &#xff08;宏的录制&#xff09; 目录 应用背景操作步骤1、宏的录制启用2、宏的使用3、宏的保存4、宏的禁用 应用背景 宏是一个自动化完成重复性工作的工具&#xff0c;使用宏可以提高我们的工作效率&#xff0c;那应该怎样使用宏这一…

日志与时间戳,客户端与服务器端,打包压缩解压解包介绍,date,cal,zip,unzip,tar指令等

日志与时间戳 计算机世界里面&#xff0c;时间其实很重要的&#xff0c;首先我们需要有日志这个概念&#xff0c;这个日志其实就跟日记一样&#xff0c;那么在日记里面的话就会有时间。时间真的非常关键&#xff0c;比方在出现问题的时候去找到这个问题出现的时间点&#xff0…

EEPROM读写测试实验(主要记录IIC通信协议)

一、简介 EEPROM&#xff0c;电可擦除可编程只读存储器&#xff0c;是一个非易失性的存储器件。RAM&#xff1a; 随机访问存储器&#xff0c;可读也可写&#xff0c;断电不保存数据&#xff0c;常用的RAM有ddr3、SDRAM。ROM仅支持读&#xff0c;不可写&#xff0c;但断电可以保…

4 通道3.2GSPS(或者配置成2 通道6.4GSPS)采样率的12 位AD 采集FMC+子卡模块

板卡概述 FMC_XM134 是一款4 通道3.2GSPS&#xff08;或者配置成2 通道6.4GSPS&#xff09;采样率的12 位AD 采集FMC子卡模块&#xff0c;该板卡为FMC标准&#xff0c;符合VITA57.4 规范&#xff0c;可以作为一个理想的IO 模块耦合至FPGA 前端&#xff0c;射频模拟信号数字化后…

外网远程访问公司内网用友畅捷通T财务软件 - 远程办公

文章目录 前言1.本地访问简介2. cpolar内网穿透3. 公网远程访问4. 固定公网地址 前言 用友畅捷通T适用于异地多组织、多机构对企业财务汇总的管理需求&#xff1b;全面支持企业对远程仓库、异地办事处的管理需求&#xff1b;全面满足企业财务业务一体化管理需求。企业一般将其…

老胡的周刊(第090期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 privateGPT[2] 为保证数据私密性&#xff0c…

antd——实现不分页的表格前端排序功能——基础积累

最近在写后台管理系统时&#xff0c;遇到一个需求&#xff0c;就是给表格中的某些字段添加排序功能。注意该表格是不分页的&#xff0c;因此排序可以只通过前端处理。 如下图所示&#xff1a; 在antd官网上是有关于表格排序的功能的。 对某一列数据进行排序&#xff0c;通过…

字符串运算公式:muParser公式库在linux平台使用

muParser是一个跨平台的公式解析库,它可以自定义多参数函数,自定义常量、变量及一元前缀、后缀操作符,二元操作符等,它将公式编译成字节码,所以计算起来非常快。 1 、muParser源码下载 官方网址http://sourceforge.net/projects/muparser/ gitee下载地址:Gitee 极速下…