當然可以!以下是一篇基於你提供的 CSDN 博客文章(原文鏈接)整理而成的技術博客,保留了關鍵代碼、流程説明和架構分析,並進行了邏輯梳理與語言優化,適合用於技術分享或學習筆記。


Android 人臉解鎖源碼剖析:從錄入到認證全流程解析

作者:Qwen
參考來源:CSDN 原文《Android 人臉解鎖源碼剖析》

在 Android 10 中,Google 引入了全新的人臉識別身份驗證堆棧(Face Authentication Stack),以支持更安全、隱私友好的人臉識別解鎖功能。本文將深入 Android 源碼,系統性地解析人臉錄入(Enrollment)、匹配(Authentication)以及屏幕解鎖(Unlock)三大核心流程,並結合關鍵代碼片段進行説明。


一、整體架構概覽

Android 人臉識別基於 BiometricPrompt API 統一框架,支持指紋、人臉、虹膜等多種生物識別方式。其核心組件如下:

  • FaceManager:私有接口,供 Keyguard 調用人臉硬件,應用層不可直接訪問。
  • FaceService:運行在 system_server 中的服務,管理人臉註冊/認證狀態機,禁止加載廠商代碼
  • faced:Linux 可執行程序,實現 IBiometricsFace@1.0 HIDL 接口,由廠商提供。
  • HIDL 接口
  • IBiometricsFace.hal
  • IBiometricsFaceClientCallback.hal
  • type.hal

✅ 所有廠商實現必須通過 HIDL 與 FaceService 通信,確保系統安全隔離。


二、人臉錄入流程(Enrollment)

1. 入口:Settings 中的 FaceEnrollEnrolling

用户在「設置 > 安全 > 人臉識別」中點擊“添加人臉”,進入 FaceEnrollEnrolling.java

// packages/apps/Settings/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
@Override
public void startEnrollment() {
    super.startEnrollment(); // 調用父類
    if (mUserId != UserHandle.USER_NULL) {
        mFaceManager.setActiveUser(mUserId);
    }
    mFaceManager.enroll(mToken, mEnrollmentCancel, mEnrollmentCallback, mDisabledFeatures);
}

2. 調用 FaceManager.enroll()

// frameworks/base/core/java/android/hardware/face/FaceManager.java
public void enroll(byte[] token, CancellationSignal cancel, 
                   EnrollmentCallback callback, int[] disabledFeatures) {
    if (mService != null) {
        try {
            mService.enroll(mToken, token, mServiceReceiver, 
                            mContext.getOpPackageName(), disabledFeatures);
        } catch (RemoteException e) {
            // 錯誤處理
        }
    }
}

3. FaceService 處理請求

// frameworks/base/services/core/java/com/android/server/biometrics/face/FaceService.java
public void enroll(final IBinder token, final byte[] cryptoToken,
                   final IFaceServiceReceiver receiver, final String opPackageName,
                   final int[] disabledFeatures) {
    EnrollClientImpl client = new EnrollClientImpl(...);
    enrollInternal(client, mCurrentUserId);
}

最終調用 startClient(client)client.start()

// EnrollClient.java
@Override
public int start() {
    final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), timeout, disabledFeatures);
    return result;
}

🔧 此處 getDaemonWrapper().enroll() 實際調用的是 faced 進程(通過 Binder),由廠商 HAL 實現。

4. 進度回調機制

HAL 層在每次採集後通過 onEnrollResult 回調:

// FaceManager.java 內部接收器
private IFaceServiceReceiver mServiceReceiver = new IFaceServiceReceiver.Stub() {
    @Override
    public void onEnrollResult(long deviceId, int faceId, int remaining) {
        mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0, new Face(null, faceId, deviceId))
                .sendToTarget();
    }
};

// 處理消息
private void sendEnrollResult(Face face, int remaining) {
    if (mEnrollmentCallback != null) {
        mEnrollmentCallback.onEnrollmentProgress(remaining); // 更新 UI 進度
    }
}

remaining == 0 時,表示錄入完成,跳轉至結束頁面:

// ParticleCollection.java
@Override
public void onEnrollmentProgressChange(int steps, int remaining) {
    if (remaining == 0) {
        updateState(STATE_COMPLETE);
    }
}

三、人臉匹配流程(Authentication)

1. 觸發時機:設備滅屏後喚醒

當設備滅屏再亮起時,Keyguard 會啓動人臉監聽:

// KeyguardUpdateMonitor.java
private void startListeningForFace() {
    if (isUnlockWithFacePossible(userId)) {
        mFaceCancelSignal = new CancellationSignal();
        mFaceManager.authenticate(null, mFaceCancelSignal, 0, 
                                  mFaceAuthenticationCallback, null, userId);
        setFaceRunningState(BIOMETRIC_STATE_RUNNING);
    }
}

2. FaceManager.authenticate()

// FaceManager.java
public void authenticate(@Nullable CryptoObject crypto,
                         @Nullable CancellationSignal cancel,
                         int flags,
                         @NonNull AuthenticationCallback callback,
                         @Nullable Handler handler,
                         int userId) {
    mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags, opPackageName);
}

3. FaceService 啓動認證客户端

類似錄入流程,創建 FaceAuthClient 並調用 start()

// AuthenticationClient.java
public int start() {
    final int result = getDaemonWrapper().authenticate(mOpId, getGroupId());
    return result;
}

⚠️ 底層 faced 開始實時比對攝像頭幀與已註冊模板。

4. 認證結果回調

成功時,HAL 調用 onAuthenticated

// BiometricServiceBase.java
public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
                               boolean authenticated,
                               ArrayList<Byte> token) {
    if (authenticated && listener != null) {
        listener.onAuthenticationSucceeded(getHalDeviceId(), identifier, getTargetUserId());
    }
}

最終傳遞到 FaceManager 的 Handler:

// FaceManager.java
private IFaceServiceReceiver mServiceReceiver = new IFaceServiceReceiver.Stub() {
    @Override
    public void onAuthenticationSucceeded(long deviceId, Face face, int userId) {
        mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, face)
                .sendToTarget();
    }
};

private void sendAuthenticatedSucceeded(Face face, int userId) {
    if (mAuthenticationCallback != null) {
        AuthenticationResult result = new AuthenticationResult(mCryptoObject, face, userId);
        mAuthenticationCallback.onAuthenticationSucceeded(result);
    }
}

四、人臉解鎖屏幕(Keyguard Unlock)

1. Keyguard 監聽認證成功

KeyguardUpdateMonitor 實現了 FaceManager.AuthenticationCallback

// KeyguardUpdateMonitor.java
FaceManager.AuthenticationCallback mFaceAuthenticationCallback = 
    new FaceManager.AuthenticationCallback() {
        @Override
        public void onAuthenticationSucceeded(FaceManager.AuthenticationResult result) {
            handleFaceAuthenticated(result.getUserId());
        }
    };

2. 觸發解鎖邏輯

private void handleFaceAuthenticated(int authUserId) {
    onFaceAuthenticated(authUserId);
}

protected void onFaceAuthenticated(int userId) {
    // 標記用户已通過人臉認證
    mUserFaceAuthenticated.put(userId, true);
    
    // 通知所有回調(包括 BiometricUnlockController)
    for (int i = 0; i < mCallbacks.size(); i++) {
        KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
        if (cb != null) {
            cb.onBiometricAuthenticated(userId, BiometricSourceType.FACE);
        }
    }
}

3. BiometricUnlockController 執行解鎖

// BiometricUnlockController.java
@Override
public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
    startWakeAndUnlock(calculateMode(biometricSourceType));
}

public void startWakeAndUnlock(int mode) {
    // 喚醒屏幕
    mPowerManager.wakeUp(SystemClock.uptimeMillis(), ...);
    
    // 通知 Keyguard 解鎖
    mKeyguardViewMediator.onWakeAndUnlocking();
    
    // 隱藏鎖屏界面
    mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(false);
}

至此,人臉解鎖完成,用户進入主屏幕。


五、總結

Android 人臉解鎖流程高度模塊化,遵循“應用 → Framework → Service → HAL → Kernel” 的分層設計:

  • 安全性:廠商代碼僅運行在 faced 進程,與 system_server 隔離。
  • 統一性:通過 BiometricPromptBiometricServiceBase 抽象,支持多模態生物識別。
  • 可擴展性:HIDL 接口標準化,便於不同廠商適配。

📌 注意:人臉解鎖在 Android 中默認為 Class 2(弱生物識別),不能用於高安全場景(如支付),除非廠商實現 Strong Biometric(需滿足活體檢測、防欺騙等要求)。


參考資料

  • Android 官方文檔 - Biometric Authentication
  • Android 10 新特性:人臉識別身份驗證
  • 原文:CSDN《Android 人臉解鎖源碼剖析》

希望這篇整理對你理解 Android 人臉解鎖機制有所幫助!歡迎點贊、收藏或在評論區交流~