title: Android 17 BiometricService 架构与性能优化 chapter: '1.24' section: '1.24' status: finalized pipeline_stage: ready-to-publish applicable_versions: Android 12 (API 31) - Android 17 (API 37) last_verified: '2026-08-18' last_verified_against: AOSP android-17.0.0_r1 confidence: high sources:
- type: aosp path: frameworks/base/core/java/android/hardware/biometrics/BiometricPrompt.java
- type: aosp path: frameworks/base/core/java/android/hardware/biometrics/BiometricManager.java
- type: aosp path: frameworks/base/core/java/android/hardware/biometrics/IAuthService.aidl
- type: aosp path: frameworks/base/core/res/AndroidManifest.xml
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/AuthService.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/BiometricService.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/PreAuthInfo.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/AuthSession.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/BiometricSensor.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/BiometricHandlerProvider.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStartUserClient.java
- type: aosp path: frameworks/base/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
- type: aosp path: frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
- type: aosp path: frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
- type: aosp path: hardware/interfaces/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
- type: aosp path: hardware/interfaces/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
- type: aosp path: hardware/interfaces/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
- type: aosp path: hardware/interfaces/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
- type: aosp path: hardware/interfaces/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
- type: official path: developer.android.com/reference/android/hardware/biometrics/BiometricManager
- type: official path: developer.android.com/reference/android/hardware/biometrics/BiometricPrompt
- type: aosp-doc path: source.android.com/docs/security/features/biometric
- type: aosp-doc path: source.android.com/docs/security/features/authentication tags:
- biometric
- system-service
- architecture
- fingerprint
- face
- hal
- tee
- performance related_chapters:
- '1.10'
- '1.23'
- '21.4'
- '20.10'
Android 17 BiometricService 架构与性能优化
版本范围是 Android 17 / API 37 / AOSP android-17.0.0_r1。这里讨论应用通过系统认证面板 BiometricPrompt 发起的认证;锁屏直接调用 FingerprintManager、录入流程和厂商私有解锁通道属于其他路径。
BiometricService 是一次 BiometricPrompt 会话的仲裁者,但它并非应用直接访问的第一个 Binder 服务,也不执行图像采集和模板匹配。应用入口、系统策略、会话状态、传感器队列、认证 UI 与安全执行环境分属不同组件。定位“生物识别慢”时,需要判断时间消耗落在哪一段。
Android 17 的真实调用链
进程与接口边界
下文保留几组与源码一一对应的术语。provider 管理一种模态的一组传感器,BiometricScheduler 为单个传感器串行调度任务。client 表示一次认证、录入或枚举任务,operation 表示 client 发给 HAL 的具体操作,session 是 framework 与 HAL 为当前用户复用的会话接口。HAL(硬件抽象层)连接 Android framework 与厂商实现;AIDL 用于当前稳定接口,HIDL 是旧版接口技术,Android 17 仍保留兼容适配。HAT(HardwareAuthToken)是安全环境生成、可供 Keystore 验证的认证令牌。
进程图展示了 SDK、system_server、SystemUI、HAL 与安全环境各自负责的部分:
App process
BiometricPrompt / BiometricManager
│ IAuthService
▼
system_server
AuthService
├─ 权限、AppOps、前台状态与 PromptInfo 检查
└─ 调用内部 IBiometricService
▼
BiometricService
├─ PreAuthInfo:计算当前可用认证器
├─ AuthSession:管理一次 Prompt 会话
└─ BiometricSensor:包装已注册认证器
│ IBiometricAuthenticator
├──────────────────────────────┐
▼ ▼
FingerprintService FaceService
→ Provider → Provider
→ per-sensor Scheduler → per-sensor Scheduler
→ AuthenticationClient → AuthenticationClient
│ AIDL ISession,或旧 HAL 兼容适配
▼
vendor biometric HAL process
│ vendor-defined secure channel
▼
secure isolated environment
采集保护、模板保护、匹配、Strong 认证的 HAT 生成
system_server ── IStatusBarService ──► SystemUI process
AuthSession AuthController / AuthContainerView
◄──────── IBiometricSysuiReceiver ────────┘
其中有四个需要区分的边界:
BiometricPrompt.Builder.build()从Context.AUTH_SERVICE取得IAuthService。普通应用不直接持有IBiometricService。AuthService与BiometricService都在system_server,前者是 SDK 入口与访问控制层,后者是内部仲裁层。AuthController运行在独立的 SystemUI 进程,不属于system_server。- HAL 运行在 vendor 侧进程;采集、模板与匹配的安全要求由安全隔离环境及厂商实现满足。TEE 是 Trusted Execution Environment(可信执行环境),不能把 HAL 进程本身称为 TEE。
对应源码入口:
BiometricPrompt.Builder.build():core/java/android/hardware/biometrics/BiometricPrompt.javaAuthService.onStart():发布Context.AUTH_SERVICEBiometricService.onStart():发布内部Context.BIOMETRIC_SERVICEAuthController:实现CommandQueue.Callbacks,接收状态栏 Binder 命令。
authenticate() 如何进入系统
BiometricPrompt.authenticate() 在应用进程完成参数检查,保存调用方提供的 Executor(决定回调在哪个线程执行)和 AuthenticationCallback,然后调用:
final long authId = mService.authenticate(
mToken,
operationId,
userId,
mBiometricServiceReceiver,
mContext.getPackageName(),
promptInfo);
这段代码用于确认两个事实:
CryptoObject存在时,operationId来自关联的加密操作;没有CryptoObject时为0。- 内部返回值是请求 ID,用于后续取消和回调关联。公开的
authenticate()仍以异步回调向应用报告结果。
AuthService.authenticate() 随后检查:
- 同用户调用所需的生物识别权限;跨用户调用所需的内部权限;
- AppOps 是否允许;
- token、receiver、包名和
PromptInfo是否为空; - 调用 UID/PID 是否位于前台;
- 非公开、测试或高级 prompt 选项所需的额外权限。
通过检查后,AuthService 清除来访 Binder identity,避免后续系统内部调用继续沿用应用身份,再把请求交给内部 BiometricService。BiometricServiceWrapper.authenticate() 只做内部权限、参数和认证器配置检查,然后把后续工作投递到专用 Handler 所在线程。它不会在应用 Binder 调用栈中等待传感器完成。
因此,authenticate() 调用返回快,只能说明请求已被系统接受,不能说明认证器已经开始采集。
新请求如何处理旧会话
Android 17 的 BiometricService 只有一个 mAuthSession。创建新会话时,如果旧会话还在,authenticateInternal() 会强制取消旧会话、关闭旧 UI,并向旧客户端返回取消。
这与“所有 App 认证请求都在 BiometricService 排队”不同。队列存在于每个传感器的 BiometricScheduler;BiometricPrompt 层的新会话会替换旧会话。公开 API 文档也明确指出:已有认证进行时再次调用 authenticate(),旧客户端会收到取消。
应用不应在配置变化、重复点击或状态重组时快速执行“取消—重建—认证”。这种写法会产生界面重建、HAL 取消确认以及 scheduler 队列清理开销,还会让一次用户操作产生多份互相覆盖的回调。
预认证:PreAuthInfo 决定谁有资格参与
BiometricService.handleAuthenticate() 先创建 PreAuthInfo。它读取请求、传感器属性、用户状态和系统策略,生成:
eligibleSensors:本次可以参与的传感器;ineligibleSensors:传感器及其不可用原因;credentialRequested/credentialAvailable;- 是否需要确认;
- 生物识别强度和 Identity Check(在受保护场景要求强生物识别的系统能力)相关状态。
资格判断项
| 检查项 | Android 17 的判断依据 | 常见结果 |
|---|---|---|
| 请求强度 | BIOMETRIC_STRONG、BIOMETRIC_WEAK 等位掩码(bit field) | 传感器强度不足 |
| 运行时强度 | OEM 声明强度与 BiometricStrengthController 更新值 | 安全更新前需降级 |
| 硬件状态 | isHardwareDetected() | 硬件不可用 |
| 录入状态 | hasEnrolledTemplates() | 尚未录入 |
| 锁定状态 | getLockoutModeForUser();预认证分支显式挡下限时锁定 | 限时锁定;永久锁定还可能通过后续 sensor error/lockout 回调进入会话处理 |
| 用户设置 | 是否允许应用使用该模态 | 对 App 禁用 |
| 设备策略 | DPM(Device Policy Manager,设备策略管理器)是否禁用指纹、人脸或虹膜 | 被管理策略禁用 |
| 人脸相机 | 相机可用性和相机隐私开关 | 相机不可用或隐私限制 |
| 设备凭据 | TrustManager.isDeviceSecure() | PIN/图案/密码不可用 |
| 显示环境 | 外接或受控虚拟显示相关策略 | 当前显示不允许认证 |
canAuthenticate(authenticators) 复用这类信息计算公开结果。它是调用时刻的状态快照,不会预留传感器,也不保证稍后的 authenticate() 一定成功。前后台状态、相机隐私、锁定、用户切换、另一个认证会话和 HAL 健康状态都可能在两次调用之间变化。
正确的应用策略是:
- 用
canAuthenticate()决定是否展示入口或引导录入; - 仍以
AuthenticationCallback作为本次认证的最终结果; - 不因为预检查成功而忽略错误回调。
强度由安全等级决定
指纹、人脸是认证模态;Class 3、Class 2、Class 1 是安全等级。二维相机不自动等于 Class 2,深度相机也不自动等于 Class 3。设备实现必须按 CDD(Compatibility Definition Document,兼容性定义文档)的架构安全与抗欺骗要求声明并通过测试。
Android API 的能力边界是:
| 类型 | BiometricPrompt | Keystore 定时授权 | Keystore 单次操作授权 |
|---|---|---|---|
BIOMETRIC_STRONG / Class 3 | 支持 | 支持 | 支持 |
BIOMETRIC_WEAK / Class 2 | 支持 | 不支持 | 不支持 |
| Class 1 / Convenience | 不进入公开 BiometricPrompt API | 不支持 | 不支持 |
DEVICE_CREDENTIAL | 支持 | 支持 | 支持 |
BiometricSensor.getCurrentStrength() 将 OEM 声明值与运行时更新值按位掩码合并,结果不会比 OEM 初始声明更强。安全更新导致的降级会直接影响 PreAuthInfo 的资格判断。
API 37 增加了受角色和权限限制的 BiometricManager.getBiometricSensorStrengths()。调用方必须位于前台,同时持有 USE_BIOMETRIC 和角色授予的 ACCESS_BIOMETRIC_SENSOR_STRENGTHS;框架权限注释列出的授予范围是钱包、设备策略管理,以及便于测试的 system shell。返回结果把每种模态映射到 BIOMETRIC_STRONG 或 LESS_THAN_STRONG,不会向调用方暴露 Class 3 以下的细分等级。普通应用仍应使用 canAuthenticate()。
传感器发现、注册与会话复用
注册从 AuthService.onStart() 发起
Android 17 源码在 AuthService 中给出了注册顺序:
AuthService.onStart()
→ registerAuthenticators()
→ FingerprintService.registerAuthenticators()
→ providers → sensors
→ BiometricService.registerAuthenticator()
→ FaceService.registerAuthenticators()
→ providers → sensors
→ BiometricService.registerAuthenticator()
→ IrisService.registerAuthenticators()
BiometricService 用 CopyOnWriteArrayList<BiometricSensor> mSensors 保存注册结果。源码中没有 SensorListState。
Android 17 优先支持稳定 AIDL HAL,同时仍有 HIDL 配置和 HidlToAidlSessionAdapter 等兼容路径。分析具体设备时,应查看 provider 类型和 HAL instance(已注册的 HAL 服务实例),不能仅凭系统版本断定设备必走 AIDL。
BiometricSensor 保存什么
每个 BiometricSensor 只包装仲裁所需的少量状态:
id、modality;- OEM 声明强度和运行时强度;
IBiometricAuthenticator impl;- 当前 sensor state;
- 用于关联准备请求与回调的 cookie,以及最近错误。
它不持有模板内容,也没有 lockoutState 字段。锁定状态通过对应 sensor service/provider 查询,并由 sensor 侧 tracker(状态跟踪器)与 AuthSessionCoordinator 协调。
AIDL session 并非每次认证都重建
Fingerprint 和 Face AIDL 的每个 sensor 都维护 mCurrentSession,provider 通过这些 sensor 与 scheduler 驱动当前用户的 HAL 会话。用户匹配且 session 健康时,认证 client 复用它;切换用户、HAL 死亡或 session 关闭时才创建或替换。
创建路径的接口形态是:
interface IFingerprint {
SensorProps[] getSensorProps();
ISession createSession(int sensorId, int userId, ISessionCallback cb);
}
interface IFace {
SensorProps[] getSensorProps();
ISession createSession(int sensorId, int userId, ISessionCallback cb);
}
所以,不能把 createSession() 固定计入每次 BiometricPrompt 延迟。若 trace 中出现用户切换、HAL 重连或 start-user client(为新用户建立 HAL 会话的任务),应单独标记为冷路径。
两层状态机:Prompt 会话与单个传感器
AuthSession 管理整次 Prompt
Android 17 的主要 session state 为:
| 状态 | 含义 |
|---|---|
STATE_AUTH_IDLE | 尚未准备认证 |
STATE_AUTH_CALLED | 已让候选传感器准备,等待 cookie |
STATE_AUTH_STARTED | 非指纹传感器已可启动,Prompt 已请求显示 |
STATE_AUTH_STARTED_UI_SHOWING | UI 动画完成,允许启动指纹 |
STATE_AUTH_PAUSED | 可重试模态暂停 |
STATE_AUTH_PAUSED_RESUMING | 正在为重试重新准备传感器 |
STATE_AUTH_PENDING_CONFIRM | 匹配成功,等待用户显式确认 |
STATE_AUTHENTICATED_PENDING_SYSUI | 已认证,等待 SystemUI 完成收尾 |
STATE_ERROR_PENDING_SYSUI | 错误已暂存,等待 UI 完成展示 |
STATE_SHOWING_DEVICE_CREDENTIAL | 转入 PIN、图案或密码 |
客户端 Binder 死亡时还会进入 STATE_CLIENT_DIED_CANCELLING 清理路径。源码的 @IntDef 没有把这个值列入主状态集合,但处理分支存在。
AuthSession 只有一个 mState。源码中没有 AUTH_STARTED_FACE 和 AUTH_STARTED_FINGERPRINT 这类并行 session state。多传感器进度由每个 BiometricSensor 的状态分别记录。
BiometricSensor 管理单个传感器
单传感器状态为:
UNKNOWN
→ WAITING_FOR_COOKIE
→ COOKIE_RETURNED
→ AUTHENTICATING
→ CANCELING
→ STOPPED
cookie 是一次准备请求的关联值,用来把以下三层动作对应起来:
AuthSession为每个 eligible sensor 生成非零 cookie。BiometricSensor.goToStateWaitingForCookie()调用prepareForAuthentication()。- 对应 provider 创建 authentication client,并把它放入该传感器的 scheduler。
- client 到达队首且可以开始时,scheduler 通过
onReadyForAuthentication(requestId, cookie)通知BiometricService。 - 所有 cookie 返回后,
AuthSession再调用startPreparedClient(cookie)。
这套“准备—就绪—启动”握手避免 Prompt 仲裁层在 sensor operation 尚未到达队首时提前启动 HAL。
启动顺序经过 UI 协调
Android 17 的启动顺序并非简单地“指纹和人脸同时开始”:
goToInitialState()
→ 所有 eligible sensors 执行 prepare
→ 等待所有 cookie 返回
→ 先启动非指纹传感器
→ 请求 SystemUI 显示 Prompt
→ SystemUI 入场动画完成
├─ onDialogAnimatedIn(startFingerprintNow = true)
│ → 启动已准备的指纹
└─ startFingerprintNow = false
→ 继续延后
→ SystemUI 稍后调用 onStartFingerprintNow()
源码注释说明了延后指纹的原因:避免指纹交互提示(affordance)在 BiometricPrompt UI 完成入场前出现。人脸可以先运行;指纹是否随入场动画结束启动,由 SystemUI 根据当前 UI 和模态策略决定。
重试时 UI 已存在,AuthSession 重新准备可重试传感器,cookie 就绪后直接恢复相应传感器,不再创建第二个对话框。
线程模型与 Binder 回调
framework 线程
| 位置 | Android 17 线程 | 主要工作 |
|---|---|---|
AuthService Binder 入口 | system_server Binder 线程 | 权限、AppOps、前台和参数检查 |
BiometricService 会话逻辑 | BiometricsCallbackHandler | 串行处理 session、sensor 与 SystemUI 回调 |
| 指纹 provider/scheduler | FingerprintHandler | 创建 client、调度单传感器操作 |
| 人脸 provider/scheduler | FaceHandler | 创建 client、调度单传感器操作 |
SystemUI AuthController | SystemUI 主线程为主 | 创建、更新和关闭认证 UI |
| App callback | 调用方传入的 Executor | onAuthentication*() |
BiometricHandlerProvider 为 BiometricsCallbackHandler 创建独立 HandlerThread,优先级为 THREAD_PRIORITY_DISPLAY;Face 和 Fingerprint handler 也是独立线程,优先级为 THREAD_PRIORITY_DEFAULT。
Sensor HAL 回调与 SystemUI 回调到达 Binder stub(接收端接口实现)后,BiometricService 都会再次 post() 到 callback handler。这样,mAuthSession 的状态转换集中在一个串行执行上下文中,避免由多个 Binder 线程直接并发修改。
应用回调线程
BiometricPrompt 的 receiver 会执行:
mExecutor.execute(() -> {
mAuthenticationCallback.onAuthenticationSucceeded(result);
});
onAuthenticationFailed()、onAuthenticationError() 和帮助信息也遵守同一 Executor。使用 Context.getMainExecutor() 时,回调中的数据库、网络、复杂解密或页面初始化都会占用应用主线程;改用后台 Executor 时,涉及 View 的操作必须切回主线程。
BiometricScheduler:每个传感器串行调度操作
scheduler 怎样排队
每个 AIDL sensor 持有一个 BiometricScheduler,包含:
- 一个保存待执行任务的
Deque<BiometricSchedulerOperation> mPendingOperations; - 一个
mCurrentOperation; - 当前用户 session;
- 最近的 operation 记录和统计信息。
队首 operation 分两类:
- cookie 为
0:scheduler 可以直接start(); - cookie 非
0:先回报 BiometricService,等待startPreparedClient(cookie)。
新 client 声明 interruptsPrecedingClients() 时,scheduler 会:
- 把可取消的 pending operation(待执行任务)标为 canceling;
- 当前 operation 已开始且可中断时,请求取消;
- 等当前 operation 的完成 callback 执行后,再启动队列中的下一项。
因此,“录入一定比认证优先”或“认证一定能抢占录入”都不成立。是否中断取决于具体 client 的属性、当前 operation 是否已经开始以及它是否可取消。
Fingerprint 与 Face HAL 的终止条件不同
Fingerprint AIDL 把方法分为 non-interrupting operation(同一 session 中排他执行的主要操作)和 interrupting operation(可在主要操作期间调用的交互方法)。一个 session 同时只能执行一个 non-interrupting operation;authenticate()、enroll()、detectInteraction() 属于可取消的 non-interrupting operation。取消后,HAL 必须用 Error::CANCELED 结束该 operation。这里的 interrupting 是 HAL 接口分类,不表示 scheduler 会抢占前一个 client。
Face AIDL 没有这组 interrupting operation 分类,接口约束是一个 session 同时只能执行一个 operation。Face 的 onAuthenticationFailed() 是终止回调;Fingerprint 的同名拒绝匹配回调不是终止回调,指纹 operation 可以继续等待下一次触摸。framework 的 scheduler 会等当前 operation 的终止回调完成,再启动下一个排队操作。
指纹 AIDL 的主要方法是:
ICancellationSignal authenticate(long operationId);
ICancellationSignal enroll(HardwareAuthToken hat);
ICancellationSignal detectInteraction();
void enumerateEnrollments();
void removeEnrollments(int[] enrollmentIds);
void generateChallenge();
void revokeChallenge(long challenge);
void resetLockout(HardwareAuthToken hat);
void close();
UDFPS(Under-Display Fingerprint Sensor,屏下指纹传感器)的 onPointerDown*()、onPointerUp*()、onUiReady() 等属于可在采集 operation 运行时调用的交互方法,不应和第二个 authenticate operation 混为一谈。
Face AIDL 也使用 authenticate() 和 detectInteraction(),没有 detectInteractive()。Android 17 还提供带 OperationContext 的变体,HAL 可以利用显示、AOD(Always-On Display,息屏显示)等上下文优化执行,也可以忽略额外上下文并按基础方法处理。
不要虚构统一超时
Android 17 的 AuthSession 没有“所有认证 30~60 秒强制结束”的统一常量。超时可能来自:
- HAL 对当前采集返回
BIOMETRIC_ERROR_TIMEOUT; - sensor client 的具体实现;
- SystemUI 的交互状态;
- scheduler watchdog 的显式调用;
- OEM HAL 或安全环境。
BiometricScheduler.startWatchdog() 中有 10 秒清理定时器,Fingerprint/Face service 也暴露了受 USE_BIOMETRIC_INTERNAL 保护的 scheduleWatchdog() 内部入口,provider 会把它转为对应 scheduler 的 startWatchdog()。这仍不是 BiometricPrompt 每次 authenticate() 自动启用的用户认证超时,不能把它描述成所有认证 10 秒或 30~60 秒强制结束。
排查超时时,应记录实际 error、modality(指纹、人脸等认证模态)、vendorCode 和当前 operation,不要套用固定秒数。
指纹、UDFPS 与人脸的性能边界
指纹路径
下面的调用链用于区分 provider 排队、client 启动和 HAL operation:
FingerprintService.prepareForAuthentication()
→ FingerprintProvider.scheduleAuthenticate()
→ FingerprintAuthenticationClient
→ per-sensor BiometricScheduler
→ AIDLSession.authenticate[WithContext](operationId)
→ ISessionCallback
provider 在自己的 handler 上构造 client。client 启动 HAL operation 后保存 ICancellationSignal;取消时调用它的 cancel(),并等待 HAL 的最终回调完成生命周期。
不要把下面这些时间合成一个“指纹算法耗时”:
- operation 在 scheduler 队列中的等待;
- 当前用户 AIDL session 的启动或重建;
- Prompt 入场完成前的指纹延后;
- UDFPS overlay(屏幕上的指纹交互层)、触摸命中、显示模式与刷新率协调;
- HAL 采集和 secure matcher(安全环境中的匹配器);
- 成功动画、对话框关闭与 App Executor 调度。
UDFPS 是 UI、显示和 HAL 的协作
SystemUI 的 AuthController 根据 sensor properties(传感器属性)创建 UdfpsController,维护 sensor bounds(传感器在屏幕上的区域)和 display scale(显示缩放比例),并向 framework 注册 UDFPS overlay controller。指纹 authentication client 收到 PointerContext 后调用 HAL 的 onPointerDownWithContext() 或兼容方法。
一次 UDFPS 卡顿可能发生在:
- Prompt 尚未完成入场;
- overlay 尚未就绪;
- 触摸未命中 sensor bounds;
- 显示模式或高刷新率请求尚未完成;
- HAL 尚未回报 acquired(样本采集状态);
- 采集质量不足,多次 acquired 后才匹配;
- 匹配完成,但成功 UI 仍在收尾。
UDFPS 延迟高度依赖面板、传感器、贴膜、亮度策略与 vendor HAL。没有硬件和 trace 证据时,不应给出跨设备通用的毫秒区间。
人脸路径
人脸采用相同的 provider/scheduler 分层,但 HAL 回调和失败终止语义与指纹不同:
FaceService.prepareForAuthentication()
→ FaceProvider.scheduleAuthenticate()
→ FaceAuthenticationClient
→ per-sensor BiometricScheduler
→ AIDLSession.authenticate[WithContext](operationId)
→ authentication frame / acquired / success / failure / error
人脸 client 可以接收 FaceAuthenticationFrame,把 acquired 信息和帮助文案交给 UI。一次拒绝匹配(reject)会结束当前 face authentication client;在 BiometricPrompt 中,AuthSession 可进入暂停状态,由用户点击重试后重新 prepare。
是否需要显式确认由三项共同决定:
- 该 sensor 是否支持确认;
- 用户设置是否要求该模态总是确认;
PromptInfo是否请求确认。
确认策略与“二维/三维”或“Class 2/Class 3”没有固定一一映射。
多模态不是融合算法
当人脸和指纹都符合本次请求条件(eligible)时,AuthSession 可以准备多个 sensor,但 Android 17 的通用 framework 代码不执行厂商级特征融合。它协调各 sensor 的启动、UI、成功、失败和取消:
- 非指纹 sensor 在所有 cookie 返回后先启动;
- 指纹等待 UI 信号;
- 任一 sensor 成功后,session 记录
mAuthenticatedSensorId; - 无需确认时取消其他 sensor;
- 需要确认时,源码会为特定侧边指纹场景保留传感器,其余 sensor 取消;
- 后到的成功或错误回调会按当前 session/requestId 状态过滤。
因此,双模态设备的总延迟不能简单写成 max(face, fingerprint)。两个模态的启动时刻不同,失败后的 UI 策略也不同。
安全边界:模板、HAT 与 Keystore
framework 看不到原始模板
Android 对 Class 2 和 Class 3 生物识别要求采集、录入和识别位于安全隔离环境中。原始生物数据和模板不得暴露给 Android framework,持久化数据需要设备专属密钥保护。
framework 能看到的只有:
- sensor metadata;
- acquired、success、failure、error 等事件;
- enrollment ID 等受限标识;
- Strong 认证成功时返回的 HardwareAuthToken;
- 用于会话协调的 requestId、cookie ID。
具体使用 TEE、Secure Element(安全元件)、StrongBox 或其他受支持安全硬件,由设备实现决定。StrongBox 主要是隔离的 KeyMint 实现和安全存储能力;它可能保存某些用户相关数据,但不能作为所有 biometric matcher 所在位置的统称。
HardwareAuthToken 的字段
Android 17 的 android.hardware.keymaster.HardwareAuthToken 包含:
challenge
userId // secure user ID,不是 Android userId/UID
authenticatorId // 当前录入集合对应的 secure authenticator ID
authenticatorType
timestamp
mac // HMAC-SHA256
HAT 有两类用途:
- 录入或解除锁定(enrollment/reset lockout):HAL 验证由设备凭据等安全认证产生的 HAT;
- Strong 生物识别成功:HAL 用传入的
operationId填入 challenge,生成 HAT,授权对应的 auth-per-use key operation(每次使用都要求认证的密钥操作)。
只有 Strong sensor 可以在成功回调中返回可供 Keystore 使用的 HAT。非 Strong sensor 即使回传 token,Android 17 的 AuthSession.onAuthenticationSucceeded() 也会将其丢弃。
成功回调为何晚于 HAL success
Strong sensor 成功后,AuthSession 暂存 token,并通知 SystemUI 播放成功或确认 UI。SystemUI dismiss 后:
AuthSession.onDialogDismissed()把生物识别 HAT 或设备凭据 attestation(凭据验证证明)交给KeyStoreAuthorization.addAuthToken();- 再调用应用侧
onAuthenticationSucceeded(); - 清理其他 sensor 和当前 session。
App 观察到的 success 时间包含 UI 收尾和 token 注入阶段。HAL 已经匹配成功,不代表 App callback 已经执行。
Gatekeeper 负责 PIN、图案和密码等设备凭据验证;设备的安全生物识别组件负责匹配;Keystore2/KeyMint 消费合适的 AuthToken。StrongBox 是隔离的 KeyMint 实现,不能据此推断 biometric matcher 也运行在 StrongBox 中。各组件共享安全认证协议,但职责不同。
失败、取消与锁定
failure、error 和 cancel 不同
| 结果 | 含义 | 会话行为 |
|---|---|---|
onAuthenticationFailed() | 采集有效但未匹配 | App 收到 failed;Face operation 结束并进入可重试暂停,Fingerprint operation 通常继续等待 |
BIOMETRIC_ERROR_TIMEOUT | 当前 sensor operation 超时 | SystemUI 以软错误处理,session 可停在可重试状态 |
| hard error(不可恢复错误) | HAL 不可用、不可恢复错误等 | 暂存错误,等待 UI 展示后结束 |
| App cancel | 调用方取消当前 requestId | sensor 进入 CANCELING,等待取消完成或强制收尾 |
| client death(客户端死亡) | App Binder 死亡 | 取消运行中 sensor,关闭 UI |
| lockout(认证锁定) | HAL/sensor tracker 报告限流状态 | 允许回退到设备凭据时转到 credential UI,否则结束 |
CancellationSignal.cancel() 发出取消请求,不保证所有层在同一时刻停止。旧 HAL 回调仍可能到达,因此 Android 17 每次回调都用 requestId、cookie 和当前 session 过滤。
锁定由 sensor 侧报告并协调
PreAuthInfo 调用每个认证器的 getLockoutModeForUser()。AIDL HAL 可通过:
onLockoutTimed(durationMillis);onLockoutPermanent();onLockoutCleared()
报告状态。framework 的 AuthSessionCoordinator 和 MultiBiometricLockoutState 在不同认证强度、sensor 与用户之间协调结果。
不要把“失败 5 次锁 30 秒”写成所有设备的 framework 实现。精确要求来自当前 Android CDD,执行细节还受 sensor strength、HAL 与设备策略影响。诊断时以实际 error、duration、sensorId 和设备 CDD 版本为准。
SystemUI 与 App 的可见完成时间
AuthController 的职责
BiometricService 通过 IStatusBarService.showAuthenticationDialog() 把 PromptInfo、sensor IDs、credential 许可、确认策略、operationId 和 requestId 传给 SystemUI。
AuthController 在 SystemUI 中:
- 创建并持有
AuthContainerView; - 根据 sensor properties 管理指纹、人脸、UDFPS 和凭据 UI;
- 检查发起认证的 App 是否退到后台;
- 把入场完成、立即启动指纹、重试、切换凭据和 dismiss(关闭对话框)事件回传给
AuthSession; - 把 acquired、success 和 error 映射为用户可见状态。
它不会调用 biometric HAL。UdfpsController 管理 overlay 和触摸交互,实际 authenticate operation 仍由 fingerprint provider/client 驱动。
三种“完成”不能混用
| 时间点 | 说明 |
|---|---|
| HAL success | secure matcher 已接受样本 |
| SystemUI success | Prompt 已进入成功或确认状态 |
| App callback | token 已处理,SystemUI 已按原因 dismiss,回调已进入应用 Executor |
用户可能在成功动画开始时就认为认证完成,业务代码则要等 App callback。性能指标必须写明采用哪个结束点。
性能定位:先分段,再解释
建议记录的时间点
人脸可在 Prompt 入场前启动,指纹通常等待 SystemUI 信号。两种模态不能共用一条假定严格递增的时间轴。应把 App、会话、UI 和每个 sensor 分开记录:
| 标记 | 事件 | 可观测位置 |
|---|---|---|
A_request | App 调用 authenticate() 前 | App 埋点 |
B_enter | AuthService.authenticate() 接收 | system_server 日志或定制 trace |
B_session | PreAuthInfo 完成并创建 AuthSession | BiometricService |
U_show | SystemUI 开始显示 Prompt | AuthController.showAuthenticationDialog() |
U_animated | Prompt 入场动画完成 | onDialogAnimatedIn() |
S_prepare[id] | 向指定 sensor 提交 prepare | prepareForAuthentication() |
S_ready[id] | 指定 sensor 的 cookie 就绪 | onReadyForAuthentication() |
S_start[id] | 对指定 sensor 调用 HAL authenticate | sensor client |
S_acquired[id] | 指定 sensor 的首个 acquired/frame | sensor client callback |
S_reject[id] | 指定 sensor 报告未匹配;Fingerprint 可出现多次 | sensor client callback |
S_end[id] | operation 终止:success/error,Face 还包括 failure | sensor client callback |
U_dismiss | SystemUI dismiss 完成回调 | onDialogDismissed() |
A_callback | App callback 开始执行 | 调用方 Executor |
跨进程计算必须使用同一单调时钟,例如 Perfetto 的 trace clock(跟踪时钟);不能直接相减各进程记录的 wall clock(日期时间)时间戳。公开 authenticate() 也不会把内部 requestId 返回给 App,因此 App 与 system_server 的事件关联需要受控的单请求测试或自有系统埋点。并发场景下不能用“时间上最近的一条 biometric 日志”代替关联 ID。
这些标记允许在同一份 trace 中分别计算:
应用到 Binder 入口耗时 = B_enter - A_request
预认证与会话创建耗时 = B_session - B_enter
sensor 排队与准备耗时 = S_ready[id] - S_prepare[id]
sensor 启动协调耗时 = S_start[id] - S_ready[id]
首个样本等待 = S_acquired[id] - S_start[id]
当前 operation 耗时 = S_end[id] - S_start[id]
Prompt 入场耗时 = U_animated - U_show
UI 与 token 收尾 = U_dismiss - 成功 sensor 的 S_end[id]
应用调度延迟 = A_callback - U_dismiss
S_start[id] 需要从 framework client 或 vendor trace 取得。对 Face,S_start[id] 可以早于 U_show;对 Fingerprint,S_start[id] 往往不早于 U_animated。仅有 App 的 A_request/A_callback 时,只能得到端到端耗时,不能据此判断安全环境或传感器慢。
系统自带诊断入口
以下命令用于查看当前 session、已注册 sensor、provider 和 scheduler 状态:
adb shell dumpsys biometric
adb shell dumpsys fingerprint
adb shell dumpsys face
dumpsys biometric 的文本输出包含 sensor 列表和 CurrentSession。Fingerprint/Face dump 可看到 provider、当前 client、pending queue(待执行队列)和最近 operation。量产设备可能限制部分 dump 内容,userdebug/eng 构建更适合深入分析。
以下命令用于抓取 framework 与 SystemUI 事件:
adb logcat -v threadtime \
-s BiometricService AuthService AuthController \
FingerprintService FaceService BiometricScheduler
tag 和详细日志受构建类型、日志级别及 OEM 修改影响。采集前应在目标构建上确认实际 tag。
Perfetto 建议至少覆盖:
sched、线程唤醒与 CPU frequency;- Binder driver;
system_server与 SystemUI;- gfx/view/window 相关轨道;
- 相机与 vendor biometric/TEE 自定义 data source(跟踪数据源)。
Android 17 的 BiometricService、AuthSession 和 AuthController 主路径没有稳定的专用 Trace.traceBegin() slice 可作为跨设备契约。不要把厂商 trace 名称写成 AOSP 保证;需要时在自有系统构建中给上述 App、UI 和 sensor 边界增加成对 trace。
症状到证据的映射
| 症状 | 先看什么 | 常见原因 |
|---|---|---|
| 点击后迟迟不弹窗 | A_request~U_show、前台状态/AppOps、PreAuthInfo | 主线程阻塞、策略检查失败、旧会话取消、SystemUI 忙 |
| 弹窗出现后指纹才慢慢亮 | S_ready~S_start、U_show~U_animated、UDFPS overlay/显示模式 | UI 协调或显示准备,不一定是 matcher |
| 有提示但迟迟不成功 | acquired/reject 序列、S_start~S_end | 样本质量、环境、HAL 或 secure matcher |
| 已显示成功,业务页面仍未继续 | 成功 sensor 的 S_end~A_callback | 成功动画、HAT 注入、App Executor 排队 |
| 第二次认证特别慢 | 旧 requestId、cancel 完成、scheduler 当前任务 | 快速重启导致清理与新请求竞争 |
| 偶发立即转 PIN | lockout error、credentialAllowed | 限时/永久锁定或传感器策略 |
| 人脸不可用但指纹正常 | 相机隐私开关、eligibleSensors | 相机隐私、相机占用、模态单独禁用 |
App 侧写法
下面的示例只展示生命周期和回调线程边界。它不把 canAuthenticate() 当成认证保证,也不在回调里执行重任务:
class LoginActivity : ComponentActivity() {
private var cancellationSignal: CancellationSignal? = null
fun requestBiometricLogin() {
if (cancellationSignal != null) return
val signal = CancellationSignal()
cancellationSignal = signal
val prompt = BiometricPrompt.Builder(this)
.setTitle("确认身份")
.setAllowedAuthenticators(
BiometricManager.Authenticators.BIOMETRIC_STRONG or
BiometricManager.Authenticators.DEVICE_CREDENTIAL
)
.build()
prompt.authenticate(
signal,
mainExecutor,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(
result: BiometricPrompt.AuthenticationResult
) {
cancellationSignal = null
continueLogin()
}
override fun onAuthenticationError(
errorCode: Int,
errString: CharSequence
) {
cancellationSignal = null
renderAuthenticationError(errorCode, errString)
}
override fun onAuthenticationFailed() {
showTryAgainHint()
}
}
)
}
override fun onDestroy() {
if (isFinishing) {
cancellationSignal?.cancel()
cancellationSignal = null
}
super.onDestroy()
}
}
示例用 mainExecutor,所以三个回调都应保持短小。若成功后要读数据库、访问网络或执行较重的密码学业务,应把任务交给后台执行器,再把 UI 结果送回主线程。
还要注意:
onAuthenticationFailed()通常不是终止回调,不要在这里立即创建新的 Prompt;- 终止后由 success 或 error 清理本地进行中状态;
- 是否在
onDestroy()取消要结合页面保留策略;配置变化时反复销毁重建会造成不必要的取消; CryptoObject使用的认证器要和密钥生成时的授权配置一致。
版本边界
| 版本 | 相关变化 |
|---|---|
| Android 9 / API 28 | 引入 framework BiometricPrompt |
| Android 11 / API 30 | 公开 BiometricManager.Authenticators,可组合 biometric 与 device credential |
| Android 12 / API 31 | AOSP 文档明确纳入 UDFPS 支持;适用范围从该版本开始 |
| Android 13 起 | 新设备实现逐步迁移到稳定 AIDL biometric HAL |
| Android 17 / API 37 | 当前源码锚点;包含 Identity Check 资格处理、受限 sensor strength 查询和现代 AIDL session context(会话上下文)能力 |
Android 17 仍保留旧设备 HAL 兼容适配。版本号只能说明 framework 能力上限,不能替代目标设备的 provider、HAL interface version、sensor properties 和 vendor 实现核查。
源码核查索引
| 问题 | Android 17 源码 |
|---|---|
| App 为何先进入 AuthService | BiometricPrompt.java、IAuthService.aidl、AuthService.java |
| 谁计算 eligible sensor | PreAuthInfo.java |
| 谁保存当前 Prompt 会话 | BiometricService.java 的 mAuthSession |
| session 与 sensor 状态是什么 | AuthSession.java、BiometricSensor.java |
| callback 在哪个线程运行 | BiometricHandlerProvider.java、BiometricPrompt.java |
| operation 为何串行 | BiometricScheduler.java、AIDL ISession.aidl |
| AIDL session 是否复用 | Fingerprint/Face aidl/Sensor.java 与 *StartUserClient.java |
| UDFPS 如何传 pointer | FingerprintAuthenticationClient.java、UdfpsController.java |
| HAT 何时交给 Keystore | AuthSession.onDialogDismissed() |
| SystemUI 如何参与 | AuthController.java、AuthContainerView.java |
官方资料:
与关联章节的分工
| 章节 | 分工 |
|---|---|
| §1.10 Binder 线程池与优先级继承 | Binder 调度和优先级传播 |
| §8.5 Keystore/KeyMint | 密钥授权、CryptoObject、KeyMint 与 StrongBox |
| §8.5 BiometricPrompt 登录性能 | 登录业务的端到端指标和线上观测 |
| §20.10 Keystore 治理 | 密钥生命周期、失效与异常治理 |
小结
Android 17 的 BiometricPrompt 路径可以归纳为四个控制点:
AuthService处理公开入口的访问控制;BiometricService用PreAuthInfo和单个AuthSession仲裁请求;- 每个 sensor 的 provider 与
BiometricScheduler串行驱动 HAL operation; - SystemUI 控制用户可见流程,安全环境完成受保护的采集、匹配与 HAT 生成。
一次慢认证可能卡在旧会话取消、预认证、scheduler、AIDL session 冷启动、Prompt 动画、UDFPS 显示协作、首个样本、secure matcher、HAT 注入或 App Executor。把 App、UI 和各 sensor 的分段标记采齐,再对照当前 requestId、sensorId、operation 和 error,才能把问题归到负责的组件。