Android14 WMS-窗口绘制之relayoutWindow流程(二)-Server端
本文接着如下文章往下讲
Android14 WMS-窗口绘制之relayoutWindow流程(一)-Client端-CSDN博客
然后就到了Server端WMS的核心实现方法relayoutWindow里
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的可见性
mViewVisibility | Vlaue | 含义 |
---|---|---|
VISIBLE | 0x00000000 | 这个视图可见 与#setVisibility和#attr_android:visibility" android:visibility}一起使用。 |
INVISIBLE | 0x00000004 | 这个视图不可见 与#setVisibility和#attr_android:visibility" android:visibility}一起使用。 |
GONE | 0x00000008 | 这个视图是不可见的,它不占用任何空间进行布局 与#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中的核心方法
下面这些流程的流程图如上
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>();
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
相关文章:

Android14 WMS-窗口绘制之relayoutWindow流程(二)-Server端
本文接着如下文章往下讲 Android14 WMS-窗口绘制之relayoutWindow流程(一)-Client端-CSDN博客 然后就到了Server端WMS的核心实现方法relayoutWindow里 WindowManagerService.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server…...
安全测试 之 安全漏洞:SQL注入
1. 背景 持续学习安全测试ing,安全测试是在IT软件产品的生命周期中,特别是产品开发基本完成到发布阶段,对产品进行检验以验证产品是否符合安全需求定义和产品质量标准的过程。也就是说安全测试是建立在功能测试的基础上进行的测试。 2. SQL…...
CUDA和驱动版本之间的对应关系
这个之前总结过,可是不太好找,专门写一篇博客再总结一下: 1. CUDA 12.5 Release Notes — Release Notes 12.5 documentation 相信很多朋友有一样的需求。...
MDK(μVsion3)问题总结及解决方法
问题 1:MDK 工具的 CARM 编译器? 我原来对 CARM 编译器比较熟悉,想用 CARM 编译器编译工程,但是却弹出一个不能执 行“cc”的错误,到 KEIL 网站查下才知道原因:由于 CARM 编译器是比较老的编译器࿰…...

手眼标定学习笔记
目录 标定代码: 手眼标定原理学习 什么是手眼标定 手眼标定的目的 eye in hand eye to hand AXXB问题的求解 标定代码: GitHub - pumpkin-ws/HandEyeCalib 推荐博文: https://zhuanlan.zhihu.com/p/486592374 手眼标定原理学习 参…...

Dell戴尔XPS 16 9640 Intel酷睿Ultra9处理器笔记本电脑原装出厂Windows11系统包,恢复原厂开箱状态oem预装系统
下载链接:https://pan.baidu.com/s/1j_sc8FW5x-ZreNrqvRhjmg?pwd5gk6 提取码:5gk6 戴尔原装系统自带网卡、显卡、声卡、蓝牙等所有硬件驱动、出厂主题壁纸、系统属性专属联机支持标志、系统属性专属LOGO标志、Office办公软件、MyDell、迈克菲等预装软…...

【第8章】SpringBoot实战篇之文章分类(上)
文章目录 前言一、后端代码1. CategoryController2. service3. CategoryMapper4. Category 二、测试1. 失败(校验)2.正常 总结 前言 从这开始进入文章相关的接口开发,本章主要介绍定义文章分类接口和新增文章分类 建表语句和测试用例,在SpringBoot专栏首…...
【QT】Qt Plugin开发
目录 插件是什么QT插件是什么 为什么要有插件开发插件开发优势插件和动态库区别 Qt PluginQT插件类型QT插件开发流程QT插件应用QT插件JSON文件 参考文章 插件是什么 插件(Plug-in,又称addin、add-in、addon或add-on,又译外挂)是一种遵循一定规范的应用程序接口编写出来的程序。…...
快速了解GPU分布通信技术:PCIe、NVLink与NVSwitch
在现代高性能计算和深度学习领域,GPU的强大计算能力使其成为不可或缺的工具。然而,随着模型复杂度的增加,单个GPU已经无法满足需求,需要多个GPU甚至多台服务器协同工作。这就要求高效的GPU互联通信技术,以确保数据传输…...

Python对获取数据的举例说明
当使用Python来获取数据时,有许多不同的方法和库可以根据你的需求来选择。以下是一些常见的示例,说明如何使用Python来从各种来源获取数据。 1. 从网站或API获取JSON数据 你可以使用requests库从网站或API获取JSON格式的数据。例如,从某个API…...

JVMの垃圾回收
在上一篇中,介绍了JVM组件中的运行时数据区域,这一篇主要介绍垃圾回收器 JVM架构图: 1、垃圾回收概述 在第一篇中介绍JVM特点时,有提到过内存管理,即Java语言相对于C,C进行的优化,可以在适当的…...
人工智能就业方向有哪些?
人工智能就业方向有哪些? 随着人工智能技术的不断发展,其应用领域也越来越广泛。对于想要进入人工智能领域的年轻人来说,选择一个合适的职业方向是至关重要的。今天给大家介绍六个热门的人工智能就业方向,分别是机器学习工程师、自然语言处理…...

自定义类型:枚举和联合体
在之前我们已经深入学习了自定义类型中的结构体类型 ,了解了结构体当中的内存对齐,位段等知识,接下来在本篇中将继续学习剩下的两个自定义类型:枚举类型与联合体类型,一起加油!! 1.枚举类型 …...
负载均衡加权轮询算法
随机数加权轮询算法 public int select() {int[] weights {10, 20, 50};int totalWeight weights[0] weights[1] weights[2];// 取随机数int offset ThreadLocalRandom.current().nextInt(totalWeight);for (int i 0; i < weights.length; i) {offset - weights[i];i…...

PyTorch 相关知识介绍
一、PyTorch和TensorFlow 1、PyTorch PyTorch是由Facebook开发的开源深度学习框架,它在动态图和易用性方面表现出色。它以Python为基础,并提供了丰富的工具和接口,使得构建和训练神经网络变得简单快捷。 发展历史和背景 PyTorch 是由 Fac…...

1千2初中英语语法题库ACCESS\EXCEL数据库
英语语法是针对英语语言进行研究后,系统地总结归纳出来的一系列语言规则。英语语法的精髓在于掌握语言的使用。比如词类有名词、代词、数词、感叹词等,时态有一般状态、进行状态、完成状态和完成进行状态四种,语态有主动语态、被动语态等。 …...

高德面试:为什么Map不能插入null?
在 Java 中,Map 是属于 java.util 包下的一个接口(interface),所以说“为什么 Map 不能插入 null?”这个问题本身问的不严谨。Map 部分类关系图如下: 所以,这里面试官其实想问的是:为…...
MySQL数据库主从配置
MySQL主从配置 1. 修改数据库my.cnf文件 修改数据库my.cnf文件,在文件中添加如下内容,其中主数据库的server-id必须要比从库的更小。 # 注册集群id server-id101 # 开启二进制日志文件 log-binmysql-bin # 设置日志格式 binlog-formatrow # 开启中继日…...
测试工程师经常使用的Python中的库,以及对应常用的函数
os (操作系统接口) 该库提供了许多与操作系统交互的函数,如文件处理、目录操作、进程管理等。 常用功能包括: os.name: 获取操作系统的名称。 os.path: 用于操作文件路径的模块,如os.path.join拼接路径。 os.mkdir: 创建目录。 os.remove: 删…...

【frp】服务端配置与systemd启动
ini配置的方式已经废弃。官方文档是toml 。阿里云ecs 部署服务端参考大神的文章 使用Frp配置内网访问(穿透) 0.54 版本 我现在用最新的0.58版本。systemd apt install systemdfrp服务端配置 /root/frp目录 vim frps.toml#服务绑定的IP与端口 bindAddr = "0.0.0.0" …...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
JavaScript 标签加载
目录 JavaScript 标签加载script 标签的 async 和 defer 属性,分别代表什么,有什么区别1. 普通 script 标签2. async 属性3. defer 属性4. type"module"5. 各种加载方式的对比6. 使用建议 JavaScript 标签加载 script 标签的 async 和 defer …...
「Java基本语法」变量的使用
变量定义 变量是程序中存储数据的容器,用于保存可变的数据值。在Java中,变量必须先声明后使用,声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例:声明与初始化 public class VariableDemo {publi…...

OPENCV图形计算面积、弧长API讲解(1)
一.OPENCV图形面积、弧长计算的API介绍 之前我们已经把图形轮廓的检测、画框等功能讲解了一遍。那今天我们主要结合轮廓检测的API去计算图形的面积,这些面积可以是矩形、圆形等等。图形面积计算和弧长计算常用于车辆识别、桥梁识别等重要功能,常用的API…...
linux设备重启后时间与网络时间不同步怎么解决?
linux设备重启后时间与网络时间不同步怎么解决? 设备只要一重启,时间又错了/偏了,明明刚刚对时还是对的! 这在物联网、嵌入式开发环境特别常见,尤其是开发板、树莓派、rk3588 这类设备。 解决方法: 加硬件…...