android 13 WMS/AMS系统开发-WindowManagerService相关relayout操作

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) {
   //ignore
   //根据client找到对应的WindowState 
            final WindowState win = windowForClientLocked(session, client, false);
           //ignore

            // Create surfaceControl before surface placement otherwise layout will be skipped
            // (because WS.isGoneForLayout() is true when there is no surface.
            if (shouldRelayout) {
                try {
                    //创建对应的window需要的SurfaceControl,传递回应用,应用用他进行绘制
                    result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
                } catch (Exception e) {
                  //ignore
                }
            }
			//调用最核心的performSurfacePlacement进行相关的layout操作
            // 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 */);
			//ignore
                
            if (!win.isGoneForLayout()) {
                win.mResizedWhileGone = false;
            }
 			//把相关config数据填回去
            win.fillClientWindowFramesAndConfiguration(outFrames, mergedConfiguration,
                    false /* useLatestConfig */, shouldRelayout);
            //把相关inset数据设置回去
            outInsetsState.set(win.getCompatInsetsState(), win.isClientLocal());
           //ignore
            getInsetsSourceControls(win, outActiveControls);
        }

        Binder.restoreCallingIdentity(origId);
        return result;
    }

主要就有2个最关键步骤:
1、创建对应Window的SurfaceControl
2、计算出对应的window区域等,把inset和config传递回去
更多内容qqun:422901085 https://ke.qq.com/course/5992266#term_id=106217431

1、创建对应Window的SurfaceControl,这个之前图层结构树部分有讲解

调用是createSurfaceControl:

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");
            surfaceController = winAnimator.createSurfaceLocked();
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        if (surfaceController != null) {
            surfaceController.getSurfaceControl(outSurfaceControl);
            ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);

        } else {
            // For some reason there isn't a surface.  Clear the
            // caller's object so they see the same state.
            ProtoLog.w(WM_ERROR, "Failed to create surface control for %s", win);
            outSurfaceControl.release();
        }

        return result;
    }

这里首先又调用到了winAnimator.createSurfaceLocked();

 WindowSurfaceController createSurfaceLocked() {
//ignore
  mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), format,
                    flags, this, attrs.type);
//ignore
}

调用到了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");//此时其实还是属于Container,因为DisplayerContent创建

        final boolean useBLAST = mService.mUseBLAST && ((win.getAttrs().privateFlags
                & WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST) != 0);

        if (useBLAST) {
            b.setBLASTLayer();//非常关键,变成非Container
        }

        mSurfaceControl = b.build();

        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }

2、计算出对应的window区域等,把inset和config传递回去

这个部分最关键方法就是 mWindowPlacerLocked.performSurfacePlacement(true /* force */);
下面来对他进行详细分析:

 final void performSurfacePlacement(boolean force) {
119          if (mDeferDepth > 0 && !force) {
120              mDeferredRequests++;
121              return;
122          }
123          int loopCount = 6;
124          do {
125              mTraversalScheduled = false;
126              performSurfacePlacementLoop();//调用performSurfacePlacementLoop
127              mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
128              loopCount--;
129          } while (mTraversalScheduled && loopCount > 0);
130          mService.mRoot.mWallpaperActionPending = false;
131      }

performSurfacePlacementLoop

private void performSurfacePlacementLoop() {
//ignore
          mService.mRoot.performSurfacePlacement();

//ignore
}

这里会调用到RootWindowContainer的performSurfacePlacement

 void performSurfacePlacement() {
782          Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
783          try {
784              performSurfacePlacementNoTrace();
785          } finally {
786              Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
787          }
788      }

接下来又到performSurfacePlacementNoTrace,接下来又会调用到最关键的applySurfaceChangesTransaction方法:

 private void applySurfaceChangesTransaction() {
       //ignore

        final int count = mChildren.size();
        for (int j = 0; j < count; ++j) {
            final DisplayContent dc = mChildren.get(j);
            dc.applySurfaceChangesTransaction();
        }

        // Give the display manager a chance to adjust properties like display rotation if it needs
        // to.
        mWmService.mDisplayManagerInternal.performTraversal(mDisplayTransaction);
        SurfaceControl.mergeToGlobalTransaction(mDisplayTransaction);
    }

这里又会调用到DisplayContent 的applySurfaceChangesTransaction

void applySurfaceChangesTransaction() {
       //执行布局相关
        // Perform a layout, if needed.
        performLayout(true /* initial */, false /* updateInputWindows */);
        pendingLayoutChanges = 0;

       //判断布局策略
            mDisplayPolicy.beginPostLayoutPolicyLw();
            forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
      
		//
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyWindowSurfaceChanges");
        try {
        //挨个迭代每个窗口执行mApplySurfaceChangesTransaction
            forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
         //做绘制前最后一些处理
        prepareSurfaces();

       //ignore
    }

这里我们这次重点是performLayout,其他后面几篇blog再讲解

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

        if (DEBUG_LAYOUT) {
            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).
        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.
        forAllWindows(mPerformLayoutAttached, true /* traverseTopToBottom */);

        // Window frames may have changed. Tell the input dispatcher about it.
        mInputMonitor.setUpdateInputWindowsNeededLw();
        if (updateInputWindows) {
            mInputMonitor.updateInputWindowsLw(false /*force*/);
        }
    }

最后也是循环遍历层级结构树的每个windowstate进行mPerformLayout的执行

private final Consumer<WindowState> mPerformLayout = w -> {
         //ignore
            getDisplayPolicy().layoutWindowLw(w, null, mDisplayFrames);
   //ignore
    };

调用是DisplayPolicy.java的layoutWindowLw

 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
        //ignore
        mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
                win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
                win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale,
                sTmpClientFrames);

        win.setFrames(sTmpClientFrames, win.mRequestedWidth, win.mRequestedHeight);
    }

这里调用是WindowLayout.computeFrames
具体computeFrames的计算代码较长,主要就是会根据系统的inset情况来决定,比如statusbar,和navigationbar等,然后给app一个合适的frame

### 解决Spring Boot API 401 Unauthorized 认证失败 当遇到`/api/wms/receiptOrder/add-or-update`接口返回401未授权错误时,通常意味着客户端未能提供有效的身份验证凭证或权限不足。为了排查并解决问题,可以从以下几个方面入手: #### 配置安全设置 确保应用程序的安全配置正确无误。如果使用的是基于角色的访问控制(RBAC),则需确认当前用户具有执行此操作所需的适当角色。 对于Spring Security,默认情况下会保护所有端点,并要求通过HTTP Basic Auth或其他方式验证每个传入请求的身份。可以通过自定义SecurityConfig类来调整这些默认行为[^1]。 ```java @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/api/**").authenticated() // 确保API路径受保护 .anyRequest().permitAll(); // 添加其他必要的配置... } } ``` #### 检查认证头 发送到服务器的每一个RESTful调用都应携带正确的认证信息。这通常是通过在HTTP头部中加入Authorization字段完成的。例如,在Postman工具里测试API时,应该指定Bearer Token作为认证机制的一部分[^2]。 ```bash curl -X POST https://example.com/api/wms/receiptOrder/add-or-update \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE" \ -d '{"key":"value"}' ``` #### 日志记录与调试 启用详细的日志可以帮助诊断具体原因。可以在application.properties文件中增加如下属性以便获取更多关于认证过程的信息[^3]: ```properties logging.level.org.springframework.security=DEBUG ``` 这样可以查看完整的握手流程以及任何潜在异常堆栈跟踪,从而更容易定位问题所在。 #### 测试Token有效性 最后一步是验证所使用的OAuth令牌是否仍然有效且尚未过期。尝试刷新token或者重新登录以获得新的access token后再试一次请求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值