欢迎光临
我们一直在努力

第 51 章:AI、AppFunctions 与计算机控制

Android 已经从一个仅能运行应用的平台,演进为能够理解应用行为的平台。一系列端侧智能服务将用户意图与应用行为关联起来:AppFunctions 框架允许助手通过强类型 RPC 契约调用应用的任意功能;计算机控制(Computer Control)为 AI 代理提供虚拟显示器,可在其上完成点击、滑动、截图操作;OnDeviceIntelligence 在隔离沙箱中运行大机器学习模型 —— 大语言模型以及其他生成式或大规模推理负载;NNAPI 向所有原生工作负载暴露硬件加速器。结合 AppSearch、内容捕获(Content Capture)、AdServices 以及联邦学习,这些子系统共同构成了 Android 的 AI 神经体系。

本章逐层梳理完整调用链路:从公开 SDK 类,经由 AIDL 接口、system_server 服务实现,一直到另一端沙箱进程或 HAL 进程。每一条代码路径均对应当前 AOSP 源码树中的真实源文件。

51.1 AOSP AI 全景概览

在深入任一框架细节之前,先整体浏览 AOSP 全部 AI/ML 相关组件。下图列出主要子系统、跨进程边界以及组件之间的数据流。

Mainline 模块 HAL / 驱动进程 隔离 / 沙箱进程 目标应用进程 system_server 应用进程 Binder IPC bindService Binder IPC 隔离 bind 调用 Binder IPC Binder IPC Binder IPC Binder IPC Binder IPC

第三方 / 系统应用 AppFunctionManager OnDeviceIntelligenceManager NNAPI C API ComputerControlExtensions AppSearchManager TextClassifierManager ContentCaptureManager AppPredictionManager TopicsManager

AppFunctionManagerServiceImpl OnDeviceIntelligenceManagerService VirtualDeviceManager ComputerControlSession Service ContentCaptureManagerService TextClassificationManagerService AppPredictionManagerService

AppFunctionService OnDeviceSandboxedInferenceService IsolatedTrainingService NNAPI HAL (IDevice) GPU / DSP / NPU

AppSearch 模块 NeuralNetworks 模块 OnDevicePersonalization 模块 AdServices 模块

51.1.1 AOSP 智能子系统分类表

子系统
API 等级
是否 Mainline 模块
用途
AppFunctions 16(引入),Android 17 趋于成熟 否(框架内置) 强类型跨应用函数调用,支持运行时注册与状态观测
Computer Control 16(Android 16) 否(框架 + 扩展库) 基于虚拟显示器实现 AI 驱动的 UI 自动化
OnDeviceIntelligence 15 及以上 NeuralNetworks 模块 沙箱化的大语言模型 / 机器学习推理
NNAPI 8.1 及以上 NeuralNetworks 模块 神经网络推理硬件加速
AppSearch 12 及以上 AppSearch 模块 端侧全文检索与索引
Content Capture 10 及以上 否(框架内置) 为智能服务实时捕获 UI 结构
TextClassifier 8.0 及以上 否(框架内置) 实体识别、语言检测
AppPrediction 10 及以上 否(框架内置) 基于使用行为的应用排序
OnDevicePersonalization 14 及以上 ODP 模块 联邦计算、隔离训练
AdServices 13 及以上 AdServices 模块 隐私保护广告定向(Topics、FLEDGE)

51.1.2 跨子系统通用设计思路

所有 AI 子系统都复用若干架构设计范式:

进程隔离 智能服务运行在隔离或沙箱进程。OnDeviceSandboxedInferenceService设置android:isolatedProcess=\”true\”。IsolatedTrainingService在独立进程加载 TFLite。即使 ComputerControlSession 也基于与主显示器隔离的虚拟显示器工作。

优先使用强类型契约,而非无约束 Bundle AppFunctions 使用 AppSearch 提供的GenericDocument作为参数序列化格式。ODI 使用PersistableBundle承载特性与请求元数据。二者均鼓励 SDK 层封装强类型包装类。

AppSearch 作为通用元数据存储 AppFunction 元数据、应用预测数据、内容捕获智能数据,全部汇聚到 AppSearch 完成索引与检索。

权限管控 + 白名单机制 AppFunctions 执行受EXECUTE_APP_FUNCTIONS(或EXECUTE_APP_FUNCTIONS_SYSTEM)权限约束,同时配合平台AllowlistManager维护签名代理白名单。Computer Control 需要ACCESS_COMPUTER_CONTROL权限。ODI 需要USE_ON_DEVICE_INTELLIGENCE。AdServices 需要ACCESS_ADSERVICES_TOPICS。

支持取消信号传递 几乎全部异步 API 都会跨 Binder 传递ICancellationSignal,调用方可终止长时间推理或函数执行。

51.2 AppFunctions 框架

AppFunctions 框架在 Android 16 以 Beta 特性面世,Android 17 正式广泛可用。它提供一套标准化机制,让 AI 助手(代理)可以发现并调用任意目标应用暴露的功能。例如助手收到指令 “把 XYZ 保存到我的笔记”,框架会将请求路由至对应的AppFunctionService实现,助手无需在编译期依赖笔记应用。

Android 17 对该框架做了大幅增强,不再局限于最初仅通过 Manifest 静态声明的模式。本章后续会详细介绍以下核心新增能力:

  • 运行时(动态)函数注册:应用可在 Activity 或 Service 中运行时注册 AppFunction 回调,不再必须声明独立AppFunctionService组件(registerAppFunction,受FLAG_ENABLE_DYNAMIC_APP_FUNCTIONS标记控制)。
  • 完备的发现、状态与观测 API,新增至AppFunctionManager:searchAppFunctions、getAppFunctionStates、getAppFunctionActivityStates、observeAppFunctions。
  • 访问管理框架:维护(代理,目标应用)二元组访问状态与标志位;提供面向用户的管理 UI;代理白名单交由平台AllowlistManager维护,不再使用 DeviceConfig 字符串。
  • 新增权限:DISCOVER_APP_FUNCTIONS(仅发现,不可执行)、EXECUTE_APP_FUNCTIONS_SYSTEM(特权系统代理,绕过白名单校验),保留原有EXECUTE_APP_FUNCTIONS。
  • Android 17 源码目录概览:

    frameworks/base/core/java/android/app/appfunctions/
    AppFunctionManager.java — 客户端系统服务入口
    AppFunctionService.java — 静态目标应用抽象基类
    AppFunction.java — 运行时函数回调接口
    RegisterAppFunctionRequest.java — 运行时注册请求Parcelable
    ExecuteAppFunctionRequest.java — 执行请求Parcelable
    ExecuteAppFunctionResponse.java — 执行响应Parcelable
    AppFunctionException.java — 分层异常错误体系
    AppFunctionMetadata.java — 静态+运行时函数元数据
    AppFunctionName.java — (包名,标识符)函数唯一标识
    AppFunctionState.java — 运行时启用/可见状态
    AppFunctionActivityId.java — Activity作用域函数键值
    AppFunctionSearchSpec.java — 检索查询条件
    AppFunctionObserver.java — 变更观测回调
    AppFunctionAccessServiceInterface.java — 访问校验本地服务
    IAppFunctionManager.aidl — system_server AIDL接口
    IAppFunctionService.aidl — 静态目标应用AIDL(oneway)
    IAppFunctionExecutor.aidl — 动态注册执行器AIDL
    IExecuteAppFunctionCallback.aidl — 异步结果回调AIDL
    ICancellationCallback.aidl — 取消信号传输AIDL

    frameworks/base/services/appfunctions/
    java/com/android/server/appfunctions/
    AppFunctionManagerService.java — SystemService封装
    AppFunctionManagerServiceImpl.java — IAppFunctionManager.Stub实现
    RemoteServiceCallerImpl.java — Service绑定逻辑
    CallerValidatorImpl.java — 权限+白名单校验
    MetadataSyncAdapter.java — AppSearch元数据同步
    AppFunctionsLoggerWrapper.java — statsd埋点日志
    allowlist/SystemAppFunctionAllowlistReader.java — AllowlistManager白名单读取
    dynamic/MultiUserDynamicAppFunctionRegistry.java — 运行时注册管理
    reader/AppFunctionMetadataReader.java — 静态/动态元数据读取
    observer/AppFunctionMetadataObserver.java — AppSearch变更观测器

    frameworks/base/services/permission/java/com/android/server/permission/access/appfunction/
    AppFunctionAccessService.kt — 持久化(代理,目标)访问状态

    51.2.1 架构概览

    51.2.2 客户端:AppFunctionManager

    AppFunctionManager以系统服务注册,服务名称Context.APP_FUNCTION_SERVICE。

    @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
    @SystemService(Context.APP_FUNCTION_SERVICE)
    public final class AppFunctionManager {

    核心 API 为executeAppFunction(),接收四个入参。Android17 要求调用方具备两项执行权限之一;应用调用自身暴露的函数无需权限。

    @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_PERMISSION_V2)
    @RequiresPermission(
    anyOf = {
    Manifest.permission.EXECUTE_APP_FUNCTIONS,
    Manifest.permission.EXECUTE_APP_FUNCTIONS_SYSTEM
    },
    conditional = true)
    @UserHandleAware
    public void executeAppFunction(
    @NonNull ExecuteAppFunctionRequest request,
    @NonNull @CallbackExecutor Executor executor,
    @NonNull CancellationSignal cancellationSignal,
    @NonNull OutcomeReceiver<ExecuteAppFunctionResponse, AppFunctionException> callback) {

    内部实现会将上层请求封装为ExecuteAppFunctionAidlRequest,补充调用者身份、时间戳信息。

    ExecuteAppFunctionAidlRequest aidlRequest =
    new ExecuteAppFunctionAidlRequest(
    request,
    mContext.getUser(),
    mContext.getPackageName(),
    /* requestTime= */ SystemClock.elapsedRealtime(),
    /* requestWallTime= */ System.currentTimeMillis());

    Binder 调用返回ICancellationSignal传输对象,绑定至客户端CancellationSignal,实现跨进程取消。

    ICancellationSignal cancellationTransport =
    mService.executeAppFunction(
    aidlRequest,
    new IExecuteAppFunctionCallback.Stub() {
    @Override
    public void onSuccess(ExecuteAppFunctionResponse result) {
    executor.execute(() -> callback.onResult(result));
    }
    @Override
    public void onError(AppFunctionException exception) {
    executor.execute(() -> callback.onError(exception));
    }
    });
    if (cancellationTransport != null) {
    cancellationSignal.setRemote(cancellationTransport);
    }

    51.2.3 启用状态管理

    每个 AppFunction 具备三态生命周期:

    常量
    数值
    含义
    APP_FUNCTION_STATE_DEFAULT 0 恢复默认状态(通常为启用)
    APP_FUNCTION_STATE_ENABLED 1 显式启用
    APP_FUNCTION_STATE_DISABLED 2 显式禁用

    应用通过setAppFunctionEnabled()控制自身函数状态。

    @UserHandleAware
    public void setAppFunctionEnabled(
    @NonNull String functionIdentifier,
    @EnabledState int newEnabledState,
    @NonNull Executor executor,
    @NonNull OutcomeReceiver<Void, Exception> callback) {

    启用状态以AppFunctionRuntimeMetadata文档持久化在 AppSearch,与描述函数 Schema 的AppFunctionStaticMetadata相互独立。

    setAppFunctionEnabled()仅对静态AppFunctionService对应的函数生效。通过registerAppFunction注册的运行时函数,生命周期与注册会话绑定,启用状态由registerAppFunction/AppFunctionRegistration.unregister控制;对动态函数调用本方法会抛出IllegalArgumentException。

    Android17 完整对外暴露运行时状态,不仅仅是启用位。AppFunctionState Parcelable 包含AppFunctionName、启用标记、可见性;可通过AppFunctionManager.getAppFunctionStates(…)批量读取。

    51.2.4 访问控制模型

    AppFunctions 访问模型分为三层校验:

    访问标志位是以(代理,目标应用)为单位存储的位掩码,常量定义在AppFunctionManager。

    标志位
    数值
    含义
    ACCESS_FLAG_PREGRANTED 1 系统预授权访问
    ACCESS_FLAG_UPGRADE_GRANTED 1 << 1 系统版本升级时授予
    ACCESS_FLAG_USER_GRANTED 1 << 2 用户通过 UI 显式授权
    ACCESS_FLAG_USER_DENIED 1 << 3 用户通过 UI 显式拒绝(优先级高于 PREGRANTED)
    ACCESS_FLAG_OTHER_GRANTED 1 << 4 ADB 或其他方式授权
    ACCESS_FLAG_OTHER_DENIED 1 << 5 ADB 或主动撤销拒绝

    Android17 代理白名单不再使用 DeviceConfig 字符串,改为平台AllowlistManager。它以SignedPackage(包名 + 证书摘要)为 Key,记录该代理允许访问的目标包集合,支持通配符代表全部目标包。AppFunctions 服务通过SystemAppFunctionAllowlistReader读取,内部使用 LruCache 按代理缓存结果。

    public class SystemAppFunctionAllowlistReader implements AppFunctionAllowlistReader {
    private final LruCache<SignedPackage, ArraySet<String>> mCache;
    private final AllowlistManager mAllowlistManager;

    @Override
    public CompletableFuture<Boolean> isAllowlisted(
    String agentPackage, String targetPackageName, int userId) { … }
    }

    CallerValidatorImpl执行前同时校验运行时权限与白名单。持有EXECUTE_APP_FUNCTIONS_SYSTEM的特权系统代理会跳过白名单;仅持有EXECUTE_APP_FUNCTIONS的代理必须出现在目标应用对应的白名单内。

    51.2.5 AIDL 接口定义

    框架定义两组 AIDL 接口:一组面向客户端,一组面向目标应用。

    IAppFunctionManager(客户端 → system_server) Android17 接口大幅扩充,增加发现、观测、运行时注册、访问管理相关接口。

    interface IAppFunctionManager {
    ICancellationSignal executeAppFunction(
    in ExecuteAppFunctionAidlRequest request,
    in IExecuteAppFunctionCallback callback);

    // 发现与观测
    void observeAppFunctions(
    in AppFunctionAidlSearchSpec aidlSearchSpec,
    in IObserveAppFunctionChangesCallback callback);
    void unregisterAppFunctionObserver(
    in String callingPackage, in UserHandle userHandle,
    in IObserveAppFunctionChangesCallback callback);
    void getAppFunctionStates(
    in List<AppFunctionName> appFunctionNames,
    in String callingPackageName, int targetUserId,
    in IGetAppFunctionStatesCallback callback);
    void getAppFunctionActivityStates(
    in List<AppFunctionActivityId> activityIds,
    in String callingPackageName, int targetUserId,
    in IGetAppFunctionActivityStatesCallback callback);

    // 启用状态生命周期
    void isAppFunctionEnabled(
    in String callingPackage, in String targetPackage,
    in String functionIdentifier, in UserHandle userHandle,
    in IIsAppFunctionEnabledCallback callback);
    void setAppFunctionEnabled(
    in String callingPackage, in String functionIdentifier,
    in UserHandle userHandle, int enabledState,
    in ISetAppFunctionEnabledCallback callback);

    // 运行时动态注册
    void registerAppFunctions(in String packageName, in List<String> functionIds,
    in IAppFunctionExecutor executor, in IBinder activityToken);
    void unregisterAppFunctions(in String packageName, in List<String> functionIds,
    in IAppFunctionExecutor executor);

    // 访问管理
    int getAccessRequestState(in String agentPackageName, int agentUserId,
    in String targetPackageName, int targetUserId);
    int getAccessFlags(in String agentPackageName, int agentUserId,
    in String targetPackageName, int targetUserId);
    boolean updateAccessFlags(in String agentPackageName, int agentUserId,
    in String targetPackageName, int targetUserId, int flagMask, int flags);
    void revokeSelfAccess(in String targetPackageName);
    List<String> getValidAgents(int userId);
    List<String> getValidTargets(int targetUserId);
    Intent createRequestAccessIntent(in String targetPackageName);
    void addOnAccessChangedListener(IOnAppFunctionAccessChangeListener listener, int userId);
    void removeOnAccessChangedListener(IOnAppFunctionAccessChangeListener listener, int userId);
    }

    注意区分查询回调IIsAppFunctionEnabledCallback和修改回调ISetAppFunctionEnabledCallback。运行时注册传递IAppFunctionExecutor,由系统直接调用,不再绑定独立组件。

    IAppFunctionService(system_server → 目标应用,oneway)

    oneway interface IAppFunctionService {
    void executeAppFunction(
    in ExecuteAppFunctionRequest request,
    in String callingPackage,
    in android.content.pm.SigningInfo callingPackageSigningInfo,
    in ICancellationCallback cancellationCallback,
    in IExecuteAppFunctionCallback callback);
    }

    oneway修饰至关重要:system_server 不会阻塞等待目标应用执行完成,结果全部经由IExecuteAppFunctionCallback回调返回。

    51.2.6 目标端:AppFunctionService

    目标应用继承AppFunctionService,实现唯一抽象方法:

    @MainThread
    public abstract void onExecuteFunction(
    @NonNull ExecuteAppFunctionRequest request,
    @NonNull String callingPackage,
    @NonNull SigningInfo callingPackageSigningInfo,
    @NonNull CancellationSignal cancellationSignal,
    @NonNull OutcomeReceiver<ExecuteAppFunctionResponse, AppFunctionException> callback);

    服务内部做调用者校验:仅拥有BIND_APP_FUNCTION_SERVICE权限的 system_server 可以调用。

    if (context.checkCallingPermission(BIND_APP_FUNCTION_SERVICE)
    == PERMISSION_DENIED) {
    throw new SecurityException(\”Can only be called by the system server.\”);
    }

    Manifest 声明示例,必须指定绑定权限:

    <service android:name=\”.YourService\”
    android:permission=\”android.permission.BIND_APP_FUNCTION_SERVICE\”>
    <intent-filter>
    <action android:name=\”android.app.appfunctions.AppFunctionService\” />
    </intent-filter>
    </service>

    51.2.7 请求与响应序列化格式

    ExecuteAppFunctionRequest与ExecuteAppFunctionResponse均使用 AppSearch 的GenericDocument作为参数载体。该设计使函数参数可以用 Schema 描述,而 AppSearch 原生支持索引与查询该 Schema。

    请求结构体:

    public final class ExecuteAppFunctionRequest implements Parcelable {
    @NonNull private final String mTargetPackageName;
    @NonNull private final String mFunctionIdentifier;
    @NonNull private final Bundle mExtras;
    @NonNull private final GenericDocumentWrapper mParameters;
    @Nullable private final AppInteractionAttribution mAttribution;

    响应结构体:

    public final class ExecuteAppFunctionResponse implements Parcelable {
    public static final String PROPERTY_RETURN_VALUE = \”androidAppfunctionsReturnValue\”;
    @NonNull private final GenericDocumentWrapper mResultDocumentWrapper;
    @NonNull private final Bundle mExtras;
    @NonNull private final List<AppFunctionUriGrant> mUriGrants;

    返回值存放在结果GenericDocument的PROPERTY_RETURN_VALUE键。Jetpack AppFunction SDK 提供强类型封装,负责打包、解析该文档。

    51.2.8 归因与交互日志

    每一次执行可以携带AppInteractionAttribution,描述触发本次调用的交互来源。Android17 将该类型从 appfunctions 包提升至android.app包,供整个应用交互 API 复用,开关标记为FLAG_ENABLE_APP_INTERACTION_API。

    public static final int INTERACTION_TYPE_OTHER = 0; // 需要自定义字符串
    public static final int INTERACTION_TYPE_USER_QUERY = 1;
    public static final int INTERACTION_TYPE_USER_SCHEDULED = 2;

    归因包含交互类型、可选自定义类型字符串(类型为INTERACTION_TYPE_OTHER时使用)、可选交互 Uri,指向原始上下文。隐私 UI 依靠该信息向用户解释函数执行缘由。

    Android17 不会持久化每次调用的历史数据库,而是把每一次执行写入平台 metrics 流水线 statsd。system_server 中的AppFunctionsLoggerWrapper运行在共享后台执行器,为每一次成功或失败输出结构化事件,归一化处理归因常量并标记函数类型。

    static final int FUNCTION_TYPE_UNSPECIFIED = 0;
    static final int FUNCTION_TYPE_STATIC = 1; // AppFunctionService实现
    static final int FUNCTION_TYPE_DYNAMIC_GLOBAL = 2; // registerAppFunction(Service/全局)
    static final int FUNCTION_TYPE_DYNAMIC_ACTIVITY = 3;// registerAppFunction(Activity作用域)

    void logAppFunctionSuccess(
    ExecuteAppFunctionAidlRequest request,
    ExecuteAppFunctionResponse response,
    int callingUid,
    long executionStartTimeMillis,
    @AppFunctionMetadata.AppFunctionType int appFunctionType) { … }

    日志事件记录调用 UID、目标包、请求中提取的交互类型、函数类型(静态 / 动态、全局 / Activity 域)、响应码,以及绑定服务完成之后统计的执行耗时。

    51.2.9 错误处理

    AppFunctionException定义了分类错误码体系:

    // 请求类错误 1000‑1999
    public static final int ERROR_DENIED = 1000;
    public static final int ERROR_INVALID_ARGUMENT = 1001;
    public static final int ERROR_DISABLED = 1002;
    public static final int ERROR_FUNCTION_NOT_FOUND = 1003;

    // 系统类错误 2000‑2999
    public static final int ERROR_SYSTEM_ERROR = 2000;
    public static final int ERROR_CANCELLED = 2001;
    public static final int ERROR_ENTERPRISE_POLICY_DISALLOWED = 2002;

    // 应用类错误 3000‑3999
    public static final int ERROR_APP_UNKNOWN_ERROR = 3000;

    getErrorCategory()将错误码区间映射为错误分类:

    public int getErrorCategory() {
    if (mErrorCode >= 1000 && mErrorCode < 2000) return ERROR_CATEGORY_REQUEST_ERROR;
    if (mErrorCode >= 2000 && mErrorCode < 3000) return ERROR_CATEGORY_SYSTEM;
    if (mErrorCode >= 3000 && mErrorCode < 4000) return ERROR_CATEGORY_APP;
    return ERROR_CATEGORY_UNKNOWN;
    }

    51.2.10 System Server 实现

    薄的SystemService:AppFunctionManagerService.java,负责发布 Binder 服务到Context.APP_FUNCTION_SERVICE,转发用户生命周期。业务逻辑主体在AppFunctionManagerServiceImpl,继承IAppFunctionManager.Stub,协调各个协作类。

    public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
    private final RemoteServiceCaller<IAppFunctionService> mRemoteServiceCaller;
    private final CallerValidator mCallerValidator;
    private final AppFunctionsLoggerWrapper mLoggerWrapper;
    private final IUriGrantsManager mUriGrantsManager;
    private final UriGrantsManagerInternal mUriGrantsManagerInternal;
    private final MultiUserDynamicAppFunctionRegistry mDynamicAppFunctionRegistry;
    private final AppFunctionMetadataReader mAppFunctionMetadataReader;
    private final AppFunctionMetadataObserver mAppFunctionMetadataObserver;
    private final VisibilityHelper mVisibilityHelper;
    private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
    // 访问校验委托给权限子系统
    private final AppFunctionAccessServiceInterface mAppFunctionAccessService;

    关键支撑类说明:

    类名
    职责
    RemoteServiceCallerImpl 绑定目标AppFunctionService,管理连接生命周期
    CallerValidatorImpl 强制校验EXECUTE_APP_FUNCTIONS/EXECUTE_APP_FUNCTIONS_SYSTEM权限,校验白名单
    MetadataSyncAdapter 应用包变更时,同步静态函数元数据至 AppSearch
    AppFunctionPackageMonitor 监听应用安装 / 更新 / 卸载事件
    MultiUserDynamicAppFunctionRegistry 保存每个用户下registerAppFunction运行时注册项
    AppFunctionMetadataReader 读取静态(AppSearch)与动态元数据,用于发现与状态查询
    AppFunctionMetadataObserver 基于 AppSearch 变更事件驱动observeAppFunctions回调
    SystemAppFunctionAllowlistReader 通过AllowlistManager解析签名代理白名单
    AppFunctionsLoggerWrapper 为每一次执行输出 statsd 埋点事件
    AppFunctionAccessService(权限子系统) 持久化(代理,目标)访问状态与标志位

    51.2.11 通过 AppSearch 实现函数发现

    应用安装、更新或设备开机时,MetadataSyncAdapter从目标应用AppFunctionService提取函数元数据,作为AppFunctionStaticMetadata文档索引存入 AppSearch。代理应用通过查询 AppSearch 完成函数发现。

    51.2.12 SafeOneTimeExecuteAppFunctionCallback

    关键防御封装,保证回调有且仅有一次被交付。

    public class SafeOneTimeExecuteAppFunctionCallback {
    private final AtomicBoolean mOnResultCalled = new AtomicBoolean(false);
    @NonNull private final IExecuteAppFunctionCallback mCallback;
    @Nullable private final CompletionCallback mCompletionCallback;
    @Nullable private final BeforeCompletionCallback mBeforeCompletionCallback;
    private final AtomicLong mExecutionStartTimeAfterBindMillis = new AtomicLong();

    public void onResult(@NonNull ExecuteAppFunctionResponse result) {
    if (!mOnResultCalled.compareAndSet(false, true)) {
    Log.w(TAG, \”Ignore subsequent calls to onResult/onError()\”);
    return;
    }
    try {
    if (mBeforeCompletionCallback != null) {
    mBeforeCompletionCallback.beforeOnSuccess(result);
    }
    mCallback.onSuccess(result);
    if (mCompletionCallback != null) {
    mCompletionCallback.finalizeOnSuccess(
    result, mExecutionStartTimeAfterBindMillis.get());
    }
    } catch (RemoteException ex) {
    Log.w(TAG, \”Failed to invoke the callback\”, ex);
    }
    }

    public void onError(@NonNull AppFunctionException error) {
    if (!mOnResultCalled.compareAndSet(false, true)) {
    Log.w(TAG, \”Ignore subsequent calls to onResult/onError()\”);
    return;
    }
    try {
    mCallback.onError(error);
    if (mCompletionCallback != null) {
    mCompletionCallback.finalizeOnError(
    error, mExecutionStartTimeAfterBindMillis.get());
    }
    } catch (RemoteException ex) {
    Log.w(TAG, \”Failed to invoke the callback\”, ex);
    }
    }

    该设计模式必要性:

  • 目标应用属于第三方代码,可能错误多次调用回调。AtomicBoolean.compareAndSet()保证仅第一次调用生效。
  • 捕获RemoteException:如果回调进程在结果返回前已死亡,异常仅打日志,不会崩溃 system_server。
  • 完成钩子:BeforeCompletionCallback与CompletionCallback允许 system_server 在回调交付前后执行附加逻辑(埋点日志、URI 授权、访问历史记录)。
  • public interface CompletionCallback {
    void finalizeOnSuccess(
    ExecuteAppFunctionResponse result, long executionStartTimeMillis);
    void finalizeOnError(
    AppFunctionException error, long executionStartTimeMillis);
    }

    public interface BeforeCompletionCallback {
    void beforeOnSuccess(ExecuteAppFunctionResponse result);
    }

  • 耗时统计:mExecutionStartTimeAfterBindMillis记录服务绑定完成之后的执行开始时刻,区分绑定开销与真正业务执行耗时。
  • 禁用机制:提供disable(),请求被取消或超时时阻止后续回调交付。
  • 51.2.13 executeAppFunction 实现深度解析

    system_server 的executeAppFunction是整个框架最核心路径,逐行解析从 AIDL 入口到绑定目标服务的完整链路。

    步骤 1:入口与初始校验

    @Override
    public ICancellationSignal executeAppFunction(
    @NonNull ExecuteAppFunctionAidlRequest requestInternal,
    @NonNull IExecuteAppFunctionCallback executeAppFunctionCallback) {

    int callingUid = Binder.getCallingUid();
    int callingPid = Binder.getCallingPid();

    final SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback =
    initializeSafeExecuteAppFunctionCallback(
    requestInternal, executeAppFunctionCallback, callingUid);

    String validatedCallingPackage;
    try {
    validatedCallingPackage =
    mCallerValidator.validateCallingPackage(requestInternal.getCallingPackage());
    mCallerValidator.verifyTargetUserHandle(
    requestInternal.getUserHandle(), validatedCallingPackage);
    } catch (SecurityException exception) {
    safeExecuteAppFunctionCallback.onError(
    new AppFunctionException(
    AppFunctionException.ERROR_DENIED, exception.getMessage()));
    return null;
    }

    SafeOneTimeExecuteAppFunctionCallback包装,保证无论目标应用多次应答还是崩溃,只返回一次成功 / 错误。

    步骤 2:线程池异步执行,不阻塞 Binder 线程

    ICancellationSignal localCancelTransport = CancellationSignal.createTransport();

    THREAD_POOL_EXECUTOR.execute(
    () -> {
    try {
    executeAppFunctionInternal(
    requestInternal,
    callingUid, callingPid,
    localCancelTransport,
    safeExecuteAppFunctionCallback,
    executeAppFunctionCallback.asBinder());
    } catch (Exception e) {
    safeExecuteAppFunctionCallback.onError(
    mapExceptionToExecuteAppFunctionResponse(e));
    }
    });
    return localCancelTransport;
    }

    任务提交至THREAD_POOL_EXECUTOR,避免占用 Binder 线程池。

    步骤 3:权限与状态基础校验(工作线程)

    @WorkerThread
    private void executeAppFunctionInternal(…) {
    // 企业策略校验
    if (!mCallerValidator.verifyEnterprisePolicyIsAllowed(callingUser, targetUser)) {
    safeExecuteAppFunctionCallback.onError(
    new AppFunctionException(
    AppFunctionException.ERROR_ENTERPRISE_POLICY_DISALLOWED, …));
    return;
    }

    // 目标包名校验非空
    if (TextUtils.isEmpty(targetPackageName)) {
    safeExecuteAppFunctionCallback.onError(
    new AppFunctionException(
    AppFunctionException.ERROR_INVALID_ARGUMENT, …));
    return;
    }

    步骤 4:链式 Future 完成权限校验 + AppSearch 读取启用状态 实现使用AndroidFuture.thenCompose()做非阻塞权限校验,紧接着查询 AppSearch 获取函数启用状态。

    mCallerValidator
    .verifyCallerCanExecuteAppFunction(
    callingUid, callingPid, targetUser,
    requestInternal.getCallingPackage(),
    targetPackageName,
    requestInternal.getClientRequest().getFunctionIdentifier())
    .thenCompose(canExecuteResult -> {
    if (canExecuteResult == CAN_EXECUTE_APP_FUNCTIONS_DENIED) {
    return AndroidFuture.failedFuture(
    new SecurityException(\”Caller does not have permission\”));
    }
    return isAppFunctionEnabled(
    functionIdentifier, targetPackageName,
    getAppSearchManagerAsUser(userHandle), THREAD_POOL_EXECUTOR)
    .thenApply(isEnabled -> {
    if (!isEnabled) {
    throw new DisabledAppFunctionException(\”Disabled\”);
    }
    return canExecuteResult;
    });
    })

    步骤 5:服务解析与绑定

    .thenAccept(canExecuteResult -> {
    int bindFlags = Context.BIND_AUTO_CREATE;
    if (canExecuteResult
    == CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION) {
    bindFlags |= Context.BIND_FOREGROUND_SERVICE;
    }
    Intent serviceIntent =
    mInternalServiceHelper.resolveAppFunctionService(
    targetPackageName, targetUser);
    // 授予隐式可见性,允许目标看到调用方
    mPackageManagerInternal.grantImplicitAccess(
    grantRecipientUserId, serviceIntent,
    grantRecipientAppId, callingUid, /* direct= */ true);
    bindAppFunctionServiceUnchecked(
    requestInternal, serviceIntent, targetUser,
    localCancelTransport, safeExecuteAppFunctionCallback,
    bindFlags, callerBinder, callingUid);
    })

    关键点:调用方具备EXECUTE_APP_FUNCTIONS权限时,使用BIND_FOREGROUND_SERVICE提升目标服务进程优先级。自调用(同一包名)不会获得该优先级提升。

    51.2.14 RemoteServiceCaller 模式

    RemoteServiceCallerImpl实现一次性 Service 绑定模式:

    public class RemoteServiceCallerImpl<T> implements RemoteServiceCaller<T> {
    public boolean runServiceCall(
    Intent intent, int bindFlags, UserHandle userHandle,
    long cancellationTimeoutMillis, CancellationSignal cancellationSignal,
    RunServiceCallCallback<T> callback, IBinder callerBinder) {

    OneOffServiceConnection serviceConnection =
    new OneOffServiceConnection(intent, bindFlags, userHandle,
    cancellationTimeoutMillis, cancellationSignal,
    callback, callerBinder);
    return serviceConnection.bindAndRun();
    }

    OneOffServiceConnection是自定义ServiceConnection,行为:

  • 调用Context.bindServiceAsUser()连接目标服务
  • 设置取消监听器,超时后执行 unbind
  • 监听调用方 Binder 死亡,调用方进程死亡则自动取消
  • 回调完成后自动解绑
  • private class OneOffServiceConnection
    implements ServiceConnection, ServiceUsageCompleteListener {

    public boolean bindAndRun() {
    boolean bindServiceResult =
    mContext.bindServiceAsUser(mIntent, this, mFlags, mUserHandle);

    if (bindServiceResult) {
    mCancellationSignal.setOnCancelListener(() -> {
    mCallback.onCancelled();
    mHandler.postDelayed(mCancellationTimeoutRunnable,
    mCancellationTimeoutMillis);
    });
    mDirectServiceVulture = () -> {
    Slog.w(TAG, \”Caller process onDeath signal received\”);
    mCancellationSignal.cancel();
    };
    mCallerBinder.linkToDeath(mDirectServiceVulture, 0);
    }
    return bindServiceResult;
    }

    该模式保证资源一定被清理,无论调用方崩溃、目标应用崩溃或者用户主动取消。

    51.2.15 多用户支持

    实现完整支持多用户。每个用户拥有:

    • 独立 AppSearch 数据库,保存静态函数元数据
    • 独立PackageMonitor监听包变更
    • MultiUserDynamicAppFunctionRegistry中独立分片保存运行时注册项
    • 权限子系统持久化独立的(代理,目标)访问状态与标志位

    public void onUserUnlocked(TargetUser user) {
    if (enableDynamicAppFunctions()) {
    mAppFunctionMetadataObserver.registerAppSearchObserverForUser(user);
    } else {
    registerAppSearchObserver(user);
    }
    trySyncRuntimeMetadata(user.getUserHandle(), …);
    PackageMonitor pkgMonitorForUser =
    AppFunctionPackageMonitor.registerPackageMonitorForUser(
    mContext, user, mAppFunctionMetadataObserver);
    mPackageMonitors.append(user.getUserIdentifier(), pkgMonitorForUser);
    mDynamicAppFunctionRegistry.onUserUnlocked(user, …);
    }

    public void onUserStopping(@NonNull TargetUser user) {
    if (enableDynamicAppFunctions()) {
    mAppFunctionMetadataObserver.unregisterAppSearchObserverForUser(user);
    } else {
    MetadataSyncPerUser.removeUserSyncAdapter(user.getUserHandle());
    }
    mPackageMonitors.get(user.getUserIdentifier()).unregister();
    mPackageMonitors.delete(user.getUserIdentifier());
    }

    public void onUserStopped(@NonNull TargetUser user) {
    mDynamicAppFunctionRegistry.onUserStopped(user);
    }

    动态函数标记开启时,每个用户的 AppSearch 观察者由AppFunctionMetadataObserver持有,变更事件同时分发给内部元数据缓存以及客户端observeAppFunctions回调。运行时注册表以 userId 为 key;当用户停止,该用户下全部注册项被销毁。

    51.2.16 代理白名单架构

    Android17 代理白名单不再是 DeviceConfig 与 Settings.Secure 字符串拼接,改用平台AllowlistManager,白名单 ID 为ALLOWLIST_ID_APP_FUNCTION。输入签名代理包,返回该代理可访问的目标包集合。AppFunctions 服务通过SystemAppFunctionAllowlistReader消费该能力。

    读取器将代理最新签名证书哈希封装为SignedPackage,向AllowlistManager查询合法目标包;查询结果放入 LruCache 缓存,相同代理重复执行可省去一次 IPC。

    @Override
    public CompletableFuture<Boolean> isAllowlisted(
    String agentPackageName, String targetPackageName, int userId) {
    if (agentPackageName.equals(targetPackageName)) {
    return AndroidFuture.completedFuture(true); // 自身函数永远允许
    }
    SignedPackage agentSignedPackage =
    new SignedPackage(agentPackageName, /* certificate digest */ …);
    maybeStartAllowlistListener();
    return getValidTargetPackages(agentSignedPackage)
    .thenApply(allowlistTargets ->
    allowlistTargets.contains(WILDCARD_PACKAGE_NAME)
    || allowlistTargets.contains(targetPackageName));
    }

    三条关键行为:

  • 自访问隐式放行:代理与目标包相同,应用永远可以调用自身函数。
  • 通配符目标:白名单配置通配符包名,代理可访问全部目标。
  • 变更监听:首次使用注册OnAllowlistChangedListener;白名单更新时缓存自动失效,不再只在开机阶段读取配置字符串。
  • 51.2.17 AppFunction 响应中的 URI 授权

    当目标应用在响应中返回 content URI,框架可以为调用代理授予临时 URI 权限。

    private final IUriGrantsManager mUriGrantsManager;
    private final UriGrantsManagerInternal mUriGrantsManagerInternal;
    private final IBinder mPermissionOwner;

    // 构造函数中初始化
    mPermissionOwner = mUriGrantsManagerInternal.newUriPermissionOwner(\”appfunctions\”);

    响应中的AppFunctionUriGrant指明需要向代理授予哪些 URI。授权经由mUriGrantsManager.grantUriPermissionFromOwner完成,绑定到 AppFunctions 专属 permission owner。权限有效期直到 owner 释放或者设备重启。

    51.2.18 Shell 命令支持

    服务实现onShellCommand(),用于开发者调试。

    @Override
    public void onShellCommand(
    FileDescriptor in, FileDescriptor out, FileDescriptor err,
    @NonNull String[] args, ShellCallback callback,
    @NonNull ResultReceiver resultReceiver) {
    new AppFunctionManagerServiceShellCommand(mContext, this)
    .exec(this, in, out, err, args, callback, resultReceiver);
    }

    adb 命令:adb shell cmd app_function

    51.2.19 服务启动与生命周期

    本框架属于SystemService。AppFunctionManagerService.onStart(),当AppFunctionManagerConfiguration.isSupported(context)为 true 时,把 Binder 服务发布到Context.APP_FUNCTION_SERVICE;开启 App Interaction API 标记时,额外发布本地服务AppInteractionService。

    @Override
    public void onStart() {
    if (AppFunctionManagerConfiguration.isSupported(getContext())) {
    publishBinderService(Context.APP_FUNCTION_SERVICE, mServiceImpl);
    }
    if (Flags.enableAppInteractionApi()) {
    publishLocalService(AppInte

    赞(0)
    未经允许不得转载:171主机测评 » 第 51 章:AI、AppFunctions 与计算机控制
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址