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 源码编写,所有代码片段均可追溯到具体文件路径。

相关推荐
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
千里马学框架2 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone2 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
1点东西2 天前
做了近两年的Agent开发,其实真正要学的就是这五件事
llm·agent·ai编程
七牛云行业应用2 天前
Qwen-Image-2.1 开源部署完整指南:Diffusers、ComfyUI 与推理服务
ai编程
致远ccc2 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
福如意如我心意2 天前
TencentDB Agent Memory和其他开源memory
ai编程
ttyyttemo2 天前
Kotlin 协程中的 Job 结构化并发与取消
android
小虎AI生活2 天前
腾讯开源了一个项目,让 AI 直接用你已经登录好的浏览器
aigc·ai编程