Android TA/CA 开发与 Binder 各层适配(含通信演示)

RK3572-Android16-记录一次OTA升级失败解决方案 这里记录一次解决RK3576 Android16 OTA 用Recovery 升级失败的一次解决案例,将部分经验作为总结。本次OTA升级耗时了几天,最终是RK给出的解决方案,再加上经验来解决了其它部分问题新平台,高一点的Android版本,可能本身有bug,多请教平台来,不要蒙着干,干不出来的。 阅读详情

Android TA/CA 开发与 Binder 各层适配(含通信演示)

适用:Android 12 ~ 16,TEE 侧以 OP-TEE(GlobalPlatform TEE Client API) 为主线,末尾附 Trusty 对照。
说明:本文的 CA/TA/HAL 代码是可直接照抄的骨架(按 OP-TEE 4.x + Android AIDL HAL 写法),
但未在本机编译验证;第 7 节的运行输出标注为"预期示例",用于对照你自己的环境。


文档地图

全文按 六部分 组织,每部分回答一个问题:

部分章节回答的问题
一 · 导览0 ~ 2有哪两条通道?术语怎么对?文件都在哪一层?
二 · 实现3 ~ 5每层要写什么代码、构建怎么配?
三 · 运行6 ~ 7一次调用怎么走完全程?怎么验证跑通了?
四 · 安全8谁能访问 TEE?域怎么划分?.te 与 neverallow 怎么过?
五 · 适配9 ~ 11Android 12→16 改了什么?大块数据怎么办?Trusty 有何不同?
六 · 排障12 ~ 13报错怎么定位?速查表在哪?

三条阅读路径

你的目的直接读
想知道"每个文件放在哪个分区、谁依赖谁"2.1 → 2.8(分块图解)
想知道"权限 / SELinux 怎么配、neverallow 怎么过"8.1 → 8.9
想从零跑通一次调用4 → 5 → 7

图片索引(源图:android/ta_ca_files_layers.drawio)

图文件出现章节
分层结构全景img/overview.png2.1
块 A:App + Frameworkimg/block1.png2.2
块 B:HAL 层(三个子容器)img/block2.png2.3
块 C:TEE 运行环境 + TAimg/block3.png2.4
块 D:策略与构建img/block4.png2.5
图例与结论img/block5.png2.6

第一部分 · 导览:两条通道、术语与全局结构

0. 先分清两条完全不同的"通道"

新手最容易混淆:Android 侧有两个叠在一起的"跨边界调用",机制完全不同。

通道跨越的边界机制你是谁
Android Binderapp ↔ system_server ↔ vendor HAL 进程binder 驱动 + Parcel + AIDL 桩Binder 客户端/服务端
TEE Session普通世界(REE)↔ 安全世界(TEE)/dev/tee0 ioctl + 共享内存 + SMC/HVCCA(Client Application)/ TA(Trusted Application)

关键点:CA 不是 Binder 服务,TA 更不是。Binder 只负责把请求送到"能调 TEEC 的那个进程"(通常是 vendor HAL 或某 native service);从那里开始才是 TEEC → 内核驱动 → TEE。

App(Java/Kotlin)
   │  Binder(app 侧代理)
   ▼
SystemServer / Framework Service(system 分区)
   │  Binder(AIDL,stable interface)
   ▼
Vendor HAL 进程(/vendor/bin/hw/android.hardware.xxx-service)
   │  ★ 进程内直接调用 libteec(不是 Binder)
   ▼
libteec.so → ioctl(/dev/tee0) → optee.ko → SMC/HVC → TEE OS
   │
   ▼
TA(<uuid>.ta,运行在 TEE 内)

1. 概念对齐:TA / CA / Session / Command

术语含义关键约束
TA(Trusted Application)运行在 TEE 内、有独立地址空间与权限的应用用 UUID 标识;只能通过 TEE 暴露的 API(加密、安全存储、时钟)访问外部资源
CA(Client Application)REE 侧调用 TA 的普通进程需要 libteec + 访问 /dev/tee0 的权限
SessionCA 与 TA 之间的一次会话上下文TEEC_OpenSession 建立,TEEC_CloseSession 关闭;TA 侧 TA_OpenSessionEntryPoint
Command会话内的一次调用TEEC_InvokeCommand(session, cmd_id, op) → TA_InvokeCommandEntryPoint
Param参数传递的 4 个槽位VALUE(≤2×32bit)/ TEMP_MEMREF / WHOLE_MEMREF / PARTIAL_MEMREF
Shared Memory跨世界共享的物理连续/注册内存TEEC_AllocateSharedMemory / TEEC_RegisterSharedMemory

为什么"4 个参数、每个 ≤ 固定大小":TEE 的 SMC 调用寄存器只有有限几个,GP 规范把参数压成"类型 + 4 个值/引用",大块数据必须走共享内存(MEMREF)。


2. 分层结构图:一张图拆成六块看

源文件:android/ta_ca_files_layers.drawio(VS Code 装 draw.io 扩展可直接打开 / 导出 PNG)。
下面 2.1~2.6 是同一张图的 6 个局部截图,可以单独看,也可以回到 2.1 的全景对位。

2.1 全景:六个块怎么分

在这里插入图片描述

这张图从左到右、从上到下是 5 个纵向层容器 + 右侧 2 个配置列:

块图中位置内容参与运行时?
A左上(第 ①② 层)App 进程、system_server 里的系统服务✅ binder 段
B中左(第 ③ 层,最大)AIDL 接口包 / HAL 服务 / CA 库✅ binder 终点 + TEE 起点
C下方(第 ④⑤ 层)TEE 驱动与 /dev/tee0、tee-supplicant、TA✅ TEE session 段
D右侧两列SELinux 策略、构建与打包❌ 只决定"能不能跑 / 装到哪"

看图顺序:2.1 全景 → 顺着箭头走 A→B→C(这就是一次调用的真实路径)→ 出问题时再回来看 D。


2.2 块 A:① App 层 + ② Framework 层

在这里插入图片描述

文件分区 / 进程作用不写会怎样
AndroidManifest.xml/system 或 /data声明 package、uses-permission(如 USE_HELLO)拿不到自定义权限,调用被 SecurityException 拒绝
HelloManager.java同 App 进程App 侧唯一入口:ServiceManager.getService("hello") → IHelloService.Stub.asInterfaceApp 被迫直接碰 libteec(不可接受)
privapp-permissions-hello.xml/system/etc/permissions/特权 app 的权限 allowlistsignature|privileged 权限只给签名不给特权 → 启动即崩
IHelloService.aidl/system(framework 接口)生成 IHelloService.Stub / Stub.Proxy无跨进程桩
HelloService.javasystem_server 进程extends IHelloService.Stub,@EnforcePermission 校验后再 binder 到 HAL任何 app 都能调 TEE(越权)
SystemServer 注册system_server(SELinux 域 system_server)ServiceManager.addService("hello", new HelloService(ctx))getService 返回 null

这一块里只有两条线:

  • 实线 binder:HelloManager ──▶ HelloService(跨进程,App 进程 → system_server)
  • 虚线 实现/注册:IHelloService.aidl ──▶ HelloService(编译期生成 + 运行时注册)

要点:App 层只声明权限、只调 Framework API;任何一层都不该让 App 直接 dlopen("libteec.so")——那等于把 TEE 的全部攻击面暴露给普通应用。


2.3 块 B:③ HAL 层(三个子容器,最容易搞混的一块)

在这里插入图片描述

第 ③ 层内部其实是 三件互相独立的东西,只是都被放在 /vendor 分区:

子容器关键文件性质作用
AIDL 接口包(绿)aidl/android/hardware/hello/IHello.aidl、aidl_api/versions_with_info、Android.bp 里的 aidl_interface纯接口,stability: "vintf"生成 BnHello(服务端)/ BpHello(客户端);aidl_api/ 是冻结快照,改了接口就得升版本
HAL 服务(蓝)service.cpp(BnHello 实现)、Android.bp(cc_binary + init_rc + vintf_fragments)、android.hardware.hello-service.rc、android.hardware.hello.xml(VINTF)一个常驻 vendor 进程注册到 servicemanager、被 init 拉起、向 framework 声明"我提供 hello 1.0"
CA 库(橙)hello_ca.c / libhello_tee_client.c、hello_ta.h、Android.bp(shared_libs: ["libteec"], vendor: true)、libteec.so、hello_ca(CLI)普通 C 库真正调 TEEC_* 的地方

这一块里的三条线:

IHello.aidl ──生成 BnHello──▶ service.cpp      (绿虚线,编译期)
service.cpp ──同进程调用───▶ CA 库             (橙实线,★ 不是 binder!)
CA 库 ──open + ioctl───────▶ /dev/tee0        (红实线,出 REE)

最容易踩的三个坑

  1. 把 CA 当成 binder 服务:CA 只是被 HAL 进程链接进去的一个库(少数方案会单独起 native service 再 binder 封装,但那是外层再包一层)。
  2. IHello.aidl 与 android.hardware.hello.xml 的版本号不一致 → HAL 起不来、service list 里找不到。
  3. hello_ca(CLI)只是调试/产线自测工具(虚线框),不要让它成为正式通路。

2.4 块 C:④ TEE 运行环境 + ⑤ TA 层

在这里插入图片描述

文件 / 节点分区作用备注
/dev/tee0、/dev/teepriv0devtmpfs字符设备节点tee0 给普通 CA 与 tee-supplicant;teepriv0 给特权客户端
optee.kovendor_dlkm 或 vendor_bootTEE 驱动GKI 设备必须放 vendor_dlkm,放错位置 = 驱动不加载
tee-supplicant/vendor/bin/常驻用户态代理:加载 TA、RPMB、文件系统/时间代理它不在时 TEEC_OpenSession 直接失败
/vendor/lib/optee_armtz/<uuid>.ta/vendorTA 二进制(按 UUID 命名)文件名必须与 TA_UUID 一致
ta/src/hello_ta.cTEE OS 内五个入口:Create/Destroy/OpenSession/CloseSession/InvokeCommand命令分发都在 InvokeCommand
user_ta_header_defines.hTEE OS 内TA_UUID / TA_FLAGS / 栈与堆大小与 CA 侧 UUID 必须逐字节一致
ta/Makefile + sub.mk构建机指定 TA_DEV_KIT_DIR、BINARY=<uuid>产物 <uuid>.ta

这一块里的三条线:

  • tee-supplicant ──加载/校验──▶ <uuid>.ta
  • optee.ko ──SMC/HVC 进入安全世界──▶ hello_ta.c
  • ta/Makefile ──编译产物──▶ <uuid>.ta(虚线,构建期)

要点:从 ③ 到 ⑤ 的物理边界只有一处——SMC/HVC 指令。/dev/tee0 之后仍是普通世界的内核态;真正"换世界"发生在 optee.ko 发 SMC 的那一刻。


2.5 块 D:策略与构建(不参与运行时,但决定成败)

在这里插入图片描述

列文件决定什么配错的典型现象
策略(红)hal_hello_default.teHAL 域能否 allow tee_deviceTEEC_ERROR_ACCESS_DENIED + avc: denied
file_contexts/dev/tee0、TA 目录打什么标签ls -Z 显示 u:object_r:device:s0(未打标签)
seapp_contextsApp 落哪个域app 起不来 / 被 neverallow 拦
mac_permissions.xml签名 → seinfo特权权限判定异常
system/sepolicy/{private,public,vendor}策略的分层归属(Treble)vendor 策略引用了 private 类型 → 编译报 neverallow
neverallow(AOSP 内)编译期断言编译直接失败,不会留到运行时
构建(绿)Android.bp编出 aidl_interface / cc_binary / cc_library模块不存在
PRODUCT_PACKAGESHAL 服务、CLI 进镜像镜像里没有可执行文件
PRODUCT_COPY_FILESTA → /vendor/lib/optee_armtzTEEC_ERROR_ITEM_NOT_FOUND
BOARD_VENDOR_SEPOLICY_DIRS策略目录被编进 vendor policy.te 写了却不生效
device.mk / product.mkseinfo、分区归属权限判定 / OTA 异常

两条虚线:hal_hello_default.te ──授予 tee_device──▶ HAL 域;PRODUCT_COPY_FILES ──安装──▶ optee_armtz。


2.6 图例与三条结论

在这里插入图片描述

线型 / 底色含义
黑 / 蓝实线运行时调用(同进程调用 / binder 跨进程)
红实线出 REE:open + ioctl → SMC/HVC
绿 / 灰虚线编译期生成、构建期安装、策略授权
黄底框CA / TA 共用头文件 hello_ta.h
红底容器安全设备与策略

三条结论(记住这三句,这张图就不用背了)

  1. 运行链只有两条:

运行链 ②:TEE session

运行链 ①:binder

binder

binder / AIDL IHello

ioctl

SMC / HVC

同进程直接调用,非 binder

App
HelloManager

system_server
HelloService

HAL 进程
service.cpp

CA 库 / libteec

/dev/tee0

TA
hello_ta.c

  1. 唯一的"共用点"是 hello_ta.h:TA_UUID 与命令号 CA/TA 必须完全一致——这是联调第一大坑(现象:TEEC_ERROR_ITEM_NOT_FOUND 或 BAD_PARAMETERS)。
  2. 策略与构建不参与运行时,但决定"能不能跑、装到哪":配错时表现为 TEEC_ERROR_ACCESS_DENIED(策略)或 TEEC_ERROR_ITEM_NOT_FOUND(没装上 / UUID 不符)。

2.7 反过来看:每层要改什么(适配清单)

层适配内容典型配置/文件
App只调 Framework API;不要直接 dlopen libteecSystemService + 权限声明
Framework Service包装成系统服务,做权限/参数校验frameworks/base/services/...、@EnforcePermission
AIDL HAL稳定接口(stability: "vintf")、版本冻结、vendor: trueaidl_interface { }、versions_with_info
HAL 实现注册到 servicemanager、由 init 拉起、VINTF fragment 声明cc_binary、.rc、manifest.xml
CA(native)链接 libteec、处理 TEEC_* 返回码与 err_originshared_libs: ["libteec"]
内核TEE 驱动(optee.ko)+ /dev/tee0、/dev/teepriv0 节点GKI 场景下放 vendor_dlkm 或 vendor_boot
TEEC 运行环境tee-supplicant 常驻(TA 加载、RPMB、文件系统代理)init.rc 里的 service
TA编译成 <uuid>.ta,装到 /vendor/lib/optee_armtz/TA_DEV_KIT_DIR + BINARY=<uuid>
SELinuxHAL 域访问 tee_device、tee_supplicant socket、tee_data_filehal_xxx_default.te
VINTFHAL 的 manifest.xml 与 framework 的 compatibility_matrix.xml 对齐vintf_fragments
构建vendor 分区、vendor: true、32/64 位一致Android.bp / PRODUCT_PACKAGES

2.8 五层文件总表与依赖关系清单

下面是把 2.2~2.5 四张分块图合并成的一张速查表,按"层 → 目录 → 文件 → 作用"排列。

层目录/分区关键文件作用
① App/system 或 /dataAndroidManifest.xml、HelloManager.java、privapp-permissions-hello.xml声明权限、调 Framework API;特权 app 需 allowlist
② Framework/system(system_server)IHelloService.aidl、HelloService.java、SystemServer 注册包一层系统服务,做权限校验,再 binder 到 HAL
③ HAL(AIDL 接口)/vendoraidl/android/hardware/hello/IHello.aidl、aidl_api/(冻结快照)、Android.bp 里的 aidl_interface稳定接口定义,生成 BnHello/BpHello
③ HAL(服务实现)/vendor/bin/hw/service.cpp、Android.bp(cc_binary + init_rc + vintf_fragments)、*.rc、*.xml(VINTF)注册 Binder 服务、被 init 拉起、声明 HAL 版本
③ CA(客户端库)/vendor/lib*/hello_ca.c / libhello_tee_client.c、hello_ta.h(CA/TA 共用)、Android.bp(shared_libs: ["libteec"])调 TEEC_*;hello_ca CLI 仅用于调试/产线自测
④ TEE 运行环境vendor / vendor_dlkm / vendor_bootoptee.ko、tee-supplicant、/dev/tee0、/dev/teepriv0、/vendor/lib/optee_armtz/<uuid>.ta驱动 + 用户态代理 + 设备节点 + TA 存放目录
⑤ TATEE OS 内ta/src/hello_ta.c、user_ta_header_defines.h(UUID/flags/栈大小)、ta/Makefile + sub.mk五个入口函数 + 命令分发;编译产物 <uuid>.ta
策略system/sepolicy、device/.../sepolicyhal_hello_default.te、file_contexts、seapp_contexts、mac_permissions.xml、neverallow(AOSP 内)决定"谁能访问 TEE、文件打什么标签、进程落哪个域"
构建设备配置PRODUCT_PACKAGES、PRODUCT_COPY_FILES(TA 装到 /vendor/lib/optee_armtz)、BOARD_VENDOR_SEPOLICY_DIRS、device.mk决定"编什么、装到哪、策略从哪来"

关键依赖关系(与图中连线一一对应):

AndroidManifest ──▶ HelloManager ──binder──▶ HelloService(system_server)
IHelloService.aidl ──实现──▶ HelloService
HelloService ──binder + IHello──▶ service.cpp
IHello.aidl ──生成 BnHello──▶ service.cpp
service.cpp ──同进程调用──▶ CA 库 ──▶ libteec.so ──open+ioctl──▶ /dev/tee0
/dev/tee0 ──▶ optee.ko ──SMC/HVC──▶ TA(hello_ta.c)
tee-supplicant ──加载/校验──▶ /vendor/lib/optee_armtz/<uuid>.ta
hello_ta.h ──共用 UUID/命令号──▶ CA 与 TA(两侧必须完全一致)
ta/Makefile ──编译产物──▶ <uuid>.ta ──PRODUCT_COPY_FILES──▶ /vendor/lib/optee_armtz
hal_hello_default.te ──授予 tee_device──▶ HAL 域
file_contexts ──打标签──▶ /dev/tee0、TA 目录

图与表对不上时以图为准(图由 ta_ca_files_layers.drawio 直接导出);三条结论见 2.6。


第二部分 · 实现:TA / CA / HAL / Service / App 五步落地

3. GP TEE Client API 速查(CA 侧必背)

函数作用常见返回值
TEEC_InitializeContext(name, ctx)打开 TEE 上下文(本质 open /dev/tee0)TEEC_SUCCESS / TEEC_ERROR_ITEM_NOT_FOUND
TEEC_OpenSession(ctx, sess, uuid, login, op, res, &origin)与 TA 建立会话TEEC_ERROR_ITEM_NOT_FOUND(TA 没装/未加载)、TEEC_ERROR_ACCESS_DENIED
TEEC_InvokeCommand(sess, cmd, op, &origin)发命令TEEC_ERROR_BAD_PARAMETERS、TEEC_ERROR_NOT_IMPLEMENTED
TEEC_CloseSession / TEEC_FinalizeContext释放—
TEEC_AllocateSharedMemory / TEEC_RegisterSharedMemory / TEEC_ReleaseSharedMemory大块数据传递—
TEEC_RequestCancellation(op)取消阻塞中的调用—

err_origin 很重要:区分是"REE 侧(TEE 客户端库)出错"还是"TA 返回的错"——排障时先看它。

错误码值含义
TEEC_SUCCESS0x00000000成功
TEEC_ERROR_ACCESS_DENIED0xFFFF0001权限/SELinux/会话限制
TEEC_ERROR_BAD_PARAMETERS0xFFFF0006参数类型或个数不对
TEEC_ERROR_ITEM_NOT_FOUND0xFFFF0008TA 不存在 / UUID 不匹配 / 装错路径
TEEC_ERROR_NOT_IMPLEMENTED0xFFFF000C命令号未实现
TEEC_ERROR_COMMUNICATION0xFFFF000E与 TEE 通信失败(驱动/固件问题)
TEEC_ERROR_SHORT_BUFFER0xFFFF0010输出缓冲不足

4. 从零跑通:目录与代码骨架

4.1 目录结构(建议)

hello-tee/
├── ta/
│   ├── Makefile
│   ├── sub.mk
│   ├── include/hello_ta.h          # UUID + 命令号(CA/TA 共用)
│   └── src/hello_ta.c
├── ca/
│   ├── src/hello_ca.c
│   └── Android.bp                  # vendor: true, shared_libs: ["libteec"]
├── hal/
│   ├── aidl/android/hardware/hello/IHello.aidl
│   ├── aidl_api/                   # 冻结版本快照
│   ├── service.cpp
│   ├── Android.bp
│   ├── android.hardware.hello-service.rc
│   └── android.hardware.hello.xml  # VINTF fragment
└── sepolicy/
    └── hal_hello_default.te

4.2 共用头文件 ta/include/hello_ta.h

#define TA_HELLO_UUID \
    { 0x6b8f1c2a, 0x4d3e, 0x4a5b, \
      { 0x9c, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 } }

#define TA_HELLO_CMD_ADD       1   /* in: value a,b ; out: value a = a+b */
#define TA_HELLO_CMD_ECHO      2   /* in/out: temp memref */

4.3 TA 实现 ta/src/hello_ta.c

#include <tee_internal_api.h>
#include <tee_internal_api_extensions.h>
#include "hello_ta.h"

TEE_Result TA_CreateEntryPoint(void) { return TEE_SUCCESS; }
void TA_DestroyEntryPoint(void) { }

TEE_Result TA_OpenSessionEntryPoint(uint32_t pt, TEE_Param p[4], void **sess_ctx)
{
    (void)pt; (void)p;
    *sess_ctx = NULL;
    return TEE_SUCCESS;
}
void TA_CloseSessionEntryPoint(void *sess_ctx) { (void)sess_ctx; }

TEE_Result TA_InvokeCommandEntryPoint(void *sess_ctx, uint32_t cmd,
                                      uint32_t pt, TEE_Param p[4])
{
    (void)sess_ctx;

    switch (cmd) {
    case TA_HELLO_CMD_ADD:
        if (pt != TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
                                  TEE_PARAM_TYPE_VALUE_INPUT,
                                  TEE_PARAM_TYPE_VALUE_OUTPUT,
                                  TEE_PARAM_TYPE_NONE))
            return TEE_ERROR_BAD_PARAMETERS;
        p[2].value.a = p[0].value.a + p[1].value.a;
        return TEE_SUCCESS;

    case TA_HELLO_CMD_ECHO:
        if (pt != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
                                  TEE_PARAM_TYPE_NONE,
                                  TEE_PARAM_TYPE_NONE,
                                  TEE_PARAM_TYPE_NONE))
            return TEE_ERROR_BAD_PARAMETERS;
        /* 示例:把首字节改写,验证共享内存双向可见 */
        if (p[0].memref.size < 1)
            return TEE_ERROR_SHORT_BUFFER;
        ((uint8_t *)p[0].memref.buffer)[0] ^= 0xFF;
        return TEE_SUCCESS;

    default:
        return TEE_ERROR_NOT_IMPLEMENTED;
    }
}

4.4 TA 构建 ta/Makefile

# 交叉编译:需先准备 optee_os 的 ta-dev-kit
CROSS_COMPILE ?= aarch64-linux-gnu-
TA_DEV_KIT_DIR ?= $(OPTEE_OS)/out/arm-plat-*/export-ta_arm64
BINARY := $(shell python3 -c "import uuid;print(uuid.UUID('6b8f1c2a-4d3e-4a5b-9c11-223344556677'))")
CFG_TEE_TA_LOG_LEVEL ?= 4

include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk

产物:<uuid>.ta(已签名)→ 推到设备 /vendor/lib/optee_armtz/。

4.5 CA 实现 ca/src/hello_ca.c

#include <stdio.h>
#include <string.h>
#include <tee_client_api.h>
#include "hello_ta.h"

static const TEEC_UUID kHelloUuid = TA_HELLO_UUID;

int main(void)
{
    TEEC_Context ctx;
    TEEC_Session sess;
    TEEC_Operation op;
    uint32_t origin = 0;
    TEEC_Result res;
    char buf[32] = "hello-tee";

    res = TEEC_InitializeContext(NULL, &ctx);
    if (res != TEEC_SUCCESS) { printf("init ctx fail 0x%x\n", res); return 1; }
    printf("TEEC_InitializeContext: OK\n");

    res = TEEC_OpenSession(&ctx, &sess, &kHelloUuid,
                           TEEC_LOGIN_PUBLIC, NULL, NULL, &origin);
    if (res != TEEC_SUCCESS) {
        printf("open session fail 0x%x origin %u\n", res, origin); return 1;
    }
    printf("TEEC_OpenSession: OK\n");

    /* 命令 1:3 + 5 */
    memset(&op, 0, sizeof(op));
    op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_VALUE_INPUT,
                                     TEEC_VALUE_OUTPUT, TEEC_NONE);
    op.params[0].value.a = 3;
    op.params[1].value.a = 5;
    res = TEEC_InvokeCommand(&sess, TA_HELLO_CMD_ADD, &op, &origin);
    if (res != TEEC_SUCCESS) { printf("invoke add fail 0x%x\n", res); return 1; }
    printf("CMD_ADD: 3 + 5 = %u\n", op.params[2].value.a);

    /* 命令 2:共享内存回环 */
    memset(&op, 0, sizeof(op));
    op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INOUT, TEEC_NONE,
                                     TEEC_NONE, TEEC_NONE);
    op.params[0].tmpref.buffer = buf;
    op.params[0].tmpref.size   = sizeof(buf);
    res = TEEC_InvokeCommand(&sess, TA_HELLO_CMD_ECHO, &op, &origin);
    if (res != TEEC_SUCCESS) { printf("invoke echo fail 0x%x\n", res); return 1; }
    printf("CMD_ECHO: buf[0] = 0x%02x (原 'h'=0x68 取反)\n", (unsigned char)buf[0]);

    TEEC_CloseSession(&sess);
    TEEC_FinalizeContext(&ctx);
    printf("done\n");
    return 0;
}

4.6 CA 的 Android.bp(vendor 侧)

cc_binary {
    name: "hello_ca",
    srcs: ["ca/src/hello_ca.c"],
    vendor: true,                       // 必须:CA 跑在 vendor 侧
    shared_libs: ["libteec"],
    cflags: ["-Wall", "-Werror"],
}

libteec 若来自 AOSP 且未标 vendor_available,需要在你的树里加一个 vendor 版本
(cc_library_shared { name: "libteec", vendor: true, ... }),不要指望从 /system 链接到 vendor 进程。


5. 把 TEE 能力暴露给 App:AIDL HAL + Service

5.1 AIDL 接口 hal/aidl/android/hardware/hello/IHello.aidl

package android.hardware.hello;

@VintfStability
interface IHello {
    int add(int a, int b);       // 返回和;错误抛异常或返回负数
    byte[] echo(in byte[] in);   // 演示大/小块数据
}

5.2 AIDL 定义 hal/Android.bp

aidl_interface {
    name: "android.hardware.hello",
    srcs: ["aidl/android/hardware/hello/IHello.aidl"],
    stability: "vintf",              // 稳定:可跨 system/vendor 边界
    vendor: true,
    versions_with_info: [{ version: "1", imports: [] }],
}

5.3 HAL 实现(调用 CA 的同一套 TEEC 代码)

// hal/service.cpp(节选)
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <aidl/android/hardware/hello/BnHello.h>

using aidl::android::hardware::hello::BnHello;

class Hello : public BnHello {
  public:
    ndk::ScopedAStatus add(int32_t a, int32_t b, int32_t* out) override {
        // 这里调用 4.5 中的 TEEC 逻辑(可抽成 hello_tee_invoke_add())
        int32_t sum = 0;
        int rc = hello_tee_invoke_add(a, b, &sum);   // 内部 TEEC_*
        if (rc != 0) return ndk::ScopedAStatus::fromServiceSpecificError(rc);
        *out = sum;
        return ndk::ScopedAStatus::ok();
    }
};

int main() {
    ABinderProcess_setThreadPoolMaxThreadCount(0);
    std::shared_ptr<Hello> hello = ndk::SharedRefBase::make<Hello>();
    const std::string name = std::string() + Hello::descriptor + "/default";
    binder_status_t st = AServiceManager_addService(hello->asBinder().get(), name.c_str());
    if (st != STATUS_OK) return 1;
    ABinderProcess_joinThreadPool();
    return 0;
}

5.4 init 与 VINTF

# hal/android.hardware.hello-service.rc
service vendor.hello-default /vendor/bin/hw/android.hardware.hello-service
    class hal
    user system
    group system
    seclabel u:r:hal_hello_default:s0
<!-- hal/android.hardware.hello.xml(VINTF fragment) -->
<manifest version="1.0" type="device">
  <hal format="aidl">
    <name>android.hardware.hello</name>
    <version>1</version>
    <fqname>IHello/default</fqname>
  </hal>
</manifest>
cc_binary {
    name: "android.hardware.hello-service",
    vendor: true,
    srcs: ["hal/service.cpp"],
    shared_libs: ["libbinder_ndk", "libteec", "android.hardware.hello-V1-ndk"],
    init_rc: ["hal/android.hardware.hello-service.rc"],
    vintf_fragments: ["hal/android.hardware.hello.xml"],
}

5.5 Framework / App

  • Framework:写一个 HelloManager(SystemService),通过 IServiceManager::waitForDeclaredService("android.hardware.hello.IHello/default") 拿代理,加 @EnforcePermission。
  • App:只调 HelloManager.add(),不要在 App 里 dlopen("libteec.so") —— 一是 SELinux 不允许,二是 App 进程拿不到 /dev/tee0。

第三部分 · 运行:一次调用的完整时序与验证

6. 一次完整调用的时序

TA(TEE 内)optee.kolibteec(进程内)Vendor HAL 进程Framework ServiceApp(Java/Kotlin)TA(TEE 内)optee.kolibteec(进程内)Vendor HAL 进程Framework ServiceApp(Java/Kotlin)binder transact(add 3, 5)权限校验(@EnforcePermission)binder transact(AIDL IHello.add)TEEC_InvokeCommand(同进程函数调用)ioctl(/dev/tee0, OPTEE_IOCTL_INVOKE)SMC/HVC 进入安全世界TA_InvokeCommandEntryPoint → 计算结果返回 TEE_SUCCESS + 参数回写ioctl 返回结果写入 out 参数binder reply返回 sum

注意:共享内存(MEMREF)的数据不走 binder——数据在 /dev/tee0 的 ioctl 里由内核映射;
但 HAL → App 这一段的 byte[] 仍然走 binder,受 1MB 事务上限约束(见第 10 节)。


7. 演示与验证

7.0 没有板子时:先在 QEMU 上把"TEE 通信"跑通

这一层验证的是最底下的 CA ↔ TA 通路(与 Android 无关),用来排除"代码写错"还是"平台没配好":

# 1) 取 OP-TEE 官方工程(qemu_v8)
mkdir optee && cd optee
repo init -u https://github.com/OP-TEE/manifest.git -m qemu_v8.xml
repo sync -j8

# 2) 编译工具链 + 全栈(optee_os / optee_client / ATF / U-Boot / Linux)
make -j"$(nproc)" toolchains
make -j"$(nproc)"

# 3) 启动 QEMU:normal world 进 Linux,tee-supplicant 由 init 拉起
make run

进入 normal world 的 Linux 后:

ls -l /dev/tee*                       # /dev/tee0 /dev/teepriv0
optee_example_hello_world             # 官方示例:TA 自增计数器
xtest 2>/dev/null | tail -3           # 全套 TEE 用例(可选,验证平台完整性)

预期输出(示例,具体文案随 optee_examples 版本略有差异)

Invoking TA to increment 0
TA incremented value to 1
Invoking TA to increment 1
TA incremented value to 2

这一步通过 = TA 加载、会话、命令、参数回传、shared memory 全部正常;
之后再把同样的 TEEC 代码搬进 Android HAL,剩下要解决的只有"权限 + 打包 + SELinux"。

7.1 最快验证:直接在设备上跑 CA(不经过 binder)

# 1) 推 TA 与 CA(需 root 或 debuggable)
adb push <uuid>.ta /vendor/lib/optee_armtz/
adb push hello_ca     /data/local/tmp/
adb shell chmod 755 /data/local/tmp/hello_ca

# 2) 确认 TEE 设备与 supplicant 在跑
adb shell ls -l /dev/tee0 /dev/teepriv0
adb shell getprop | grep -i tee
adb shell ps -A | grep tee_supplicant

# 3) 跑(先确认 SELinux 允许,见第 8 节)
adb shell /data/local/tmp/hello_ca

预期输出(示例)

TEEC_InitializeContext: OK
TEEC_OpenSession: OK
CMD_ADD: 3 + 5 = 8
CMD_ECHO: buf[0] = 0x97 (原 'h'=0x68 取反)
done

7.2 走完整 binder 链路

adb shell service list | grep hello          # 应看到 android.hardware.hello.IHello/default
adb shell cmd hello add 3 5                  # 若你实现了 cmd 子命令
adb logcat -s HelloHal HelloService          # HAL/Framework 侧日志
adb shell dmesg | grep -i optee              # 驱动层:会话/命令、SMC 次数

预期输出(示例)

# service list
... android.hardware.hello.IHello/default ...
# cmd hello add 3 5
8
# dmesg
[  12.345678] optee: initialized driver
[  20.112233] optee: session 00000000-... opened
[  20.113001] optee: invoke cmd 1

7.3 自检清单

检查项命令/位置期望
TEE 驱动加载lsmod | grep optee、dmesg | grep optee有 initialized
设备节点ls -lZ /dev/tee0存在,SELinux 标签为 tee_device
TA 是否装对ls /vendor/lib/optee_armtz/有 <uuid>.ta,UUID 与 CA 一致
supplicantps -A | grep tee_supplicant常驻
权限dmesg/logcat 里的 avc: denied无(或按第 8 节补策略)
HAL 注册service list、dumpsys有 IHello/default

第四部分 · 安全:权限模型、SELinux 域与 neverallow

8. 权限模型与域划分(Android 权限 / SELinux 域 / TEE 登录)

8.1 三层权限,各管一段,缺一不可

层管什么谁来配失败表现
Android 权限app 有没有资格"发起这个请求"AndroidManifest + @EnforcePermissionSecurityException
SELinux 域进程能不能 open /dev/tee0、连 supplicant、注册 binder 服务sepolicy/*.te、file_contextsavc: denied → TEEC_ERROR_ACCESS_DENIED
TEE login 身份TA 认不认这个调用方(uid/gid/application id)TEEC_OpenSession(login, ...) + TA 侧校验TA 返回 TEE_ERROR_ACCESS_DENIED

记忆法:权限决定"能不能提请求",域决定"能不能碰设备",login 决定"TA 认不认你"。

8.2 Android 侧的应用域划分(UID + SELinux domain)

应用/进程形态UID 来源典型 SELinux 域能否访问 TEE 设备
三方应用(Play 安装)u0_aXXuntrusted_app(按 targetSdk 细分 untrusted_app_27/29/30/31…)❌ 默认禁止
预装、非特权system/u0_aXXsystem_app(platform 签名)❌ 默认禁止
预装特权(priv-app)systempriv_app❌ 默认禁止(除非显式加规则,且不推荐)
platform 签名普通应用u0_aXXplatform_app❌
system_serversystemsystem_server❌(应通过 HAL)
隔离进程(isolatedProcess)无名 UIDisolated_app❌
Instant App动态 UIDephemeral_app❌
厂商 HALsystem/vendorhal_xxx_default✅(唯一常见被授权方)
tee-supplicantsystem/root独立域(tee_supplicant 或厂商自定义)✅(它是 TEE 的代理,不是 TA 客户端)
su / root 调试rootsu调试可用,不可作为产品方案

域是怎么被选中的:不是由包名决定,而是 seapp_contexts 按条件匹配(seinfo、isPrivApp、isSystemServer、minTargetSdkVersion…):

# system/sepolicy/private/seapp_contexts(示意,实际条目随版本不同)
user=_app isPrivApp=true                      domain=priv_app        type=privapp_data_file levelFrom=user
user=system seinfo=platform                   domain=system_app      type=system_data_file  levelFrom=user
user=_app isEphemeralApp=true                 domain=ephemeral_app   type=app_data_file     levelFrom=user
user=_app minTargetSdkVersion=29              domain=untrusted_app_29 type=app_data_file    levelFrom=user
user=_app                                     domain=untrusted_app   type=app_data_file     levelFrom=user

结论:"换个包名/换个签名"不会自动获得 TEE 权限;要新域就必须改 seapp_contexts + 写 .te + 过 neverallow。

8.3 Android 权限类型(决定"谁可以请求")

类型声明方式谁可以拿到用途
normal<permission android:protectionLevel="normal">任意 app,安装即得低风险能力
dangerous同上 dangerous需运行时申请 + 用户授权隐私类(相机、位置…)
signaturesignature与声明者同签名的 app平台内部能力
signature|privileged组合平台签名 或 预装特权 app(+ allowlist)系统级但非核心
internal不导出仅系统内部不建议用于厂商能力

特权应用要显式 allowlist(否则开机报 privapp-permissions 违规):

<!-- vendor/etc/permissions/privapp-permissions-vendor-hello.xml(路径随分区/版本,需核对) -->
<permissions>
  <privapp-permissions package="com.vendor.hello">
    <permission name="android.permission.HELLO_TEE_ACCESS"/>
  </privapp-permissions>
</permissions>

Framework 侧做二次校验:

@RequiresPermission("android.permission.HELLO_TEE_ACCESS")
public int add(int a, int b) { ... }

8.4 核心规则:谁能访问 TEE 设备

规则说明
只给 HAL 域allow hal_xxx_default tee_device:chr_file rw_file_perms;,不要给 appdomain/system_app
appdomain 默认被 neverallow 挡住AOSP 用 neverallow 禁止通用应用域直接访问 TEE 设备(条目随版本变化,可在 system/sepolicy 中搜 tee_device 核对)
system_server 不直连system_server 通过 binder 调 HAL,避免把 TEE 权限扩散到系统进程
一域一能力多个 HAL 需要 TEE 时,共用同一域或各自加规则,不要复用 system_app 域
调试用 root 不算方案su 下能跑通 ≠ 产品可用;必须按正式域验证

8.5 SELinux 规则模板(HAL 扮演 CA)

# sepolicy/hal_hello_default.te(示意,宏名/类型名需按你树的定义调整)
type hal_hello_default, domain;
type hal_hello_service, service_manager_type;

hal_server_domain(hal_hello_default, hal_hello)
hal_client_domain(system_server, hal_hello)

# 1) 访问 TEE 字符设备
allow hal_hello_default tee_device:chr_file rw_file_perms;

# 2) 与 tee-supplicant 通信(TA 加载、RPMB、文件代理)
allow hal_hello_default tee_supplicant:unix_stream_socket connectto;
allow hal_hello_default tee_data_file:dir r_dir_perms;
allow hal_hello_default tee_data_file:file r_file_perms;

# 3) HAL 服务注册
add_service(hal_hello_default, hal_hello_service)
# file_contexts(标签定义,类型名按你的树)
/dev/tee0                      u:object_r:tee_device:s0
/dev/teepriv0                  u:object_r:tee_device:s0
/vendor/lib/optee_armtz(/.*)?  u:object_r:tee_data_file:s0

若 TA 目录在 /vendor/lib/optee_armtz,读该目录本身(dir r_dir_perms)和读 .ta 文件是两条规则,缺一条就 avc denied。

8.6 TEE 侧:login method 与身份校验

login 方式传给 TA 的身份适用
TEEC_LOGIN_PUBLIC无身份(匿名)公开能力(如随机数)
TEEC_LOGIN_USER调用进程 uid按用户隔离的数据
TEEC_LOGIN_GROUP调用进程 gid按组授权(推荐给 HAL:HAL 用固定 gid)
TEEC_LOGIN_APPLICATIONCA 的 application identity只允许某个受信 CA

TA 侧校验示例(TEE_GetPropertyAsIdentity):

TEE_Identity id;
TEE_Result res = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT,
                                           TEE_PROPSET_CURRENT_CLIENT, &id);
if (res != TEE_SUCCESS || id.login != TEE_LOGIN_GROUP || id.uuid != kAllowedUuid)
    return TEE_ERROR_ACCESS_DENIED;

推荐组合:TEEC_LOGIN_GROUP + HAL 进程固定 gid + TA 校验 gid/uuid,形成"Android 层 SELinux + TEE 层身份"的双重门。

8.7 判定树:一个能力该放哪一层

某个功能需要 TEE 能力?
├─ 是 → 由厂商 HAL 提供 AIDL 接口;app 只拿 normal/dangerous 权限
│        (HAL 域访问 tee_device,TA 校验 login)
└─ 必须让 app 进程自己调 libteec?
     ├─ 否 → 结束(强烈推荐这条路)
     └─ 是 → 该 app 需同时满足:
              ① 预装(system/vendor 分区)
              ② 独立 SELinux 域(seapp_contexts + .te + 过 neverallow)
              ③ 被授予 tee_device 访问
              ④ TA login 白名单接受它
              ⑤ 接受"绕过 HAL 校验"的安全评审

8.8 常见坑

现象原因处理
avc: denied { open } scontext=... tcontext=... tee_device域没权限在该域加规则,不要全局放开
只有 read 被拒、open 通过tee_data_file 只有 dir 规则补 file r_file_perms
加了规则仍 denied进程实际不在你以为的域ps -Z 看真实 scontext;检查 seapp_contexts 优先级
开机 privapp-permissions 报错特权 app 权限未入 allowlist补 privapp-permissions-*.xml
HAL 起来了但 app 调不到缺 binder_call(app_domain, hal_hello) 或服务名不匹配看 dmesg 的 avc: denied { call }
想图省事设 permissive会掩盖真实权限问题只在调试期临时用,提交前必须移除
vendor 特权 app 权限拿不到Android 11+ 对 vendor 特权应用有额外限制按你的版本核对 vendor 特权应用策略

8.9 .te 与 neverallow 到底是什么

上面 8.7 提到"独立域 = seapp_contexts + .te + 过 neverallow"。这三样东西经常被混着说,这里拆开讲清楚。

8.9.1 .te = SELinux 策略源文件(Type Enforcement)
# sepolicy/hal_hello_default.te
type hal_hello_default, domain;                    # ① 定义一个域(type)
type hal_hello_service, service_manager_type;

hal_server_domain(hal_hello_default, hal_hello)    # ② 宏:把域加入 hal_hello 的 attribute 家族
hal_client_domain(system_server, hal_hello)        #    允许 system_server 调它

allow hal_hello_default tee_device:chr_file rw_file_perms;   # ③ 具体许可:谁 对 什么 做什么

一条 allow 的语义固定为三段:源域(scontext)→ 目标类型(tcontext)→ 权限(perm)。缺一段就不是完整规则。

一套策略不只 .te,而是四个文件配合:

文件作用你通常要改吗
*.te域/类型/allow 规则✅ 要
file_contexts给文件打标签(/dev/tee0 → tee_device)✅ 要(新设备节点/新 TA 目录)
seapp_contexts进程按条件选域(app → untrusted_app / priv_app …)仅当你要开新 app 域
mac_permissions.xml按签名给 app 分配 seinfo(喂给 seapp_contexts)仅当新 seinfo

目录结构(Treble 三分区):

system/sepolicy/
├── private/     # 平台私有策略 + 绝大多数 neverallow
├── public/      # 对外导出的 type(vendor 才能引用)
├── vendor/      # vendor 策略
└── prebuilts/api/<ver>/   # 各 API 级别快照(兼容性校验)

device/<vendor>/<board>/sepolicy/   # 板级策略(BOARD_VENDOR_SEPOLICY_DIRS)
8.9.2 策略是怎么"编出来"的

编译期校验

违反断言

*.te / *.cil 源文件

checkpolicy / secilc

file_contexts / seapp_contexts / mac_permissions.xml

build 脚本合并

plat_sepolicy.cil

vendor_sepolicy.cil

sepolicy 二进制
(system + vendor 各一份)

neverallow 断言

❌ build 失败

关键:neverallow 参与的是编译这一步,不参与运行时判定。

8.9.3 neverallow = 构建期的"禁止断言"
# system/sepolicy/private/...(示意,实际文本随版本不同)
neverallow { appdomain -shell } tee_device:chr_file *;
  • 含义:除 shell 外,任何 appdomain 都不允许访问 tee_device;
  • 它不是给内核执行的规则,而是给 checkpolicy / secilc 编译器看的约束;
  • 只要你的 .te(含宏展开后的结果)推出了被禁止的访问,编译直接失败:
libsepol.report_failure: neverallow on line 123 of system/sepolicy/private/xxx.te
  (or line 456 of .../neverallow) violated by
  allow untrusted_app tee_device:chr_file { read write };
libsepol.check_assertions: 1 neverallow failures occurred

所以"加 allow 能生效"和"加 allow 能编译过"是两件事:前者是运行时,后者是构建期。neverallow 的作用就是防止 OEM 用一条 allow 把平台安全模型悄悄打穿。

8.9.4 "过 neverallow"的六种做法
#做法说明
①换域,而不是硬加权限TEE 访问放 hal_xxx_default(HAL 域);这是唯一架构正确的路
②用官方宏,别手写属性hal_server_domain / hal_client_domain / app_domain,宏负责把域加入正确的 attribute
③新域不要继承 appdomain若必须让预装 app 直连,定义独立域(如 vendor_tee_app),用 type vendor_tee_app, domain;,不要挂到 appdomain 上
④跨分区引用要导出vendor 引用 system 的 tee_device 时,该 type 必须在 system/sepolicy/public/ 可见
⑤不要改 AOSP 的 neverallow会造成 CTS/GTS 与兼容性校验失败;确有必要要走上游评审
⑥本地先跑编译m sepolicy / m vendor_sepolicy.cil,报错行号直接指向被违反的 neverallow
8.9.5 一个"合法路径"示例(预装 TEE app)
# 1) 新域,不挂 appdomain
type vendor_tee_app, domain;
allow vendor_tee_app tee_device:chr_file rw_file_perms;

# 2) seapp_contexts:只把特定 seinfo 的包切到这个域
#    user=_app seinfo=vendor_tee domain=vendor_tee_app type=app_data_file levelFrom=user

# 3) mac_permissions.xml:给该签名分配 seinfo=vendor_tee

即使这样能编译通过,安全评审仍会问"为什么不走 HAL"——因为它绕过了 HAL 的参数校验与限流。
这就是 8.7 判定树把"app 直连 TA"列为最后选项的原因。

8.9.6 本地验证命令
# 只编策略(最快发现 neverallow 冲突)
m sepolicy
m vendor_sepolicy.cil

# 设备上确认某进程真实落在哪个域(最常用来纠正"我以为它在 hal_xxx")
adb shell ps -Z | grep hello
adb shell ls -Z /dev/tee0

# 查某域到底有没有这条权限(需策略工具 sesearch)
sesearch --allow -s hal_hello_default -t tee_device out/.../sepolicy
8.9.7 一句话总结

.te 是"我要什么权限"的声明,neverallow 是"平台不允许出现什么"的断言。
你写的规则必须同时满足两边——撞上 neverallow 就得改架构(把访问挪到 HAL 域 / 新开域并评审),
而不是"缺什么加什么"。


第五部分 · 适配与演进:版本、性能、TEE 方案对比

9. 版本适配要点(Android 12 → 16)

版本与 TA/CA 相关的关键变化你要做的事
12新 HAL 必须 AIDL(HIDL 停止新增);Treble VINTF 强制从第一天就用 aidl_interface + stability: "vintf"
13AIDL 版本冻结实践成熟;vendor.api 校验更严提交 aidl_api/ 冻结快照,改接口必须升版本
14AIDL HAL 全面替代 HIDL;GKI 下 vendor 模块化TEE 驱动作为 vendor 模块(vendor_dlkm/vendor_boot)
15VNDK 逐步下线;支持 16KB 页vendor 侧自带 libteec/依赖;native 库按 16KB 对齐
1616KB 页设备增多;更强调 vendor/system 依赖隔离确认 .so 用 -Wl,-z,max-page-size=16384 构建

16KB 页对齐(Android 15+ 设备必须):

cc_binary {
    name: "hello_ca",
    vendor: true,
    ldflags: ["-Wl,-z,max-page-size=16384"],
    ...
}

VNDK 下线的影响:不要再依赖 /system/lib64 里的库,libteec、libbinder_ndk 等要么在 vendor 侧自带,
要么使用可 vendor 使用的稳定库(NDK/AIDL NDK backend)。


10. 大块数据与性能

问题原因做法
HAL 返回 byte[] 超过 ~1MB 报 TransactionTooLargeExceptionBinder 事务缓冲按进程共享,约 1MB用 SharedMemory(ashmem/memfd)+ ParcelFileDescriptor,或分块
TEE 侧大数据SMC 参数只有 4 个槽、每槽有限TEEC_AllocateSharedMemory / MEMREF_PARTIAL,注意 4KB/页对齐
频繁调用开销每次 InvokeCommand 都是 ioctl + SMC会话复用(不要每次 OpenSession);批量命令;共享内存常驻
并发多线程共享同一 session用 TEEC_OpenSession 的 TEEC_MULTI_SESSION/每线程独立会话,或 CA 侧加锁

11. OP-TEE 与 Trusty 的差异(Android 官方 TEE)

维度OP-TEE(GP 路线)Trusty(Google 路线)
客户端 APIGP TEEC_*(libteec)libtrusty(tipc_connect/tipc_send/tipc_read)
设备节点/dev/tee0、/dev/teepriv0/dev/trusty-ipc-dev0
TA 形态<uuid>.ta 动态加载编译进 Trusty 镜像或作为 app 加载(trusty/user/app/...)
安全存储supplicant + RPMB/文件系统storage 服务代理 + RPMB
Android 集成自定义 HAL / vendor 服务通常由 Keymaster/Keymint、Gatekeeper 等官方 HAL 使用
适配思路换 CA 侧 API 层;TA 入口函数换成 tipc 消息循环—

结论:"Binder 各层适配"的思路两者一致(App → Service → HAL → TEE),差别只在 HAL 里调的是 TEEC_* 还是 tipc_*。


第六部分 · 排障与速查

12. 常见错误与排障

现象最可能原因定位
TEEC_InitializeContext 返回 0xFFFF0008/dev/tee0 不存在 / 驱动没加载ls /dev/tee*、dmesg | grep optee
TEEC_InitializeContext 返回 0xFFFF0001SELinux 拒绝 openavc: denied 日志
TEEC_OpenSession 返回 0xFFFF0008TA 未安装 / 路径不对 / UUID 不一致ls /vendor/lib/optee_armtz/、比对 UUID 字节序
OpenSession 返回 0xFFFF0001TA 的 TA_FLAGS 限制 / 登录方式不对检查 TA_FLAG_*、TEEC_LOGIN_PUBLIC
InvokeCommand 返回 0xFFFF0006paramTypes 与 TA 期望不一致两侧打印 pt 对比
InvokeCommand 返回 0xFFFF000C命令号未实现检查 cmd 常量与 TA 的 switch
service list 里没有 HALinit 没拉起 / VINTF 不匹配 / 注册名错ps -A | grep hello、logcat | grep -i vintf
App 调不到Framework 服务没加权限或没注册dumpsys activity service、SELinux binder 规则
只有 32 位 CA 能跑、64 位不行.so 架构不一致(libteec 32/64 混用)file hello_ca、getprop ro.product.cpu.abi

13. 一页速查

边界:App ─binder→ Service ─binder→ HAL ─libteec→ /dev/tee0 ─SMC→ TA
核心 API:TEEC_InitializeContext → OpenSession → InvokeCommand → Close/Finalize
四个参数:VALUE(2×32b) / TEMP_MEMREF / WHOLE_MEMREF / PARTIAL_MEMREF
TA 五入口:Create/DestroyEntryPoint、Open/CloseSessionEntryPoint、InvokeCommandEntryPoint
必查项:/dev/tee0 权限、TA 在 /vendor/lib/optee_armtz、tee-supplicant 在跑、SELinux avc
版本要点:AIDL+VINTF 稳接口、VNDK 下线自带库、16KB 页对齐、TEE 驱动走 vendor 模块
大块数据:TEE 侧用共享内存;binder 侧用 SharedMemory(>1MB 必踩)
AutoSAR开发实战:如何用Matlab/Simulink从零搭建SWC组件(附完整代码示例) 本文详细介绍了使用Matlab/Simulink从零开发AutoSAR SWC组件的全流程,包括环境配置、ARXML文件导入、算法模型开发、代码生成与集成验证等关键步骤。通过实战案例和完整代码示例,帮助开发者掌握AutoSAR标准下的软件开发技术,提升汽车电子系统的开发效率。 阅读详情

相关推荐

Moodle平台题库建设技术

Moodle平台题库建设技术简述1新的改变1功能快捷键1合理的创建标题,有助于目录的生成1如何改变文本的样式1插入链接与图片1如何插入一段漂亮的代码片1生成一个适合你的列表1创建一个表格1设定内容居中、居左、居右1SmartyPants1创建一个自定义列表1如何创建一个注脚注释也是必不可少的1KaTeX数学公式1新的甘特图功能,丰富你的文章1UML 图表1FLowchart流程图1导出与导入导出1...

lxf78的博客 4534

Binder fuzz安全研究

扣吧力作,欢迎转载,转载请注明来自colbert337.github.io 最近扣吧忙成狗了,好久没更新博客,对不住大家了,今天趁天气暖和点,来一篇干货。 由于好久没搞Android了,写得不专业的地方,请见谅哈。 0.为什么要研究Binder fuzz 以目前最热门的指纹方案为例。 TZ:Trustzone(请自行百度) CA:Trustzone框架中的Clinet App

omnispace的博客 2714

鸿蒙【ArkTS】使用TS装饰器封装网络请求HTTP

在HarmonyOS应用开发中,通过HTTP访问网络,可以使用官方提供的@ohos.net.http模块。但是官方提供的直接使用不太好使用,需要封装下才好。这里采用TS的装饰器实现AOP效果 完成前后端接口风格的统一

weixin_60376559的博客 5611

农民斗地主——Binder fuzz安全研究

扣吧力作,欢迎转载,转载请注明来自colbert337.github.io 最近扣吧忙成狗了,好久没更新博客,对不住大家了,今天趁天气暖和点,来一篇干货。 由于好久没搞Android了,写得不专业的地方,请见谅哈。 0.为什么要研究Binder fuzz 以目前最热门的指纹方案为例。 TZ:Trustzone(请自行百度) CA:Trustzone框架中的Clinet App

omnispace的博客 1186

LiblibAI新手教程:从零开始训练你的第一个LoRA模型(保姆级指南)

本文提供LiblibAI平台上从零开始训练LoRA模型的保姆级教程,涵盖数据准备、参数优化到效果调优全流程。详细解析LoRA技术优势,包括云端计算资源、自动化预处理工具等,帮助新手快速掌握自定义模型训练技巧,实现高效AI绘画创作。

dell8的博客 621

手把手教你用STM32标准库写一个能OTA升级的Bootloader(附完整代码)

本文详细介绍了如何使用STM32标准库开发支持OTA无线升级的Bootloader系统,包括Flash分区规划、Bootloader核心实现、无线升级流程及安全校验机制。通过实战代码示例,帮助开发者快速掌握STM32固件升级技术,提升物联网设备的远程维护能力。

weixin_30181209的博客 263

openvela frameworks 顶层仓库全景解析:24 个子仓库的服务框架地图与构建集成

> 导读:本文以 openvela 操作系统服务框架的承载仓库 `frameworks` 为切入点,系统梳理其"顶层仓库(super repository)管理多个子仓库"的组织方式,完整解析蓝牙、电话、图形、多媒体、运行时应服务、TypeScript/Wasm 运行时、安全(TEE/OPTEE)与系统基础服务等 24 个子仓库的职责边界,并结合仓库构建文件说明其接入整体构建体系的机制。读完本文,

gitblog_00199的博客 417

解决 TensorFlow 和 Keras 的 Python 版本兼容问题:详细技术指南

本文提供了TensorFlow和Keras与Python版本不兼容问题的完整解决方案。通过版本对照表指出不同TensorFlow版本对应的Python支持范围,强调2.13.x仅支持Python 3.9-3.11,且不兼容Python 3.12+。给出最佳实践建议:使用虚拟环境管理项目依赖,推荐venv或conda创建独立环境;指导正确安装TensorFlow和Keras版本,建议优先使用tf.keras避免冲突;针对常见报错如DLL加载失败、模块导入错误等提供具体解决方法。最后给出一个在兼容环境中运行的M

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1664

Folia 全屏歌词播放器安装指南:10 分钟跑通

Folia 是一款以全屏沉浸式歌词动画为核心的音乐播放器,支持网易云音乐、QQ 音乐、酷狗、Navidrome 和本地音乐库,歌词匹配、AI 配色主题、多种全屏歌词排版都是它的基本盘。这篇指南帮你把桌面版装到 Windows、macOS 或 Linux 上:网络和手速正常的话,10 分钟内从下载到第一首带歌词的歌在整块屏幕上动起来。 [![Folia 全屏歌词播放器心象主题歌词动画](https

gitblog_00310的博客 374

SoC验证新思路:除了UVM仿真,你还可以试试Cadence JasperGold的形式化验证

本文深入探讨了Cadence JasperGold形式化验证在SoC设计中的创新应用,对比传统UVM仿真验证,详细解析了其数学穷尽性验证优势。通过实战案例展示了JasperGold在总线协议、时钟域交叉等关键场景的验证方法,并提供了混合验证流程设计与效能优化方案,帮助工程师提升验证效率30%以上。

weixin_30566063的博客 121

Transformer实战(38)——视觉Transformer (Vision Transformer, ViT)

Transformer 在自然语言处理 (NLP) 领域取得了显著成就,在许多不同的任务中都表现出色。在本节中,我们将探索视觉 Transformer (Vision Transformer, ViT) 模型。正如 NLP 领域创建了多种模型一样,视觉领域也开发了多种模型,每种模型都为计算机视觉提供了新的视角。通过本节,将学习如何使用 ViT 等模型进行计算机视觉任务,了解基于 Transformer 的预训练计算机视觉模型的工作原理,以及如何针对特定任务进行微调。

盼小辉丶的博客 2870

note

CPU,此处CPU与BL芯片断开,没有连背光芯片。屏,此处屏与BL芯片断开,没有连背光芯片。虽然signal函数更简单些。行 3744: 07-22 23:56:01.139 <6>[ 5.577037][ T919] [2024:07:22 15:55:51](7)[919:modprobe][drm] [lcdkit /I]: type:66, name:[qcom,mdss-dsi-apl-bl-mode-off-command], length:16, pkt-count=1。

m0_73462935的博客 10万+

Orin 调试GMSL camera 96712手册重点

96712基础理解

乐于分享 9193

Android 开发入门实践(二):Kotlin 空安全,从可空类型到安全访问

延续 NewsApp 项目中的新闻标题练习,记录 Kotlin 安全调用。

Easyhood的博客 289

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Android 模块化收口:能力组合框架、手写 LifecycleOwner 与热修复共存

二十多个模块业务高度相似却各有差异,核心矛盾在于“统一与灵活”的平衡。通过角色接口组合(如IProjectAware、IVoiceAware)实现能力按需注入,新增功能零侵入;用模板方法锁定生命周期流程,确保顺序一致;结合@CallSuper与工厂方法,既约束关键逻辑,又保留子类自由。最终实现:骨架统一、填空自由,管得住业务,又不侵入业务。

mmsx990的博客 397

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Android 开发入门实践(十三):用 Intent、UiState 和 Reducer 理解 MVI 的状态更新

本文记录第141—145课对MVI架构的入门实践,通过“返回列表”功能逐步构建意图(NewsIntent)、状态(NewsUiState)与状态转换(reduce)机制。基于单向数据流,用户操作生成意图,ViewModel通过Reducer根据旧状态计算新状态,并通过StateFlow更新Compose界面。代码实现清晰分离关注点,强化了对状态管理、事件驱动与数据流的理解。

Easyhood的博客 324

Android Message源码阅读

本文梳理了Android Handler机制中Message的核心设计:链表结构、消息复用池(sPool)及回收机制,重点解析了异步消息与同步屏障(SyncBarrier)的协同机制。当主线程需优先处理UI绘制等高优先级任务时,系统通过postSyncBarrier插入屏障,使Looper跳过普通同步消息,优先执行标记为异步的UI渲染任务,确保帧率流畅。该机制是保障Android界面响应性的关键技术之一。

u012116089的博客 201

安卓部署Linux性能实测:一颗移动处理器,能否胜任日常 Linux 开发?

本文通过在一加Ace5上部署NimoteCode的ARM64 Linux环境,测试了其在CoreMark、SQLite编译及并行构建中的表现。结果显示,尽管单核性能约2.34GHz,多核扩展比达6.15×,但优化编译耗时仍高达35秒,反映移动处理器虽具备一定开发能力,却受限于文件系统开销与运行环境(如PRoot)。实际开发中,非优化构建效率较高,而并行编译可显著提速。结论:安卓手机可作为轻量级开发辅助工具,但无法替代桌面环境,真正价值在于便携性与即时响应,而非全功能替代。

一个不知名码农的专栏 323

Android 17 全栈性能分析关键字与源码手册

FrameTimeline 找异常帧,ATrace 找阶段,thread_state 找等待类型,ftrace 找内核原因,Simpleperf 找 CPU 热点,驱动源码找最终触发条件;任何根因结论都必须回到同一对象、同一时间窗口和同一条依赖链。

weixin_43228946的博客 372

CTF 命令执行题学习笔记:终端特殊字符 $IFS 与 %09 的用法(HelloCTF RCE-labs)

空格被过滤时:用%09(TAB)或$IFS代替空格关键词被过滤时:用通配符?或字符类[f]拼出被禁的词,让 WAF 在原始字符串里看不到它,shell 在执行时再展开这类技巧在后续的命令执行题里会反复用到,建议亲手在靶机上敲一遍感受一下。

YY888888_的博客 542

Android 开发入门实践(九):把新闻数据与页面状态交给 ViewModel

本文记录第110—117课学习成果:将页面标题、新闻列表及选中编号逐步迁移至NewsViewModel,通过ViewModelProvider获取实例并读取数据。页面调用ViewModel方法处理选择与返回,实现状态管理解耦。过程中纠正了对Activity重建机制的误解,并厘清mutableStateOf的可观察性与ViewModel对象生命周期的区别,深化了对Compose状态更新机制的理解。

Easyhood的博客 220

云手机私有化部署完整方案:基于ARM服务器搭建私有安卓云集群

ARM 服务器是私有化安卓云集群最优硬件底座,原生架构匹配 Android,高密度、低损耗,非常适合企业内网场景。整套私有化方案的核心,从来不是 “跑起来安卓”,而是隔离可控、可审计、可运维、可扩容。两条路线各有取舍:开源自建灵活、门槛高;商用私有化交付开箱即用、安全能力完备,是当前企业生产环境主流方案。六边云手机私有化方案,补齐了自建方案在驱动适配、管控平台、审计合规、信创适配上的短板,适合对数据主权、内网隔离有强需求的政企、自研 App、垂直行业客户。

a598652的博客 333

Android 顶点上传:Heap 到 Direct 的零拷贝,省的是 JNI 次数

一帧数十万次putFloat的性能瓶颈源于频繁跨JNI边界,每次开销远超传输字节数。通过将写入与上传解耦:用堆内ByteBuffer高速写入,最后一次性put(writeBuf)批量传至堆外DirectByteBuffer,将数百万次边界调用压缩为一次,实现近10倍性能提升。关键在于复用堆外缓冲区、统一端序,并结合“更新-绘制”分离,仅在数据变更时上传顶点,平移缩放时零开销重绘,彻底释放CPU瓶颈。

mmsx990的博客 478

谷歌相机9.2下载(GCam 安卓通用版 安装与使用说明)

谷歌相机9.2版移植自Pixel原生相机,支持Camera2 API的Android 10+设备安装,凭借多帧合成技术在夜景、HDR+与人像模式表现优异。可提升暗光画质、优化动态范围与背景虚化效果,支持视频防抖及配置文件自定义。安装需确认机型兼容性,建议备份原相机,避免冲突。资源可通过kuake链接获取,仅限学习测试使用。

2611_96675819的博客 159

Android 系统启动与调试中的日志抓取方式全解析

│ 用户操作/系统事件 ││ │▼ ▼│ (驱动/硬件/内存管理) │ │ (App/SystemServer) ││ │ │ ││ │▼ ▼│ dmesg 命令 │ │ logd daemon ││ cat /proc/kmsg │ │ (分类存储到分区) ││ │▼ ▼│ 串口 UART │ │ logcat 命令 ││ (硬件直连,最早输出) │ │ adb logcat ││ │▼│ (汇总所有日志+系统状态) │工具最佳用途关键优势主要局限dmesg。

zhaoshuzhaoshu的专栏 266

【Android】听写播放器改版:中英文书写速度拆项与「正在读」高亮

现象:把播放页主体抽成后,里面给LazyColumn加想让它占满剩余高度,编译报错(weight 不可用)。原因weight不是通用修饰符,是RowScope的扩展函数。是个普通函数,函数体里没有接收者,自然调不到。解决private fun ColumnScope.PlaybackBody(...) { /* 这里就能用 Modifier.weight(1f) */ }调用处仍在原来的Column { }里,无需改动。预防:Compose 的布局修饰符都是作用域绑定。

木头大左的博客 241

Android 开发入门实践(十):用 Kotlin 协程完成模拟加载、取消与异常处理

本文记录第118—125课对NewsApp的协程改造:从viewModelScope.launch启动协程,逐步加入delay模拟等待、suspend函数封装、withContext(Dispatchers.IO)切换线程并观察上下文恢复机制。通过日志验证withContext完成后恢复原执行上下文(非自动回主线程),纠正了初始理解偏差。引入Job管理任务,实现加载取消与重复点击防护,结合异常处理与状态管理,完成可观察、可中断的异步流程。

Easyhood的博客 390
上一篇: PCIe 从架构到 P2P 直通:一次把路由讲清楚
inquisiter
博客等级 码龄10年 374粉丝 228原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值