Activity Embedding 架构和应用启动流程
创建时间:2026-06-11 代码路径:
frameworks/base/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/
一、AE 整体架构
Activity Embedding 是 Jetpack WindowManager 提供的分屏能力,允许应用在同一个 Task 内将多个 Activity 并排显示。其核心思想是:
- 通过
TaskFragment作为 Activity 的容器 - 应用侧通过
SplitController管理分屏规则 - 通过
WindowContainerTransaction (WCT)与系统侧 WMS 交互 - 最终由
TaskFragmentOrganizerController在系统侧执行实际窗口操作
scss
┌─────────────────────────────────────────────────────────────┐
│ 应用进程 │
│ Activity.startActivity() │
│ ↓ │
│ ActivityStartMonitor (拦截) │
│ ↓ │
│ SplitController (决策) → TransactionManager (事务管理) │
│ ↓ │
│ JetpackTaskFragmentOrganizer │
│ ↓ [跨 Binder: applyTransaction] │
├─────────────────────────────────────────────────────────────┤
│ 系统进程 (WMS) │
│ TaskFragmentOrganizerController │
│ ↓ │
│ 解析 WCT → 创建 TaskFragment → 启动 Activity │
│ ↓ │
│ [回调: onTransactionReady] │
└─────────────────────────────────────────────────────────────┘
二、核心组件
| 组件 | 作用 |
|---|---|
SplitController |
主控制器,管理分屏状态、拦截 Activity 启动 |
ActivityStartMonitor |
继承 Instrumentation.ActivityMonitor,拦截所有 Activity 启动请求 |
TransactionManager |
管理 WindowContainerTransaction 生命周期 |
SplitPresenter |
负责分屏的实际呈现(创建 TF、设置边界等) |
JetpackTaskFragmentOrganizer |
继承 TaskFragmentOrganizer,负责组织 TaskFragment |
WindowContainerTransaction |
携带窗口操作(创建 TF、重托管 Activity 等)的事务对象 |
TaskFragmentOrganizerController |
系统侧,接收应用侧的 WCT 并执行实际窗口操作 |
三、Activity 启动拦截机制
3.1 注册拦截器
SplitController 在构造时注册 ActivityStartMonitor:
java
// SplitController 构造函数
mActivityStartMonitor = new ActivityStartMonitor();
instrumentation.addMonitor(mActivityStartMonitor);
3.2 拦截入口:onStartActivity()
每次 Activity 启动都会触发 ActivityStartMonitor.onStartActivity(),这是 AE 介入的第一个时机。
核心逻辑:
-
早期退出检查 :如果
ActivityOptions中已经设置了KEY_LAUNCH_TASK_FRAGMENT_TOKEN,说明 Activity 已经被指定了目标 TF,AE 不需要介入,直接走正常启动流程。 -
获取启动者 :获取
launchingActivity(启动新 Activity 的那个 Activity),用于判断是否与启动者分屏。 -
决策阶段 :调用
resolveStartActivityIntent()决定目标 TF。如果返回 null,说明不匹配任何 AE 规则,取消事务;否则继续。 -
修改 ActivityOptions :将决策出的 TF token 放入
options.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN, tfToken),告诉系统侧 Activity 应该放到哪个 TF 中。 -
继续启动流程 :调用
super.onStartActivity()走正常流程,系统会检查KEY_LAUNCH_TASK_FRAGMENT_TOKEN并将 Activity 放到指定的 TF 中。
3.3 伪代码
kotlin
onStartActivity(who, intent, options):
if options.has(KEY_LAUNCH_TASK_FRAGMENT_TOKEN):
return super.onStartActivity(who, intent, options) // 已指定TF,不干预
launchingActivity = who (如果是Activity上下文)
startNewTransaction()
targetTF = resolveStartActivityIntent(wct, taskId, intent, launchingActivity)
if targetTF != null:
applyTransaction(wct) // ★ 立即应用WCT到系统侧
options.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN, targetTF.token)
else:
abortTransaction() // 不需要AE,取消事务
return super.onStartActivity(who, intent, options)
四、目标 TF 决策流程
resolveStartActivityIntent() 是 AE 的决策核心,根据预先注册的 SplitPairRule 来判断新 Activity 是否需要分屏。
4.1 决策步骤
scss
resolveStartActivityIntentByRule():
1. 检查 shouldExpand(intent) → 如果应全屏,返回 empty expanded TF
2. 与 launchingActivity 分屏 → getSecondaryContainerForSplitIfAny()
├─ 获取 SplitPairRule
├─ 可复用现有 TF?→ 返回现有容器
└─ 否则 → createNewSplitWithEmptySideContainer() 创建新 TF
3. 与 Task 顶部 Activity 分屏 → getSecondaryContainerForSplitIfAny()
4. 与另一侧顶部 Activity 分屏 → getSecondaryContainerForSplitIfAny()
5. 以上都不匹配 → 返回 null(不需要 AE 介入)
4.2 SplitPairRule 匹配
通过 getSplitRule(primaryActivity, intent) 获取规则,规则在应用初始化时通过 setEmbeddingRules() 注册。规则定义了:
- 哪些 Activity 可以与哪些 intent 分屏
- 分屏比例
- 最小尺寸限制
- finish 行为等
4.3 TF 创建判断
在 getSecondaryContainerForSplitIfAny() 中:
kotlin
if 规则匹配:
if 可以复用现有副容器:
return existingSecondaryContainer
else:
return createNewSplitWithEmptySideContainer() // ★ 创建新TF
可复用的条件:
- 规则匹配且
canReuseContainer()通过 expandSplitContainerIfNeeded()成功- 不需要
clearTop
五、TaskFragment 的创建过程
5.1 创建时机
TF 创建发生在 createNewSplitWithEmptySideContainer() 中:
java
// 创建新的副TF容器
TaskFragmentContainer secondaryContainer =
new TaskFragmentContainer.Builder(mController, taskId, primaryActivity)
.setPendingAppearedIntent(secondaryIntent)
.build();
// 将创建TF的操作写入WCT
createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
primaryActivity.getActivityToken(), secondaryRelBounds, windowingMode);
// 设置分屏关系
setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule, splitAttributes);
关键点 :此时 TF 并未真正创建 ,只是将"创建 TF"这个操作写入了 WindowContainerTransaction。TF 的实际创建发生在 WCT 被应用到系统侧时。
5.2 WCT 中包含的操作
| 操作 | 方法 | 作用 |
|---|---|---|
| 创建 TF | wct.createTaskFragment(params) |
创建新 TaskFragment |
| 设置边界 | wct.setRelativeBounds(...) |
设置 TF 的相对位置 |
| 设置相邻 | wct.setAdjacentTaskFragments(...) |
设置两个 TF 为分屏关系 |
| 启动 Activity | wct.startActivityInTaskFragment(...) |
在指定 TF 中启动 Activity |
| 重托管 Activity | wct.reparentActivityToTaskFragment(...) |
将已有 Activity 移到指定 TF |
| 设置伴侣 | wct.setCompanionTaskFragment(...) |
设置关联 finish 行为 |
六、WCT 到系统侧的交互
6.1 应用侧发起
java
// TransactionManager.TransactionRecord.apply()
void apply(boolean shouldApplyIndependently) {
if (mTaskFragmentTransactionToken != null) {
// 情况A:响应系统回调
mOrganizer.onTransactionHandled(...);
} else {
// 情况B:主动发起新事务(Activity启动属于此)
mOrganizer.applyTransaction(mTransaction, transitionType, shouldApplyIndependently);
}
}
6.2 跨 Binder 调用
java
// TaskFragmentOrganizer.applyTransaction()
wct.setTaskFragmentOrganizer(mInterface); // 设置调用者身份
getController().applyTransaction(wct, transitionType, shouldApplyIndependently, null);
// ↑ 这里通过 Binder 跨进程调用到系统侧的 TaskFragmentOrganizerController
6.3 系统侧接收和执行
在 TaskFragmentOrganizerController.applyTransaction() 中:
- 验证 WCT 有效性(检查调用者是否是已注册的 Organizer)
- 解析 WCT 中的所有操作:
CREATE_TASK_FRAGMENT→ 创建 TaskFragment 对象并关联到 OrganizerSET_RELATIVE_BOUNDS→ 设置 TaskFragment 的位置和大小SET_ADJACENT_TASK_FRAGMENTS→ 建立分屏关系START_ACTIVITY_IN_TASK_FRAGMENT→ 在指定的 TF 中启动 Activity
- 启动 Transition(过渡动画)
- 生成
TaskFragmentTransaction回调到应用侧
七、系统侧回调:onTransactionReady
TF 创建完成后,系统侧会回调 onTransactionReady() 到应用侧:
java
// SplitController.onTransactionReady()
void onTransactionReady(@NonNull TaskFragmentTransaction transaction) {
// 解析 changes
for (change : transaction.getChanges()) {
switch (change.getType()) {
case TYPE_TASK_FRAGMENT_APPEARED:
onTaskFragmentAppeared(wct, taskFragmentInfo);
break;
case TYPE_ACTIVITY_REPARENTED_TO_TASK:
onActivityReparentedToTask(wct, activityStackToken, fragmentToken);
break;
case TYPE_TASK_FRAGMENT_INFO_CHANGED:
onTaskFragmentInfoChanged(wct, taskFragmentInfo);
break;
// ... 其他状态
}
}
// 最终确认
transactionRecord.apply(false);
}
回调时机:在 TF 创建完成、Activity 被成功托管后触发。
八、完整流程总结
scss
【1】用户点击启动应用B
↓
【2】Activity.startActivity(intentB)
↓
【3】ActivityStartMonitor.onStartActivity() 拦截
├─ 检查 KEY_LAUNCH_TASK_FRAGMENT_TOKEN → 已设置则放行
└─ 获取 launchingActivity(应用A的Activity)
↓
【4】resolveStartActivityIntent() 决策
├─ getSplitRule(A, intentB) → 匹配规则?
├─ 匹配成功 → 创建新 TF 或复用现有 TF
└─ 匹配失败 → 取消事务,正常启动
↓
【5】createTaskFragment() 将创建操作写入 WCT
├─ wct.createTaskFragment(params)
├─ wct.setRelativeBounds(bounds)
└─ wct.setAdjacentTaskFragments(primary, secondary)
↓
【6】options.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN, tfToken)
↓
【7】TransactionRecord.apply() → TaskFragmentOrganizer.applyTransaction()
↓ 跨 Binder 调用到系统侧
↓
【8】TaskFragmentOrganizerController.applyTransaction(wct)
├─ 解析 WCT 操作
├─ 创建 TaskFragment(系统侧实际对象)
├─ 设置分屏关系
└─ 启动 Transition
↓
【9】系统回调 onTransactionReady() → 应用侧
├─ 处理 TF APPEARED 事件
└─ 最终确认 apply
↓
【10】super.onStartActivity() 继续正常启动
├─ 系统检查 KEY_LAUNCH_TASK_FRAGMENT_TOKEN
└─ ActivityB 被启动并托管到指定的 TF 中
↓
【完成】应用B与应用A分屏显示
九、关键要点
-
拦截时机 :在 Activity 启动前(
onStartActivity回调中)介入,不是拦截 AMS,而是拦截Instrumentation.ActivityMonitor。 -
决策依据 :通过
SplitPairRule匹配,规则在应用初始化时注册。 -
TF 创建时机:创建操作先写入 WCT,在 WCT 被 apply 到系统侧时才真正创建。
-
关键修改 :通过修改
ActivityOptions中的KEY_LAUNCH_TASK_FRAGMENT_TOKEN告诉系统侧目标 TF。 -
双向通信:
- 应用侧 → 系统侧:
applyTransaction(wct)发送操作指令 - 系统侧 → 应用侧:
onTransactionReady(transaction)回调状态变化
- 应用侧 → 系统侧:
十、相关文件路径
bash
frameworks/base/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/
├── SplitController.java # 主控制器
├── SplitPresenter.java # 分屏呈现
├── TransactionManager.java # 事务管理
├── JetpackTaskFragmentOrganizer.java # TF组织者
└── TaskFragmentContainer.java # TF容器
frameworks/base/core/java/android/window/
└── TaskFragmentOrganizer.java # 系统侧TF组织者基类
frameworks/base/services/core/java/com/android/server/wm/
└── TaskFragmentOrganizerController.java # 系统侧控制器