Android Q 上的Biometric生物识别之Fingerprint指纹识别流程

本文深入解析了Android系统中指纹识别的全过程,从指纹录入、匹配到屏幕解锁的详细流程及关键代码路径,揭示了FingerprintHIDL接口如何连接硬件与软件,实现指纹功能。

第一部分、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<
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值