前言
打开MainActivity,然后进入最近任务触发分屏,可以成功进入分屏模式。
本篇文章我们来具体梳理一下这个过程的源码调用流程。
一 launcher3阶段
1.1 源码
java
//packages/apps/Launcher3/quickstep/src/com/android/quickstep/views/TaskView.java
public class TaskView extends FrameLayout implements Reusable {
private void onClick(View view) {
if (getTask() == null) {
return;
}
if (confirmSecondSplitSelectApp()) {
return;
}
launchTasks();
...代码省略...
}
private boolean confirmSecondSplitSelectApp() {
boolean isSelectingSecondSplitApp = getRecentsView().isSplitSelectionActive();
if (isSelectingSecondSplitApp) {
//调用RecentsView的confirmSplitSelect方法
getRecentsView().confirmSplitSelect(this);
}
return isSelectingSecondSplitApp;
}
}
//packages/apps/Launcher3/quickstep/src/com/android/quickstep/views/RecentsView.java
public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>,
STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
TaskVisualsChangeListener {
protected SplitSelectStateController mSplitSelectStateController;
public void confirmSplitSelect(TaskView taskView) {
...代码省略...
pendingAnimation.addEndListener(aBoolean -> {
pendingAnimation.addEndListener(aBoolean ->
//待动画结束,执行SplitSelectStateController的setSecondTaskId方法
mSplitSelectStateController.setSecondTaskId(taskView.getTask(),
aBoolean1 -> RecentsView.this.resetFromSplitSelectionState()));
...代码省略...
}
}
//packages/apps/Launcher3/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
public class SplitSelectStateController {
public void setSecondTaskId(Task task, Consumer<Boolean> callback) {
mSecondTask = task;
launchTasks(mInitialTask, mSecondTask, mStagePosition, callback,
false /* freezeTaskList */, DEFAULT_SPLIT_RATIO);
}
private final SystemUiProxy mSystemUiProxy;
public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition,
Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
...代码省略...
mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(),
taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
splitRatio, adapter);
...代码省略...
}
}
//packages/apps/Launcher3/quickstep/src/com/android/quickstep/SystemUiProxy.java
public class SystemUiProxy implements ISystemUiProxy, NavHandle {
private ISplitScreen mSplitScreen;
public void startTasksWithLegacyTransition(int mainTaskId, Bundle mainOptions, int sideTaskId,
Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition,
float splitRatio, RemoteAnimationAdapter adapter) {
if (mSystemUiProxy != null) {
try {
mSplitScreen.startTasksWithLegacyTransition(mainTaskId, mainOptions, sideTaskId,
sideOptions, sidePosition, splitRatio, adapter);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startTasksWithLegacyTransition");
}
}
}
}
1.2 时序图

二 SystemUI阶段
2.1 源码
java
public class SplitScreenController implements DragAndDropPolicy.Starter,
RemoteCallable<SplitScreenController> {
private static class ISplitScreenImpl extends ISplitScreen.Stub {
@Override
public void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
float splitRatio, RemoteAnimationAdapter adapter) {
executeRemoteCallWithTaskPermission(mController, "startTasks",
(controller) -> controller.mStageCoordinator.startTasksWithLegacyTransition(
mainTaskId, mainOptions, sideTaskId, sideOptions, sidePosition,
splitRatio, adapter));
}
}
}
class StageCoordinator implements SplitLayout.SplitLayoutHandler,
RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, Transitions.TransitionHandler {
private final ShellTaskOrganizer mTaskOrganizer;
void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
float splitRatio, RemoteAnimationAdapter adapter) {
//设置分割线的可见性
setDividerVisibility(false /* visible */);
//初始化分屏的分割线的布局
mSplitLayout.init();
// Set false to avoid record new bounds with old task still on top;
mShouldUpdateRecents = false;
final WindowContainerTransaction wct = new WindowContainerTransaction();
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
//创建一个远程动画的回调binder对象
IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
@Override
public void onAnimationStart(@WindowManager.TransitionOldType int transit,
RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
final IRemoteAnimationFinishedCallback finishedCallback) {
...代码省略...
}
@Override
public void onAnimationCancelled() {
...代码省略...
}
};
//创建RemoteAnimationAdapter类型的远程动画
RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
if (mainOptions == null) {
//构建出对应的mainOptions,及上分屏的启动option
mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
} else {
ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
mainOptions = mainActivityOptions.toBundle();
}
//准备好对应的sideOptions,下分屏的option
sideOptions = sideOptions != null ? sideOptions : new Bundle();
setSideStagePosition(sidePosition, wct);
//设置分界线比例
mSplitLayout.setDivideRatio(splitRatio);
if (mMainStage.isActive()) {
mMainStage.moveToTop(getMainStageBounds(), wct);
} else {
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
}
mSideStage.moveToTop(getSideStageBounds(), wct);
//准备好对应的option参数
// Make sure the launch options will put tasks in the corresponding split roots
addActivityOptions(mainOptions, mMainStage);
addActivityOptions(sideOptions, mSideStage);
// Add task launch requests
wct.startTask(mainTaskId, mainOptions);//主分屏task
wct.startTask(sideTaskId, sideOptions);//次分屏task
//最后把前面准备好的参数统一apply到SystemServer里面
mTaskOrganizer.applyTransaction(wct);
}
}
2.2 时序图

三 SystemServer阶段
3.1 源码
java
//frameworks/base/services/core/java/com/android/server/wm/WindowOrganizerController.java
public class ShellTaskOrganizer extends TaskOrganizer implements CompatUIController.CompatUICallback {
//父类方法
public void applyTransaction(@NonNull WindowContainerTransaction t) {
try {
if (!t.isEmpty()) {
//调用ActivityTaskManagerService的getWindowOrganizerController方法得到WindowOrganizerController对象
//并调用WindowOrganizerController对象的applyTransaction方法
getWindowOrganizerController().applyTransaction(t);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
static IWindowOrganizerController getWindowOrganizerController() {
return IWindowOrganizerControllerSingleton.get();
}
private static final Singleton<IWindowOrganizerController> IWindowOrganizerControllerSingleton =
new Singleton<IWindowOrganizerController>() {
@Override
protected IWindowOrganizerController create() {
try {
return ActivityTaskManager.getService().getWindowOrganizerController();
} catch (RemoteException e) {
return null;
}
}
};
}
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
WindowOrganizerController mWindowOrganizerController;
@Override
public IWindowOrganizerController getWindowOrganizerController() {
return mWindowOrganizerController;
}
}
//base/services/core/java/com/android/server/wm/WindowOrganizerController.java
class WindowOrganizerController extends IWindowOrganizerController.Stub {
@Override
public void applyTransaction(WindowContainerTransaction t) {
...代码省略...
applyTransaction(t, -1 /*syncId*/, null /*transition*/, caller);
...代码省略...
}
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
@Nullable Transition transition, @NonNull CallerInfo caller) {
...代码省略...
ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
//获取WindowContainerTransaction的change部分
Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
t.getChanges().entrySet().iterator();
while (entries.hasNext()) {//遍历每个变化的元素
final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next();
final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
if (wc == null || !wc.isAttached()) {
Slog.e(TAG, "Attempt to operate on detached container: " + wc);
continue;
}
// Make sure we add to the syncSet before performing
// operations so we don't end up splitting effects between the WM
// pending transaction and the BLASTSync transaction.
if (syncId >= 0) {
addToSyncSet(syncId, wc);
}
if (transition != null) transition.collect(wc);
//注释1,这里一般就是前面说过的上屏和下屏的对应Task,调用applyWindowContainerChange方法进行对应处理
int containerEffect = applyWindowContainerChange(wc, entry.getValue());
effects |= containerEffect;
// Lifecycle changes will trigger ensureConfig for everything.
if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0
&& (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
haveConfigChanges.add(wc);
}
}
// 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) {
//注释2,调用applyHierarchyOp方法,对reorder和starTask的操作进行处理
effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,
isInLockTaskMode, caller, t.getErrorCallbackToken(),
t.getTaskFragmentOrganizer());
}
}
...代码省略...
}
private int applyWindowContainerChange(WindowContainer wc, WindowContainerTransaction.Change c) {
sanitizeWindowContainer(wc);
//调用applyChanges
int effects = applyChanges(wc, c);
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) {
...代码省略...
//最重要就是获取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);
...代码省略...
}
}
调用applyHierarchyOp方法将task放到最上层
java
class WindowOrganizerController extends IWindowOrganizerController.Stub {
//HIERARCHY_OP_TYPE_REORDER和HIERARCHY_OP_TYPE_REPARENT类型
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
@Nullable ITaskFragmentOrganizer organizer) {
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;
}
case HIERARCHY_OP_TYPE_LAUNCH_TASK: {
...代码省略...
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 */);
...代码省略...
return TRANSACT_EFFECTS_LIFECYCLE;
}
}
调用applyHierarchyOp方法对数据进行拆解,然后调用ActivityTaskSupervisor的startActivityFromRecents方法:
java
class WindowOrganizerController extends IWindowOrganizerController.Stub {
//HIERARCHY_OP_TYPE_REORDER和HIERARCHY_OP_TYPE_REPARENT类型
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
@Nullable ITaskFragmentOrganizer organizer) {
final int type = hop.getType();
...代码省略...
switch (type) {
...代码省略...
case HIERARCHY_OP_TYPE_REORDER:
case HIERARCHY_OP_TYPE_REPARENT:
...代码省略...
case HIERARCHY_OP_TYPE_LAUNCH_TASK: {
mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
"launchTask HierarchyOp");
final Bundle launchOpts = hop.getLaunchOptions();
final int taskId = launchOpts.getInt(
WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
final SafeActivityOptions safeOptions =
SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
final Integer[] starterResult = {null};
// startActivityFromRecents should not be called in lock.
mService.mH.post(() -> {
try {
//调用ActivityTaskSupervisor的startActivityFromRecents方法
starterResult[0] = mService.mTaskSupervisor.startActivityFromRecents(
caller.mPid, caller.mUid, taskId, safeOptions);
} catch (Throwable t) {
starterResult[0] = ActivityManager.START_CANCELED;
Slog.w(TAG, t);
}
synchronized (mGlobalLock) {
mGlobalLock.notifyAll();
}
});
while (starterResult[0] == null) {
try {
mGlobalLock.wait();
} catch (InterruptedException ignored) {
}
}
break;
}
...代码省略...
return effects;
}
}
}
//base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
RootWindowContainer mRootWindowContainer;
final ActivityTaskManagerService mService;
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;
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);
...代码省略...
if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)
&& task.getRootActivity() != null) {
//获取task的Activity
final ActivityRecord targetActivity = task.getTopNonFinishingActivity();
...代码省略...
//调用
mService.moveTaskToFrontLocked(null /* appThread */,
null /* callingPackage */, task.mTaskId, 0, options);
...代码省略...
}
}
}
}
}
}
RootWindowContainer的anyTaskForId方法
java
class RootWindowContainer extends WindowContainer<DisplayContent>
implements DisplayManager.DisplayListener {
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
}
}
//省略
}
}
ActivityTaskManagerService的moveTaskToFrontLocked方法
java
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
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方法
java
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/** 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();
}
//省略
}
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);
}
}
3.2 时序图
