Android R系统Fingerprint指纹流程归纳

2023-05-16

孩子长大,倘无才能,可寻点小事情过活,万不可做空头文学家或美术家。

                                                                                   ------ 鲁迅


1. Android R中framework中需要新的配置项才会在SetupWizard中启动Settings的BiometricEnrollActivity界面,否则不会启动指纹录制流程。

    <!-- List of biometric sensors on the device, in decreasing strength. Consumed by AuthService
         when registering authenticators with BiometricService. Format must be ID:Modality:Strength,
         where: IDs are unique per device, Modality as defined in BiometricAuthenticator.java,
         and Strength as defined in Authenticators.java -->
    <string-array name="config_biometric_sensors" translatable="false" >
        <!-- <item>0:2:15</item>  ID0:Fingerprint:Strong --> // 这里要定义,否则在服务初始化registerAuthenticator阶段,将没有监测到物理sensor:BIOMETRIC_ERROR_HW_NOT_PRESENT
    </string-array>

2. SetupWizard/Settings中录制指纹成功后,SystemUI模块中灭屏逻辑(KeyguardUpdateMonitor::handleStartedGoingToSleep)会去触发启动指纹验证解锁流程。

    判断是否可以启动指纹监听:shouldListenForFingerprint--> startListeningForFingerprint --> 调用authenticate方法进入系统层面,这里传入了回调函数mFingerprintAuthenticationCallback用于接受后续的验证成功失败以及错误等回调。

系统端的authenticate方法会去调用FingerprintServiceWrapper类,这个是FingerpringManager和FingerprintService的server端,通过其binder call也可见是manager的server端。

    /**
     * Receives the incoming binder calls from FingerprintManager.
     */
    private final class FingerprintServiceWrapper extends IFingerprintService.Stub {

    @Override // Binder call
        public long preEnroll(IBinder token) {}

    @Override // Binder call
        public int postEnroll(IBinder token) {}

    @Override // Binder call
        public void enroll(final IBinder token, final byte[] cryptoToken, final int     
              userId, final IFingerprintServiceReceiver receiver, final int flags,final 
              String opPackageName) {}

    @Override // Binder call
        public void authenticate(final IBinder token, final long opId, final int 
              groupId, final IFingerprintServiceReceiver receiver, final int flags,
              final String opPackageName) {}

    @Override // Binder call
        public void remove(final IBinder token, final int fingerId, final int groupId,
                final int userId, final IFingerprintServiceReceiver receiver) {}

    @Override // Binder call
        public void rename(final int fingerId, final int groupId, final String name) {}
    …………………………

}

authenticate --> BiometricServiceBase::authenticateInternal  --> startAuthentication  -->startClient  --> mCurrentClient.start() ==> AuthenticationClient类中的start方法。

在调用过程中authenticateInternal之前,我们创建了client实例,其扩展了AuthenticationClientImpl以及父类AuthenticationClient以及ClientMonitor:

final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
                    mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
                    mCurrentUserId, groupId, opId, restricted, opPackageName,
                    0 /* cookie */, false /* requireConfirmation */);

其中,SystemUI传入的callback回调,保存在了Manager端的mAuthenticationCallback中,以参数的形式将另外的mServiceReceiver传入了ServiceListenerImpl类中,这个后面会用于回调到SystemUI中。

与daemon通信,DaemonWrapper是FingerprintService的内部辅助类,封装具体调用到Fingerprint Daemon服务的逻辑。

mCurrentClient.start(){
    int result = getDaemonWrapper().authenticate(mOpId, getGroupId());
}

    /**
     * Wraps the HAL-specific code and is passed to the ClientMonitor implementations 
       so that they
     * can be shared between the multiple biometric services.
     */
    private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() {
        @Override
        public int authenticate(long operationId, int groupId) throws RemoteException 
        {
            IBiometricsFingerprint daemon = getFingerprintDaemon();
            return daemon.authenticate(operationId, groupId);
        }

        @Override
        public int cancel() throws RemoteException {
            IBiometricsFingerprint daemon = getFingerprintDaemon();
            return daemon.cancel();
        }

        @Override
        public int remove(int groupId, int biometricId) throws RemoteException {
            IBiometricsFingerprint daemon = getFingerprintDaemon();
            return daemon.remove(groupId, biometricId);
        }

        @Override
        public int enumerate() throws RemoteException {
            IBiometricsFingerprint daemon = getFingerprintDaemon();
            return daemon.enumerate();
        }

        @Override
        public int enroll(byte[] cryptoToken, int groupId, int timeout,
                ArrayList<Integer> disabledFeatures) throws RemoteException {
            IBiometricsFingerprint daemon = getFingerprintDaemon();
            return daemon.enroll(cryptoToken, groupId, timeout);
        }
    };


    /** Gets the fingerprint daemon */
    private synchronized IBiometricsFingerprint getFingerprintDaemon() {
        if (mDaemon == null) {
            Slog.v(TAG, "mDaemon was null, reconnect to fingerprint");
            try {
                // 获取daemon服务
                mDaemon = IBiometricsFingerprint.getService();
            } catch (java.util.NoSuchElementException e) {
                // Service doesn't exist or cannot be opened. Logged below.
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to get biometric interface", e);
            }
            if (mDaemon == null) {
                Slog.w(TAG, "fingerprint HIDL not available");
                return null;
            }

            mDaemon.asBinder().linkToDeath(this, 0);

            try {
                //设置hal daemon到Fingerprint service的回调接口,获取hal设备id。
                mHalDeviceId = mDaemon.setNotify(mDaemonCallback);  
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to open fingerprint HAL", e);
                mDaemon = null; // try again later!
            }

            if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
            if (mHalDeviceId != 0) {
                loadAuthenticatorIds();
                updateActiveGroup(ActivityManager.getCurrentUser(), null);
                doTemplateCleanupForUser(ActivityManager.getCurrentUser());
            } else {
                Slog.w(TAG, "Failed to open Fingerprint HAL!");
                MetricsLogger.count(getContext(), "fingerprintd_openhal_error", 1);
                mDaemon = null;
            }
        }
        return mDaemon;
    }

HAL后面的逻辑这里不分析(后续完善)。当SystemUI通过authenticate启动验证流程后,指纹端就随时监听器件,当有手指按压触发中断,设备端会通过设置到hal的mDaemonCallback回调,调用onAcquired以及onAuthenticated,onAuthenticated方法中携带有指纹验证相关数据。

mDaemonCallback::onAuthenticated --> BiometricServiceBase::handleAuthenticated  --> client.onAuthenticated

client是我们之前调用authenticateInternal之前构建的AuthenticationClientImpl,其实现的方法在父类AuthenticationClient中,通过验证identifier的id确认是否通过指纹验证。

final boolean authenticated = identifier.getBiometricId() != 0;

// 这里的listener同样是我们在authenticate时构建的new ServiceListenerImpl(receiver,其receiver就是SystemUI的回调方法。
final BiometricServiceBase.ServiceListener listener = getListener();
if (authenticated) {
    listener.onAuthenticationSucceeded();
} else {
    listener.onAuthenticationFailedInternal();
}
   /**
     * Receives callbacks from the ClientMonitor implementations. The results are forwarded to
     * the FingerprintManager.
     */
    private class ServiceListenerImpl implements ServiceListener {
        private IFingerprintServiceReceiver mFingerprintServiceReceiver;

        public ServiceListenerImpl(IFingerprintServiceReceiver receiver) {
            mFingerprintServiceReceiver = receiver;
        }

        @Override
        public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)
                throws RemoteException {
            if (mFingerprintServiceReceiver != null) {
                final Fingerprint fp = (Fingerprint) identifier;
                mFingerprintServiceReceiver.onEnrollResult(fp.getDeviceId(), fp.getBiometricId(),
                        fp.getGroupId(), remaining);
            }
        }

        @Override
        public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
                throws RemoteException {
            if (mFingerprintServiceReceiver != null) {
                mFingerprintServiceReceiver.onAcquired(deviceId, acquiredInfo, vendorCode);
            }
        }

        @Override
        public void onAuthenticationSucceeded(long deviceId,
                BiometricAuthenticator.Identifier biometric, int userId)
                throws RemoteException {
            if (mFingerprintServiceReceiver != null) {
                if (biometric == null || biometric instanceof Fingerprint) {
                    mFingerprintServiceReceiver.onAuthenticationSucceeded(deviceId,
                            (Fingerprint) biometric, userId, isStrongBiometric());
                } else {
                    Slog.e(TAG, "onAuthenticationSucceeded received non-fingerprint biometric");
                }
            }
        }

        @Override
        public void onAuthenticationFailed(long deviceId) throws RemoteException {
            if (mFingerprintServiceReceiver != null) {
                mFingerprintServiceReceiver.onAuthenticationFailed(deviceId);
            }
        }

        @Override
        public void onError(long deviceId, int error, int vendorCode, int cookie)
                throws RemoteException {
            if (mFingerprintServiceReceiver != null) {
                mFingerprintServiceReceiver.onError(deviceId, error, vendorCode);
            }
        }
    }

这里的mFingerprintServiceReceiver是authenticate时,传入的manager内部类,负责将结果进一步封装,通过handler机制,传递回SystemUI中。

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,
                boolean isStrongBiometric) {
            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, isStrongBiometric ? 1 : 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();
        }
    };

sendAuthenticatedSucceeded方法中的mAuthenticationCallback,即:

// SystemUI中代码:
mFpm.authenticate(null, mFingerprintCancelSignal, 0, mFingerprintAuthenticationCallback,
                    null, userId);

// 系统处理callback,保存到mAuthenticationCallback
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 (mService != null) try {
            useHandler(handler);
            mAuthenticationCallback = callback;
            mCryptoObject = crypto;
            long sessionId = crypto != null ? crypto.getOpId() : 0;
            Slog.i("fingerprint_linhui","authenticate, pkg="+mContext.getOpPackageName(), new Throwable());
            mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
                    mContext.getOpPackageName());


// sendAuthenticatedSucceeded中调用回SystemUI:
    private void sendAuthenticatedSucceeded(Fingerprint fp, int userId, boolean isStrongBiometric) {
        if (mAuthenticationCallback != null) {
            final AuthenticationResult result =
                    new AuthenticationResult(mCryptoObject, fp, userId, isStrongBiometric);
            mAuthenticationCallback.onAuthenticationSucceeded(result);
        }
    }
}

我们SystemUI中通过如下方法传入的回调了mFingerprintAuthenticationCallback,所以接下来就进入到了SystemUI中的逻辑:

private FingerprintManager.AuthenticationCallback mFingerprintAuthenticationCallback
            = new AuthenticationCallback() {

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

        @Override
        public void onAuthenticationSucceeded(AuthenticationResult result) {
            handleFingerprintAuthenticated(result.getUserId(), result.isStrongBiometric());
        }
}

接着就是走解锁的逻辑: onBiometricAuthenticated  --> startWakeAndUnlock,后续不再赘述,解锁失败也是同样的回调逻辑。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android R系统Fingerprint指纹流程归纳 的相关文章

  • 是否可以以编程方式更改操作栏选项卡指示器

    如何以编程方式更改操作栏的选定选项卡指示器 我读过关于选项卡样式 http developer android com guide topics ui actionbar html Style和 Tab setCustomView 方法 但
  • 使用 Firebase 数据填充 Android spinner

    我在填充时遇到一些问题propertyAddress从我的properties桌子到我的旋转器MaintenanceActivity 问题本身不在于代码 而在于可以使用 Firebase 控制台修改的数据库规则 目前 我的规则是这样的 ru
  • Android spinner 将多列(连接)Sqlite 数据库加载到表中

    我正在学习如何创建一个从 SQLite 加载下拉列表的微调器 我有一个由旋转器和表格组成的用户界面 如果用户单击微调器 表的内容将根据微调器上选定的 ID 根据数据库加载 如果未选择名称 它将加载表中的所有内容 但是我找不到如何根据微调器上
  • 以编程方式设置 windowlightstatusbar 属性

    如您所知 我们可以设置windowLightStatusBar通过以下代码从 xml 中获取
  • Android NDK:断言失败:TARGET_PLATFORM 未定义

    使用 NDK r5b 时 当我使用以下命令在 jni 目录中进行构建时 NDK DIR ndk build 效果很好 但是当我切换到 r6b 只需以不同的方式设置 NDK DIR 并运行相同的命令时 我得到 usr local androi
  • MissingDimensionStrategy 无处不在 - 有没有更好的方法?

    我有一个图书馆项目 让我们称之为lib1有定制的flavorDimensions指定的 更准确地说有buld尺寸与实际口味full and production 该库被另一个库项目使用 lib2 没有自定义flavorDimensions指
  • 检查 key 是否存在 firebase Android

    我想检查 firebase 数据库中是否存在密钥 例如 我想查找关键的 upvotes 以查看它是否存在 Here is an exmaple upvotes key does not exist in here 现在我尝试检查密钥 upv
  • 如何在Android中创建类似架子的视图?

    如何在android中创建一个类似书架的视图 在任意行中显示多本书 此外 它应该具有像 Moon reader 应用程序那样的水平和垂直功能 我可以编写一个水平移动的架子视图 但它不能完全工作 我使用 xml 文件来查看包含图像 文本和按钮
  • 文本末尾有额外的换行符

    使用此方法设置文本后 我似乎得到了一些额外的换行符TextView message setText Html fromHtml message 我怎样才能删除这些 它们导致我的布局扭曲 因为它在输出中添加了两条额外的行 该字符串已通过以下方
  • 如何在 Android 中签署 AAR Artifacts?

    我目前正在开发一个 AAR android 库 我想用我自己的密钥对已发布的工件进行签名 以便我可以确定我是否发布了具有相同名称和功能的假 aar 注意事项1 我希望能够以编程方式检查我的库的真实性 即使是一个伪造的库 只是伪造了我的 aa
  • VS Code:无法安装以下 Android SDK 包,因为某些许可证尚未被接受

    我想做的是使用 VS Code 构建我的 flutter 应用程序 当我运行以下命令时flutter build apk FAILURE Build failed with an exception Where Build file F y
  • 使用协程对任务进行排队

    我最近开始阅读有关协程的内容 我想询问某个场景 考虑一个带有一个按钮的简单屏幕 单击后 它会执行一堆打印语句和一些延迟 其间 到目前为止 我正在使用协程来实现这一目标 现在 我的问题是 如果用户反复向该按钮发送垃圾邮件 是否有一种方法可以将
  • Android - 带图像的按钮 - 禁用按钮时图像变暗

    在 Android 中 我有一个包含图像和文本的按钮 禁用该按钮时 文本会自动变灰 但图像保持不变 当按钮被禁用时是否可以使图像变暗而不需要两个单独的图像 在您的代码中 您还可以使用彩色滤光片 http developer android
  • 覆盖乔达一周的第一天?

    是否有可能覆盖乔达弱的第一天sunday 因为 Joda 使用Monday作为一周的第一天 如果有办法的话 谁能解释一下 我在 SOF 中提到了以下主题 乔达时间 一周的第一天 https stackoverflow com questio
  • Android:调用超类的原因?

    我正在查看 Android 开发人员网站上的记事本教程 我有一个关于调用活动超类的重写函数的问题 例如 public class Notepadv3 extends ListActivity Override public boolean
  • 在 Android 模拟器上运行 Google 地图 v2

    我尝试在我的 Android 应用程序中实现 Google 地图 v2 但不幸的是 我收到的不是地图 而是以下消息 是否可以在 Android 模拟器 平台 4 2 上运行这些地图 目前 引用 Google Android Map API
  • Firebase 邀请发送电子邮件,但不发送短信。返回结果代码 0

    我正在尝试使用 Firebase 在我的 Android 应用程序中实现应用程序邀请系统 该代码与他们中给出的完全相同guide https firebase google com docs invites android private
  • 如何在flutter app android中添加Startapp广告?

    我想用其他广告更改 AdMob 广告 一些个人问题 如何在flutter app android中添加Startapp广告 有什么方法可以将启动广告添加到我的 flutter 应用程序 android 中 StartApp 现已更名为 St
  • java.lang.IllegalStateException:FragmentManager 已被销毁

    活动中onResume我称之为 volley request 的方法 它获取项目列表 然后将它们加载到此活动内的 ListFragment 中 当我第一次进入活动时 一切正常 但当我重新进入活动时 ListFragment 为空 并且控制台
  • 如何从 Android 应用程序调用 REST API? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我是 android 新手 也是编程新手 如何从 Android 应用程序调用 REST api GET POST 请求 请给我推荐一

随机推荐