分析思路
本地通过dump activity containers,View树以及window等方式均未找到自由窗口状态栏相关代码,最终通过winscope dumpsys SF找到相关线索。
winscope
通过winscope查看View结构

关键代码
代码路径:frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
java
void relayout(RelayoutParams params, SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT, WindowContainerTransaction wct, T rootView,
RelayoutResult<T> outResult) {
......
// DecorationContainerSurface
if (mDecorationContainerSurface == null) {
final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
mDecorationContainerSurface = builder
.setName("Decor container of Task=" + mTaskInfo.taskId)
.setContainerLayer()
.setParent(mTaskSurface)
.build();
startT.setTrustedOverlay(mDecorationContainerSurface, true)
.setLayer(mDecorationContainerSurface,
TaskConstants.TASK_CHILD_LAYER_WINDOW_DECORATIONS);
}
startT.setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight)
.show(mDecorationContainerSurface);
// CaptionContainerSurface, CaptionWindowManager
if (mCaptionContainerSurface == null) {
final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
mCaptionContainerSurface = builder
.setName("Caption container of Task=" + mTaskInfo.taskId)
.setContainerLayer()
.setParent(mDecorationContainerSurface)
.build();
}
final int captionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
final int captionWidth = taskBounds.width();
startT.setWindowCrop(mCaptionContainerSurface, captionWidth, captionHeight)
.show(mCaptionContainerSurface);
if (ViewRootImpl.CAPTION_ON_SHELL) {
outResult.mRootView.setTaskFocusState(mTaskInfo.isFocused);
// Caption insets
mCaptionInsetsRect.set(taskBounds);
mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight + params.mCaptionY;
wct.addInsetsSource(mTaskInfo.token,
mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect);
} else {
startT.hide(mCaptionContainerSurface);
}
// Task surface itself
float shadowRadius = loadDimension(resources, params.mShadowRadiusId);
int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor();
mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
final Point taskPosition = mTaskInfo.positionInParent;
startT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight)
.setShadowRadius(mTaskSurface, shadowRadius)
.setColor(mTaskSurface, mTmpColor)
.show(mTaskSurface);
finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight);
if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
finishT.setCornerRadius(mTaskSurface, params.mCornerRadius);
}
if (mCaptionWindowManager == null) {
// Put caption under a container surface because ViewRootImpl sets the destination frame
// of windowless window layers and BLASTBufferQueue#update() doesn't support offset.
mCaptionWindowManager = new WindowlessWindowManager(
mTaskInfo.getConfiguration(), mCaptionContainerSurface,
null /* hostInputToken */);
}
Slog.i("WindowDecoration","mViewHost:"+(mViewHost == null ? "null":mViewHost.toString()),new Exception());
// Caption view
mCaptionWindowManager.setConfiguration(taskConfig);
final WindowManager.LayoutParams lp =
new WindowManager.LayoutParams(captionWidth, captionHeight,
WindowManager.LayoutParams.TYPE_APPLICATION,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
lp.setTrustedOverlay();
if (mViewHost == null) {
mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
mCaptionWindowManager);
if (params.mApplyStartTransactionOnDraw) {
mViewHost.getRootSurfaceControl().applyTransactionOnDraw(startT);
}
mViewHost.setView(outResult.mRootView, lp);
} else {
if (params.mApplyStartTransactionOnDraw) {
mViewHost.getRootSurfaceControl().applyTransactionOnDraw(startT);
}
mViewHost.relayout(lp);
}
}
从代码中可以看出"Caption of Task"是一个SurfaceControlViewHost对象,且其在Shell相关代码路径下,说该View是属于SystemUI进程。
如代码中所示,添加log打印堆栈。
堆栈跟踪
这里的流程我们同样以从多任务启动自由窗口为例
java
WindowDecoration: mViewHost:null
WindowDecoration: java.lang.Exception
WindowDecoration: at com.android.wm.shell.windowdecor.WindowDecoration.relayout(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:282)
WindowDecoration: at com.android.wm.shell.windowdecor.CaptionWindowDecoration.relayout(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:120)
WindowDecoration: at com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel.createWindowDecoration(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:196)
WindowDecoration: at com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel.onTaskChanging(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:128)
WindowDecoration: at com.android.wm.shell.freeform.FreeformTaskTransitionObserver.onToFrontTransitionReady(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:147)
WindowDecoration: at com.android.wm.shell.freeform.FreeformTaskTransitionObserver.onTransitionReady(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:104)
WindowDecoration: at com.android.wm.shell.transition.Transitions.dispatchReady(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:707)
WindowDecoration: at com.android.wm.shell.transition.Transitions.onTransitionReady(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:669)
WindowDecoration: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.lambda$onTransitionReady$0(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:1353)
WindowDecoration: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.$r8$lambda$qsRfWn1ItrZqnFeABBdxU50jPc4(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:0)
WindowDecoration: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl$$ExternalSyntheticLambda0.run(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:0)
WindowDecoration: at android.os.Handler.handleCallback(Handler.java:958)
WindowDecoration: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowDecoration: at android.os.Looper.loopOnce(Looper.java:205)
WindowDecoration: at android.os.Looper.loop(Looper.java:294)
WindowDecoration: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowDecoration: mViewHost:android.view.SurfaceControlViewHost@12f4198
WindowDecoration: java.lang.Exception
WindowDecoration: at com.android.wm.shell.windowdecor.WindowDecoration.relayout(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:282)
WindowDecoration: at com.android.wm.shell.windowdecor.CaptionWindowDecoration.relayout(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:120)
WindowDecoration: at com.android.wm.shell.windowdecor.CaptionWindowDecoration.relayout(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:96)
WindowDecoration: at com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel.onTaskInfoChanged(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:108)
WindowDecoration: at com.android.wm.shell.freeform.FreeformTaskListener.onTaskInfoChanged(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:136)
WindowDecoration: at com.android.wm.shell.ShellTaskOrganizer.onTaskInfoChanged(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:527)
WindowDecoration: at android.window.TaskOrganizer$1.lambda$onTaskInfoChanged$6(TaskOrganizer.java:340)
WindowDecoration: at android.window.TaskOrganizer$1.$r8$lambda$FmJPvZyGqAGeVe9o6dSQkNL3f3g(Unknown Source:0)
WindowDecoration: at android.window.TaskOrganizer$1$$ExternalSyntheticLambda3.run(Unknown Source:4)
WindowDecoration: at android.os.Handler.handleCallback(Handler.java:958)
WindowDecoration: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowDecoration: at android.os.Looper.loopOnce(Looper.java:205)
WindowDecoration: at android.os.Looper.loop(Looper.java:294)
WindowDecoration: at android.os.HandlerThread.run(HandlerThread.java:67)
这里我们主要关注mViewHost:null 的这次即可,不为null,则不会进入创建流程。
从堆栈中可以看出这个方法是从TransitionPlayerImpl.onTransitionReady到WindowDecoration.relayout结束
代码路径:frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
java
@BinderThread
private class TransitionPlayerImpl extends ITransitionPlayer.Stub {
@Override
public void onTransitionReady(IBinder iBinder, TransitionInfo transitionInfo,
SurfaceControl.Transaction t, SurfaceControl.Transaction finishT)
throws RemoteException {
mMainExecutor.execute(() -> Transitions.this.onTransitionReady(
iBinder, transitionInfo, t, finishT));
}
......
}
这里是通过ITransitionPlayer跨进程通信,找到了mTransitionPlayer,在TransitionController中(system_server侧)

搜索其调用 mTransitionPlayer.onTransitionReady(

发现什么都没有,找下mTransitionPlayer相关的get方法
代码路径:frameworks/base/services/core/java/com/android/server/wm/TransitionController.java
java
@Nullable ITransitionPlayer getTransitionPlayer() {
return mTransitionPlayer;
}
再次通过getTransitionPlayer().onTransitionReady查找相应调用
最终我们得出TransitionPlayerImpl.onTransitionReady是通过system_server侧Transition.onTransactionReady中mController.getTransitionPlayer().onTransitionReady而来。

可在此处添加堆栈查看system_server侧调用逻辑。
java
Transition: getTransitionPlayer().onTransitionReady
Transition: java.lang.Exception
Transition: at com.android.server.wm.Transition.onTransactionReady(Transition.java:1575)
Transition: at com.android.server.wm.BLASTSyncEngine$SyncGroup.finishNow(BLASTSyncEngine.java:263)
Transition: at com.android.server.wm.BLASTSyncEngine$SyncGroup.tryFinish(BLASTSyncEngine.java:202)
Transition: at com.android.server.wm.BLASTSyncEngine$SyncGroup.-$$Nest$mtryFinish(BLASTSyncEngine.java:0)
Transition: at com.android.server.wm.BLASTSyncEngine.onSurfacePlacement(BLASTSyncEngine.java:552)
Transition: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:810)
Transition: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:756)
Transition: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
Transition: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
Transition: at com.android.server.wm.WindowManagerService.relayoutWindow(WindowManagerService.java:2410)
Transition: at com.android.server.wm.Session.relayout(Session.java:249)
Transition: at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:701)
Transition: at com.android.server.wm.Session.onTransact(Session.java:178)
Transition: at android.os.Binder.execTransactInternal(Binder.java:1344)
Transition: at android.os.Binder.execTransact(Binder.java:1275)
这里走了窗口绘制流程,也就是说Caption view的创建是应用onresume流程之后开始的。
Layout Inspector
在android studio中选择tools->Legacy Layout Inspector,找到systemUI进程

其中可以找到对应的caption

选中后我们可以看到其结构

这个里面我们可以看到这些控件的id。
综上所述,android14中,CaptionWindow是systemUI上单独的进程不在应用本身上。