上一篇:我们已经分析了 QSEECOM 的种种局限。为了解决这些问题,高通设计了全新的 SMCInvoke 框架。本篇将深入 SMCInvoke 的核心——MINK 微内核的 Object-Capability 模型,以及如何将其扩展为跨世界的面向对象通信架构。

1. 从 QSEECOM 到 SMCInvoke:为什么需要重新设计?

前一篇我们详细分析了 QSEECOM 的架构与限制——扁平的请求-响应模型、缺乏对象与能力系统、Client 身份验证不足、共享内存安全风险,以及无法适应 Hypervisor 时代的虚拟化需求。
SMCInvoke 并非简单的 API 升级,而是一次架构层面的范式转变。它的核心思想是:将 HLOS↔TZ 通信建立在面向对象的 Capability 系统之上,使得每一次跨世界调用都具备身份可追溯、权限可控制、接口可定义的安全属性。
SMCInvoke 的理论基础来自 QTEE 中的 MINK 微内核——一个 capability-based 的 IPC 框架。

理解 SMCInvoke,必须先理解 MINK。

2. MINK 微内核简介

MINK(Mini-Kernel)是 QTEE 内部的核心微内核,与传统的宏内核不同,它遵循微内核哲学:

  • 内核与域Kernel Domain(特权模式):负责进程、线程、内存管理等最小必要功能
  • 用户域User Domain / Process(用户模式):每个 TA 运行在独立的用户态进程中
  • 域间通信 通过 Object Invocation 实现,这是 MINK 的核心原语
graph TB
  subgraph KD["Kernel Domain(特权模式)"]
    MINK["MINK Kernel"]
  end

  subgraph P1["Process 1(TA-A)"]
    O1["Object A1"]
    O2["Object A2"]
  end

  subgraph P2["Process 2(TA-B)"]
    O3["Object B1"]
  end

  subgraph P3["Process 3(TA-C)"]
    O4["Object C1"]
  end

  O1 -- "invoke" --> MINK
  MINK -- "dispatch" --> O3
  O2 -- "invoke" --> MINK
  MINK -- "dispatch" --> O4
  O3 -- "invoke" --> MINK
  MINK -- "dispatch" --> O2

MINK 多进程 Object Invocation 模型,参考 [4] 80-NH537-4 §3.1-3.5

MINK 类似 L4 或 Mach 的 IPC 机制,但有一个关键区别:消息不发给进程或端口,而是发给具体的 Object

3. MINK 中的 Object 模型

Object 在 MINK 中是一个简单的 C 结构体:

struct Object {
    ObjectInvoke invoke;   // 函数指针:对象的 invoke 处理函数
    ObjectCxt context;     // 上下文指针:传递给 invoke 的第一个参数
};

当一个 Object 被调用时:

int Object_invoke(Object o, ObjectOp op, ObjectArg args[], ObjectCounts k) {
    return o.invoke(o.context, op, args, k);
}

参数说明:

  • op:操作码,标识要调用的方法 ID,由 MINK IDL 自动分配
  • args[]:参数数组,可包含 buffer 参数和 object 参数
  • k:参数计数,通过 ObjectCounts_pack(nBufIn, nBufOut, nObjIn, nObjOut) 构造

4. MINK 的 IPC 机制与代理链

当 Object 与其调用者位于不同域时,MINK 通过 代理链 实现跨域调用:

graph LR
  subgraph "调用者进程"
    Caller["Caller"]
    OutProxy["Outbound Proxy<br/>(minkIPC)"]
  end

  subgraph "内核域"
    MINK["MINK Kernel"]
    InProxy["Inbound Proxy"]
  end

  subgraph "目标进程"
    TargetObj["Target Object"]
  end

  Caller -- "invoke" --> OutProxy
  OutProxy -- "trap 指令" --> MINK
  MINK -- "验证 & 调度" --> InProxy
  InProxy -- "invoke" --> TargetObj

MINK IPC 代理链:Outbound Proxy → Kernel → Inbound Proxy,参考 [4] 80-NH537-4 §3.5、[2] 80-PF777-58 §5.1.6

调用者进程
Outbound Proxy(用户态)
trap 指令
MINK Kernel(内核域,验证参数)
Inbound Proxy(目标进程用户态)
Target Object

  • Outbound Proxy:所有跨域调用的用户态入口,共享同一个 invoke 函数 minKIPC,执行 trap 指令
  • Inbound Proxy:内核调用用户态进程中的 Object 时,挂起调用线程,唤醒目标进程
  • 同域调用:不经过代理,直接调用

这里有三种调用对象:
用户态→内核态(Outbound Proxy)

  • 所有 Outbound Proxy 共享同一个 invoke 函数——minkIPC
  • minkIPC 执行 trap 指令陷入内核
  • 内核验证对象索引和参数后,调用目标 Object 的 invoke 函数

内核态→用户态(Inbound Proxy)

  • 内核需要调用用户态进程中的 Object
  • Inbound Proxy 挂起调用线程,唤醒目标进程
  • 目标进程处理完毕后,唤醒原始调用者

用户态→用户态

  • 链式组合 Outbound + Inbound Proxy,无需特殊代理。

5. Capability(能力)系统

MINK 中的 Object 引用就是 Capability,具有以下安全属性:

属性 说明
不可伪造 进程只能访问已被授予引用的 Object
即引用即授权 持有 Object 引用就拥有调用权
可传递 可通过 invoke 的 Object 参数将引用授予其他域
不泄漏调用者 被调用 Object 无法获知调用者域的属性
不泄漏被调用者 持有引用无法获知 Object 所在进程

这比 QSEECOM 中 “任何拥有 /dev/qseecom 权限的进程都可以通信” 的粗粒度控制有了质的提升。

6. 进程模型

MINK 的进程模型有几个重要特征:

  • 每个进程有独立的地址空间和对象表——对象表类似于 POSIX 的文件描述符表
  • 进程是单线程的——没有用户态线程创建 API
  • 同步 IPC——调用 invoke 时阻塞,直到被调用方返回
  • 进程终止安全:若被调用进程异常终止,invoke 立即返回 Object_ERROR_DEFUNCT

7. SMCInvoke 分层架构全景

7.1 分层架构

在这里插入图片描述

SMCInvoke 将 MINK 的 Object Invocation 机制扩展到 HLOS ↔ TZ 跨世界通信场景,并在中间加入了 Hypervisor 层的安全审查。

graph TB
    subgraph "HLOS Userspace (System)"
        JavaApp["3rd Party Java App"]
        MinkSocket["mink-socket-jni.aar"]
    end

    subgraph "HLOS Userspace (Vendor)"
        SMCClient["SMCInvoke Client<br/>(Native App)"]
        QSEEComClient["QSEECom Compact Client"]
        SSGTZD["SSGTZD Daemon"]
        LibMink["libminkdescriptor.so"]
        QSEEComCompact["libQSEEComCompact.so"]
    end

    subgraph "HLOS Kernel"
        SMCDrv["SMCInvoke Driver<br/>(/dev/smcinvoke)"]
    end

    subgraph "EL2 - Hypervisor"
        HypRouter["Hyp Invoke Router"]
    end

    subgraph "Secure World - TZ"
        TZRouter["TZ Invoke Router"]
        IClientEnv["IClientEnv"]
        IAppLoader["IAppLoader"]
        TA["Trusted Application"]
    end

    JavaApp - "AIDL / Socket" --- SSGTZD
    SMCClient -- "libminkdescriptor" --- SMCDrv
    QSEEComClient -- "libQSEEComCompact" --- SMCDrv
    SSGTZD -- "libminkdescriptor" --- SMCDrv
    SMCDrv -- "SMC" --- HypRouter
    HypRouter -- "验证 & 转发" --- TZRouter
    TZRouter -- "调度" --- IClientEnv
    IClientEnv -- "open" --- IAppLoader
    IAppLoader -- "load" --- TA

图:SMCInvoke 分层架构(参考 [3]80-16234-1 §2、[1]80-PK177-40 § SMCInvoke)

分层列表:

  1. HLOS Userspace(System):Java App + mink-socket-jni.aar
  2. HLOS Userspace(Vendor):Native SMCInvoke Client、SSGTZD 守护进程、libminkdescriptor.so
  3. HLOS Kernel:SMCInvoke Driver(/dev/smcinvoke
  4. EL2 Hypervisor:Hyp Invoke Router(验证参数、翻译地址、隔离 VM)
  5. Secure World:TZ Invoke Router、IClientEnv、IAppLoader、TA

7.2 数据流:一次完整的 Invoke

sequenceDiagram
    participant CA as HLOS Client<br/>(Native App)
    participant Lib as libminkdescriptor.so
    participant Drv as SMCInvoke Driver<br/>(Kernel)
    participant Hyp as Hyp Invoke Router<br/>(EL2)
    participant TZR as TZ Invoke Router
    participant TZObj as TZ Object<br/>(TA)

    CA->>Lib: Object_invoke(obj, op, args, counts)
    Lib->>Drv: ioctl(SMCINVOKE_IOCTL_INVOKE_REQ)
    Drv->>Drv: 构建 SMC 命令记录
    Drv->>Hyp: SMC 调用
    Hyp->>Hyp: 验证参数、翻译地址
    Hyp->>TZR: 转发到 TZ
    TZR->>TZR: 验证、翻译、加锁
    TZR->>TZObj: 调用目标 Object 的 invoke
    TZObj-->>TZR: 返回结果
    TZR-->>Hyp: 返回
    Hyp-->>Drv: 返回
    Drv-->>Lib: ioctl 返回
    Lib-->>CA: Object_invoke 返回值

图:SMCInvoke 完整 Invoke 数据流(参考 [3]80-16234-1 §2、[1]80-PK177-40 § SMCInvoke)

7.3 各层职责

层次 组件 核心职责
HLOS Userspace Native Client / Java App 业务逻辑,调用 MINK Object
HLOS Userspace libminkdescriptor.so 用户态→内核态的桥接库
HLOS Userspace SSGTZD 守护进程,为 Java 层提供 TZ 连接
HLOS Userspace libQSEEComCompat.so QSEECom 兼容层,旧客户端迁移用
HLOS Kernel SMCInvoke Driver 接收 ioctl,构建 SMC 命令记录
EL2 Hyp Invoke Router 验证 SMC 参数、翻译地址、隔离 VM
Secure World TZ Invoke Router 验证、翻译、加锁,调度到目标 Object

8. 三类核心对象

8.1 Remote Object(远程对象)

  • 归属:TZ 侧
  • HLOS 持有:代理引用(Outbound Proxy)
  • 用途:HLOS 调用 TZ 侧的服务
  • 示例IAppLoaderIClientEnv、TA 暴露的 app_getAppObject() 返回的对象

8.2 Callback Object(回调对象)

  • 归属:HLOS 侧
  • TZ 持有:代理引用(Inbound Proxy)
  • 用途:TZ 主动调用 HLOS 侧的服务,替代 QSEECOM 的 Listener
  • 优势:轻量级,不需要注册独立阻塞线程,由 SMCInvoke Driver 的回调机制自动处理

8.3 Memory Object(内存对象)

  • 归属:HLOS 侧
  • 用途:高效共享大块缓冲区(类似 ION fd 但更安全)
  • 特点:TZ 侧直接访问 HLOS 的内存区域,但通过 Object Capability 控制访问范围,不能随意读写任意地址
graph LR
  subgraph "HLOS"
    CA["Client App"]
    CB["Callback Object"]
    MO["Memory Object"]
  end

  subgraph "TZ"
    RO["Remote Object<br/>(IAppLoader, TA...)"]
    TA["TA"]
  end

  CA -- "invoke Remote Obj" --> RO
  RO -- "invoke Callback Obj" --> CB
  MO -- "共享缓冲区" --> TA
  TA -- "读写" --> MO

SMCInvoke 三类对象及其归属关系,参考 [3] 80-16234-1 §5、[4] 80-NH537-4 §3.4-3.6

9. SMCInvoke Driver 与 ioctl 接口

SMCInvoke Driver 暴露 /dev/smcinvoke,主要 ioctl 命令:

IOCTL 功能
SMCINVOKE_IOCTL_INVOKE_REQ 发起 Object Invoke 请求
SMCINVOKE_IOCTL_ACCEPT_REQ 接受来自 TZ 的回调请求
SMCINVOKE_IOCTL_SERVER_REQ 处理 TZ 发起的回调
SMCINVOKE_IOCTL_ACK_LOCAL_OBJ 确认本地对象引用

源码位置:kernel/drivers/soc/qcom/smcinvoke.c

10. Callback Object 取代 Listener 的流程

sequenceDiagram
  participant CA as HLOS Client
  participant Drv as SMCInvoke Driver
  participant TZ as TZ / TA

  CA->>Drv: INVOKE_REQ (携带 Callback Obj)
  Drv->>TZ: SMC 转发
  TZ->>TZ: 处理中...需要 HLOS 服务
  TZ->>Drv: 回调 Callback Obj (SMC)
  Drv->>CA: ACCEPT_REQ (回调请求)
  CA->>CA: 执行回调逻辑
  CA->>Drv: SERVER_REQ (回调响应)
  Drv->>TZ: SMC 转发回调结果
  TZ-->>Drv: 原始 invoke 返回
  Drv-->>CA: INVOKE_REQ 返回

Callback Object 取代 Listener 的回调流程,参考 [3] 80-16234-1 §4.5、[1] 80-PK177-40 §SMCInvoke

  1. HLOS Client 在 invoke TA 时,将一个 Callback Object 作为输入参数传递给 TZ
  2. TZ 在需要 HLOS 服务时,通过标准的 Object_invoke 调用该 Callback Object
  3. SMCInvoke Driver 自动处理回调路由(ACCEPT_REQSERVER_REQ ioctl)
  4. HLOS 侧执行回调逻辑,结果通过 Driver 返回给 TZ

这种模型比 Listener 更轻量、更易于管理多个并发回调。

11. MINK IDL:接口定义语言

QSEECOM 的最大问题之一是缺少 IDL。MINK IDL 提供轻量级接口描述,自动生成 stub 和 skeleton。

IDL 类型系统:

类型分类 类型说明
数值类型 int8/16/32/64, uint8/16/32/64, float32/64,小端字节序
缓冲区 buffer 变长字节序列
对象引用 interface MINK Object 引用
数组 TYPE[] 固定大小成员的有序集合
结构体 struct NAME { ... } 固定大小成员组合
接口 interface NAME { method; error; } 定义方法集合

IDL 示例:

interface ISMCIEExample : IUnknown {
    method sayHello(int32 count, buffer name, buffer out greeting);
    method add(int32 a, int32 b, int32 out result);
    method getCounter(int32 out value);
    error helloFailed;
    error addOverflow;
};

Bundling 优化:MINK IDL 自动将多个小型固定大小参数(≤16 字节)打包到一个 buffer 中,减少 invoke 参数数量,降低跨域通信开销。

// 假设方法有 3 个小型输入参数(各 4 字节):
method foo(int32 a, int32 b, int32 c, buffer data);

// 自动 Bundling:
// args[0] = input buffer: {int32 a, int32 b, int32 c}  ← 打包在一起
// args[1] = input buffer: data                         ← 单独传递

12. 一次完整的 SMCInvoke 调用数据流

HLOS Client (Native App)
  | Object_invoke(obj, op, args, counts)
  v
libminkdescriptor.so
  | ioctl(SMCINVOKE_IOCTL_INVOKE_REQ)
  v
SMCInvoke Driver (kernel)
  | 构建 SMC 命令记录
  | SMC 调用
  v
Hyp Invoke Router (EL2)
  | 验证参数、翻译地址
  v
TZ Invoke Router
  | 验证、翻译、加锁
  | 调用目标 Object 的 invoke
  v
TZ Object (TA)
  | 处理业务逻辑
  | 返回结果
  v 原路返回

SMCInvoke 的架构从根本上解决了 QSEECOM 的诸多局限,将通信模型从 “数据通道” 升级为 “面向对象的能力系统”。

→ 下一篇
了解了 SMCInvoke 的架构后,我们需要从开发者和系统集成者的角度进行最终对比:两个框架在接口、安全模型、迁移成本等方面究竟有何具体差异?高通提供了怎样的兼容层来帮助现有 QSEECOM 客户端平滑迁移?下一篇将给出完整的对比表和迁移指南。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐