android T split screen process system server side operation

hi, fans and friends:

background review

The analysis of the systemui side of the split screen has been completed in the previous section. The main tasks of the systemui side are as follows:
1. The division line display and the calculation of the upper and lower screen areas are determined.
2. The position of the roottask of the split screen is placed on the top
3. 1. Start the task on the upper and lower screens.
Any operation related to the task above needs to be packaged into WindowContainerTransition for cross-process transfer to the systemserver side.
In fact, it can be guessed that the systemserver side also needs a similar 3-step operation.

Explanation of the free video tutorial at station b:
https://www.bilibili.com/video/BV1wj411o7A9/
insert image description here
You can see the general Task area and structure through the picture below. In fact, if you have studied the wms topic in the early stage, you can see this It is also very simple, and the above three steps are also very easy to understand, and you can even write the relevant code yourself
insert image description here

Source code analysis of systemserver

Here the cross-process will call applyTransaction of WindowOrganizerController

//frameworks/base/services/core/java/com/android/server/wm/WindowOrganizerController.java
 private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
            @Nullable Transition transition, @NonNull CallerInfo caller,
            @Nullable Transition finishTransition) {
    
    
        try {
    
    
          
            Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
                    t.getChanges().entrySet().iterator();//获取transition的change部分,这里主要是我们的bounds这部分数据带有这个
            while (entries.hasNext()) {
    
    //遍历每个Change
                final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next();
                final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
             
//获取一个的change,而且取出change中包裹的具体WindowContainer,这里就一般是前面说过的上屏和下屏的对应Task,然后调用applyWindowContainerChange进行对应处理
                int containerEffect = applyWindowContainerChange(wc, entry.getValue(),
                        t.getErrorCallbackToken());
           
            }
            // Hierarchy changes
            final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
            final int hopSize = hops.size();
            if (hopSize > 0) {
    
    
                final boolean isInLockTaskMode = mService.isInLockTaskMode();
                for (int i = 0; i < hopSize; ++i) {
    
    
                //这里就是对reorder和starTask的操作进行处理
                    effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,
                            isInLockTaskMode, caller, t.getErrorCallbackToken(),
                            t.getTaskFragmentOrganizer(), finishTransition);
                }
            }
            //省略
       
    }

To sum up, the processing on the systemserver side is actually the same as that on the systemui client side:
1. For the area size bounds change to Change type, applyWindowContainerChange is performed on this Change.
2. For the two types of task-related operations, both reorder and startTask It is packaged as HierarchyOp, and the applyHierarchyOp method is called for this type of processing

Detailed analysis below

Task area size bounds change processing applyWindowContainerChange


 private int applyWindowContainerChange(WindowContainer wc,
            WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) {
    
    
       //省略
       //这里主要会调用applyChanges
        int effects = applyChanges(wc, c, errorCallbackToken);

        if (wc instanceof DisplayArea) {
    
    
            effects |= applyDisplayAreaChanges(wc.asDisplayArea(), c);
        } else if (wc instanceof Task) {
    
    
            effects |= applyTaskChanges(wc.asTask(), c);
        }

        return effects;
    }
    private int applyChanges(WindowContainer<?> container,
            WindowContainerTransaction.Change change, @Nullable IBinder errorCallbackToken) {
    
    
        //最重要就是获取change的configration,因为bounds变化被包在了configration里面,这里再调用container的进行通知configration的变化
                final Configuration c =
                        new Configuration(container.getRequestedOverrideConfiguration());
                c.setTo(change.getConfiguration(), configMask, windowMask);
                //Task容器调用这个onRequestedOverrideConfigurationChanged,代表根据传递过来的Configration作为自己的覆盖变化,即也就把对应的bounds设置给了Task
                container.onRequestedOverrideConfigurationChanged(c);
          
        return effects;
    }

The reorder operation of RootTask of applyHierarchyOp

 private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
            int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
            @NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
            @Nullable ITaskFragmentOrganizer organizer, @Nullable Transition finishTransition) {
    
    
        final int type = hop.getType();
        //省略
        switch (type) {
    
    
            case HIERARCHY_OP_TYPE_REORDER:
            case HIERARCHY_OP_TYPE_REPARENT: {
    
    
            //首相要从hop中获取出WindowContainer
                final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
                 //省略
                 //调用sanitizeAndApplyHierarchyOp进行处理
                effects |= sanitizeAndApplyHierarchyOp(wc, hop);
                break;
            }
           //省略
        return effects;
    }

  private int sanitizeAndApplyHierarchyOp(WindowContainer container,
            WindowContainerTransaction.HierarchyOp hop) {
    
    
            
     //这里获取task,其实就是RootTask,分屏最顶端那个taskId为4的
        final Task task = container.asTask();
     //省略
           //需要把task进行位置放到所有task顶端位置
            task.getParent().positionChildAt(
                    hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
                    task, false /* includingParents */);
                    
     //省略
     //因为进行了task的位置变化,所以这里返回了一个会影响各个Activity生命周期的mask
        return TRANSACT_EFFECTS_LIFECYCLE;
    }

Overall, this reorder is relatively simple to operate, that is, put RootTask first, that is, display it at the front

applyHierarchyOp's startTask operation

 private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
            int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
            @NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
            @Nullable ITaskFragmentOrganizer organizer, @Nullable Transition finishTransition) {
    
    
        final int type = hop.getType();
          switch (type) {
    
    
 				 case HIERARCHY_OP_TYPE_LAUNCH_TASK: {
    
    
            
            //这个launchOpts就是systemui传递时候的mainOptions和sideOptions,注意一下这个launchOpts里面有一个非常关键数据KEY_LAUNCH_ROOT_TASK_TOKEN,即stage.mRootTaskInfo.token
                final Bundle launchOpts = hop.getLaunchOptions();
                //注意这里是获取具体要启动app的taskId,不是上下分屏的id
                final int taskId = launchOpts.getInt(
                        WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
                        //转化成SafeActivityOptions类型
                final SafeActivityOptions safeOptions =
                        SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
                        //这里有个线程切换操作,而且还会等执行完成,所以核心是mService.mTaskSupervisor.startActivityFromRecents
                        
                waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents(
                        caller.mPid, caller.mUid, taskId, safeOptions));
                break;
            }
            }
            }

It can be easily seen from the above that the data is disassembled, and then the mService.mTaskSupervisor.startActivityFromRecents method is called:


int startActivityFromRecents(int callingPid, int callingUid, int taskId,
            SafeActivityOptions options) {
    
    
        final Task task;
        final int taskCallingUid;
        final String callingPackage;
        final String callingFeatureId;
        final Intent intent;
        final int userId;
        //获取传递进来的options,通过它主要可以获取上下分屏的容器task(示意图第二层)
        final ActivityOptions activityOptions = options != null
                ? options.getOptions(this)
                : null;
        boolean moveHomeTaskForward = true;
        synchronized (mService.mGlobalLock) {
    
    
            int activityType = ACTIVITY_TYPE_UNDEFINED;
            if (activityOptions != null) {
    
    
                activityType = activityOptions.getLaunchActivityType();
              //省略
 
           //这里主要通过taskId来获取一个Task,但是这个方法不仅仅只干了获取task的事情,还干了把taskId对应的Task进行reparent到新上下分屏的容器Task,这样实现了层级结构树上面的挂载完成,剩下就是一系列操作来保证Activiyt生命周期正常相关
         
                task = mRootWindowContainer.anyTaskForId(taskId,
                        MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
              //获取了task之后进行相关的Activity操作
                if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)
                        && task.getRootActivity() != null) {
    
    
                        //获取task的Activity
                    final ActivityRecord targetActivity = task.getTopNonFinishingActivity();

               
                    try {
    
    
                    //这里非常关键的把task移动到前台,在里面会对focus和resume进行设置
                        mService.moveTaskToFrontLocked(null /* appThread */,
                                null /* callingPackage */, task.mTaskId, 0, options);
                      //省略

Here are some inconspicuous but very important features of anyTaskForId


 Task anyTaskForId(int id, @RootWindowContainer.AnyTaskForIdMatchTaskMode int matchMode,
            @Nullable ActivityOptions aOptions, boolean onTop) {
    
    
      

        final PooledPredicate p = PooledLambda.obtainPredicate(
                Task::isTaskId, PooledLambda.__(Task.class), id);
        Task task = getTask(p);//遍历获取Task
        p.recycle();

        if (task != null) {
    
    
            if (aOptions != null) {
    
    //注意这里aOptions不为null,而且携带了task
             		//这里有调用了getOrCreateRootTask来获取targetRootTask
                final Task targetRootTask =
                        getOrCreateRootTask(null, aOptions, task, onTop);
                if (targetRootTask != null && task.getRootTask() != targetRootTask) {
    
    
                    final int reparentMode = onTop
                            ? REPARENT_MOVE_ROOT_TASK_TO_FRONT : REPARENT_LEAVE_ROOT_TASK_IN_PLACE;
                    task.reparent(targetRootTask, onTop, reparentMode, ANIMATE, DEFER_RESUME,
                            "anyTaskForId");
                }
            }
            return task;
        }

       //省略
    }
    
    Task getOrCreateRootTask(@Nullable ActivityRecord r,
            @Nullable ActivityOptions options, @Nullable Task candidateTask,
            @Nullable Task sourceTask, boolean onTop,
            @Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags) {
    
    
        // First preference goes to the launch root task set in the activity options.
        if (options != null) {
    
    
        //这里终于体现systemui传递的mainoptions作用了
            final Task candidateRoot = Task.fromWindowContainerToken(options.getLaunchRootTask());
            if (candidateRoot != null && canLaunchOnDisplay(r, candidateRoot)) {
    
    
                return candidateRoot;//大家看这里就直接返回了options带的task
            }
        }
        //省略
        }

Finally, look at the most important moveTaskToFrontLocked method:


 void moveTaskToFrontLocked(@Nullable IApplicationThread appThread,
            @Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options) {
    
    
        //省略
        try {
    
    
            final Task task = mRootWindowContainer.anyTaskForId(taskId);
            //省略
            ActivityOptions realOptions = options != null
                    ? options.getOptions(mTaskSupervisor)
                    : null;
                    //这方法最为关键,寻找到task而且移到最前端
            mTaskSupervisor.findTaskToMoveToFront(task, flags, realOptions, "moveTaskToFront",
                    false /* forceNonResizable */);
				
				//开始启动StartingWindow
            final ActivityRecord topActivity = task.getTopNonFinishingActivity();
            if (topActivity != null) {
    
    

                // We are reshowing a task, use a starting window to hide the initial draw delay
                // so the transition can start earlier.
                topActivity.showStartingWindow(true /* taskSwitch */);
            }
 //省略
    }

Let's take a look at the key method findTaskToMoveToFront


/** This doesn't just find a task, it also moves the task to front. */
    void findTaskToMoveToFront(Task task, int flags, ActivityOptions options, String reason,
            boolean forceNonResizeable) {
    
    
            //这里currentRootTask就是taskId =4的根task
        Task currentRootTask = task.getRootTask();
        //省略
            final ActivityRecord r = task.getTopNonFinishingActivity();
            //这里又调用到了关键moveTaskToFront方法
            currentRootTask.moveTaskToFront(task, false /* noAnimation */, options,
                    r == null ? null : r.appTimeTracker, reason);

           //省略
    }
final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options,
            AppTimeTracker timeTracker, boolean deferResume, String reason) {
    
    
       //省略

					//这里又关键调用到了顶部ActivityRecord的moveFocusableActivityToTop方法
            // Set focus to the top running activity of this task and move all its parents to top.
            top.moveFocusableActivityToTop(reason);
 //省略
            if (!deferResume) {
    
    //进行对应resume操作
                mRootWindowContainer.resumeFocusedTasksTopActivities();
            }
       //省略
    }

Let's look at the last key method moveFocusableActivityToTop

boolean moveFocusableActivityToTop(String reason) {
    
    
      
        final Task rootTask = getRootTask();
   			//这里调用了rootTask把当前app的task移到最前
        rootTask.moveToFront(reason, task);
        // Report top activity change to tracking services and WM
        if (mRootWindowContainer.getTopResumedActivity() == this) {
    
     //注意这里可能大家有疑问为啥都可以getTopResumedActivity到了,还需要设置,那是因为getTopResumedActivity可能真正ResumedActivity为null,但是会通过获取getFocusedActivity获取作为ResumedActivity
          //这个操作关键,把ActivityRecord开始要变成Resumed状态了,这个就不展开,前面课程视频讲解
            mAtmService.setResumedActivityUncheckLocked(this, reason);
        }
        return true;
    }
   @Nullable
    ActivityRecord getTopResumedActivity() {
    
    
        final Task focusedRootTask = getTopDisplayFocusedRootTask();
 				//getTopResumedActivity这个时候是为null哦
        final ActivityRecord resumedActivity = focusedRootTask.getTopResumedActivity();
        if (resumedActivity != null && resumedActivity.app != null) {
    
    
            return resumedActivity;
        }
        // The top focused root task might not have a resumed activity yet - look on all displays in
        // focus order.
        //前面发现为null后就获取getFocusedActivity
        return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedActivity);
    }

Here is a summary sequence diagram:
insert image description here

Guess you like

Origin blog.csdn.net/learnframework/article/details/130965167