Activity Embedding 架构和应用启动流程

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 介入的第一个时机。

核心逻辑:

  1. 早期退出检查 :如果 ActivityOptions 中已经设置了 KEY_LAUNCH_TASK_FRAGMENT_TOKEN,说明 Activity 已经被指定了目标 TF,AE 不需要介入,直接走正常启动流程。

  2. 获取启动者 :获取 launchingActivity(启动新 Activity 的那个 Activity),用于判断是否与启动者分屏。

  3. 决策阶段 :调用 resolveStartActivityIntent() 决定目标 TF。如果返回 null,说明不匹配任何 AE 规则,取消事务;否则继续。

  4. 修改 ActivityOptions :将决策出的 TF token 放入 options.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN, tfToken),告诉系统侧 Activity 应该放到哪个 TF 中。

  5. 继续启动流程 :调用 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() 中:

  1. 验证 WCT 有效性(检查调用者是否是已注册的 Organizer)
  2. 解析 WCT 中的所有操作:
    • CREATE_TASK_FRAGMENT → 创建 TaskFragment 对象并关联到 Organizer
    • SET_RELATIVE_BOUNDS → 设置 TaskFragment 的位置和大小
    • SET_ADJACENT_TASK_FRAGMENTS → 建立分屏关系
    • START_ACTIVITY_IN_TASK_FRAGMENT → 在指定的 TF 中启动 Activity
  3. 启动 Transition(过渡动画)
  4. 生成 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分屏显示

九、关键要点

  1. 拦截时机 :在 Activity 启动前(onStartActivity 回调中)介入,不是拦截 AMS,而是拦截 Instrumentation.ActivityMonitor。

  2. 决策依据 :通过 SplitPairRule 匹配,规则在应用初始化时注册。

  3. TF 创建时机:创建操作先写入 WCT,在 WCT 被 apply 到系统侧时才真正创建。

  4. 关键修改 :通过修改 ActivityOptions 中的 KEY_LAUNCH_TASK_FRAGMENT_TOKEN 告诉系统侧目标 TF。

  5. 双向通信:

    • 应用侧 → 系统侧: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  # 系统侧控制器
相关推荐
Jiude1 小时前
从“超级 Agent”到能力平台:多 Agent 系统的架构取舍
前端·后端·架构
mldong1 小时前
13 套工作流后端共用一个 App 检查更新接口:0 张表,一行 SQL 没写
后端·架构
Thneonl1 小时前
drain 卡了 40 分钟:PDB 才是节点维护的主语
后端·架构
这个DBA有点耶1 小时前
数据库迁移不停机方案:双轨并行技术架构与3TB核心系统落地实践
数据库·架构·dba
哈基米南北1 小时前
Android 输入法框架浅析
源码
哈基米南北1 小时前
Shell Transition 机制详解
源码
京东云开发者1 小时前
从零构建一个生产级记忆型 AI Agent —— AgentScope 项目全景技术与学习指南
后端·架构·ai编程
哈基米南北1 小时前
Android 启动窗口(Starting Window)技术文档
源码
哈基米南北1 小时前
PhoneWindow、DecorView 和 ViewRootImpl 的关系与工作原理
源码