android T分屏流程systemserver端操作

hi,粉丝朋友们:

背景回顾

上一节已经对分屏的systemui端分析完成,systemui端主要干的事情还是以下几点:
1、分割线显示及分割上下屏区域的计算确定
2、对分屏roottask的位置放到最top
3、对上下屏幕task的启动
上面会涉及到task任何操作都需要包装到WindowContainerTransition中进行跨进程传递到systemserver端
这里其实也可以猜想出systemserver端也一样要有类似的3步操作。

b站免费视频教程讲解:
https://www.bilibili.com/video/BV1wj411o7A9/
在这里插入图片描述
可以看看通过下图先有个大概的Task区域及结构的了解,其实这个如果前期学习过wms专题的话这个看起来也很简单,对上面3个步骤也非常好理解,甚至可以自己写出相关的代码
在这里插入图片描述

systemserver端的源码分析

这里跨进程会调用到WindowOrganizerController的applyTransaction

//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);
                }
            }
            //省略
       
    }

总结一下systemserver端处理其实和systemui客户端一样的:
1、针对区域大小bounds类变化变成是Change类型,就对这个Change相关进行applyWindowContainerChange
2、针对task相关的2类操作,reorder和startTask两类都是包装成了HierarchyOp,对这类也是调用了applyHierarchyOp方法来进行处理

下面一一进行详细分析

Task区域大小bounds变化处理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;
    }

applyHierarchyOp的RootTask的reorder操作

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

总体来看这个reorder相对来说操作还是比较简单,就是一个把RootTask放到第一位,即显示再最前面

applyHierarchyOp的startTask操作

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

上面可以简单看出就是对数据进行拆解出来,然后调用mService.mTaskSupervisor.startActivityFromRecents方法:


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);
                      //省略

这里补充一下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
            }
        }
        //省略
        }

最后看看最重要的moveTaskToFrontLocked方法:


 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 */);
            }
 //省略
    }

下面看看这个关键方法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();
            }
       //省略
    }

下面看看最后关键方法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);
    }

下面来个总结时序图:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值