文章目录
应用窗口挂载流程
应用启动流程中会触发ActivityRecord,Task,WindowState的创建与挂载,其中WindowState的处理上在addWindow流程。
ActivityRecord的创建
启动流程开始的时候会执行到ActivityStarter::executeRequest,在这个方法里会创建一个ActivityRecord。
# ActivityStarter
private int executeRequest(Request request) {
......
final ActivityRecord r = new ActivityRecord.Builder(mService)
.setCaller(callerApp)
.setLaunchedFromPid(callingPid)
.setLaunchedFromUid(callingUid)
.setLaunchedFromPackage(callingPackage)
.setLaunchedFromFeature(callingFeatureId)
.setIntent(intent)
.setResolvedType(resolvedType)
.setActivityInfo(aInfo)
.setConfiguration(mService.getGlobalConfiguration())
.setResultTo(resultRecord)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setComponentSpecified(request.componentSpecified)
.setRootVoiceInteraction(voiceSession != null)
.setActivityOptions(checkedOptions)
.setSourceRecord(sourceRecord)
.build();
......
// 继续执行startActivityUnchecked
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
inTask, inTaskFragment, restrictedBgActivity, intentGrants);
......
}
tips:ActivityRecord的构造方法会创建一个Token,这个token就是阅读源码经常看到看到代表activity的那个token。
Task的创建与挂载
流程开始会执行到ActivityStarter::startActivityInner方法,在这里会执行ActivityStarter::getOrCreateRootTask方法来创建(获取)一个Task
调用链如下:
# ActivityStarter
private Task getOrCreateRootTask(ActivityRecord r, int launchFlags, Task task,
ActivityOptions aOptions) {
final boolean onTop =
(aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
final Task sourceTask = mSourceRecord != null ? mSourceRecord.getTask() : null;
return mRootWindowContainer.getOrCreateRootTask(r, aOptions, task, sourceTask, onTop,
mLaunchParams, launchFlags);
}
// onTop 表示是否要移到到当前栈顶,那肯定是要的,新启动的Activity当前要再最上面,这里 aOptions 为null,所以为true
// sourceTask 表示从哪里启动的,当前launch所在的Task 就是sourceTask
# RootWindowContainer
Task getOrCreateRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@Nullable Task candidateTask, boolean onTop) {
return getOrCreateRootTask(r, options, candidateTask, null /* sourceTask */, onTop,
null /* launchParams */, 0 /* launchFlags */);
}
Task getOrCreateRootTask(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable Task candidateTask,
@Nullable Task sourceTask, boolean onTop,
@Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags) {
......
final int activityType = resolveActivityType(r, options, candidateTask);
if (taskDisplayArea != null) {
if (canLaunchOnDisplay(r, taskDisplayArea.getDisplayId())) {
// 重点*1. 传递到TaskDisplayArea
return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
sourceTask, launchParams, launchFlags, activityType, onTop);
} else {
taskDisplayArea = null;
}
}
......
}
// 经过同名调用后,逻辑进入到 TaskDisplayArea
# TaskDisplayArea
Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,
@Nullable Task candidateTask, @Nullable Task sourceTask,
@Nullable ActivityOptions options, int launchFlags) {
if(....) {
// 拿到之前创建的Task
return candidateTask.getRootTask();
}
......// 第一次显示所以是新建Task
return new Task.Builder(mAtmService)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
.setOnTop(onTop)
.setParent(this) // 主要这个this被设置为Parent。所以直接挂载到了DefaultTaskDisplayArea下
.setSourceTask(sourceTask)
.setActivityOptions(options)
.setLaunchFlags(launchFlags)
.build();
}
// 看方法名是获取或创建Task, 这边是新启动的Activity所以需要创建Task。如果是以默认启动方式打开应用内的另一个Activity,就走的是上面的 return candidateTask.getRootTask();
接下来就是真正触发Task的创建。
// 另外设置的parent就是层级结构树应用所在的名为“DefaultTaskDisplayArea”的TaskDisplayArea
# Task
# Task.Builder
Task build() {
if (mParent != null && mParent instanceof TaskDisplayArea) {
validateRootTask((TaskDisplayArea) mParent);
}
if (mActivityInfo == null) {
mActivityInfo = new ActivityInfo();
mActivityInfo.applicationInfo = new ApplicationInfo();
}
mUserId = UserHandle.getUserId(mActivityInfo.applicationInfo.uid);
mTaskAffiliation = mTaskId;
mLastTimeMoved = System.currentTimeMillis();
mNeverRelinquishIdentity = true;
mCallingUid = mActivityInfo.applicationInfo.uid;
mCallingPackage = mActivityInfo.packageName;
mResizeMode = mActivityInfo.resizeMode;
mSupportsPictureInPicture = mActivityInfo.supportsPictureInPicture();
if (mActivityOptions != null) {
mRemoveWithTaskOrganizer = mActivityOptions.getRemoveWithTaskOranizer();
}
// 重点* 1. 创建task
final Task task = buildInner();
task.mHasBeenVisible = mHasBeenVisible;
// Set activity type before adding the root task to TaskDisplayArea, so home task can
// be cached, see TaskDisplayArea#addRootTaskReferenceIfNeeded().
if (mActivityType != ACTIVITY_TYPE_UNDEFINED) {
task.setActivityType(mActivityType);
}
// 重点* 2. 入栈 这里的 mOnTop为true
if (mParent != null) {
if (mParent instanceof Task) {
final Task parentTask = (Task) mParent;
parentTask.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM,
(mActivityInfo.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
} else {
mParent.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM);
}
}
// Set windowing mode after attached to display area or it abort silently.
if (mWindowingMode != WINDOWING_MODE_UNDEFINED) {
task.setWindowingMode(mWindowingMode, true /* creating */);
}
// 返回
return task;
}
// 创建
Task buildInner() {
return new Task(mAtmService, mTaskId, mIntent, mAffinityIntent, mAffinity,
mRootAffinity, mRealActivity, mOrigActivity, mRootWasReset, mAutoRemoveRecents,
mAskedCompatMode, mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved,
mNeverRelinquishIdentity, mLastTaskDescription, mLastSnapshotData,
mTaskAffiliation, mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid,
mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight,
mActivityInfo, mVoiceSession, mVoiceInteractor, mCreatedByOrganizer,
mLaunchCookie, mDeferTaskAppear, mRemoveWithTaskOrganizer);
}
小结:
最后描述一下最后创建的2个重点部分:
看到通过buildInner 创建了一个task,而buildInner 也很简单粗暴,通过各个变量直接new Task 对象。
mParent 不为null, 是 因为在创建的时候 setParent(this),当前的这个this,就是 getDefaultTaskDisplayArea返回的也就是应用Activity存在的"DefaultTaskDisplayArea"。
ActivityRecord的挂载
调用链:
ActivityStarer::setNewTask ActivityStarer::addOrReparentStartingActivity
# ActivityStarer
private void setNewTask(Task taskToAffiliate) {
// 为true
final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
// 就是mTargetRootTask,也就是刚刚创建的Task
final Task task = mTargetRootTask.reuseOrCreateTask(
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
task.mTransitionController.collectExistenceChange(task);
// ActivityRecord的挂载
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask");
// 需要注意这里的日志打印
ProtoLog.v(WM_DEBUG_TASKS, "Starting new activity %s in new task %s",
mStartActivity, mStartActivity.getTask());
// mLaunchTaskBehind 为false,所以taskToAffiliate 为null
if (taskToAffiliate != null) {
mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
}
}
这里的task 和mTargetRootTask是同一个对象, 进源码跟到流程也是一样。 然后进入 addOrReparentStartingActivity
# ActivityStarer
private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
// newParent = task 都是刚刚创建的Task
TaskFragment newParent = task;
......
if (mStartActivity.getTaskFragment() == null
|| mStartActivity.getTaskFragment() == newParent) {
// 重点, 将 ActivityRecord挂在到新创建的Task中,并且是顶部
newParent.addChild(mStartActivity, POSITION_TOP);
} else {
mStartActivity.reparent(newParent, newParent.getChildCount() /* top */, reason);
}
}
WindowState的创建与挂载
WindowManagerService::addWindow WindowState::init – WindowState的创建 WindowToken::addWindow – WindowState的挂载
# WindowManagerService
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, int requestUserId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
......// token处理
// 创建WindowState
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
......
// 7. 窗口添加进容器
win.attach();
......
win.mToken.addWindow(win);
......
}
"win.mToken"窗口的token是ActyivityRecord
# ActivityRecord
@Override
void addWindow(WindowState w) {
super.addWindow(w);
......
}
直接调用其父类方法,ActivityRecord是WindowToken
# WindowToken
void addWindow(final WindowState win) {
ProtoLog.d(WM_DEBUG_FOCUS,
"addWindow: win=%s Callers=%s", win, Debug.getCallers(5));
if (win.isChildWindow()) {
// Child windows are added to their parent windows.
return;
}
// This token is created from WindowContext and the client requests to addView now, create a
// surface for this token.
// 真正添加进子容器,调用的是WindowContainer的方法
if (!mChildren.contains(win)) {
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", win, this);
// 定义在WindowContainer中,其实就是挂载到父容器下了
addChild(win, mWindowComparator);
mWmService.mWindowsChanged = true;
// TODO: Should we also be setting layout needed here and other places?
}
}
系统窗口的挂载
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, int requestUserId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
......
// 系统应用获取不到token
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
......
if (token == null) {
......
} else {
final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
token = new WindowToken.Builder(this, binder, type)
.setDisplayContent(displayContent)
.setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
.setRoundedCornerOverlay(isRoundedCornerOverlay)
.build();
}
}
// 创建WindowState
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
......
// 窗口添加进容器
win.attach();
......
win.mToken.addWindow(win);
......
WindowState的创建和应用窗口一样,区别在与WindowToken,系统窗口执行addWindow方法是没有token的,所以会执行创建逻辑。 在创建的时候会根据窗口类型选择挂载的层级。
WindowToken的挂载
WindowToken的构造方法如下:
# WindowToken
protected WindowToken(WindowManagerService service, IBinder _token, int type,
boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens,
boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
super(service);
token = _token;
windowType = type;
......
if (dc != null) {
// 添加token
dc.addWindowToken(token, this);
}
}
创建WindowToken的时候会由DisplayContent执行挂载逻辑,
# DisplayContent
DisplayAreaPolicy mDisplayAreaPolicy;
void addWindowToken(IBinder binder, WindowToken token) {
......
// 放入集合
mTokenMap.put(binder, token);
if (token.asActivityRecord() == null) {
......
// 找到对应的位置挂载
final DisplayArea.Tokens da = findAreaForToken(token).asTokens();
da.addChild(token);
}
}
DisplayArea findAreaForToken(WindowToken windowToken) {
// 根据type查找
return findAreaForWindowType(windowToken.getWindowType(), windowToken.mOptions,
windowToken.mOwnerCanManageAppTokens, windowToken.mRoundedCornerOverlay);
}
DisplayArea findAreaForWindowType(int windowType, Bundle options,
boolean ownerCanManageAppToken, boolean roundedCornerOverlay) {
// 应用类型
if (windowType >= FIRST_APPLICATION_WINDOW && windowType <= LAST_APPLICATION_WINDOW) {
return mDisplayAreaPolicy.getTaskDisplayArea(options);
}
// 输入法窗口
if (windowType == TYPE_INPUT_METHOD || windowType == TYPE_INPUT_METHOD_DIALOG) {
return getImeContainer();
}
// 其他类型
return mDisplayAreaPolicy.findAreaForWindowType(windowType, options,
ownerCanManageAppToken, roundedCornerOverlay);
}
状态栏不属于应用窗口,走后面的逻辑,DisplayAreaPolicy是个接口,真正的实现是DisplayAreaPolicyBuilder的内部类Result
# DisplayAreaPolicyBuilder
static class Result extends DisplayAreaPolicy {
final BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
......
@Override
public DisplayArea.Tokens findAreaForWindowType(int type, Bundle options,
boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
return mSelectRootForWindowFunc.apply(type, options).findAreaForWindowTypeInLayer(type,
ownerCanManageAppTokens, roundedCornerOverlay);
}
......
}
mSelectRootForWindowFunc是一个存放RootDisplayArea的map,所以后续逻辑在RootDisplayArea中
// 根据type 找到在容器树的位置, 如果是应用或者输入法都走不到这
# RootDisplayArea
// 这个就是层级树的
private DisplayArea.Tokens[] mAreaForLayer;
@Nullable
DisplayArea.Tokens findAreaForWindowTypeInLayer(int windowType, boolean ownerCanManageAppTokens,
boolean roundedCornerOverlay) {
// 获取到type
int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType,
ownerCanManageAppTokens, roundedCornerOverlay);
if (windowLayerFromType == APPLICATION_LAYER) {
throw new IllegalArgumentException(
"There shouldn't be WindowToken on APPLICATION_LAYER");
}
// 根据type查找对应的位置
return mAreaForLayer[windowLayerFromType];
}
getWindowLayerFromTypeLw会根据type找到对应的层级,返回一个int。
然后根据这个值去mAreaForLayer拿到对应的DisplayArea.Tokens,将系统窗口的WindowToken挂载进去
mAreaForLayer其实就是开始构建层级树的那个集合。
mAreaForLayer的赋值
在开机构建窗口层级树的逻辑,最后会执行到RootDisplayArea::onHierarchyBuilt将层级树的集合传递出去。
# DisplayAreaPolicyBuilder.HierarchyBuilder
private final RootDisplayArea mRoot;
private void build(@Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {
......// 层级树的构建
// 通知根节点已经完成了所有DisplayArea的添加 (将displayAreaForLayer保存在RootDisplayArea成员变量roomAreaForLayer中,供后面逻辑使用)
mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);
}
RootDisplayArea下的mAreaForLayer变量赋值
# RootDisplayArea
private DisplayArea.Tokens[] mAreaForLayer;
void onHierarchyBuilt(ArrayList<Feature> features, DisplayArea.Tokens[] areaForLayer,
Map<Feature, List<DisplayArea<WindowContainer>>> featureToDisplayAreas) {
if (mHasBuiltHierarchy) {
throw new IllegalStateException("Root should only build the hierarchy once");
}
mHasBuiltHierarchy = true;
mFeatures = Collections.unmodifiableList(features);
// 赋值
mAreaForLayer = areaForLayer;
mFeatureToDisplayAreas = featureToDisplayAreas;
}
所以mAreaForLayer保存了层级树各个层级的对象因此根据index可以获取到对应的DisplayArea.Tokens,并执行系统窗口WindowToken的挂载。
SurfaceLayer树
安卓真正控制显示的是在SurfaceFlinger层,SurfaceFlinger层也有这么一个窗口树,严格来说是SurfaceFlinger也有一个对应的Layer树。
背景知识
- 触发创建Surface时就会触发创建出一个Layer,所以Surface和Layer是一一对应的,只不过在framework层侧重Surface,在SurfaceFlinger侧重Layer,即surface和layer是显示载体对象在framework层和surfaceflinger层不同的名字而已。
- 应用层只要有Surface,就可以将View的数据绘制保存到Surface中,也就可以显示到屏幕上
- Layer有多种类型,最常见的是“容器类型”(ContainerLayer)和“buff类型”(BufferLayer),只有“buff类型”的Layer才能保存UI数据。
容器类型的创建
前面介绍窗口树的时候,知道那些类其实都是“容器”,作为容器他们本身是没有UI数据的,真正有显示数据的就是 “isBuffLayer= true”的这层Layer。
SurfaceFlinger没有这么复杂构建Layer树的逻辑,因为只要Framework创建一个“容器”类的同时也触发创建一个Surface,这样SurfaceFlinger层就也能同步构造出一个Layer(Surface)树。
DisplayContent的Surface构建
首先看一下 屏幕(DisplayContent)对应的Surface是怎么创建的。
在构建流程开始的时候就为 DisplayContent的创建了Surface,代码如下:
# DisplayContent
private void configureSurfaces(Transaction transaction) {
// 构建一个SurfaceControl
final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession)
.setOpaque(true)
.setContainerLayer() // 设置为容器类型的Layer
.setCallsite("DisplayContent");
// 设置名字后构建 (Display 0 name="XXX")
mSurfaceControl = b.setName(getName()).setContainerLayer().build();
// 设置策略并构建显示区域层次结构
if (mDisplayAreaPolicy == null) {
// WMS的getDisplayAreaPolicyProvider方法按返回 DisplayAreaPolicy.Provider
// 然后其 instantiate的实现 目前只有DisplayAreaPolicy的内部类DefaultProvider
mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
mWmService, this /* content */, this /* root */,
mImeWindowsContainer);
}
......
}
在构建窗口树源码分析的时候知道DisplayContent::configureSurfaces 是在 DisplayContent构造方法里执行的,也就是说在构建窗口树的时候,创建了DisplayContent容器的同时,也创建好了对应的Surface,这是第一个映射关系。
注意build的时候 setContainerLayer这个设置, 将其设置为容器类型的Layer
其他容器Surface的创建与挂载
层级树其他的各个容器创建的也会触发创建出对应的一个Surface,具体的调用链如下:
WindowContainer::addChild
WindowContainer::setParent
WindowState::onParentChanged
WindowContainer::createSurfaceControl
WindowContainer::setInitialSurfaceControlProperties
SurfaceControl.Builder::build
SurfaceControl::init
调用链从WindowContainer::addChild 开始是因为每个容器类创建的时候,都会挂载到父节点下,挂载的方式也就是执行WindowContainer::addChild方法,添加到父容器的孩子集合下。
以一个应用的Task容器创建挂载为例:
假设其他窗口树已经构建好(也已经有了一个对应的Layer树,暂时不知道是怎么来的没关系,稍后就明白了),这个时候应用启动了,肯定是需要创建一个Task,Task创建好后是还是一个单独的容器,这个时候会执行 WindowContainer::addChild 和 WindowContainer::setParent方法,执行完后Task就挂着到窗口树上了。
# WindowContainer
// 当前容器的孩子容器集合
protected final WindowList<E> mChildren = new WindowList<E>();
@CallSuper
protected void addChild(E child, Comparator<E> comparator) {
......
// 1. 添加到集合中,也就是挂载
if (positionToAdd == -1) {
mChildren.add(child);
} else {
mChildren.add(positionToAdd, child);
}
// Set the parent after we've actually added a child in case a subclass depends on this.
// 2. 调用孩子容器设置父节点的方法
child.setParent(this);
}
首先将子容器添加到 mChildren 集合中,然后调用子容器的 setParent 方法。 这么2步执行后, 孩子与父容器就有绑定关系了,也就是成功挂载到了父节点执行。(细品,其实就是java集合操作) 先看一下这2个方法的代码:
# WindowContainer
// 当前容器的孩子容器集合
protected final WindowList<E> mChildren = new WindowList<E>();
@CallSuper
protected void addChild(E child, Comparator<E> comparator) {
......
// 1. 添加到集合中,也就是挂载
if (positionToAdd == -1) {
mChildren.add(child);
} else {
mChildren.add(positionToAdd, child);
}
// Set the parent after we've actually added a child in case a subclass depends on this.
// 2. 调用孩子容器设置父节点的方法
child.setParent(this);
}
首先将子容器添加到 mChildren 集合中,然后调用子容器的 setParent 方法。 这么2步执行后, 孩子与父容器就有绑定关系了,也就是成功挂载到了父节点执行。(细品,其实就是java集合操作)
setParent 方法具体代码如下:
# WindowContainer
// 父节点
private WindowContainer<WindowContainer> mParent = null;
final protected void setParent(WindowContainer<WindowContainer> parent) {
if (parent == null) {
Slog.d(TAG, "setParent old=" + mParent + ",new=" + parent + ",this window=" +
this + ",callers=" + Debug.getCallers(6));
}
final WindowContainer oldParent = mParent;
mParent = parent;
......
onParentChanged(mParent, oldParent);
......
}
现在 Task 就成功找到组织了,挂着到窗口树上了。
但是这个时候,SurfaceFlinger那边还是没变化的,所以继续看后续流程。
# WindowContainer
void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent,
PreAssignChildLayersCallback callback) {
super.onParentChanged(newParent, oldParent);
// 正常肯定是有父节点的
if (mParent == null) {
return;
}
if (mSurfaceControl == null) {
// If we don't yet have a surface, but we now have a parent, we should
// build a surface.
// 父亲有了,但是自身还为null,则触发创建自身Surface的逻辑
createSurfaceControl(false /*force*/);
} else {
......// 有则进行 reparent
reparentSurfaceControl(getSyncTransaction(), mParent.mSurfaceControl);
}
......
}
// 重点,触发Surface的创建
void createSurfaceControl(boolean force) {
setInitialSurfaceControlProperties(makeSurface());
}
注释比较详细就不多说了,这里肯定是走createSurfaceControl()逻辑,然后注意makeSurface()方法会创建出Surface,然后再调用setInitialSurfaceControlProperties。先看 makeSurface 方法。
# WindowContainer
// 当前容器的Surface
protected SurfaceControl mSurfaceControl;
SurfaceControl.Builder makeSurface() {
// 拿到父节点,调用makeChildSurface
final WindowContainer p = getParent();
// 传递当前,也就是Task
return p.makeChildSurface(this);
}
SurfaceControl.Builder makeChildSurface(WindowContainer child) {
// 拿到父亲
final WindowContainer p = getParent();
// Give the parent a chance to set properties. In hierarchy v1 we rely
// on this to set full-screen dimensions on all our Surface-less Layers.
// 调用父亲的makeChildSurface方法,再调用setParent
return p.makeChildSurface(child)
.setParent(mSurfaceControl);
}
这里方法虽然不多,但是逻辑有点绕,做一下解释:
1、是子容器调用的 makeChildSurface 方法,那子容器类就是 Task,父容器就是 DefaultTaskDisplayArea
2、执行 父容器 makeChildSurface方法的时候,又调用了getParent 获取父容器,执行 makeChildSurface,(眉头一皱,事情并不简单)这是开始递归了。
3、先不管递归,总之肯定的是 makeChildSurface方法不管怎么递归返回的还是一个SurfaceControl.Builder,然后调用setParent将DefaultTaskDisplayArea的Surface设置为其父节点。
4、对于递归调用,最终要的就是找到递归结束的条件,当前这个递归结束的条件就是 DisplayContent 类重写了makeChildSurface方法,也就是说调到 DisplayContent::makeChildSurface 就意味着递归的结束。
所以现在来看看 DisplayContent::makeChildSurface方法:
# DisplayContent
@Override
SurfaceControl.Builder makeChildSurface(WindowContainer child) {
SurfaceSession s = child != null ? child.getSession() : getSession();
// 创建一个容器类型 Surface的Builder
final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(s).setContainerLayer();
if (child == null) {
return b;
}
// 设置容器名
return b.setName(child.getName())
.setParent(mSurfaceControl);
}
这里的参数 child 就是Task,
1、首先创建一个容器类型 SurfaceControl.Builder
2、设置name,当前场景是把Task的名字设置过去
3、然后设置一下父亲为DisplayContent的Surface
这里要注意,这里设置父节点最终是无效的,会被覆盖掉,因为上面分析看到了把 DefaultTaskDisplayArea设置为Task父容器。从代码的执行顺序上来说,DisplayContent的这次setParent先执行,会被后面的覆盖掉。 从结果来看,Task也确实是挂在DefaultTaskDisplayArea下的。 (不可能每个容器都直接作为DisplayContent的子节点)
到这里,Framework层的窗口树, SurfaceFlinger的Surface树构建的差不多了,但是手机上还是不会有内容的,为什么呢? 因为这些都是 “容器”,真正的显示需要有Buff类型的Surface。
再看一次这个图, 对应的窗口树到了WindowState就结束了, SurfaceFliner 这边可以看到WindowState下还有一个节点,这个节点才是真正有UI数据的 Layer。
在Activity启动流程中时执行到目标应用进程创建时会触发Task和ActivityRecord创建和挂载。 这个时候WindowState还没出现,另外到这一步Activity的onCreate也没执行到,所以界面上肯定是没有UI显示的。
Activity进程创建后,会先执行addWindow流程触发 WindowState的创建和挂载,但是这步执行完也还是没有画面的, 因为WindowState也是一个“容器”。
真正触发显示图层创建的是在【relayoutWindow】流程,具体的流程不是当前的主题,目前只关注【relayoutWindow】流程中“Buff”类型图层的创建。
relayoutWindow
创建真正显示的surface的地方 relayoutWindow的调用链如下:
WindowManagerService::relayoutWindow
WindowManagerService::createSurfaceControl
WindowStateAnimator::createSurfaceLocked -- 创建“Buff” 类型Surface
WindowStateAnimator::resetDrawState -- 设置窗口状态为DRAW_PENDING
WindowSurfaceController::init
SurfaceControl.Builder::build
SurfaceControl::init
WindowSurfaceController::getSurfaceControl -- 给应用端Surface赋值
# WindowManagerService
public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls, Bundle outSyncIdBundle) {
......
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
......
}
createSurfaceControl 方法有4个参数:
1、outSurfaceControl: WMS创建好一个Surface后,还需要返回给应用端用于View的绘制,就是通过这个参数,由参数命名也可以知道这是一个“出参”。
2、result: 方法执行结果
3、win: 当前窗口对应的WindowState,稍后创建Surface会挂载到这个WindowState节点之下
4、winAnimator:WindowStateAnimator对象,管理窗口状态和动画,稍后通过其内部方法创建Surface
# WindowManagerService
private int createSurfaceControl(SurfaceControl outSurfaceControl, int result,
WindowState win, WindowStateAnimator winAnimator) {
// 1. 创建WindowSurfaceController对象
WindowSurfaceController surfaceController;
try {
// 2. 创建“Buff”类型Surface
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
surfaceController = winAnimator.createSurfaceLocked();
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
if (surfaceController != null) {
// 3. 出参给应用端
surfaceController.getSurfaceControl(outSurfaceControl);
// 打印日志,outSurfaceControl复制到了framework的值
ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);
}......
return result;
}
这个方法主要有三步,都是围绕着 WindowSurfaceController 来的:
1、先创建出一个WindowSurfaceController 对象 surfaceController
2、通过WindowStateAnimator::createSurfaceLocked 对 surfaceController 赋值,根据方法名猜测是创建了一个Surface
3、通过 WindowSurfaceController::getSurfaceControl,给应用端 Surface 赋值
看来重点是在第二步:
WindowStateAnimator::createSurfaceLocked 是如何创建Surface的。
# WindowStateAnimator
WindowSurfaceController mSurfaceController;
// WindowState的状态
int mDrawState;
WindowSurfaceController createSurfaceLocked() {
final WindowState w = mWin;
if (mSurfaceController != null) {
return mSurfaceController;
}
w.setHasSurface(false);
// 打印窗口状态
ProtoLog.i(WM_DEBUG_ANIM, "createSurface %s: mDrawState=DRAW_PENDING", this);
// 重点* 1. 重置窗口状态
resetDrawState();
......
// 重点* 2. 创建WindowSurfaceController
mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), format,
flags, this, attrs.type);
......
return mSurfaceController;
}
这里有2个重点:
- 设置窗口状态为 DRAW_PENDING
- 创建Surface
# WindowStateAnimator
void resetDrawState() {
// 设置windowState状态为DRAW_PENDING
mDrawState = DRAW_PENDING;
if (mWin.mActivityRecord == null) {
return;
}
if (!mWin.mActivityRecord.isAnimating(TRANSITION)) {
mWin.mActivityRecord.clearAllDrawn();
}
}
WindowState有很多状态,以后会单独说,这里需要注意:
- WindowState状态是保存在WindowStateAnimator中
- WindowStateAnimator::createSurfaceLocked方法会将WindowState状态设置为DRAW_PENDING,表示等待绘制。
创建“Buff”类型的Surface
回到主流程,看看 WindowSurfaceController 的构造方法:
# WindowSurfaceController
SurfaceControl mSurfaceControl;
WindowSurfaceController(String name, int format, int flags, WindowStateAnimator animator,
int windowType) {
mAnimator = animator;
// 1. 也会作为Surface的name
title = name;
mService = animator.mService;
// 2. 拿到WindowState
final WindowState win = animator.mWin;
mWindowType = windowType;
mWindowSession = win.mSession;
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl");
// 3. 重点* 构建Surface(也是通过makeSurface 方法)
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);
// 高版本都为BLAST
if (useBLAST) {
// 4. 重点* 设置为“Buff”图层
b.setBLASTLayer();
}
// 触发build
mSurfaceControl = b.build();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
这个方法有4个点:
- 第一个参数传递的字符串最终也会作为Surface的name
- 获取到WindowState对象,后面会设置为创建Surface的父节点
- 构建出一个Surface对象, 注意name和 父节点的设置。 另外可以知道也是通过makeSurface()方法构建的, 这个方法在 2.1小结看到是构建出一个“容器”类型的Surface。
- 将Surface设置为“Buff”类型,这个非常重要,因为上一步默认还是“容器”类型,所以需要设置成“Buff”类型,再后面就是build出一个Surface了
那么到这里Surface的创建就完成了,这里可能有的人如果对Surface知识不太清楚的话会比较迷糊,WindowSurfaceController,SurfaceController,Surface到底是什么关系,这个不在当前流程的重点,暂且理解为同级吧,有WindowSurfaceController就可以拿到内部的SurfaceController,而SurfaceController又可以获取到Surface。
返回surface到应用端
最后再来看一下 WMS这边创建好后的Surface是如何设置给应用端的。
应用端View的绘制信息都是保存到Surface上的,因为必定要有一个"Buff"类型的Surface,也就是上面流程中创建的这个Surface。
应用端的ViewRootImpl触发WMS的relayoutWindow会传递一个出参 :outSurfaceControl过来, 现在WMS会通过以下方法将刚刚创建好是Surface传递到应用端。
这样一来应用端就有了可以保持绘制数据的Surface,然后就可以执行 View::draw。
# WindowSurfaceController
void getSurfaceControl(SurfaceControl outSurfaceControl) {
// 将framework层的SurfaceControl copy给应用层传递过来的outSurfaceControl
outSurfaceControl.copyFrom(mSurfaceControl, "WindowSurfaceController.getSurfaceControl");
}