以运用窗口和体系窗口2大类型窗口的挂载为例介绍窗口是怎么挂载到层级树中的。

1. 运用窗口挂载

运用启动流程中会触发ActivityRecord,Task,WindowState的创立与挂载,其间WindowState的处理上在addWindow流程。

ActivityTaskManagerService::startActivity ActivityTaskManagerService::startActivityAsUser ActivityTaskManagerService::startActivityAsUser ActivityStartController::obtainStarter ActivityStarter::execute ActivityStarter::executeRequest — 构建 ActivityRecord –2.2.1 创立ActivityRecord ActivityStarter::startActivityUnchecked ActivityStarter::startActivityInner — 2.2.2 要害函数startActivityInner ActivityStarter::getOrCreateRootTask — 2.2.2.1 创立或者拿到Task ActivityStarter::setNewTask — 2.2.2.2 将task与activityRecord 绑定 RootWindowContainer::resumeFocusedTasksTopActivities –2.2.2.3 显现Activity

addWindow流程调用链: WindowManagerImpl::addView — 创立ViewRootImpl WindowManagerGlobal::addView
ViewRootImpl::setView — 与WMS通讯 addView Session.addToDisplayAsUser WindowManagerService::addWindow WindowState::init — WindowState的创立 WindowToken::addWindow — WindowState的挂载

1.1 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。

1.2 Task的创立与挂载

流程开端会履行到ActivityStarter::startActivityInner办法,在这儿会履行ActivityStarter::getOrCreateRootTask办法来创立(获取)一个Task 调用链如下: ActivityStarter::getOrCreateRootTask RootWindowContainer::getOrCreateRootTask RootWindowContainer::getOrCreateRootTask TaskDisplayArea::getOrCreateRootTask TaskDisplayArea::getOrCreateRootTask Task::Build —创立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个要点部分:

  1. 看到经过buildInner 创立了一个task,而buildInner 也很简单粗暴,经过各个变量直接new Task 目标。
  2. mParent 不为null, 是 因为在创立的时分 setParent(this),当时的这个this,便是 getDefaultTaskDisplayArea回来的也便是运用Activity存在的”DefaultTaskDisplayArea”。

在 RootWindowContainer::getOrCreateRootTask 表现。

WindowContainer窗口层级-3-实例剖析
注意log里的 #17 的这个Task,与前面的层级结构树新增的Task,是对应的上的。并且this= DefaultTaskDisplayArea 阐明也确实是往DefaultTaskDisplayArea里添加了。

1.3 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);
        }
    }

这儿的逻辑设计到的Task便是上一步创立的Task,mStartActivity则是“电话”在之前逻辑创立的ActivityRecord. setNewTask的堆栈信息如下

WindowContainer窗口层级-3-实例剖析
别的这段逻辑里有个ProtoLog打印,日志如下:

WindowContainer窗口层级-3-实例剖析

1.4 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?
        }
    }

2. 体系窗口挂载

2.1 WindowToken,WindowState的创立与挂载

    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的,所以会履行创立逻辑。 在创立的时分会依据窗口类型选择挂载的层级。

2.2 WindowToken的挂载

WMS::addWindow WindowToken::init DisplayContent::addWindowToken mTokenMap::put — 存入mTokenMap DisplayContent::findAreaForToken — 找到对应的层级 DisplayContent::findAreaForWindowType DisplayAreaPolicyBuilder.Result::findAreaForWindowType RootDisplayArea::findAreaForWindowTypeInLayer — 在 mAreaForLayer中依据type查找对应的方位

        DisplayArea.Tokens::addChild  -- 挂载

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其实便是开端构建层级树的那个调集。

2.2.1 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的挂载。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。