Android Q 上的Biometric生物識別之Fingerprint指紋識別流程

第一部分、Fingerprint HIDL

在配有指紋傳感器的設備上,用戶可以註冊一個或多個指紋,並使用這些指紋來解鎖設備以及執行其他任務。Android 會利用 Fingerprint HIDL(硬件接口定義語言)連接到供應商專用庫和指紋硬件(例如指紋傳感器)。
要實現Fingerprint HIDL,你必須在某個供應商專用庫中實現 IBiometricsFingerprint.hal

指紋匹配條件

設備的指紋傳感器通常處於閒置狀態。不過,爲了響應對authenticateenroll 的調用,指紋傳感器會監聽觸摸操作(並且屏幕可能會在用戶觸摸傳感器時被喚醒)。指紋匹配的概要流程包括以下步驟:

1.用戶將手指放在傳感器上。
2.供應商專用庫會根據當前已經註冊指紋模板集來判斷是否匹配。
3.匹配結果會傳遞到FingerprintService

指紋匹配架構

Fingerprint HAL會與以下組件交互 :

· BiometricManager 會在應用進程中與應用直接交互,每個應用都有一個 IBiometricsFringerprint.hal 實例。
· FingerprintService 在系統進程中運行,可處理與 Fingerprint HAL 之間的通信。
· Fingerprint HALIBiometricsFringerprint HIDL 接口 C/C++實現。它包含可與設備專與硬件進行通信的供應商專用庫。
· Keystore APIKeyMaster 組件提供由硬件支持的加密功能,以便在安全環境(例如可信執行環境( TEE ))中安全地存儲密鑰。

第二部分、指紋模塊流程分析

要實現Fingerprint HIDL,你必須在某個供應商專用庫中實現IBiometricsFingerprint.hal.

IBiometricsFingerprint.hal中主要包含以下主要方法:enroll();preEnroll();getAuthenticatorld();cancel();enumerate();remove();setActiveGroup();authenticate();setNotify();postEnroll()。

指紋模塊中的錄入,匹配,移除是三個大部分;

一、指紋錄入

指紋錄入的入口在Settings中的FingerprintEnrollEnrolling.java類中

在這個類中沒有看到明顯的錄入的方法,只有一些UI的加載和一些錄入動畫的邏輯。

在此類中的updateProgress(boolean animate)更新錄入進度的方法中用

	int progress = getProgress(
                mSidecar.getEnrollmentSteps(), mSidecar.getEnrollmentRemaining());

來獲取實際的進度;
此類中沒有mSidecar的獲取方法,但是此類繼承自BiometricsEnrolling,我們去他的父類中找找

BiometricsEnrollEnrolling.java

在此類中我們可以看到mSidecar的獲取邏輯

	    public void startEnrollment() {
        mSidecar = (BiometricEnrollSidecar) getSupportFragmentManager()
                .findFragmentByTag(TAG_SIDECAR);
        if (mSidecar == null) {
            mSidecar = getSidecar();/*重點關注*/
            getSupportFragmentManager().beginTransaction().add(mSidecar, TAG_SIDECAR)
                    .commitAllowingStateLoss();
        }
        mSidecar.setListener(this);
    }

通過BiometricEnrollSider強轉類型或是getSider()方法,而getSider()在此類中是一個抽象方法,具體在子類中實現,具體在他的子類中也是返回了一個繼承自BiometricEnrollSidecarFingerprintEnrollSider對象

FingerprintEnrollSidecar.java

在此類中我們終於發現了核心代碼在該類的startEnrollment()方法中使用mFingerprintManager.enroll(mToken,mEnrollmentCancel,0,mUserId,mEnrollmentCallback);來監聽錄入過程中的onEnrollmentProgress,onEnrollmentHelp,onEnrollmentError的錄入狀態

FingerprintEnrollSidecar的父類是BiometricEnrollSidecar,該類是繼承自InstrumentedFragment,所以說明該類爲一個Fragment,該類的生命週期也遵循Fragment

BiometricEnrollSidecaronStart方法中有執行startEnrollment()

frameworks/base/core/java/android/hardware/fingerprint/FingerprintManager.java

從調用FingerprintManager.enroll方法開始錄入的

	 public void enroll(byte [] token, CancellationSignal cancel, int flags,
            int userId, EnrollmentCallback callback) {
        if (userId == UserHandle.USER_CURRENT) {
            userId = getCurrentUserId();
        }
        if (callback == null) {
            throw new IllegalArgumentException("Must supply an enrollment callback");
        }

        if (cancel != null) {
            if (cancel.isCanceled()) {
                Slog.w(TAG, "enrollment already canceled");
                return;
            } else {
                cancel.setOnCancelListener(new OnEnrollCancelListener());
            }
        }

        if (mService != null) try {
            mEnrollmentCallback = callback;
            /*重點關注*/
            mService.enroll(mToken, token, userId, mServiceReceiver, flags,
                    mContext.getOpPackageName());
        } catch (RemoteException e) {
            Slog.w(TAG, "Remote exception in enroll: ", e);
            if (callback != null) {
                // Though this may not be a hardware issue, it will cause apps to give up or try
                // again later.
                callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
                        getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
                            0 /* vendorCode */));
            }
        }
    }

FingerprintManagerenroll方法可以看出主要是通過調用mService.enroll開始進行錄入的,而這個mService也就是傳進來的

	FIngerprintManager(Context context, IFingerprintService){
	...
		mService = service;	
	...
	}

的實現類的參數。

frameworks /base /services/ core/ java com/ android /server /biometrics/ fingerprint /FingerprintService.java

FingerprintService中註冊了IFingerprintService
private final class FingerprintServiceWrapper extends IFingerPrintService.Stub實現了enroll方法

	        public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
                final IFingerprintServiceReceiver receiver, final int flags,
                final String opPackageName) {
            checkPermission(MANAGE_FINGERPRINT);

            final boolean restricted = isRestricted();
            final int groupId = userId; // default group for fingerprint enrollment
            final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
                    mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
                    cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */) {
                @Override
                public boolean shouldVibrate() {
                    return true;
                }

                @Override
                protected int statsModality() {
                    return FingerprintService.this.statsModality();
                }
            };
			  /*重點關注*/
            enrollInternal(client, userId);
        }

在FingerprintService的父類BiometricServiceBase中

frameworks/base/services/core/java/com/android/server/biometrics/BiometricServiceBase.java

	    protected void enrollInternal(EnrollClientImpl client, int userId) {
        if (hasReachedEnrollmentLimit(userId)) {
            return;
        }

        // Group ID is arbitrarily set to parent profile user ID. It just represents
        // the default biometrics for the user.
        if (!isCurrentUserOrProfile(userId)) {
            return;
        }

        mHandler.post(() -> {
        	/*重點關注*/
            startClient(client, true /* initiatedByClient */);
        });
    }

startClient(client, true /* initiatedByClient */);

    private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
        ClientMonitor currentClient = mCurrentClient;
        if (currentClient != null) {
            if (DEBUG) Slog.v(getTag(), "request stop current client " +
                    currentClient.getOwnerString());
            // This check only matters for FingerprintService, since enumerate may call back
            // multiple times.
            if (currentClient instanceof InternalEnumerateClient
                    || currentClient instanceof InternalRemovalClient) {
                // This condition means we're currently running internal diagnostics to
                // remove extra templates in the hardware and/or the software
                // TODO: design an escape hatch in case client never finishes
                if (newClient != null) {
                    Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
                            + newClient.getClass().getSuperclass().getSimpleName()
                            + "(" + newClient.getOwnerString() + ")"
                            + ", initiatedByClient = " + initiatedByClient);
                }
            } else {
                currentClient.stop(initiatedByClient);

                // Only post the reset runnable for non-cleanup clients. Cleanup clients should
                // never be forcibly stopped since they ensure synchronization between HAL and
                // framework. Thus, we should instead just start the pending client once cleanup
                // finishes instead of using the reset runnable.
                mHandler.removeCallbacks(mResetClientState);
                mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
            }
            mPendingClient = newClient;
        } else if (newClient != null) {
            // For BiometricPrompt clients, do not start until
            // <Biometric>Service#startPreparedClient is called. BiometricService waits until all
            // modalities are ready before initiating authentication.
            if (newClient instanceof AuthenticationClient) {
                AuthenticationClient client = (AuthenticationClient) newClient;
                if (client.isBiometricPrompt()) {
                    if (DEBUG) Slog.v(getTag(), "Returning cookie: " + client.getCookie());
                    mCurrentClient = newClient;
                    if (mBiometricService == null) {
                        mBiometricService = IBiometricService.Stub.asInterface(
                                ServiceManager.getService(Context.BIOMETRIC_SERVICE));
                    }
                    try {
                        mBiometricService.onReadyForAuthentication(client.getCookie(),
                                client.getRequireConfirmation(), client.getTargetUserId());
                    } catch (RemoteException e) {
                        Slog.e(getTag(), "Remote exception", e);
                    }
                    return;
                }
            }

            // We are not a BiometricPrompt client, start the client immediately
            mCurrentClient = newClient;
             /*重點關注*/
            startCurrentClient(mCurrentClient.getCookie());

		
        }
    }
    

在此將EnrollClient的對象傳進去

startCurrentClient(mCurrentClient.getCookie());


    protected void startCurrentClient(int cookie) {
        if (mCurrentClient == null) {
            Slog.e(getTag(), "Trying to start null client!");
            return;
        }
        if (DEBUG) Slog.v(getTag(), "starting client "
                + mCurrentClient.getClass().getSuperclass().getSimpleName()
                + "(" + mCurrentClient.getOwnerString() + ")"
                + " cookie: " + cookie + "/" + mCurrentClient.getCookie());
        if (cookie != mCurrentClient.getCookie()) {
            Slog.e(getTag(), "Mismatched cookie");
            return;
        }
        notifyClientActiveCallbacks(true);
        /*重點關注*/
        mCurrentClient.start();
    }
   

frameworks/base/services/core/java/com/android/server/biometrics/EnrollClient.java

    @Override
    public int start() {
        mEnrollmentStartTimeMs = System.currentTimeMillis();
        final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
        try {
            final ArrayList<Integer> disabledFeatures = new ArrayList<>();
            for (int i = 0; i < mDisabledFeatures.length; i++) {
                disabledFeatures.add(mDisabledFeatures[i]);
            }
			/*重點關注*/
            final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), timeout,
                    disabledFeatures);
            if (result != 0) {
                Slog.w(getLogTag(), "startEnroll failed, result=" + result);
                mMetricsLogger.histogram(mConstants.tagEnrollStartError(), result);
                onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
                        0 /* vendorCode */);
                return result;
            }
        } catch (RemoteException e) {
            Slog.e(getLogTag(), "startEnroll failed", e);
        }
        return 0; // success
    }

start 方法會調用fingerprintd,調用底層的指紋庫,底層庫返回結果後會調用onEnrollResult來反饋結果receiver,再往上層反饋。這就是指紋的錄製流程。在onEnrollResult中當remaining等於0的時候完成錄製,調用addBiometricForUser

FingerprintManager.java中註冊了IFingerprintServiceReceiver,實現onEnrollResult方法發送 MSG_ENROLL_RESULT

frameworks/base/core/java/android/hardware/fingerprint/FingerprintManager.java

    private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {

        @Override // binder call
        public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
           /*重點關注*/
            mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
                    new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
        }

        .......
    };

}
  @Override
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case MSG_ENROLL_RESULT:
                    /*重點關注*/
                    sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
                    break;
          .......
            }
        }
    };

調用回調方法

 private void sendEnrollResult(Fingerprint fp, int remaining) {
        if (mEnrollmentCallback != null) {
        	/*重點關注*/
            mEnrollmentCallback.onEnrollmentProgress(remaining);
        }
    }

再看看Settings
FingerprintEnrollSidecar中通過實現錄入的回調接口FingerprintManager.EnrollmentCallback來監聽錄入過程中onEnrollmentProgress, onEnrollmentHelp, onEnrollmentError的錄入狀態
並在他的父類BiometricEnrollSidercar寫有一個內部接口Listener

packages/apps/Settings/src/com/android/settings/biometrics/BiometricEnrollSidecar.java

  public interface Listener {
      void onEnrollmentHelp(int helpMsgId, CharSequence helpString);
      void onEnrollmentError(int errMsgId, CharSequence errString);
      void onEnrollmentProgressChange(int steps, int remaining);
  }

BiometricsEnrollEnrolling 實現了 FingerprintEnrollSidecar.Listener,從而實現了 CallBack

二、指紋匹配

指紋解鎖的入口在Keyguard

系統滅屏之後會調用PhoneWindowManagerstartedGoingToSleep方法,繼而調用KeyguardDelegate.onStartedGoingToSleep方法。

繼而又會調用KeyguardServiceWrapper.java ==》onStartedGoingToSleep()方法;再調用KeyguardService.java ==》onStartedGoingToSleep()方法;並最終在KeyguardViewMediator.java ==》dispatchStartedGoingToSleep() 達到對GoingToSleep事件的監聽

frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java

public void dispatchStartedGoingToSleep(int why) {
        /*重點關注*/
        mHandler.sendMessage(mHandler.obtainMessage(MSG_STARTED_GOING_TO_SLEEP, why, 0));
    }

MSG_STARTED_GOING_TO_SLEEP

case MSG_STARTED_GOING_TO_SLEEP:
                    /*重點關注*/
                    handleStartedGoingToSleep(msg.arg1);
                    break;

handleStartedGoingToSleep(msg.arg1);

    protected void handleStartedGoingToSleep(int arg1) {
        clearBiometricRecognized();
        final int count = mCallbacks.size();
        for (int i = 0; i < count; i++) {
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
            if (cb != null) {
                cb.onStartedGoingToSleep(arg1);
            }
        }
        mGoingToSleep = true;
        /*重點關注*/
        updateBiometricListeningState();//更新生物識別狀態
    }

updateBiometricListeningState()

 //在這個方法中我們可以看到同時更新了指紋和人臉的狀態
    private void updateBiometricListeningState() {
       /*重點關注*/
        updateFingerprintListeningState();
        updateFaceListeningState();
    }

updateFingerprintListeningState()


    private void updateFingerprintListeningState() {
        // If this message exists, we should not authenticate again until this message is
        // consumed by the handler
        if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
            return;
        }
        mHandler.removeCallbacks(mRetryFingerprintAuthentication);
        boolean shouldListenForFingerprint = shouldListenForFingerprint();
        boolean runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
                || mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING;
        if (runningOrRestarting && !shouldListenForFingerprint) {
            stopListeningForFingerprint();
        } else if (!runningOrRestarting && shouldListenForFingerprint) {
            /*重點關注*/
            startListeningForFingerprint();
        }
    }

startListeningForFingerprint();


    private void startListeningForFingerprint() {
        if (mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING) {
            setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);
            return;
        }
        if (mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
            // Waiting for restart via handleFingerprintError().
            return;
        }
        if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
        int userId = getCurrentUser();
        if (isUnlockWithFingerprintPossible(userId)) {
            if (mFingerprintCancelSignal != null) {
                mFingerprintCancelSignal.cancel();
            }
            mFingerprintCancelSignal = new CancellationSignal();
            /*重點關注*/
            mFpm.authenticate(null, mFingerprintCancelSignal, 0, mFingerprintAuthenticationCallback,
                    null, userId);
            setFingerprintRunningState(BIOMETRIC_STATE_RUNNING);
        }
    }

frameworks/base/core/java/android/hardware/fingerprint/FingerprintManager.java

    @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
    public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
            int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
        if (callback == null) {
            throw new IllegalArgumentException("Must supply an authentication callback");
        }

        if (cancel != null) {
            if (cancel.isCanceled()) {
                Slog.w(TAG, "authentication already canceled");
                return;
            } else {
                cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
            }
        }

        if (mService != null) try {
            useHandler(handler);
            mAuthenticationCallback = callback;
            mCryptoObject = crypto;
            long sessionId = crypto != null ? crypto.getOpId() : 0;
            /*重點關注*/
            //這裏又是調用FingerprintService的authenticate方法
            mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
                    mContext.getOpPackageName());
        } catch (RemoteException e) {
            Slog.w(TAG, "Remote exception while authenticating: ", e);
            if (callback != null) {
                // Though this may not be a hardware issue, it will cause apps to give up or try
                // again later.
                callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
                        getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
                            0 /* vendorCode */));
            }
        }
    }

frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java

        @Override // Binder call
        public void authenticate(final IBinder token, final long opId, final int groupId,
                final IFingerprintServiceReceiver receiver, final int flags,
                final String opPackageName) {
            updateActiveGroup(groupId, opPackageName);
            final boolean restricted = isRestricted();
            final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
                    mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
                    mCurrentUserId, groupId, opId, restricted, opPackageName,
                    0 /* cookie */, false /* requireConfirmation */);
            /*重點關注*/
            authenticateInternal(client, opId, opPackageName);
        }

frameworks/base/services/core/java/com/android/server/biometrics/BiometricServiceBase.java


    protected void authenticateInternal(AuthenticationClientImpl client, long opId,
            String opPackageName, int callingUid, int callingPid, int callingUserId) {
        if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
                callingUserId)) {
            if (DEBUG) Slog.v(getTag(), "authenticate(): reject " + opPackageName);
            return;
        }

        mHandler.post(() -> {
            mMetricsLogger.histogram(getConstants().tagAuthToken(), opId != 0L ? 1 : 0);

            // Get performance stats object for this user.
            HashMap<Integer, PerformanceStats> pmap
                    = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
            PerformanceStats stats = pmap.get(mCurrentUserId);
            if (stats == null) {
                stats = new PerformanceStats();
                pmap.put(mCurrentUserId, stats);
            }
            mPerformanceStats = stats;
            mIsCrypto = (opId != 0);
			/*重點關注*/
            startAuthentication(client, opPackageName);
        });
    }

startAuthentication(client, opPackageName);

    private void startAuthentication(AuthenticationClientImpl client, String opPackageName) {
        if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");

        int lockoutMode = getLockoutMode();
        if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
            Slog.v(getTag(), "In lockout mode(" + lockoutMode + ") ; disallowing authentication");
            int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
                    BiometricConstants.BIOMETRIC_ERROR_LOCKOUT :
                    BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
            if (!client.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */)) {
                Slog.w(getTag(), "Cannot send permanent lockout message to client");
            }
            return;
        }
        /*重點關注*/
        startClient(client, true /* initiatedByClient */);
        //這裏將AuthenticationClient傳遞進去
    }    

startClient(client, true /* initiatedByClient */);

 private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
        ClientMonitor currentClient = mCurrentClient;
        if (currentClient != null) {
            if (DEBUG) Slog.v(getTag(), "request stop current client " +
                    currentClient.getOwnerString());
            // This check only matters for FingerprintService, since enumerate may call back
            // multiple times.
            if (currentClient instanceof InternalEnumerateClient
                    || currentClient instanceof InternalRemovalClient) {
                // This condition means we're currently running internal diagnostics to
                // remove extra templates in the hardware and/or the software
                // TODO: design an escape hatch in case client never finishes
                if (newClient != null) {
                    Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
                            + newClient.getClass().getSuperclass().getSimpleName()
                            + "(" + newClient.getOwnerString() + ")"
                            + ", initiatedByClient = " + initiatedByClient);
                }
            } else {
                currentClient.stop(initiatedByClient);

                // Only post the reset runnable for non-cleanup clients. Cleanup clients should
                // never be forcibly stopped since they ensure synchronization between HAL and
                // framework. Thus, we should instead just start the pending client once cleanup
                // finishes instead of using the reset runnable.
                mHandler.removeCallbacks(mResetClientState);
                mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
            }
            mPendingClient = newClient;
        } else if (newClient != null) {
            // For BiometricPrompt clients, do not start until
            // <Biometric>Service#startPreparedClient is called. BiometricService waits until all
            // modalities are ready before initiating authentication.
            if (newClient instanceof AuthenticationClient) {
                AuthenticationClient client = (AuthenticationClient) newClient;
                if (client.isBiometricPrompt()) {
                    if (DEBUG) Slog.v(getTag(), "Returning cookie: " + client.getCookie());
                    mCurrentClient = newClient;
                    if (mBiometricService == null) {
                        mBiometricService = IBiometricService.Stub.asInterface(
                                ServiceManager.getService(Context.BIOMETRIC_SERVICE));
                    }
                    try {
                        mBiometricService.onReadyForAuthentication(client.getCookie(),
                                client.getRequireConfirmation(), client.getTargetUserId());
                    } catch (RemoteException e) {
                        Slog.e(getTag(), "Remote exception", e);
                    }
                    return;
                }
            }

            // We are not a BiometricPrompt client, start the client immediately
            mCurrentClient = newClient;
            /*重點關注*/
            startCurrentClient(mCurrentClient.getCookie());
            //這裏繼續將AuthenticationClient傳遞進去
        }
    }

startCurrentClient(mCurrentClient.getCookie());

    protected void startCurrentClient(int cookie) {
        if (mCurrentClient == null) {
            Slog.e(getTag(), "Trying to start null client!");
            return;
        }
        if (DEBUG) Slog.v(getTag(), "starting client "
                + mCurrentClient.getClass().getSuperclass().getSimpleName()
                + "(" + mCurrentClient.getOwnerString() + ")"
                + " cookie: " + cookie + "/" + mCurrentClient.getCookie());
        if (cookie != mCurrentClient.getCookie()) {
            Slog.e(getTag(), "Mismatched cookie");
            return;
        }
        notifyClientActiveCallbacks(true);
        /*重點關注*/
        mCurrentClient.start();
        //這裏調用的是AuthenticationClient的start方法
    }

frameworks/base/services/core/java/com/android/server/biometrics/AuthenticationClient.java

    public int start() {
        mStarted = true;
        onStart();
        try {
            /*重點關注*/
            final int result = getDaemonWrapper().authenticate(mOpId, getGroupId());
            if (result != 0) {
                Slog.w(getLogTag(), "startAuthentication failed, result=" + result);
                mMetricsLogger.histogram(mConstants.tagAuthStartError(), result);
                onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
                        0 /* vendorCode */);
                return result;
            }
            if (DEBUG) Slog.w(getLogTag(), "client " + getOwnerString() + " is authenticating...");
        } catch (RemoteException e) {
            Slog.e(getLogTag(), "startAuthentication failed", e);
            return ERROR_ESRCH;
        }
        return 0; // success
    }

start方法會調用fingerprintd,調用底層的指紋庫,底層庫返回結果後會調用onAuthenticated來反饋結果給receiver,在往上層反饋

三、指紋解鎖屏幕

frameworks/base/services/core/java/com/android/server/biometrics/AuthenticationClient.java

    public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
            boolean authenticated, ArrayList<Byte> token) {
        super.logOnAuthenticated(getContext(), authenticated, mRequireConfirmation,
                getTargetUserId(), isBiometricPrompt());

        final BiometricServiceBase.ServiceListener listener = getListener();

        mMetricsLogger.action(mConstants.actionBiometricAuth(), authenticated);
        boolean result = false;

        try {
            if (DEBUG) Slog.v(getLogTag(), "onAuthenticated(" + authenticated + ")"
                    + ", ID:" + identifier.getBiometricId()
                    + ", Owner: " + getOwnerString()
                    + ", isBP: " + isBiometricPrompt()
                    + ", listener: " + listener
                    + ", requireConfirmation: " + mRequireConfirmation
                    + ", user: " + getTargetUserId());

            if (authenticated) {
                mAlreadyDone = true;

                if (listener != null) {
                    vibrateSuccess();
                }
                result = true;
                if (shouldFrameworkHandleLockout()) {
                    resetFailedAttempts();
                }
                onStop();

                final byte[] byteToken = new byte[token.size()];
                for (int i = 0; i < token.size(); i++) {
                    byteToken[i] = token.get(i);
                }
                if (isBiometricPrompt() && listener != null) {
                    // BiometricService will add the token to keystore
                    listener.onAuthenticationSucceededInternal(mRequireConfirmation, byteToken);
                } else if (!isBiometricPrompt() && listener != null) {
                    KeyStore.getInstance().addAuthToken(byteToken);
                    try {
                        // Explicitly have if/else here to make it super obvious in case the code is
                        // touched in the future.
                        if (!getIsRestricted()) {
                            /*重點關注*/
                            listener.onAuthenticationSucceeded(
                                    getHalDeviceId(), identifier, getTargetUserId());
                        } else {
                            listener.onAuthenticationSucceeded(
                                    getHalDeviceId(), null, getTargetUserId());
                        }
                    } catch (RemoteException e) {
                        Slog.e(getLogTag(), "Remote exception", e);
                    }
                } else {
                    // Client not listening
                    Slog.w(getLogTag(), "Client not listening");
                    result = true;
                }
            } else {
                if (listener != null) {
                    vibrateError();
                }

                // Allow system-defined limit of number of attempts before giving up
                final int lockoutMode = handleFailedAttempt();
                if (lockoutMode != LOCKOUT_NONE && shouldFrameworkHandleLockout()) {
                    Slog.w(getLogTag(), "Forcing lockout (driver code should do this!), mode("
                            + lockoutMode + ")");
                    stop(false);
                    final int errorCode = lockoutMode == LOCKOUT_TIMED
                            ? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
                            : BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
                    onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
                } else {
                    // Don't send onAuthenticationFailed if we're in lockout, it causes a
                    // janky UI on Keyguard/BiometricPrompt since "authentication failed"
                    // will show briefly and be replaced by "device locked out" message.
                    if (listener != null) {
                        if (isBiometricPrompt()) {
                            listener.onAuthenticationFailedInternal(getCookie(),
                                    getRequireConfirmation());
                        } else {
                            listener.onAuthenticationFailed(getHalDeviceId());
                        }
                    }
                }
                result = lockoutMode != LOCKOUT_NONE; // in a lockout mode
            }
        } catch (RemoteException e) {
            Slog.e(getLogTag(), "Remote exception", e);
            result = true;
        }
        return result;
    }

frameworks/base/services/core/java/com/android/server/biometrics/BiometricServiceBase.java

    protected interface ServiceListener {
        default void onEnrollResult(BiometricAuthenticator.Identifier identifier,
                int remaining) throws RemoteException {};

        void onAcquired(long deviceId, int acquiredInfo, int vendorCode) throws RemoteException;

		/*重點關注*/
        default void onAuthenticationSucceeded(long deviceId,
                BiometricAuthenticator.Identifier biometric, int userId) throws RemoteException {
            throw new UnsupportedOperationException("Stub!");
        }

        default void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)
                throws RemoteException {
            throw new UnsupportedOperationException("Stub!");
        }

        default void onAuthenticationFailed(long deviceId) throws RemoteException {
            throw new UnsupportedOperationException("Stub!");
        }

        default void onAuthenticationFailedInternal(int cookie, boolean requireConfirmation)
                throws RemoteException {
            throw new UnsupportedOperationException("Stub!");
        }

        void onError(long deviceId, int error, int vendorCode, int cookie) throws RemoteException;

        default void onRemoved(BiometricAuthenticator.Identifier identifier,
                int remaining) throws RemoteException {};

        default void onEnumerated(BiometricAuthenticator.Identifier identifier,
                int remaining) throws RemoteException {};
    }

onAuthenticationSucceeded


    /**
     * Wraps the callback interface from Service -> BiometricPrompt
     */
    protected abstract class BiometricServiceListener implements ServiceListener {
        private IBiometricServiceReceiverInternal mWrapperReceiver;

        public BiometricServiceListener(IBiometricServiceReceiverInternal wrapperReceiver) {
            mWrapperReceiver = wrapperReceiver;
        }

        public IBiometricServiceReceiverInternal getWrapperReceiver() {
            return mWrapperReceiver;
        }

        @Override
        public void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)
                throws RemoteException {
            if (getWrapperReceiver() != null) {
            
                /*重點關注*/
                getWrapperReceiver().onAuthenticationSucceeded(requireConfirmation, token);
            }
        }

        @Override
        public void onAuthenticationFailedInternal(int cookie, boolean requireConfirmation)
                throws RemoteException {
            if (getWrapperReceiver() != null) {
                getWrapperReceiver().onAuthenticationFailed(cookie, requireConfirmation);
            }
        }
    }

frameworks/base/core/java/android/hardware/fingerprint/FingerprintManager.java

 private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {

        @Override // binder call
        public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
            mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
                    new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
        }

        @Override // binder call
        public void onAcquired(long deviceId, int acquireInfo, int vendorCode) {
            mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode,
                    deviceId).sendToTarget();
        }

        @Override // binder call
        /*重點關注*/
        public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
        }

        @Override // binder call
        public void onAuthenticationFailed(long deviceId) {
            mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
        }

        @Override // binder call
        public void onError(long deviceId, int error, int vendorCode) {
            mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
        }

        @Override // binder call
        public void onRemoved(long deviceId, int fingerId, int groupId, int remaining) {
            mHandler.obtainMessage(MSG_REMOVED, remaining, 0,
                    new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
        }

        @Override // binder call
        public void onEnumerated(long deviceId, int fingerId, int groupId, int remaining) {
            // TODO: propagate remaining
            mHandler.obtainMessage(MSG_ENUMERATED, fingerId, groupId, deviceId).sendToTarget();
        }
    };

}

MSG_AUTHENTICATION_SUCCEEDED

                case MSG_AUTHENTICATION_SUCCEEDED:
                /*重點關注*/
                    sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
                    break;

sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);

    private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
        if (mAuthenticationCallback != null) {
            final AuthenticationResult result =
                    new AuthenticationResult(mCryptoObject, fp, userId);
             /*重點關注*/
            mAuthenticationCallback.onAuthenticationSucceeded(result);
        }
    }

AuthenticationCallbackFpm的一個內部回調接口


  public static abstract class AuthenticationCallback
            extends BiometricAuthenticator.AuthenticationCallback {
        /**
         * Called when an unrecoverable error has been encountered and the operation is complete.
         * No further callbacks will be made on this object.
         * @param errorCode An integer identifying the error message
         * @param errString A human-readable error string that can be shown in UI
         */
        @Override
        public void onAuthenticationError(int errorCode, CharSequence errString) { }

        /**
         * Called when a recoverable error has been encountered during authentication. The help
         * string is provided to give the user guidance for what went wrong, such as
         * "Sensor dirty, please clean it."
         * @param helpCode An integer identifying the error message
         * @param helpString A human-readable string that can be shown in UI
         */
        @Override
        public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }

        /**
         * Called when a fingerprint is recognized.
         * @param result An object containing authentication-related data
         */
         /*重點關注*/
        public void onAuthenticationSucceeded(AuthenticationResult result) { }

        /**
         * Called when a fingerprint is valid but not recognized.
         */
        @Override
        public void onAuthenticationFailed() { }

        /**
         * Called when a fingerprint image has been acquired, but wasn't processed yet.
         *
         * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants
         * @hide
         */
        @Override
        public void onAuthenticationAcquired(int acquireInfo) {}
    };

frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java

AuthenticationCallback接口在KeyguardUpdateMonitor.java中實現,用於監聽FingerprintService中指紋的解鎖狀態

    private FingerprintManager.AuthenticationCallback mFingerprintAuthenticationCallback
            = new AuthenticationCallback() {

        @Override
        public void onAuthenticationFailed() {
            handleFingerprintAuthFailed();
        }

        @Override
        public void onAuthenticationSucceeded(AuthenticationResult result) {
            Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded");
            /*重點關注*/
            handleFingerprintAuthenticated(result.getUserId());
            Trace.endSection();
        }

        @Override
        public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
            handleFingerprintHelp(helpMsgId, helpString.toString());
        }

        @Override
        public void onAuthenticationError(int errMsgId, CharSequence errString) {
            handleFingerprintError(errMsgId, errString.toString());
        }

        @Override
        public void onAuthenticationAcquired(int acquireInfo) {
            handleFingerprintAcquired(acquireInfo);
        }
    };

handleFingerprintAuthenticated(result.getUserId());

    private void handleFingerprintAuthenticated(int authUserId) {
        Trace.beginSection("KeyGuardUpdateMonitor#handlerFingerPrintAuthenticated");
        try {
            final int userId;
            try {
                userId = ActivityManager.getService().getCurrentUser().id;
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to get current user id: ", e);
                return;
            }
            if (userId != authUserId) {
                Log.d(TAG, "Fingerprint authenticated for wrong user: " + authUserId);
                return;
            }
            if (isFingerprintDisabled(userId)) {
                Log.d(TAG, "Fingerprint disabled by DPM for userId: " + userId);
                return;
            }
            /*重點關注*/
            onFingerprintAuthenticated(userId);
        } finally {
            setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
        }
        Trace.endSection();
    }

onFingerprintAuthenticated(userId);

    @VisibleForTesting
    protected void onFingerprintAuthenticated(int userId) {
        Trace.beginSection("KeyGuardUpdateMonitor#onFingerPrintAuthenticated");
        mUserFingerprintAuthenticated.put(userId, true);
        // Update/refresh trust state only if user can skip bouncer
        if (getUserCanSkipBouncer(userId)) {
            mTrustManager.unlockedByBiometricForUser(userId, BiometricSourceType.FINGERPRINT);
        }
        // Don't send cancel if authentication succeeds
        mFingerprintCancelSignal = null;
        for (int i = 0; i < mCallbacks.size(); i++) {
            /*重點關注*/
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
            if (cb != null) {
                /*重點關注*/
                cb.onBiometricAuthenticated(userId, BiometricSourceType.FINGERPRINT);
            }
        }

        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE),
                BIOMETRIC_CONTINUE_DELAY_MS);

        // Only authenticate fingerprint once when assistant is visible
        mAssistantVisible = false;

        Trace.endSection();
    }

可以看到在onFingerprintAuthenticated()方法中調用了KeyguardUpdateMonitorCallback這個抽象類的onBiometricAuthenticated()抽象方法,而BiometricUnlockController extends KeyguardUpdateMonitorCallback,並註冊了回調mUpdateMonitor.registerCallback(this)

frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java

    /**
     * Called when a biometric is recognized.
     * @param userId the user id for which the biometric sample was authenticated
     * @param biometricSourceType
     */
     /*重點關注*/
    public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) { }

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java

    @Override
    public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
        Trace.beginSection("BiometricUnlockController#onBiometricAuthenticated");
        if (mUpdateMonitor.isGoingToSleep()) {
            mPendingAuthenticatedUserId = userId;
            mPendingAuthenticatedBioSourceType = biometricSourceType;
            Trace.endSection();
            return;
        }
        mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
                .setType(MetricsEvent.TYPE_SUCCESS).setSubtype(toSubtype(biometricSourceType)));
         /*重點關注*/
        startWakeAndUnlock(calculateMode(biometricSourceType));
    }

startWakeAndUnlock(calculateMode(biometricSourceType));

    public void startWakeAndUnlock(int mode) {
        // TODO(b/62444020): remove when this bug is fixed
        Log.v(TAG, "startWakeAndUnlock(" + mode + ")");
        boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
        mMode = mode;
        mHasScreenTurnedOnSinceAuthenticating = false;
        if (mMode == MODE_WAKE_AND_UNLOCK_PULSING && pulsingOrAod()) {
            // If we are waking the device up while we are pulsing the clock and the
            // notifications would light up first, creating an unpleasant animation.
            // Defer changing the screen brightness by forcing doze brightness on our window
            // until the clock and the notifications are faded out.
            mStatusBarWindowController.setForceDozeBrightness(true);
        }
        // During wake and unlock, we need to draw black before waking up to avoid abrupt
        // brightness changes due to display state transitions.
        boolean alwaysOnEnabled = DozeParameters.getInstance(mContext).getAlwaysOn();
        boolean delayWakeUp = mode == MODE_WAKE_AND_UNLOCK && alwaysOnEnabled && mWakeUpDelay > 0;
        Runnable wakeUp = ()-> {
            if (!wasDeviceInteractive) {
                if (DEBUG_BIO_WAKELOCK) {
                    Log.i(TAG, "bio wakelock: Authenticated, waking up...");
                }
                mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
                        "android.policy:BIOMETRIC");
            }
            if (delayWakeUp) {
               /*重點關注*/
                mKeyguardViewMediator.onWakeAndUnlocking();
            }
            Trace.beginSection("release wake-and-unlock");
            releaseBiometricWakeLock();
            Trace.endSection();
        };

        if (!delayWakeUp) {
            wakeUp.run();
        }
        switch (mMode) {
            case MODE_DISMISS_BOUNCER:
                Trace.beginSection("MODE_DISMISS");
                mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
                        false /* strongAuth */);
                Trace.endSection();
                break;
            case MODE_UNLOCK:
            case MODE_SHOW_BOUNCER:
                Trace.beginSection("MODE_UNLOCK or MODE_SHOW_BOUNCER");
                if (!wasDeviceInteractive) {
                    mPendingShowBouncer = true;
                } else {
                    showBouncer();
                }
                Trace.endSection();
                break;
            case MODE_WAKE_AND_UNLOCK_FROM_DREAM:
            case MODE_WAKE_AND_UNLOCK_PULSING:
            case MODE_WAKE_AND_UNLOCK:
                if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) {
                    Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
                    mMediaManager.updateMediaMetaData(false /* metaDataChanged */,
                            true /* allowEnterAnimation */);
                } else if (mMode == MODE_WAKE_AND_UNLOCK){
                    Trace.beginSection("MODE_WAKE_AND_UNLOCK");
                } else {
                    Trace.beginSection("MODE_WAKE_AND_UNLOCK_FROM_DREAM");
                    mUpdateMonitor.awakenFromDream();
                }
                mStatusBarWindowController.setStatusBarFocusable(false);
                if (delayWakeUp) {
                    mHandler.postDelayed(wakeUp, mWakeUpDelay);
                } else {
                    mKeyguardViewMediator.onWakeAndUnlocking();
                }
                if (mStatusBar.getNavigationBarView() != null) {
                    mStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
                }
                Trace.endSection();
                break;
            case MODE_ONLY_WAKE:
            case MODE_NONE:
                break;
        }
        mStatusBar.notifyBiometricAuthModeChanged();
        Trace.endSection();
    }

frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java

    public void onWakeAndUnlocking() {
        Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking");
        mWakeAndUnlocking = true;
        /*重點關注*/
        keyguardDone();
        Trace.endSection();
    }

keyguardDone();

    public void keyguardDone() {
        Trace.beginSection("KeyguardViewMediator#keyguardDone");
        if (DEBUG) Log.d(TAG, "keyguardDone()");
        userActivity();
        EventLog.writeEvent(70000, 2);
        /*重點關注*/
        Message msg = mHandler.obtainMessage(KEYGUARD_DONE);
        mHandler.sendMessage(msg);
        Trace.endSection();
    }

KEYGUARD_DONE

                case KEYGUARD_DONE:
                    Trace.beginSection("KeyguardViewMediator#handleMessage KEYGUARD_DONE");
                    /*重點關注*/
                    handleKeyguardDone();
                    Trace.endSection();
                    break;

handleKeyguardDone();

    private void handleKeyguardDone() {
        Trace.beginSection("KeyguardViewMediator#handleKeyguardDone");
        final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
        mUiOffloadThread.submit(() -> {
            if (mLockPatternUtils.isSecure(currentUser)) {
                mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed(currentUser);
            }
        });
        if (DEBUG) Log.d(TAG, "handleKeyguardDone");
        synchronized (this) {
            resetKeyguardDonePendingLocked();
        }

        mUpdateMonitor.clearBiometricRecognized();

        if (mGoingToSleep) {
            Log.i(TAG, "Device is going to sleep, aborting keyguardDone");
            return;
        }
        if (mExitSecureCallback != null) {
            try {
                mExitSecureCallback.onKeyguardExitResult(true /* authenciated */);
            } catch (RemoteException e) {
                Slog.w(TAG, "Failed to call onKeyguardExitResult()", e);
            }

            mExitSecureCallback = null;

            // after succesfully exiting securely, no need to reshow
            // the keyguard when they've released the lock
            mExternallyEnabled = true;
            mNeedToReshowWhenReenabled = false;
            updateInputRestricted();
        }
		/*重點關注*/
        handleHide();
        Trace.endSection();
    }

handleHide();

    private void handleHide() {
        Trace.beginSection("KeyguardViewMediator#handleHide");

        // It's possible that the device was unlocked in a dream state. It's time to wake up.
        if (mAodShowing) {
            PowerManager pm = mContext.getSystemService(PowerManager.class);
            pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
                    "com.android.systemui:BOUNCER_DOZING");
        }

        synchronized (KeyguardViewMediator.this) {
            if (DEBUG) Log.d(TAG, "handleHide");

            if (mustNotUnlockCurrentUser()) {
                // In split system user mode, we never unlock system user. The end user has to
                // switch to another user.
                // TODO: We should stop it early by disabling the swipe up flow. Right now swipe up
                // still completes and makes the screen blank.
                if (DEBUG) Log.d(TAG, "Split system user, quit unlocking.");
                return;
            }
            mHiding = true;

            if (mShowing && !mOccluded) {
                mKeyguardGoingAwayRunnable.run();
            } else {
                /*重點關注*/
                handleStartKeyguardExitAnimation(
                        SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
                        mHideAnimation.getDuration());
            }
        }
        Trace.endSection();
    }

handleStartKeyguardExitAnimation

    private void handleStartKeyguardExitAnimation(long startTime, long fadeoutDuration) {
        Trace.beginSection("KeyguardViewMediator#handleStartKeyguardExitAnimation");
        if (DEBUG) Log.d(TAG, "handleStartKeyguardExitAnimation startTime=" + startTime
                + " fadeoutDuration=" + fadeoutDuration);
        synchronized (KeyguardViewMediator.this) {

            if (!mHiding) {
                // Tell ActivityManager that we canceled the keyguardExitAnimation.
                setShowingLocked(mShowing, mAodShowing, true /* force */);
                return;
            }
            mHiding = false;

            if (mWakeAndUnlocking && mDrawnCallback != null) {

                // Hack level over 9000: To speed up wake-and-unlock sequence, force it to report
                // the next draw from here so we don't have to wait for window manager to signal
                // this to our ViewRootImpl.
                mStatusBarKeyguardViewManager.getViewRootImpl().setReportNextDraw();
                notifyDrawn(mDrawnCallback);
                mDrawnCallback = null;
            }

            // only play "unlock" noises if not on a call (since the incall UI
            // disables the keyguard)
            if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) {
                playSounds(false);
            }

            mWakeAndUnlocking = false;
            setShowingLocked(false, mAodShowing);
            mDismissCallbackRegistry.notifyDismissSucceeded();
            /*重點關注*/
            mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
            resetKeyguardDonePendingLocked();
            mHideAnimationRun = false;
            adjustStatusBarLocked();
            sendUserPresentBroadcast();
        }
        Trace.endSection();
    }

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java

    /**
     * Hides the keyguard view
     */
    public void hide(long startTime, long fadeoutDuration) {
        mShowing = false;
        mKeyguardMonitor.notifyKeyguardState(
                mShowing, mKeyguardMonitor.isSecure(), mKeyguardMonitor.isOccluded());
        launchPendingWakeupAction();

        if (KeyguardUpdateMonitor.getInstance(mContext).needsSlowUnlockTransition()) {
            fadeoutDuration = KEYGUARD_DISMISS_DURATION_LOCKED;
        }
        long uptimeMillis = SystemClock.uptimeMillis();
        long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis);

        if (mStatusBar.isInLaunchTransition() ) {
            mStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() {
                @Override
                public void run() {
                    mStatusBarWindowController.setKeyguardShowing(false);
                    mStatusBarWindowController.setKeyguardFadingAway(true);
                    hideBouncer(true /* destroyView */);
                    updateStates();
                }
            }, new Runnable() {
                @Override
                public void run() {
                    mStatusBar.hideKeyguard();
                    mStatusBarWindowController.setKeyguardFadingAway(false);
                    mViewMediatorCallback.keyguardGone();
                    executeAfterKeyguardGoneAction();
                }
            });
        } else {
            executeAfterKeyguardGoneAction();
            boolean wakeUnlockPulsing =
                    mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
            if (wakeUnlockPulsing) {
                delay = 0;
                fadeoutDuration = 240;
            }
            mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
            mBiometricUnlockController.startKeyguardFadingAway();
            /*重點關注*/
            hideBouncer(true /* destroyView */);
            if (wakeUnlockPulsing) {
                mStatusBar.fadeKeyguardWhilePulsing();
                wakeAndUnlockDejank();
            } else {
                boolean staying = mStatusBar.hideKeyguard();
                if (!staying) {
                    mStatusBarWindowController.setKeyguardFadingAway(true);
                    // hide() will happen asynchronously and might arrive after the scrims
                    // were already hidden, this means that the transition callback won't
                    // be triggered anymore and StatusBarWindowController will be forever in
                    // the fadingAway state.
                    mStatusBar.updateScrimController();
                    wakeAndUnlockDejank();
                } else {
                    mStatusBar.finishKeyguardFadingAway();
                    mBiometricUnlockController.finishKeyguardFadingAway();
                }
            }
            updateStates();
            mStatusBarWindowController.setKeyguardShowing(false);
            mViewMediatorCallback.keyguardGone();
        }
        StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
            StatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN);
    }

hideBouncer

    private void hideBouncer(boolean destroyView) {
        if (mBouncer == null) {
            return;
        }
        /*重點關注*/
        mBouncer.hide(destroyView);
        cancelPendingWakeupAction();
    }

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java

    public void hide(boolean destroyView) {
        if (isShowing()) {
            StatsLog.write(StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
                StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
            mDismissCallbackRegistry.notifyDismissCancelled();
        }
        mIsScrimmed = false;
        mFalsingManager.onBouncerHidden();
        mCallback.onBouncerVisiblityChanged(false /* shown */);
        cancelShowRunnable();
        if (mKeyguardView != null) {
            mKeyguardView.cancelDismissAction();
            mKeyguardView.cleanUp();
        }
        mIsAnimatingAway = false;
        if (mRoot != null) {
            mRoot.setVisibility(View.INVISIBLE);
            if (destroyView) {

                // We have a ViewFlipper that unregisters a broadcast when being detached, which may
                // be slow because of AM lock contention during unlocking. We can delay it a bit.
                /*重點關注*/
                mHandler.postDelayed(mRemoveViewRunnable, 50);
            }
        }
    }

mRemoveViewRunnable

private final Runnable mRemoveViewRunnable = this::removeView;

removeView;

    protected void removeView() {
        if (mRoot != null && mRoot.getParent() == mContainer) {
            /*重點關注*/
            mContainer.removeView(mRoot);
            mRoot = null;
        }
    }

至此鎖屏界面移除的邏輯基本clear

發佈了46 篇原創文章 · 獲贊 24 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章