Android14 WMS-窗口绘制之relayoutWindow流程(二)-Server端

本文接着如下文章往下讲

Android14 WMS-窗口绘制之relayoutWindow流程(一)-Client端-CSDN博客

然后就到了Server端WMS的核心实现方法relayoutWindow里29f881a37fcb498095f0b6ace978d5e4.jpg  

WindowManagerService.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
...public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,int requestedWidth, int requestedHeight, int viewVisibility, int flags, int seq,int lastSyncSeqId, ClientWindowFrames outFrames,MergedConfiguration outMergedConfiguration, SurfaceControl outSurfaceControl,InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,Bundle outSyncIdBundle) {

  由于此方法太长,所以分开讲述

1. 第一步

        if (outActiveControls != null) {outActiveControls.set(null);}int result = 0;boolean configChanged = false;
//获取发起者的Uid和Pidfinal int pid = Binder.getCallingPid();final int uid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();synchronized (mGlobalLock) {
//通过IBinder client查询mWindowMap中对应的WindowState final WindowState win = windowForClientLocked(session, client, false);if (win == null) {return 0;}if (win.mRelayoutSeq < seq) {win.mRelayoutSeq = seq;} else if (win.mRelayoutSeq > seq) {return 0;}if (win.cancelAndRedraw() && win.mPrepareSyncSeqId <= lastSyncSeqId) {// The client has reported the sync draw, but we haven't finished it yet.// Don't let the client perform a non-sync draw at this time.result |= RELAYOUT_RES_CANCEL_AND_REDRAW;}
//获取window对应的DisplayContent final DisplayContent displayContent = win.getDisplayContent();
//获取window对应的DisplayPolicy final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
//获取window对应的WindowStateAnimator WindowStateAnimator winAnimator = win.mWinAnimator;if (viewVisibility != View.GONE) {
//如果不是Gone,则更新全局变量之窗口申请的宽高 mRequestedWidth mRequestedHeight win.setRequestedSize(requestedWidth, requestedHeight);}

2. 第二步

            int attrChanges = 0;int flagChanges = 0;int privateFlagChanges = 0;
//如果窗口的属性不为空,则说明有要更新的窗口属性if (attrs != null) {
//调整窗口参数,主要是针对某些窗口类型,清理一些窗口属性参数displayPolicy.adjustWindowParamsLw(win, attrs);
...
窗口type在窗口add之后不能被改变,否则就会异常,窗口type是区分窗口层级很重要的一个东西if (win.mAttrs.type != attrs.type) {throw new IllegalArgumentException("Window type can not be changed after the window is added.");}
...
//异或^     两个位相同为0,相异为1flagChanges = win.mAttrs.flags ^ attrs.flags;privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags;attrChanges = win.mAttrs.copyFrom(attrs);final boolean layoutChanged =(attrChanges & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0;if (layoutChanged || (attrChanges& WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED) != 0) {
窗口布局有变化,需要更新win.mLayoutNeeded = true;}if (layoutChanged && win.providesDisplayDecorInsets()) {configChanged = displayPolicy.updateDecorInsetsInfo();}
//看下有没有锁屏相关的flag变化if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0|| (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) {win.mActivityRecord.checkKeyguardFlagsChanged();}if ((privateFlagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {updateNonSystemOverlayWindowsVisibilityIfNeeded(win, win.mWinAnimator.getShown());}if ((attrChanges & (WindowManager.LayoutParams.PRIVATE_FLAGS_CHANGED)) != 0) {winAnimator.setColorSpaceAgnosticLocked((win.mAttrs.privateFlags& WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);}
...}

3. 第三步

            int attrChanges = 0;int flagChanges = 0;int privateFlagChanges = 0;
//如果窗口的属性不为空,则说明有要更新的窗口属性if (attrs != null) {
//调整窗口参数,主要是针对某些窗口类型,清理一些窗口属性参数displayPolicy.adjustWindowParamsLw(win, attrs);
...
窗口type在窗口add之后不能被改变,否则就会异常,窗口type是区分窗口层级很重要的一个东西if (win.mAttrs.type != attrs.type) {throw new IllegalArgumentException("Window type can not be changed after the window is added.");}
...
//异或^     两个位相同为0,相异为1flagChanges = win.mAttrs.flags ^ attrs.flags;privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags;attrChanges = win.mAttrs.copyFrom(attrs);final boolean layoutChanged =(attrChanges & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0;if (layoutChanged || (attrChanges& WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED) != 0) {
窗口布局有变化,需要更新win.mLayoutNeeded = true;}if (layoutChanged && win.providesDisplayDecorInsets()) {configChanged = displayPolicy.updateDecorInsetsInfo();}
//看下有没有锁屏相关的flag变化if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0|| (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) {win.mActivityRecord.checkKeyguardFlagsChanged();}if ((privateFlagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {updateNonSystemOverlayWindowsVisibilityIfNeeded(win, win.mWinAnimator.getShown());}if ((attrChanges & (WindowManager.LayoutParams.PRIVATE_FLAGS_CHANGED)) != 0) {winAnimator.setColorSpaceAgnosticLocked((win.mAttrs.privateFlags& WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);}
...}

4. 第四步

//06-01 10:12:18.006  1890  2256 V WindowManager: Relayout Window{8d0d088 u0 
//com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: 
//viewVisibility=0 req=7104x3840 {(0,0)(fillxfill) sim={adjust=resize forwardNavigation} 
//ty=BASE_APPLICATION wanim=0x10302f2
//06-01 10:12:18.006  1890  2256 V WindowManager:   fl=LAYOUT_IN_SCREEN //LAYOUT_INSET_DECOR 
//SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
//06-01 10:12:18.006  1890  2256 V WindowManager:   pfl=NO_MOVE_ANIMATION 
//FORCE_DRAW_STATUS_BAR_BACKGROUND HIDE_NON_SYSTEM_OVERLAY_WINDOWS USE_BLAST 
//FIT_INSETS_CONTROLLED
//06-01 10:12:18.006  1890  2256 V WindowManager:   vsysui=LIGHT_STATUS_BAR 
//LIGHT_NAVIGATION_BAR
//06-01 10:12:18.006  1890  2256 V WindowManager:   apr=LIGHT_STATUS_BARS 
//LIGHT_NAVIGATION_BARS
//06-01 10:12:18.006  1890  2256 V WindowManager:   bhv=DEFAULT
//06-01 10:12:18.006  1890  2256 V WindowManager:   fitSides=}if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility+ " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {winAnimator.mAlpha = attrs.alpha;}
//设置窗口大小win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);if (win.mAttrs.surfaceInsets.left != 0|| win.mAttrs.surfaceInsets.top != 0|| win.mAttrs.surfaceInsets.right != 0|| win.mAttrs.surfaceInsets.bottom != 0) {winAnimator.setOpaqueLocked(false);}final int oldVisibility = win.mViewVisibility;// If the window is becoming visible, visibleOrAdding may change which may in turn// change the IME target.
//窗口由不可见/Gone变为可见final boolean becameVisible =(oldVisibility == View.INVISIBLE || oldVisibility == View.GONE)&& viewVisibility == View.VISIBLE;boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0|| becameVisible;
//窗口焦点更新--当之前的可见性和现在不一致,并且窗口没有携带FLAG_NOT_FOCUSABLE,并且mRelayoutCalled为falseboolean focusMayChange = win.mViewVisibility != viewVisibility|| ((flagChanges & FLAG_NOT_FOCUSABLE) != 0)|| (!win.mRelayoutCalled);boolean wallpaperMayMove = win.mViewVisibility != viewVisibility&& win.hasWallpaper();wallpaperMayMove |= (flagChanges & FLAG_SHOW_WALLPAPER) != 0;if ((flagChanges & FLAG_SECURE) != 0 && winAnimator.mSurfaceController != null) {winAnimator.mSurfaceController.setSecure(win.isSecureLocked());}final boolean wasVisible = win.isVisible();win.mRelayoutCalled = true;win.mInRelayout = true;
//设置窗口可见性为申请的可见性,可见则viewVisibility=0win.setViewVisibility(viewVisibility);ProtoLog.i(WM_DEBUG_SCREEN_ON,"Relayout %s: oldVis=%d newVis=%d. %s", win, oldVisibility,viewVisibility, new RuntimeException().fillInStackTrace());
//06-01 10:12:18.008  1890  2256 W WindowManager: setLayoutNeeded: 
//callers=com.android.server.wm.WindowState.setDisplayLayoutNeeded:2671 
//com.android.server.wm.WindowManagerService.relayoutWindow:2419 
//com.android.server.wm.Session.relayout:249 win.setDisplayLayoutNeeded();win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
 

viewVisibility代表当前View的可见性

mViewVisibilityVlaue含义
VISIBLE0x00000000

这个视图可见

与#setVisibility和#attr_android:visibility" android:visibility}一起使用。

INVISIBLE0x00000004

这个视图不可见

与#setVisibility和#attr_android:visibility" android:visibility}一起使用。

GONE0x00000008

这个视图是不可见的,它不占用任何空间进行布局

与#setVisibility和#attr_android:visibility" android:visibility}一起使用。

5. 第五步 创建Surface图层流程

            // We should only relayout if the view is visible, it is a starting window, or the// associated appToken is not hidden.
//只有当视图可见、并且它是STARTING窗口或关联的 appToken 未隐藏时,我们才应该重新布局。final boolean shouldRelayout = viewVisibility == View.VISIBLE &&(win.mActivityRecord == null || win.mAttrs.type == TYPE_APPLICATION_STARTING|| win.mActivityRecord.isClientVisible());// If we are not currently running the exit animation, we need to see about starting// one.// This must be called before the call to performSurfacePlacement.
//如果我们当前没有运行退出动画,满足下列条件,则需执行退出动画if (!shouldRelayout && winAnimator.hasSurface() && !win.mAnimatingExit) {if (DEBUG_VISIBILITY) {
//06-01 10:12:14.228  1890  2256 I WindowManager: Relayout invis Window{8c33950 u0 
//NotificationShade}: mAnimatingExit=falseSlog.i(TAG_WM,"Relayout invis " + win + ": mAnimatingExit=" + win.mAnimatingExit);}result |= RELAYOUT_RES_SURFACE_CHANGED;// When FLAG_SHOW_WALLPAPER flag is removed from a window, we usually set a flag// in DC#pendingLayoutChanges and update the wallpaper target later.// However it's possible that FLAG_SHOW_WALLPAPER flag is removed from a window// when the window is about to exit, so we update the wallpaper target// immediately here. Otherwise this window will be stuck in exiting and its// surface remains on the screen.// TODO(b/189856716): Allow destroying surface even if it belongs to the//  keyguard target.if (wallpaperMayMove) {displayContent.mWallpaperController.adjustWallpaperWindows();}
//执行窗口退出动画tryStartExitingAnimation(win, winAnimator);}// Create surfaceControl before surface placement otherwise layout will be skipped// (because WS.isGoneForLayout() is true when there is no surface.
//outSurfaceControl是client端传入的,在ViewRootImpl全局变量中就实例化好了
//http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/view/ViewRootImpl.java#708
//private final SurfaceControl mSurfaceControl = new SurfaceControl();
//所以这个不会为空if (shouldRelayout && outSurfaceControl != null) {try {
//创建图层result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);} catch (Exception e) {displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);ProtoLog.w(WM_ERROR,"Exception thrown when creating surface for client %s (%s). %s",client, win.mAttrs.getTitle(), e);Binder.restoreCallingIdentity(origId);return 0;}}
 

5.1 WindowManagerService#createSurfaceControl

WindowManagerService.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    private int createSurfaceControl(SurfaceControl outSurfaceControl, int result,WindowState win, WindowStateAnimator winAnimator) {if (!win.mHasSurface) {result |= RELAYOUT_RES_SURFACE_CHANGED;}WindowSurfaceController surfaceController;try {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
//创建window对应的surface图层surfaceController = winAnimator.createSurfaceLocked();
...if (surfaceController != null) {surfaceController.getSurfaceControl(outSurfaceControl);ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);} else {
...}

 5.2  WindowStateAnimator#createSurfaceLocked

WindowStateAnimator.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java

    WindowSurfaceController createSurfaceLocked() {final WindowState w = mWin;if (mSurfaceController != null) {return mSurfaceController;}
//设置是否有Surface标志位为falsew.setHasSurface(false);ProtoLog.i(WM_DEBUG_ANIM, "createSurface %s: mDrawState=DRAW_PENDING", this);
//重置图层绘制状态resetDrawState();
//要开始绘制图层了,要先freeze(冻住)住屏幕,等待绘制完成再Unfreeze,这里有个超时机制,即
//冻住屏幕有个最大时间WINDOW_FREEZE_TIMEOUT_DURATION--2000msmService.makeWindowFreezingScreenIfNeededLocked(w);int flags = SurfaceControl.HIDDEN;final WindowManager.LayoutParams attrs = w.mAttrs;
//如果window是加密窗口,则添加此flagif (w.isSecureLocked()) {flags |= SurfaceControl.SECURE;}if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {flags |= SurfaceControl.SKIP_SCREENSHOT;}
//06-01 10:12:18.009  1890  2256 V WindowManager: Creating surface in session 
//android.view.SurfaceSession@fcb7984 window WindowStateAnimator{31728a0 
//com.android.settings/com.android.settings.homepage.SettingsHomepageActivity} format=-1 
//flags=4if (DEBUG_VISIBILITY) {Slog.v(TAG, "Creating surface in session "+ mSession.mSurfaceSession + " window " + this+ " format=" + attrs.format + " flags=" + flags);}// Set up surface control with initial size.try {// This can be removed once we move all Buffer Layers to use BLAST.final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
//创建图层----创建WindowSurfaceController,主要是管理图层的,可设置图层位置,大小,是否可见等 mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), format,flags, this, attrs.type);
//将 Surface 设置为与颜色空间无关。mSurfaceController.setColorSpaceAgnostic(w.getPendingTransaction(),(attrs.privateFlags & LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
//图层创建好了,更新是否有Surface的标志位为truew.setHasSurface(true);
...
//06-01 10:12:18.015  1890  2256 V WindowManager: Got surface: 
//Surface(name=com.android.settings/com.android.settings.homepage.SettingsHomepageActivit//y)@0xafd3c59, set left=0 top=0if (DEBUG) {Slog.v(TAG, "Got surface: " + mSurfaceController+ ", set left=" + w.getFrame().left + " top=" + w.getFrame().top);}
...mLastHidden = true;
//06-01 10:12:18.015  1890  2256 V WindowManager: Created surface 
//WindowStateAnimator{31728a0 
//com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}if (DEBUG) Slog.v(TAG, "Created surface " + this);return mSurfaceController;}

  5.3 WindowSurfaceController之创建图层

    WindowSurfaceController(String name, int format, int flags, WindowStateAnimator animator,int windowType) {mAnimator = animator;title = name;mService = animator.mService;final WindowState win = animator.mWin;mWindowType = windowType;mWindowSession = win.mSession;Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl");
//创建图层final SurfaceControl.Builder b = win.makeSurface().setParent(win.getSurfaceControl()).setName(name).setFormat(format).setFlags(flags).setMetadata(METADATA_WINDOW_TYPE, windowType).setMetadata(METADATA_OWNER_UID, mWindowSession.mUid).setMetadata(METADATA_OWNER_PID, mWindowSession.mPid).setCallsite("WindowSurfaceController");final boolean useBLAST = mService.mUseBLAST && ((win.getAttrs().privateFlags& WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST) != 0);if (useBLAST) {b.setBLASTLayer();}mSurfaceControl = b.build();Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}
-------------------------------------------------------------------
//http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/view/SurfaceControl.java#857public static class Builder {/*** Begin building a SurfaceControl.*/public Builder() {}/*** Construct a new {@link SurfaceControl} with the set parameters. The builder* remains valid.*/@NonNullpublic SurfaceControl build() {if (mWidth < 0 || mHeight < 0) {throw new IllegalStateException("width and height must be positive or unset");}if ((mWidth > 0 || mHeight > 0) && (isEffectLayer() || isContainerLayer())) {throw new IllegalStateException("Only buffer layers can set a valid buffer size.");}if (mName == null) {Log.w(TAG, "Missing name for SurfaceControl", new Throwable());}if ((mFlags & FX_SURFACE_MASK) == FX_SURFACE_NORMAL) {setBLASTLayer();}return new SurfaceControl(mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,mLocalOwnerView, mCallsite);}---------------------------------------------------------private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,String callsite)throws OutOfResourcesException, IllegalArgumentException {if (name == null) {throw new IllegalArgumentException("name must not be null");}mName = name;mWidth = w;mHeight = h;mLocalOwnerView = localOwnerView;Parcel metaParcel = Parcel.obtain();long nativeObject = 0;try {if (metadata != null && metadata.size() > 0) {metaParcel.writeInt(metadata.size());for (int i = 0; i < metadata.size(); ++i) {metaParcel.writeInt(metadata.keyAt(i));metaParcel.writeByteArray(ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()).putInt(metadata.valueAt(i)).array());}metaParcel.setDataPosition(0);}nativeObject = nativeCreate(session, name, w, h, format, flags,parent != null ? parent.mNativeObject : 0, metaParcel);} finally {metaParcel.recycle();}if (nativeObject == 0) {throw new OutOfResourcesException("Couldn't allocate SurfaceControl native object");}assignNativeObject(nativeObject, callsite);}

6. 第六步 刷新界面和更新焦点

// We may be deferring layout passes at the moment, but since the client is interested// in the new out values right now we need to force a layout.mWindowPlacerLocked.performSurfacePlacement(true /* force */);

6.1 WindowSurfacePlacer#performSurfacePlacement 刷新界面和更新焦点

performSurfacePlacement 看方法名,perform surface place,即负责所有窗口的Surface的摆放工作,如何显示位置,大小等等,是WMS中的核心方法

90e8fa75df9f4c1bb4ed707d707d3fe1.jpg

下面这些流程的流程图如上

    final void performSurfacePlacement(boolean force) {if (mDeferDepth > 0 && !force) {mDeferredRequests++;return;}
//最大执行6次循环int loopCount = 6;do {mTraversalScheduled = false;performSurfacePlacementLoop();mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);loopCount--;} while (mTraversalScheduled && loopCount > 0);mService.mRoot.mWallpaperActionPending = false;}private void performSurfacePlacementLoop() {
//此方法下面已经有地方将mInLayout置为true,说明已经正在执行performSurfacePlacementLoop方法了if (mInLayout) {
...return;}// TODO(multi-display):final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
//mWaitingForConfig作用是Used to gate application window layout until we have sent the complete configuration.
//当没有完成configuration change的时候,无需做relayout,直到configuration change完成if (defaultDisplay.mWaitingForConfig) {// Our configuration has changed (most likely rotation), but we// don't yet have the complete configuration to report to// applications.  Don't do any window layout until we have it.return;}
//屏幕没准备好,直接返回if (!mService.mDisplayReady) {// Not yet initialized, nothing to do.return;}
//对应第一行标志位,表示正在layoutmInLayout = true;
//内存不足时,强制清理mForceRemoves集合,释放内存if (!mService.mForceRemoves.isEmpty()) {// Wait a little bit for things to settle down, and off we go.while (!mService.mForceRemoves.isEmpty()) {final WindowState ws = mService.mForceRemoves.remove(0);Slog.i(TAG, "Force removing: " + ws);ws.removeImmediately();}Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");Object tmp = new Object();synchronized (tmp) {try {tmp.wait(250);} catch (InterruptedException e) {}}}try {
//核心的一步mService.mRoot.performSurfacePlacement();
//标志位置为false,走完上面这步,layout就完成了mInLayout = false;if (mService.mRoot.isLayoutNeeded()) {
//需要layout,并且count<6if (++mLayoutRepeatCount < 6) {requestTraversal();} else {
...}

6.2 RootWindowContainer#performSurfacePlacement

RootWindowContainer.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

    void performSurfacePlacement() {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");try {performSurfacePlacementNoTrace();} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}}

 6.3 RootWindowContainer#performSurfacePlacementNoTrace - part1

这个方法也很长,当窗口的某些东西改变的时候,就会走到这里,由于太长,我们分开去讲

    void performSurfacePlacementNoTrace() {if (DEBUG_WINDOW_TRACE) {
//06-01 10:12:18.016  1890  2256 V WindowManager: performSurfacePlacementInner: entry. 
//Called by com.android.server.wm.RootWindowContainer.performSurfacePlacement:765 
//com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop:177 
//com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement:126 Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "+ Debug.getCallers(3));}int i;if (mWmService.mFocusMayChange) {mWmService.mFocusMayChange = false;
//更新焦点窗口mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);}mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;mUserActivityTimeout = -1;mObscureApplicationContentOnSecondaryDisplays = false;mSustainedPerformanceModeCurrent = false;mWmService.mTransactionSequence++;// TODO(multi-display): recents animation & wallpaper need support multi-display.final DisplayContent defaultDisplay = mWmService.getDefaultDisplayContentLocked();
//获取WindowSurfacePlacer,这个类专门用于摆放windows和他们的surfaces,
//全系统只有一个实例,在WMS实例化中进行的final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
//要开始进行过渡动画了if (SHOW_LIGHT_TRANSACTIONS) {Slog.i(TAG,">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");}Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
//设置surface参数,start a transaction,对一组 SurfaceControl 的原子更改。
//即通过SurfaceControl来通知native开始一个TransactionmWmService.openSurfaceTransaction();try {
//执行Transaction
//下面详细解释这里applySurfaceChangesTransaction();} catch (RuntimeException e) {Slog.wtf(TAG, "Unhandled exception in Window Manager", e);} finally {
//close surface TransactionmWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);if (SHOW_LIGHT_TRANSACTIONS) {Slog.i(TAG,"<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");}}
...
剩下的分另一半说

6.3.1 RootWindowContainer#applySurfaceChangesTransaction

RootWindowContainer.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

    private void applySurfaceChangesTransaction() {// TODO(multi-display): Support these features on secondary screens.final DisplayContent defaultDc = mDefaultDisplay;final DisplayInfo defaultInfo = defaultDc.getDisplayInfo();final int defaultDw = defaultInfo.logicalWidth;final int defaultDh = defaultInfo.logicalHeight;final SurfaceControl.Transaction t = defaultDc.getSyncTransaction();
...
//mChildren为“List of children for this window container”,
//也就是这个WindowContainer的一系列子windowContainer的集合final int count = mChildren.size();
//循环遍历for (int j = 0; j < count; ++j) {
//获取到这个WindowContainer对应的DisplayContent final DisplayContent dc = mChildren.get(j);
//对这个DisplayContent进行applySurfaceChangesTransactiondc.applySurfaceChangesTransaction();}// Give the display manager a chance to adjust properties like display rotation if it needs// to.mWmService.mDisplayManagerInternal.performTraversal(t);if (t != defaultDc.mSyncTransaction) {SurfaceControl.mergeToGlobalTransaction(t);}}

借用一张图来表示mChildren,mChildren里保存的都是WidowContainer,并且这些WidowContainer按Z值排序,Z值越大越靠前

WindowContainer.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java "List of children for this window container. List is in z-order as the children appear on screen with the top-most window container at the tail of the list."

  protected final WindowList<E> mChildren = new WindowList<E>();

05342f3048dc4ea3adefed42dde7e65c.png

 6.3.2 DisplayContent#applySurfaceChangesTransaction

DisplayContent.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

    void applySurfaceChangesTransaction() {final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;beginHoldScreenUpdate();mTmpUpdateAllDrawn.clear();
...// Perform a layout, if needed.performLayout(true /* initial */, false /* updateInputWindows */);pendingLayoutChanges = 0;Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");try {mDisplayPolicy.beginPostLayoutPolicyLw();
//遍历windows   执行mApplyPostLayoutPolicyforAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);mDisplayPolicy.finishPostLayoutPolicyLw();} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}mInsetsStateController.onPostLayout();mTmpApplySurfaceChangesTransactionState.reset();Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyWindowSurfaceChanges");try {
//遍历windows
//执行mApplySurfaceChangesTransactionforAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}prepareSurfaces();
...finishHoldScreenUpdate();}

 6.3.3 DisplayContent#performLayout

DisplayContent.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

    void performLayout(boolean initial, boolean updateInputWindows) {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performLayout");try {performLayoutNoTrace(initial, updateInputWindows);} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}}private void performLayoutNoTrace(boolean initial, boolean updateInputWindows) {if (!isLayoutNeeded()) {return;}
//将mLayoutNeeded = false;
//会打印堆栈:06-01 10:12:18.016  1890  2256 W WindowManager: clearLayoutNeeded: 
//callers=com.android.server.wm.DisplayContent.performLayoutNoTrace:5051 
//com.android.server.wm.DisplayContent.performLayout:5041 
//com.android.server.wm.DisplayContent.applySurfaceChangesTransaction:4963 clearLayoutNeeded();if (DEBUG_LAYOUT) {
//06-01 10:12:18.016  1890  2256 V WindowManager: performLayout: dw=3840 dh=7104 Slog.v(TAG, "-------------------------------------");Slog.v(TAG, "performLayout: dw=" + mDisplayInfo.logicalWidth+ " dh=" + mDisplayInfo.logicalHeight);}int seq = mLayoutSeq + 1;if (seq < 0) seq = 0;mLayoutSeq = seq;mTmpInitial = initial;// First perform layout of any root windows (not attached to another window).
//首先给所有windows执行layout,mPerformLayout稍后解释forAllWindows(mPerformLayout, true /* traverseTopToBottom */);// Now perform layout of attached windows, which usually depend on the position of the// window they are attached to. XXX does not deal with windows that are attached to windows// that are themselves attached.
//给所有attached windows执行layout操作forAllWindows(mPerformLayoutAttached, true /* traverseTopToBottom */);// Window frames may have changed. Tell the input dispatcher about it.
//更新input windowmInputMonitor.setUpdateInputWindowsNeededLw();if (updateInputWindows) {mInputMonitor.updateInputWindowsLw(false /*force*/);}}

DisplayContent#  mPerformLayout赋值如下:

DisplayContent.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

    private final Consumer<WindowState> mPerformLayout = w -> {if (w.mLayoutAttached) {return;}// Don't do layout of a window if it is not visible, or soon won't be visible, to avoid// wasting time and funky changes while a window is animating away.final boolean gone = w.isGoneForLayout();if (DEBUG_LAYOUT) {Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame+ " config reported=" + w.isLastConfigReportedToClient());final ActivityRecord activity = w.mActivityRecord;if (gone) Slog.v(TAG, "  GONE: mViewVisibility=" + w.mViewVisibility+ " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible()+ " visibleRequested=" + (activity != null && activity.isVisibleRequested())+ " parentHidden=" + w.isParentWindowHidden());else Slog.v(TAG, "  VIS: mViewVisibility=" + w.mViewVisibility+ " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible()+ " visibleRequested=" + (activity != null && activity.isVisibleRequested())+ " parentHidden=" + w.isParentWindowHidden());}// If this view is GONE, then skip it -- keep the current frame, and let the caller know// so they can ignore it if they want.  (We do the normal layout for INVISIBLE windows,// since that means "perform layout as normal, just don't display").if (!gone || !w.mHaveFrame || w.mLayoutNeeded) {if (mTmpInitial) {w.resetContentChanged();}w.mSurfacePlacementNeeded = true;w.mLayoutNeeded = false;final boolean firstLayout = !w.isLaidOut();
// Called for each window attached to the window manager as layout is proceeding
//在布局进行时调用附加到窗口管理器的每个窗口getDisplayPolicy().layoutWindowLw(w, null, mDisplayFrames);w.mLayoutSeq = mLayoutSeq;// If this is the first layout, we need to initialize the last frames and inset values,// as otherwise we'd immediately cause an unnecessary resize.if (firstLayout) {// The client may compute its actual requested size according to the first layout,// so we still request the window to resize if the current frame is empty.if (!w.getFrame().isEmpty()) {w.updateLastFrames();}w.onResizeHandled();}if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame=" + w.getFrame()+ " mParentFrame=" + w.getParentFrame()+ " mDisplayFrame=" + w.getDisplayFrame());}};

DisplayPolicy#layoutWindowLw

    public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
...mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,win.getRequestedVisibleTypes(), win.mGlobalScale, sTmpClientFrames);win.setFrames(sTmpClientFrames, win.mRequestedWidth, win.mRequestedHeight);}

DisplayContent#  ​​​​​​​​​​​​​​mApplyPostLayoutPolicy赋值如下:

    private final Consumer<WindowState> mApplyPostLayoutPolicy =w -> getDisplayPolicy().applyPostLayoutPolicyLw(w, w.mAttrs, w.getParentWindow(), mImeLayeringTarget);

DisplayPolicy.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java

    /*** Called following layout of all window to apply policy to each window.** @param win The window being positioned.* @param attrs The LayoutParams of the window.* @param attached For sub-windows, the window it is attached to. Otherwise null.*/public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached, WindowState imeTarget) {

 DisplayContent#  ​​​​​​​mApplySurfaceChangesTransaction赋值如下

    private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;final boolean obscuredChanged = w.mObscured !=mTmpApplySurfaceChangesTransactionState.obscured;final RootWindowContainer root = mWmService.mRoot;// Update effect.w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;if (!mTmpApplySurfaceChangesTransactionState.obscured) {final boolean isDisplayed = w.isDisplayed();if (isDisplayed && w.isObscuringDisplay()) {// This window completely covers everything behind it, so we want to leave all// of them as undimmed (for performance reasons).mObscuringWindow = w;mTmpApplySurfaceChangesTransactionState.obscured = true;}final boolean displayHasContent = root.handleNotObscuredLocked(w,mTmpApplySurfaceChangesTransactionState.obscured,mTmpApplySurfaceChangesTransactionState.syswin);if (!mTmpApplySurfaceChangesTransactionState.displayHasContent&& !getDisplayPolicy().isWindowExcludedFromContent(w)) {mTmpApplySurfaceChangesTransactionState.displayHasContent |= displayHasContent;}if (w.mHasSurface && isDisplayed) {if ((w.mAttrs.flags & FLAG_KEEP_SCREEN_ON) != 0) {mTmpHoldScreenWindow = w;} else if (w == mLastWakeLockHoldingWindow) {ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON,"handleNotObscuredLocked: %s was holding screen wakelock but no longer "+ "has FLAG_KEEP_SCREEN_ON!!! called by%s",w, Debug.getCallers(10));}final int type = w.mAttrs.type;if (type == TYPE_SYSTEM_DIALOG|| type == TYPE_SYSTEM_ERROR|| (type == TYPE_NOTIFICATION_SHADE&&  mWmService.mPolicy.isKeyguardShowing())) {mTmpApplySurfaceChangesTransactionState.syswin = true;}if (mTmpApplySurfaceChangesTransactionState.preferredRefreshRate == 0&& w.mAttrs.preferredRefreshRate != 0) {mTmpApplySurfaceChangesTransactionState.preferredRefreshRate= w.mAttrs.preferredRefreshRate;}mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing|= w.mAttrs.preferMinimalPostProcessing;mTmpApplySurfaceChangesTransactionState.disableHdrConversion|= !(w.mAttrs.isHdrConversionEnabled());final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy().getPreferredModeId(w);if (w.getWindowingMode() != WINDOWING_MODE_PINNED&& mTmpApplySurfaceChangesTransactionState.preferredModeId == 0&& preferredModeId != 0) {mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId;}final float preferredMinRefreshRate = getDisplayPolicy().getRefreshRatePolicy().getPreferredMinRefreshRate(w);if (mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate == 0&& preferredMinRefreshRate != 0) {mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate =preferredMinRefreshRate;}final float preferredMaxRefreshRate = getDisplayPolicy().getRefreshRatePolicy().getPreferredMaxRefreshRate(w);if (mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate == 0&& preferredMaxRefreshRate != 0) {mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate =preferredMaxRefreshRate;}}}if (obscuredChanged && w.isVisible() && mWallpaperController.isWallpaperTarget(w)) {// This is the wallpaper target and its obscured state changed... make sure the// current wallpaper's visibility has been updated accordingly.mWallpaperController.updateWallpaperVisibility();}w.handleWindowMovedIfNeeded();final WindowStateAnimator winAnimator = w.mWinAnimator;//Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");w.resetContentChanged();// Moved from updateWindowsAndWallpaperLocked().if (w.mHasSurface) {// Take care of the window being ready to display.final boolean committed = winAnimator.commitFinishDrawingLocked();if (isDefaultDisplay && committed) {if (w.hasWallpaper()) {ProtoLog.v(WM_DEBUG_WALLPAPER,"First draw done in potential wallpaper target %s", w);mWallpaperMayChange = true;pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;if (DEBUG_LAYOUT_REPEATS) {surfacePlacer.debugLayoutRepeats("wallpaper and commitFinishDrawingLocked true",pendingLayoutChanges);}}}}final ActivityRecord activity = w.mActivityRecord;if (activity != null && activity.isVisibleRequested()) {activity.updateLetterboxSurface(w);final boolean updateAllDrawn = activity.updateDrawnWindowStates(w);if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(activity)) {mTmpUpdateAllDrawn.add(activity);}}w.updateResizingWindowIfNeeded();};

在这个过程中会通过commitFinishDrawingLocked去检查当前窗口的mDrawState情况。Surface的mDrawState的绘制状态是由ViewRootImpl通过Session调用到WMS端,然后在WMS端设置的。

当此window窗口的mDrawState变化状态从NO_SURFACE -> DRAW_PENDING -> COMMIT_DRAW_PENDING  -> HAS_DRAWN-> READY_TO_SHOW,然后才会将图层置为可见状态,设置为可见的log如下:

05-25 10:56:31.956  1915  1973 V WindowManager: performShow on Window{f4647f5 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: mDrawState=READY_TO_SHOW readyForDisplay=true starting=false during animation: policyVis=true parentHidden=false tok.visibleRequested=true tok.visible=true animating=false tok animating=false Callers=com.android.server.wm.WindowState.performShowLocked:4372 com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked:256 com.android.server.wm.DisplayContent.lambda$new$8:1082 com.android.server.wm.DisplayContent.$r8$lambda$NJwM1ysKPNyOazqyI2QXlp2I4yA:0 
05-25 10:56:31.962  1915  1973 V WindowManager: Showing Window{f4647f5 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: mDrawState=READY_TO_SHOW readyForDisplay=true starting=false during animation: policyVis=true parentHidden=false tok.visibleRequested=true tok.visible=true animating=true tok animating=false Callers=com.android.server.wm.WindowState.performShowLocked:4387 com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked:256 com.android.server.wm.DisplayContent.lambda$new$8:1082 com.android.server.wm.DisplayContent.$r8$lambda$NJwM1ysKPNyOazqyI2QXlp2I4yA:0

 大概log如下:

06-01 10:12:18.006  1890  2256 V WindowManager: Relayout Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: viewVisibility=0 req=7104x3840 {(0,0)(fillxfill) sim={adjust=resize forwardNavigation} ty=BASE_APPLICATION wanim=0x10302f2
06-01 10:12:18.006  1890  2256 V WindowManager:   fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
06-01 10:12:18.006  1890  2256 V WindowManager:   pfl=NO_MOVE_ANIMATION FORCE_DRAW_STATUS_BAR_BACKGROUND HIDE_NON_SYSTEM_OVERLAY_WINDOWS USE_BLAST FIT_INSETS_CONTROLLED
06-01 10:12:18.006  1890  2256 V WindowManager:   vsysui=LIGHT_STATUS_BAR LIGHT_NAVIGATION_BAR
06-01 10:12:18.006  1890  2256 V WindowManager:   apr=LIGHT_STATUS_BARS LIGHT_NAVIGATION_BARS
06-01 10:12:18.006  1890  2256 V WindowManager:   bhv=DEFAULT
06-01 10:12:18.006  1890  2256 V WindowManager:   fitSides=}
06-01 10:12:18.008  1890  2256 W WindowManager: setLayoutNeeded: callers=com.android.server.wm.WindowState.setDisplayLayoutNeeded:2671 com.android.server.wm.WindowManagerService.relayoutWindow:2419 com.android.server.wm.Session.relayout:249 
06-01 10:12:18.009  1890  2256 V WindowManager: Creating surface in session android.view.SurfaceSession@fcb7984 window WindowStateAnimator{31728a0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity} format=-1 flags=4
06-01 10:12:18.015  1890  2256 V WindowManager: Got surface: Surface(name=com.android.settings/com.android.settings.homepage.SettingsHomepageActivity)/@0xafd3c59, set left=0 top=0
06-01 10:12:18.015  1890  2256 I WindowManager: >>> OPEN TRANSACTION createSurfaceLocked
06-01 10:12:18.015  1890  2256 I WindowManager:   SURFACE CREATE pos=(0,0) HIDE: Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}
06-01 10:12:18.015  1890  2256 V WindowManager: Created surface WindowStateAnimator{31728a0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}
06-01 10:12:18.016  1890  2256 V WindowManager: performSurfacePlacementInner: entry. Called by com.android.server.wm.RootWindowContainer.performSurfacePlacement:765 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop:177 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement:126 
06-01 10:12:18.016  1890  2256 I WindowManager: >>> OPEN TRANSACTION performLayoutAndPlaceSurfaces
...
06-01 10:12:18.020  1890  2256 I WindowManager: <<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces
06-01 10:12:18.021  1890  2256 E WindowManager: performSurfacePlacementInner exit
06-01 10:12:18.021  1890  2256 V WindowManager: Already visible and does not turn on screen, skip preparing: Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}
06-01 10:12:18.022  1890  2256 W WindowManager: Moving IM target from null to null since mInputMethodWindow is null
06-01 10:12:18.022  1890  2256 V WindowManager: Win Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: isDrawn=false, animating=false
06-01 10:12:18.022  1890  2256 V WindowManager: Not displayed: s=Surface(name=com.android.settings/com.android.settings.homepage.SettingsHomepageActivity)/@0xafd3c59 pv=true mDrawState=1 ph=false th=true a=false
06-01 10:12:18.022  1890  2256 V WindowManager: Relayout complete Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: outFrames=ClientWindowFrames{frame=[0,0][7104,3840] display=[0,0][7104,3840] parentFrame=[0,0][0,0]}
06-01 10:12:18.214  1890  1950 I WindowManager: commitFinishDrawingLocked: Window{d8b1e28 u0 Splash Screen com.android.settings} cur mDrawState=HAS_DRAWN
06-01 10:12:18.214  1890  1950 D ActivityTaskManager: updateWindows: starting Window{d8b1e28 u0 Splash Screen com.android.settings} isOnScreen=true allDrawn=false freezingScreen=false
06-01 10:12:18.214  1890  1950 V WindowManager: Resizing Window{d8b1e28 u0 Splash Screen com.android.settings}: configChanged=false last=Rect(0, 0 - 7104, 3840) frame=Rect(0, 0 - 7104, 3840)
06-01 10:12:18.215  1890  1950 V WindowManager: performShow on Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: mDrawState=READY_TO_SHOW readyForDisplay=true starting=false during animation: policyVis=true parentHidden=false tok.visibleRequested=true tok.visible=true animating=false tok animating=false Callers=com.android.server.wm.WindowState.performShowLocked:4372 com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked:256 com.android.server.wm.DisplayContent.lambda$new$8:1082 com.android.server.wm.DisplayContent.$r8$lambda$NJwM1ysKPNyOazqyI2QXlp2I4yA:0 
...
06-01 10:12:18.220  1890  1950 V WindowManager: Win Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: isDrawn=true, animating=true06-01 10:12:18.228  1890  1950 V WindowManager: Showing Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: mDrawState=READY_TO_SHOW readyForDisplay=true starting=false during animation: policyVis=true parentHidden=false tok.visibleRequested=true tok.visible=true animating=true tok animating=false Callers=com.android.server.wm.WindowState.performShowLocked:4387 com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked:256 com.android.server.wm.DisplayContent.lambda$new$8:1082 com.android.server.wm.DisplayContent.$r8$lambda$NJwM1ysKPNyOazqyI2QXlp2I4yA:0 

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

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

相关文章

任务3.5 清洗网址中的垃圾字符

本实战任务聚焦于数据清洗在Java编程中的应用&#xff0c;特别是清洗网址中的垃圾字符。数据清洗是确保数据质量的重要环节&#xff0c;它帮助开发者去除数据中的异常、错误或无关字符&#xff0c;从而提高数据分析的准确性和有效性。 任务背景&#xff1a;理解数据清洗的重要性…

刷代码随想录有感(93):贪心算法——无重叠区间(区间重叠问题:求区间重叠次数)

题干: 代码&#xff1a; class Solution { public:static bool cmp(vector<int>& a, vector<int>& b){return a[0] < b[0];}int eraseOverlapIntervals(vector<vector<int>>& intervals) {sort(intervals.begin(), intervals.end(), c…

vulnhub靶机实战_DC-2

下载 靶机下载链接汇总&#xff1a;https://download.vulnhub.com/使用搜索功能&#xff0c;搜索dc类型的靶机即可。本次实战使用的靶机是&#xff1a;DC-2下载链接&#xff1a;https://download.vulnhub.com/dc/DC-2.zip 启动 下载完成后&#xff0c;打开VMware软件&#xf…

SendGrid发送邮件时如何调用API接口群发?

SendGrid发送邮件模板如何定制&#xff1f;邮件发送限制有哪些&#xff1f; SendGrid发送邮件是一种方便快捷的方式&#xff0c;可以在应用程序或网站中轻松地发送大量邮件。通过调用SendGrid的API接口&#xff0c;您可以实现群发邮件&#xff0c;无论是通知用户、发送营销邮件…

HDFS文件块损坏处理方案

1、问题概述 flume采集文本文件存储到hdfs中hive的ods层目录,并在hive中通过msck repair table刷新元数据,加载文本文件。报错如下: 2、问题分析 文件块BP-531411289-172.31.57.12-1539657748238出现了未知异常,导致namenode不能获取该文件块的信息,该文件块是由flume采…

小程序开发平台——搭建全功能小程序商城功能 前后端分离 带完整的安装代码包以及搭建教程

系统概述 随着电子商务的蓬勃发展&#xff0c;越来越多的企业和商家希望拥有自己的线上商城&#xff0c;以拓展销售渠道和提升用户体验。然而&#xff0c;传统的商城开发方式往往成本高、周期长&#xff0c;且难以满足快速变化的市场需求。因此&#xff0c;我们致力于打造一款…

成立不到一年,EDA“黑马”再获亿元级融资,国产自主黄金期加速到来

本土EDA厂商派兹互连 再获亿元级融资 电巢获悉&#xff0c;成都派兹互连电子技术有限公司(以下简称“派兹互连”)于近日完成超亿元产业方追加投资&#xff0c;本轮融资将用于研发投入、产品迭代及技术创新等方面。 同时我们了解到&#xff0c;派兹互连已与多家领先EDA/CAE产品…

干货分享:有哪些好用的绩效管理工具?

绩效管理在诸多企业中占据着举足轻重的地位&#xff0c;但同时也是一个令人头痛的问题。特别是在年终的绩效考评环节&#xff0c;它往往变得流于形式&#xff0c;成了一项例行公事。尽管每个人都被要求参与这一流程&#xff0c;但很少有人真正关心考核结果是否公正合理&#xf…

模拟实现priority_queue

文章目录 priority_queue简介priority_queue的实现Myless和Mygreaterpushpop常规接口 全部代码测试代码 总结 priority_queue简介 priority_queue是优先级队列。 什么是优先级队列&#xff1f; 优先级队列&#xff08;Priority Queue&#xff09;是一种数据结构&#xff0c;用于…

579页 | 工业数字孪生建模与应用(免费下载)

【1】关注本公众号&#xff0c;转发当前文章到微信朋友圈 【2】私信发送 工业数字孪生建模与应用 【3】获取本方案PDF下载链接&#xff0c;直接下载即可。 如需下载本方案PPT/WORD原格式&#xff0c;请加入微信扫描以下方案驿站知识星球&#xff0c;获取上万份PPT/WORD解决方…

节点间通路

题目链接 节点间通路 题目描述 注意点 图是有向图节点编号大于等于 0 小于 n图中可能存在自环和平行边 解答思路 初始想到的是使用广度优先遍历&#xff0c;从start开始&#xff0c;存储每个点所能到达的其他节点集合&#xff0c;直到到达target或者不能到达新的节点为止&…

“新高考”下分班怎么分?

来自安徽的张女士告诉我&#xff1a;上一年孩子升入了高中&#xff0c;但没想到才高一&#xff0c;孩子就面临了一个困难的挑选&#xff1a;312”分班&#xff01; 什么是312”分班呢&#xff1f;许多人或许不明白&#xff0c;便是要求学生在高一入学时&#xff0c;针对于3门必…

服务器数据恢复—raid5阵列磁盘坏道离线导致数据丢失的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌x3850 X5服务器&#xff0c;服务器上有一组由5块硬盘组建的raid5阵列&#xff08;包含一块热备盘&#xff09;&#xff0c;安装linux操作系统&#xff0c;运行oracle数据库。 服务器故障&#xff1a; 服务器上raid5阵列中两块硬盘由于未…

Vue进阶之Vue无代码可视化项目(四)

Vue无代码可视化项目 左侧栏第一步LeftPanel.vueLayoutView.vuebase.css第二步LayoutView.vueLeftPanel.vue编排引擎smooth-dnd安装创建文件SmoothDndContainer.tsutils.tsSmoothDndDraggable.tsLeftPanel.vue左侧栏 第一步 创建LeftPanel LeftPanel.vue <script setup…

空间数据采集与组织、转换与处理;统计数据、GPS数据、矢量数据、栅格数据、遥感云平台数据、点云数据、多维数据获取及处理

你还在为找不到合适的数据而苦恼吗&#xff1f;你还在面对大量数据束手无策&#xff0c;不知如何处理吗&#xff1f;对于从事生产和科研的人员来说&#xff0c;空间数据的采集与管理是地理信息系统&#xff08;GIS&#xff09;和空间分析领域的关键环节。通过准确高效地采集和管…

层出不穷的大模型产品如何选

目录 1.概述 2.使用体验分享 2.1.功能情况 2.2.内容生成质量 2.3.隐私安全性 2.4.小结 3.独特优势和倾向选择 4.未来发展方向 4.1.技术创新 4.2.可持续可扩展性 4.3.用户体验 4.4.应用场景 4.5.政府赋能 4.6.小结 1.概述 目前市面上的大模型AIGC产品有很多&#…

代码随想录——二叉搜索树中的插入操作(Leetcode701)

题目链接 递归 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

如何理解与学习数学分析——第二部分——数学分析中的基本概念——第7章——连续性

第2 部分&#xff1a;数学分析中的基本概念 (Concepts in Analysis) 7. 连续性(Continuity) 本章首先讨论连续性的直观概念&#xff0c;并介绍与早期数学中常见的函数不同的函数。解释了连续性的定义&#xff0c;并演示了如何使用它来证明函数在一点上连续&#xff0c;以及证…

支付宝推出AI毛发自测工具,上传照片即可自测脱发等级

根据国家卫健委此前公布的数据&#xff0c;我国超过2.5亿人有脱发困扰&#xff0c;平均每6人中就有1人脱发&#xff0c;且近些年来&#xff0c;脱发群体呈年轻化趋势。为了帮助应对“秃”如其来的脱发问题&#xff0c;今日&#xff0c;支付宝发布“AI毛发自测”工具&#xff0c…

Mixly UDP局域网收发数据

一、开发环境 软件&#xff1a;Mixly 2.0在线版 硬件&#xff1a;ESP32-C3&#xff08;立创实战派&#xff09; 固件&#xff1a;ESP32C3 Generic(UART) 测试工具&#xff1a;NetAssist V5.0.1 二、实现功能 ESP32作为wifi sta连接到路由器&#xff0c;连接成功之后将路由器…