Android 16 AppFunction 机制分析

从源码层面分析 AppFunction 框架的设计意图、核心组件和调用链路。读完本文,你应该能回答三个问题:AppFunction 解决什么问题?一个完整调用在系统层面经历了哪些步骤?如何为自己的 App 接入 AppFunction?


一、AppFunction 解决什么问题

Android 的跨 App 通信方式发展到现在,经历过几代方案。Intent 解决了"启动另一个 App"的问题,ContentProvider 解决了"跨 App 共享数据"的问题,但它们有一个共同的局限:调用方无法像调用本地函数那样,给目标 App 传递结构化参数并拿到结构化返回值。

AppFunction 填补的正是这个缺口。 它在 Android 16(API 36)中引入,让 App A 能以函数调用的方式请求 App B 执行一个操作,传入参数,接收返回值。整个调用链路------函数发现、权限校验、Service 绑定、参数传递、取消机制------全部由 system_server 接管,开发者不需要手动处理 Binder 通信。

这本质上是一个系统级 RPC(Remote Procedure Call)框架,运行在 Android Framework 层。AppFunctionManager 的角色不是执行者,而是路由器------它知道哪个 App 注册了哪些函数,并负责安全地建立连接。

用调用方、system_server、提供方三者的交互来理解:

javascript 复制代码
调用方 App A                system_server                    提供方 App B
(比如闹钟 App)              (AppFunctionManagerService)       (比如日历 App)

"帮我查下周三              收到请求:                          CalendarProvider
的日程是否冲突"               ① 查元数据 → 找到日历 App
  → executeAppFunction       ② 权限校验 → 通过
    ("com.calendar",         ③ 绑定 Service
     "checkConflict",        ④ 调用 onExecuteFunction()
     {date: "周三"})         ⑤ 接收返回值 → 返回调用方 →   处理并返回 {conflict: false}
  ← 收到结果 {conflict: false}

调用方只知道目标 App 的包名和函数名,不需要知道目标 App 的进程状态、Service 是否已启动、数据传输协议是什么------这些全部交给 system_server 处理。


二、源码跟踪:一个完整的 add 调用

与其抽象地描述架构,不如直接跟踪一段真实代码。下面引用 Android CTS 测试套件中的代码,CTS(Compatibility Test Suite)是 Google 用来验证 Android 兼容性的测试框架,每个 AppFunction API 都经过它测试,可以保证准确性。

场景:一个提供方 App(CTS 测试包)暴露了 add(a, b) 函数,调用方传 a=1, b=2,返回 3。

2.1 时序图

scss 复制代码
调用方                         system_server                       提供方 Service
(测试用例)                     (AppFunctionManagerService)          (TestAppFunctionService)

   │  ① 构建请求                    │                                    │
   │  Request.Builder               │                                    │
   │  ("cts", "add")                │                                    │
   │  .setParams({a:1, b:2})       │                                    │
   │                                │                                    │
   │  ② manager.executeAppFunction()│                                    │
   │───────────────────────────────>│                                    │
   │                                │                                    │
   │                                │  ③ Binder 进入 system_server       │
   │                                │     验证 callingPackage             │
   │                                │     检查企业策略                    │
   │                                │     查 AppSearch 元数据              │
   │                                │     → "add" 已注册, enabled=true    │
   │                                │     权限校验                        │
   │                                │     → restrictExecFunc=true,        │
   │                                │       调用方持有权限 → pass          │
   │                                │     resolveAppFunctionService       │
   │                                │                                    │
   │                                │  ④ bindService(BIND_AUTO_CREATE)   │
   │                                │───────────────────────────────────>│
   │                                │                                    │ onCreate()
   │                                │                                    │
   │                                │  ⑤ 调用 onExecuteFunction()        │
   │                                │     传入: request, callingPackage,  │
   │                                │           signingInfo,              │
   │                                │           cancellationSignal,       │
   │                                │           callback                  │
   │                                │───────────────────────────────────>│
   │                                │                                    │
   │                                │                                    │  ⑥ 路由 + 计算
   │                                │                                    │  switch(funcId):
   │                                │                                    │    case "add":
   │                                │                                    │      a = params.getLong("a") → 1
   │                                │                                    │      b = params.getLong("b") → 2
   │                                │                                    │      sum = 1+2 = 3
   │                                │                                    │
   │                                │  ⑦ callback.onResult({             │
   │                                │     returnValue: 3 })               │
   │                                │<───────────────────────────────────│
   │                                │                                    │
   │                                │  ⑧ 记录日志 → 返回结果给调用方       │
   │                                │                                    │
   │  ⑨ OutcomeReceiver.onResult() │                                    │
   │     收到 resultDoc              │                                    │
   │     .getLong("returnValue")    │                                    │
   │     → 3 ✅                     │                                    │
   │<───────────────────────────────│                                    │
   │                                │  ⑩ unbindService                   │
   │                                │───────────────────────────────────>│ onDestroy()

2.2 逐步骤源码

下面每一段代码都可以在 AOSP 中找到原文,路径已标注。

步骤 ①-②:调用方代码

java 复制代码
// 文件: cts/tests/appfunctions/src/android/app/appfunctions/cts/AppFunctionManagerTest.kt
// 简化自: executeAppFunction_platformManager_platformAppFunctionService_success_nonParam()

// 1. 构建参数
GenericDocument params = new GenericDocument.Builder<>("", "", "")
    .setPropertyLong("a", 1)
    .setPropertyLong("b", 2)
    .build();

// 2. 构建请求
ExecuteAppFunctionRequest request = new ExecuteAppFunctionRequest.Builder(
    "android.app.appfunctions.cts",   // 目标包名
    "add"                             // 函数名
).setParameters(params).build();

// 3. 获取系统服务
AppFunctionManager manager = context.getSystemService(AppFunctionManager.class);

// 4. 执行异步调用
manager.executeAppFunction(
    request,
    context.getMainExecutor(),
    new CancellationSignal(),
    new OutcomeReceiver<ExecuteAppFunctionResponse, AppFunctionException>() {
        @Override
        public void onResult(ExecuteAppFunctionResponse response) {
            long result = response.getResultDocument()
                .getPropertyLong(ExecuteAppFunctionResponse.PROPERTY_RETURN_VALUE);
            // result == 3
        }

        @Override
        public void onError(AppFunctionException error) {
            Log.e(TAG, "Failed: " + error.getErrorMessage());
        }
    }
);

调用方的代码很简洁:构建参数 → 构建请求 → 获取系统服务 → 异步执行。所有复杂逻辑都在 system_server 内部。

步骤 ③:system_server 核心路由逻辑

scss 复制代码
// 文件: frameworks/base/services/appfunctions/java/com/android/server/appfunctions/
//       AppFunctionManagerServiceImpl.java
// 简化自 executeAppFunctionInternal() 方法

@WorkerThread
private void executeAppFunctionInternal(ExecuteAppFunctionAidlRequest request, ...) {
    // 3.1 企业策略检查
    if (!mCallerValidator.verifyEnterprisePolicyIsAllowed(callingUser, targetUser)) {
        callback.onError(ERROR_ENTERPRISE_POLICY_DISALLOWED);
        return;
    }

    // 3.2 调用者权限检查(查 AppSearch 元数据 + 执行权限验证)
    mCallerValidator
        .verifyCallerCanExecuteAppFunction(callingUid, ..., functionIdentifier)
        .thenCompose(canExecuteResult -> {
            if (canExecuteResult == DENIED) {
                return failedFuture(new SecurityException("no permission"));
            }
            // 3.3 检查函数是否被用户禁用
            return isAppFunctionEnabled(functionIdentifier, targetPackage, ...);
        })
        .thenAccept(canExecuteResult -> {
            // 3.4 解析目标 Service 的 Intent
            Intent serviceIntent = mInternalServiceHelper
                .resolveAppFunctionService(targetPackageName, targetUser);

            // 3.5 绑定 Service
            bindAppFunctionServiceUnchecked(request, serviceIntent, ...);
        });
}

system_server 在 Binder 线程上执行这五步检查,全部通过后才会连接目标 Service。任何一步失败都会直接回调 onError。

步骤 ⑥-⑦:提供方 Service 实现

less 复制代码
// 文件: cts/tests/appfunctions/testutils/src/android/app/appfunctions/testutils/
//       TestAppFunctionService.java

public class TestAppFunctionService extends AppFunctionService {

    @Override
    @MainThread   // 系统保证在主线程回调
    public void onExecuteFunction(
            @NonNull ExecuteAppFunctionRequest request,
            @NonNull String callingPackage,
            @NonNull SigningInfo callingPackageSigningInfo,
            @NonNull CancellationSignal cancellationSignal,
            @NonNull OutcomeReceiver<ExecuteAppFunctionResponse, AppFunctionException> callback) {

        // 1. 注册取消监听
        cancellationSignal.setOnCancelListener(() -> cancelOperation());

        // 2. 按函数名路由
        switch (request.getFunctionIdentifier()) {
            case "add" -> {
                long a = request.getParameters().getPropertyLong("a"); // 1
                long b = request.getParameters().getPropertyLong("b"); // 2
                long sum = a + b; // 3

                // 3. 构建返回值,使用 PROPERTY_RETURN_VALUE 作为 key
                GenericDocument result = new GenericDocument.Builder<>("", "", "")
                    .setPropertyLong(
                        ExecuteAppFunctionResponse.PROPERTY_RETURN_VALUE, sum)
                    .build();

                // 4. 回传结果
                callback.onResult(new ExecuteAppFunctionResponse(result));
            }
            // ... 其他 case ...
        }
    }
}

三、函数元数据:AppFunctionManager 怎么知道有哪些函数

AppFunctionManager 不是静态配置的,它的函数发现依靠 Android 的 AppSearch 索引引擎。整个流程在 App 安装时自动触发。

第一步:App 在 assets/appfunctions.xml 中声明函数定义。

xml 复制代码
<!-- 文件: cts/tests/appfunctions/assets/appfunctions.xml -->
<appfunctions>
    <appfunction>
        <function_id>add</function_id>                    <!-- 函数唯一标识 -->
        <enabled_by_default>true</enabled_by_default>      <!-- 默认启用 -->
        <schema_category>utils</schema_category>           <!-- 分类标签 -->
        <restrict_callers_with_execute_app_functions>true  <!-- 需要执行权限 -->
        </restrict_callers_with_execute_app_functions>
    </appfunction>
    <appfunction>
        <function_id>add_disabledByDefault</function_id>
        <enabled_by_default>false</enabled_by_default>     <!-- 默认禁用 -->
    </appfunction>
</appfunctions>

第二步:在 AndroidManifest.xml 中关联 Service 和元数据。

xml 复制代码
<!-- 文件: cts/tests/appfunctions/AndroidManifest.xml -->
<service android:name=".TestAppFunctionService"
    android:permission="android.permission.BIND_APP_FUNCTION_SERVICE"
    android:exported="true"
    android:process=":appfunctions">
    <property
        android:name="android.app.appfunctions"
        android:value="appfunctions.xml"/>
    <intent-filter>
        <action android:name="android.app.appfunctions.AppFunctionService"/>
    </intent-filter>
</service>

第三步:安装时自动索引。 App 安装后,appsindexer 解析 XML,将函数信息写入 AppSearch 的 AppFunctionStaticMetadata 数据库。这是一个 GenericDocument 类型的结构化索引,AppFunctionManagerService 在收到调用请求时从这里检索目标函数的元数据。

AppSearch 中实际存储了两层元数据:

层次 命名空间 内容 写入者 读取者
静态元数据 AppFunctionStaticMetadata XML 声明的函数信息(functionId、enabledByDefault、schemaCategory) appsindexer(安装时) AppFunctionManagerService
运行时元数据 AppFunctionRuntimeMetadata 用户控制的状态(启用/禁用) AppFunctionManager(setAppFunctionEnabled) AppFunctionManagerService

两者通过 JoinSpec 关联查询,最终判断一个函数是否可以被调用。这体现了 Android 设计中的一个思路------静态声明 + 运行时覆盖,注册和授权解耦。


四、核心组件全景图

把前面分散的信息汇总成一张图:

css 复制代码
┌───────────────────────────────────────────────────────────────────┐
│                        调用方 App A                                 │
│  AppFunctionManager                                                │
│    .executeAppFunction(request, executor, cancelSig, callback)     │
│    .isAppFunctionEnabled(functionId)           ← 查询启用状态       │
│    .setAppFunctionEnabled(functionId, state)    ← 用户开关          │
│    .getAppFunctionRuntimeMetadata(...)          ← 发现可用函数      │
└───────────────────────────┬───────────────────────────────────────┘
                            │ Binder IPC
                            ▼
┌───────────────────────────────────────────────────────────────────┐
│                    system_server (特权进程)                         │
│                                                                    │
│  AppFunctionManagerService           ← Binder Stub, 对外接口       │
│       │                                                            │
│  AppFunctionManagerServiceImpl       ← 核心实现                     │
│       │                                                            │
│       ├─ CallerValidator             → 权限校验(3 层)             │
│       ├─ ServiceHelper               → 解析目标 Service Intent      │
│       ├─ RemoteServiceCaller         → bindService + IPC 封装      │
│       ├─ AppFunctionManagerHelper    → AppSearch 元数据查询         │
│       └─ AppFunctionsLoggerWrapper   → StatsLog 埋点               │
│                                                                    │
│  检查流程(顺序执行):                                              │
│    1. 校验调用方包名                                                 │
│    2. 验证用户句柄                                                   │
│    3. 企业策略检查                                                   │
│    4. AppSearch 查元数据 → 验证函数存在 + 权限 + 启用状态             │
│    5. 解析目标 Service Intent                                        │
│    6. bindService + IPC 调用                                        │
└───────────────────────────┬───────────────────────────────────────┘
                            │ Binder IPC
                            ▼
┌───────────────────────────────────────────────────────────────────┐
│                       提供方 App B                                  │
│                                                                    │
│  AppFunctionService                                                │
│    .onExecuteFunction(request, callingPkg, signingInfo, cancel,    │
│                        callback)                                    │
│                                                                    │
│    数据流:                                                          │
│      入参: GenericDocument { "a": 1, "b": 2 }                      │
│      返回: ExecuteAppFunctionResponse(                              │
│              GenericDocument { "returnValue": 3 })                  │
└───────────────────────────────────────────────────────────────────┘

权限模型

AppFunction 的权限分为两层,分别保护提供方和调用方:

| 权限 | 声明位置 | 保护级别 | 作用 |
|-----------------------------|---------------------------|-----------|--------------------------------|-------------------------------------|
| BIND_APP_FUNCTION_SERVICE | 提供方 Manifest 的 service 标签 | signature | 只有系统能绑定你的 Service,第三方 App 无法连接 |
| EXECUTE_APP_FUNCTIONS | 调用方 Manifest | internal | privileged | 允许调用其他 App 的函数;没有此权限只能调用自己 App 内的函数 |

两层权限的设计意图很明确:提供方只信任系统,调用方需显式声明意图。两者叠加后,攻击者无法伪造调用链,也无法绕过系统直接连接提供方。


五、调用链路总结

将前面分析的所有步骤压缩成一张时序图:

scss 复制代码
App A                       system_server                       App B
  │                              │                                 │
  │ manager.executeAppFunction() │                                 │
  │─────────────────────────────>│                                 │
  │                              │                                 │
  │                     ┌────────┴──────────┐                      │
  │                     │ ① 校验包名        │                      │
  │                     │ ② 企业策略        │                      │
  │                     │ ③ 查 AppSearch    │                      │
  │                     │    元数据 + 权限   │                      │
  │                     │ ④ 检查启用状态    │                      │
  │                     │ ⑤ 解析 Service    │                      │
  │                     └────────┬──────────┘                      │
  │                              │                                 │
  │                              │ bindService() +                 │
  │                              │ onExecuteFunction()             │
  │                              │────────────────────────────────>│
  │                              │                                 │
  │                              │                  switch(funcId)  │
  │                              │                  parse params    │
  │                              │                  execute logic   │
  │                              │                  callback.onResult│
  │                              │                                 │
  │                              │  callback.onResult()            │
  │                              │<────────────────────────────────│
  │                              │                                 │
  │                              │ unbindService()                 │
  │                              │────────────────────────────────>│
  │                              │                                 │ onDestroy()
  │  OutcomeReceiver.onResult()  │                                 │
  │<─────────────────────────────│                                 │

调用方全程不知道自己经历了 Service 的冷启动、Binder 通信、异步回调线程切换------它只看到请求发出去了,结果回来了。


六、开发最小步骤:为自己的 App 接入 AppFunction

第 1 步:创建 AppFunctionService

scala 复制代码
public class MyAppFunctionService extends AppFunctionService {

    @Override
    public void onExecuteFunction(
            ExecuteAppFunctionRequest request,
            String callingPackage,
            SigningInfo signingInfo,
            CancellationSignal cancelSignal,
            OutcomeReceiver<ExecuteAppFunctionResponse, AppFunctionException> callback) {

        // onExecuteFunction 在主线程回调,耗时操作需切线程
        mExecutor.execute(() -> {
            try {
                switch (request.getFunctionIdentifier()) {
                    case "createNote":
                        String title = request.getParameters().getPropertyString("title");
                        String content = request.getParameters().getPropertyString("content");
                        String noteId = myNoteRepo.create(title, content);

                        GenericDocument result = new GenericDocument.Builder<>("", "", "")
                            .setPropertyString("returnValue", noteId)
                            .build();
                        callback.onResult(new ExecuteAppFunctionResponse(result));
                        break;

                    default:
                        callback.onError(new AppFunctionException(
                            AppFunctionException.ERROR_FUNCTION_NOT_FOUND,
                            "Unknown function"));
                }
            } catch (Exception e) {
                callback.onError(new AppFunctionException(
                    AppFunctionException.ERROR_APP_UNKNOWN_ERROR, e.getMessage()));
            }
        });
    }
}

第 2 步:配置 Manifest

ini 复制代码
<service android:name=".MyAppFunctionService"
    android:permission="android.permission.BIND_APP_FUNCTION_SERVICE"
    android:exported="true"
    android:process=":functions">
    <property
        android:name="android.app.appfunctions"
        android:value="appfunctions.xml"/>
    <intent-filter>
        <action android:name="android.app.appfunctions.AppFunctionService"/>
    </intent-filter>
</service>

第 3 步:声明函数元数据

assets/appfunctions.xml

xml 复制代码
<appfunctions>
    <appfunction>
        <function_id>createNote</function_id>
        <enabled_by_default>true</enabled_by_default>
        <restrict_callers_with_execute_app_functions>true</restrict_callers_with_execute_app_functions>
    </appfunction>
</appfunctions>

第 4 步:调用方调用

java 复制代码
AppFunctionManager manager = context.getSystemService(AppFunctionManager.class);

GenericDocument params = new GenericDocument.Builder<>("", "", "")
    .setPropertyString("title", "shopping list")
    .setPropertyString("content", "milk, eggs")
    .build();

ExecuteAppFunctionRequest request = new ExecuteAppFunctionRequest.Builder(
    "com.example.notesapp",
    "createNote"
).setParameters(params).build();

manager.executeAppFunction(request, executor, new CancellationSignal(),
    new OutcomeReceiver<>() {
        @Override
        public void onResult(ExecuteAppFunctionResponse response) {
            String noteId = response.getResultDocument()
                .getPropertyString("returnValue");
            Log.i(TAG, "Note created: " + noteId);
        }

        @Override
        public void onError(AppFunctionException error) {
            Log.e(TAG, "Failed: " + error.getErrorMessage());
        }
    });

七、开发注意事项

要点 说明
独立进程 Service 推荐 android:process=":functions",与主 App UI 进程隔离
线程切换 onExecuteFunction 在主线程回调,耗时操作必须切换到后台线程
异常保护 所有代码包裹 try-catch,crash 不要泄漏到 system_server
取消支持 监听 CancellationSignal,支持调用方主动取消
回调保证 必须且仅一次调用 callback.onResultcallback.onError,否则调用方永久等待
安全层次 Signature 权限 → 调用方权限 → 元数据 restrict → 用户运行时开关 → SigningInfo 透传

八、当前状态

组件 状态
AOSP 框架基础设施 就绪(Android 16)
CTS 测试覆盖 完整(平台 API + Sidecar 库 + 异常路径)
Sidecar 扩展库 就绪(com.android.extensions.appfunctions
预定义 Schema 独立 SDK(Google Maven),不在 AOSP 中
参考 App 目前仅 CTS 测试提供完整示例

本文基于 AOSP frameworks/basects/tests/appfunctions 源码编写,所有代码片段均可追溯到具体文件路径。

相关推荐
空杯_北冥有鱼1 小时前
第六篇:SpringAI 入门 06|官方核心概念全解析(Models/Prompt/Embedding/RAG/Tool Calling
ai编程
helloweilei1 小时前
手撸一个会“思考”的AI智能体
ai编程
会飞的蛛1 小时前
AI Coding 的终局,不是写更好的 Prompt,而是给 Agent 套上 Harness
ai编程
赛博三把手1 小时前
「2026 最新推荐」AI 大模型 API 中转站 | 国内直连 ChatGPT/Claude/Gemini 稳定优质的 API 接口服务
人工智能·github·ai编程
Coffeeee1 小时前
Android16升级,预测性返回适配起来到底难不难
android·程序员·kotlin
_李小白1 小时前
【android opencv学习笔记】Day 33: 直线检测之图像轮廓检测
android·opencv·学习
Mars-xq1 小时前
vscode 开发Android
android·ide·vscode
__Witheart__1 小时前
关于 uname 查看的内核版本号的后缀
android·linux·ubuntu·rockchip
QING6182 小时前
Kotlin 协程新手指南 —— 结构化并发
android·kotlin·android jetpack