Fingerprint -- 指纹录入流程


# 核心源码

关键类 路径
FingerprintEnrollIntroduction.java packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
BiometricEnrollIntroduction.java packages/apps/Settings/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
FingerprintEnrollEnrolling.java packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
BiometricsEnrollEnrolling.java packages/apps/Settings/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
FingerprintEnrollSidecar.java packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
BiometricEnrollSidecar.java packages/apps/Settings/src/com/android/settings/biometrics/BiometricEnrollSidecar.java
FingerprintEnrollFindSensor.java packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
FingerprintManager.java frameworks/base/core/java/android/hardware/fingerprint/FingerprintManager.java
FingerprintService.java frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
BiometricServiceBase.java frameworks/base/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
EnrollClient.java frameworks/base/services/core/java/com/android/server/biometrics/EnrollClient.java


# 相关类

关键类 说明
BiometricEnrollBase 指纹录制的基类。
FingerprintEnrollFindSensor 指纹开始准备录入的 Activity,继承 BiometricEnrollBase
FingerprintEnrollSidecar 注册 EnrollmentCallback,监听指纹录入状态,继承 BiometricEnrollSidecar
FingerprintEnrollEnrolling 指纹录入过程的 Activity,继承 BiometricEnrollBase 类。
FingerprintEnrollFinish 指纹录制结束后调用的 Activity,继承 BiometricEnrollBase 类。
FingerprintRemoveSidecar 管理指纹删除操作。
FingerprintFindSensorAnimation 指纹动画接口。
FingerprintLocationAnimationView 指纹动画,实现了 FingerprintFindSensorAnimation 接口。


本篇文章,我们从源码角度探讨指纹录入的过程(测试样机:Pixel),我们先看下 UI 图,这个你应该不陌生了。


UerIv8.png


一、FingerprintEnrollIntroduction

接下来我们就从指纹引导界面开始源码分析,图 1 的逻辑就在 FingerprintEnrollIntroduction 类,点击 Next 执行下一步,会执行 onNextButtonClick() 方法。

1.1 FingerprintEnrollIntroduction.onNextButtonClick()

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java

public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mFingerprintManager = Utils.getFingerprintManagerOrNull(this);

        mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);

        // Cancel Button
        mFooterBarMixin.setSecondaryButton(
                new FooterButton.Builder(this)
                        .setText(R.string.security_settings_face_enroll_introduction_cancel)
                        .setListener(this::onCancelButtonClick)
                        .setButtonType(FooterButton.ButtonType.SKIP)
                        .setTheme(R.style.SudGlifButton_Secondary)
                        .build()
        );

        // Next Button
        mFooterBarMixin.setPrimaryButton(
                new FooterButton.Builder(this)
                        .setText(R.string.wizard_next)
                        .setListener(this::onNextButtonClick)    // 点击 "下一步" 的处理流程
                        .setButtonType(FooterButton.ButtonType.NEXT)
                        .setTheme(R.style.SudGlifButton_Primary)
                        .build()
        );
    }

}

我们可以发现:FingerprintEnrollIntroduction 继承自 BiometricEnrollIntroductiononNextButtonClick() 方法在其父类 BiometricEnrollIntroduction 中处理。


二、BiometricEnrollIntroduction

2.1 BiometricEnrollIntroduction.onNextButtonClick()

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

public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
        implements LinkSpan.OnClickListener {

    @Override
    protected void onNextButtonClick(View view) {
        mNextClicked = true;
        if (checkMaxEnrolled() == 0) {
            // Lock thingy is already set up, launch directly to the next page
            launchNextEnrollingActivity(mToken);    // 接下来就要拉起指纹录入界面
        } else {
            setResult(RESULT_FINISHED);
            finish();
        }
    }

}

2.2 BiometricEnrollIntroduction.launchNextEnrollingActivity()

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

public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
        implements LinkSpan.OnClickListener {

    private void launchNextEnrollingActivity(byte[] token) {
        Intent intent = getEnrollingIntent();    // 获取 FingerprintEnrollFindSensor
        if (token != null) {
            intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
        }
        if (mUserId != UserHandle.USER_NULL) {
            intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
        }
        intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, mFromSettingsSummary);
        startActivityForResult(intent, BIOMETRIC_FIND_SENSOR_REQUEST);    // 跳转 FingerprintEnrollFindSensor
    }

    protected abstract Intent getEnrollingIntent();    // 抽象方法,由子类 FingerprintEnrollIntroduction 实现
}

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java

public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {

    @Override
    protected Intent getEnrollingIntent() {
        return new Intent(this, FingerprintEnrollFindSensor.class);    // 获取 FingerprintEnrollFindSensor
    }

}


三、FingerprintEnrollFindSensor

我们把上面的图再拿过来,此时就进入了图 2 界面的逻辑,我们接着往下看。


UerIv8.png


3.1 FingerprintEnrollFindSensor.onCreate()

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java

public class FingerprintEnrollFindSensor extends BiometricEnrollBase {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getContentView());
        mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
        // Skip button
        mFooterBarMixin.setSecondaryButton(
                new FooterButton.Builder(this)
                        .setText(R.string.skip_label)
                        .setListener(this::onSkipButtonClick)
                        .setButtonType(FooterButton.ButtonType.SKIP)
                        .setTheme(R.style.SudGlifButton_Secondary)
                        .build()
        );

        // Touch the sensor
        setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);

        // 执行 startLookingForFingerprint() 方法
        startLookingForFingerprint(); // already confirmed, so start looking for fingerprint

        // 演示动画
        View animationView = findViewById(R.id.fingerprint_sensor_location_animation);
        if (animationView instanceof FingerprintFindSensorAnimation) {
            mAnimation = (FingerprintFindSensorAnimation) animationView;
        } else {
            mAnimation = null;
        }
    }

}

到这里都只是涉及到 UI 界面的相关逻辑,接下来的代码逻辑就稍微复杂一点了,我们仔细深挖研究。

3.2 FingerprintEnrollFindSensor.startLookingForFingerprint()

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java

public class FingerprintEnrollFindSensor extends BiometricEnrollBase {

    private FingerprintEnrollSidecar mSidecar;
    private boolean mNextClicked;

    private void startLookingForFingerprint() {
        // FingerprintEnrollSidecar 这个 fragment 的生命周期正式开启
        mSidecar = (FingerprintEnrollSidecar) getSupportFragmentManager().findFragmentByTag(
                FingerprintEnrollEnrolling.TAG_SIDECAR);
        if (mSidecar == null) {
            mSidecar = new FingerprintEnrollSidecar();
            // 添加 FingerprintEnrollEnrolling
            getSupportFragmentManager().beginTransaction()
                    .add(mSidecar, FingerprintEnrollEnrolling.TAG_SIDECAR)
                    .commitAllowingStateLoss();
        }

        // FingerprintEnrollEnrolling 实现了 BiometricEnrollSidecar.Listener 接口
        mSidecar.setListener(new Listener() {    // 匿名内部类的方式实现接口方法
            @Override
            public void onEnrollmentProgressChange(int steps, int remaining) {
                mNextClicked = true;
                proceedToEnrolling(true /* cancelEnrollment */);
            }

            @Override
            public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
            }

            @Override
            public void onEnrollmentError(int errMsgId, CharSequence errString) {
                if (mNextClicked && errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
                    mNextClicked = false;
                    proceedToEnrolling(false /* cancelEnrollment */);
                }
            }
        });
    }

}

这里面有个重点方法:onEnrollmentProgressChange(),如果我们此时用手指贴在指纹传感器上,会产生反馈信息的回调,此时 onEnrollmentProgressChange() 方法被执行,进入执行 proceedToEnrolling() 方法,我们看下这个方法:

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java

public class FingerprintEnrollFindSensor extends BiometricEnrollBase {

    private void proceedToEnrolling(boolean cancelEnrollment) {
        if (mSidecar != null) {
            if (cancelEnrollment) {
                if (mSidecar.cancelEnrollment()) {
                    // Enrollment cancel requested. When the cancellation is successful,
                    // onEnrollmentError will be called with FINGERPRINT_ERROR_CANCELED, calling
                    // this again.
                    return;
                }
            }
            getSupportFragmentManager().beginTransaction().remove(mSidecar).
                    commitAllowingStateLoss();
            mSidecar = null;
            // getFingerprintEnrollingIntent() 方法会返回一个包含 FingerprintEnrollEnrolling 的 Intent
            startActivityForResult(getFingerprintEnrollingIntent(), ENROLL_REQUEST);
        }
    }

}

正常流程会走到 startActivityForResult() 方法,跳转到 FingerprintEnrollEnrolling 界面。


四、FingerprintEnrollEnrolling

我们把上面的图再拿过来,此时就进入了图 3 界面的逻辑,我们接着往下看。


UerIv8.png


4.1 FingerprintEnrollEnrolling.onStart()

我们重点关注 onStart() 方法:

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java

/**
 * Activity which handles the actual enrolling for fingerprint.
 */
public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {

    @Override
    protected void onStart() {
        super.onStart();    // 调用父类 BiometricEnrollSidecar 的 onStart() 方法
        updateProgress(false /* animate */);    // 更新录入进度
        updateDescription();
        if (mRestoring) {
            startIconAnimation();
        }
    }

}

FingerprintEnrollEnrolling 类继承自 BiometricsEnrollEnrolling 类,而 BiometricsEnrollEnrolling 类实现了 BiometricEnrollSidecar.Listener 接口,所以 FingerprintEnrollEnrolling 也实现了 BiometricEnrollSidecar.Listener 接口。

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java

/**
 * Activity which handles the actual enrolling for fingerprint.
 */
public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {

    // 指纹录制时提示(比如太快,移动手指之类)
    @Override
    public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
        if (!TextUtils.isEmpty(helpString)) {
            mErrorText.removeCallbacks(mTouchAgainRunnable);
            showError(helpString);
        }
    }

    // 提示指纹录制过程中超时,或者未注册
    @Override
    public void onEnrollmentError(int errMsgId, CharSequence errString) {
        int msgId;
        switch (errMsgId) {
            case FingerprintManager.FINGERPRINT_ERROR_TIMEOUT:
                msgId = R.string.security_settings_fingerprint_enroll_error_timeout_dialog_message;
                break;
            default:
                msgId = R.string.security_settings_fingerprint_enroll_error_generic_dialog_message;
                break;
        }
        showErrorDialog(getText(msgId), errMsgId);
        stopIconAnimation();
        mErrorText.removeCallbacks(mTouchAgainRunnable);
    }

    // 录制过程中进度的变化(手指按压指纹传感区,onEnrollmentProgressChange() 会被触发,执行一系列处理工作)
    @Override
    public void onEnrollmentProgressChange(int steps, int remaining) {
        updateProgress(true /* animate */);    // 更新进度
        updateDescription();    // 更新描述
        clearError();
        animateFlash();    // 更新动画
        mErrorText.removeCallbacks(mTouchAgainRunnable);
        mErrorText.postDelayed(mTouchAgainRunnable, HINT_TIMEOUT_DURATION);
    }

}


五、BiometricsEnrollEnrolling

5.1 BiometricsEnrollEnrolling.onStart()

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

public abstract class BiometricsEnrollEnrolling extends BiometricEnrollBase
        implements BiometricEnrollSidecar.Listener {

    @Override
    protected void onStart() {
        super.onStart();
        if (shouldStartAutomatically()) {    // 恒定为 true
            startEnrollment();    // 调用 startEnrollment() 方法
        }
    }

}

5.2 BiometricsEnrollEnrolling.startEnrollment()

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

public abstract class BiometricsEnrollEnrolling extends BiometricEnrollBase
        implements BiometricEnrollSidecar.Listener {

    protected BiometricEnrollSidecar mSidecar;

    protected abstract BiometricEnrollSidecar getSidecar();    // 抽象方法,由子类实现

    public void startEnrollment() {
        // 调用 BiometricEnrollSidecar 的 onStart() 方法
        mSidecar = (BiometricEnrollSidecar) getSupportFragmentManager()
                .findFragmentByTag(TAG_SIDECAR);
        if (mSidecar == null) {
            mSidecar = getSidecar();    // 获取 mSidecar
            getSupportFragmentManager().beginTransaction().add(mSidecar, TAG_SIDECAR)
                    .commitAllowingStateLoss();
        }
        mSidecar.setListener(this);
    }

}

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java

public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {

    @Override
    protected BiometricEnrollSidecar getSidecar() {
        // 返回了一个继承自 BiometricEnrollSidecar 的 FingerprintEnrollSidecar 对象
        return new FingerprintEnrollSidecar();
    }

}


六、FingerprintEnrollSidecar

6.1 FingerprintEnrollSidecar.startEnrollment()

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java

/**
 * Sidecar fragment to handle the state around fingerprint enrollment.
 */
public class FingerprintEnrollSidecar extends BiometricEnrollSidecar {

    private FingerprintManager mFingerprintManager;

    @Override
    protected void startEnrollment() {
        super.startEnrollment();
        if (mUserId != UserHandle.USER_NULL) {
            mFingerprintManager.setActiveUser(mUserId);
        }
        /*
         * 调用 FingeprintManager 的 enroll() 方法开始录入,并且传入了 EnrollmentCallback 对象
         * EnrollmentCallback 是指纹录入结果的回调,分别调用了 BiometricEnrollSidecar.Listener 接口中的方法,
         * 这样就能更新指纹录制的进度和录制结果。
         */
        mFingerprintManager.enroll(mToken, mEnrollmentCancel, 0 /* flags */, mUserId, mEnrollmentCallback);
    }

我们看下 EnrollmentCallback 对象是什么:

// packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java

public class FingerprintEnrollSidecar extends BiometricEnrollSidecar {

    private FingerprintManager.EnrollmentCallback mEnrollmentCallback
            = new FingerprintManager.EnrollmentCallback() {

        @Override
        public void onEnrollmentProgress(int remaining) {
            FingerprintEnrollSidecar.super.onEnrollmentProgress(remaining);
        }

        @Override
        public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
            FingerprintEnrollSidecar.super.onEnrollmentHelp(helpMsgId, helpString);
        }

        @Override
        public void onEnrollmentError(int errMsgId, CharSequence errString) {
            FingerprintEnrollSidecar.super.onEnrollmentError(errMsgId, errString);
        }
    };

}


七、FingerprintManager

7.1 FingerprintManager.enroll()

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

public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {

    private IFingerprintService mService;

    // CancellationSignal 类提供删除信号类,提供终止操作的能力
    @RequiresPermission(MANAGE_FINGERPRINT)
    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;
            // 调用 FingerprintServiceWrapper 的 enroll() 方法
            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 */));
            }
        }
    }

}


八、FingerprintService

8.1 FingerprintServiceWrapper.enroll()

FingerprintManagerFingerprintService 直接通过 aidl 进行通信,在 FingerprintService 中内部类 FingerprintServiceWrapper 实现了 IFingerprintService.Stub,我们调用的 FingerMangerenroll() 方法就是调用 FingerprintServiceWrapper 类中的 enroll() 方法。

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

public class FingerprintService extends BiometricServiceBase {

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

        @Override // Binder call
        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 */,
                    ENROLL_TIMEOUT_SEC) {
                @Override
                public boolean shouldVibrate() {
                    return true;
                }

                @Override
                protected int statsModality() {
                    return FingerprintService.this.statsModality();
                }
            };

            enrollInternal(client, userId);    // 调用 BiometricServiceBase 的 enrollInternal() 方法
        }

    }

}


九、BiometricServiceBase

9.1 BiometricServiceBase.enrollInternal()

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

public abstract class BiometricServiceBase extends SystemService
        implements IHwBinder.DeathRecipient {

    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() 方法
        });
    }        

}

9.2 BiometricServiceBase.startClient()

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

public abstract class BiometricServiceBase extends SystemService
        implements IHwBinder.DeathRecipient {

    private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
        ClientMonitor currentClient = mCurrentClient;
        if (currentClient != null) {
            if (DEBUG) Slog.v(getTag(), "request stop current client " +
                    currentClient.getOwnerString());
            if (currentClient instanceof InternalEnumerateClient
                    || currentClient instanceof InternalRemovalClient) {
                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);

                mHandler.removeCallbacks(mResetClientState);
                mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
            }
            mPendingClient = newClient;
        } else if (newClient != null) {
            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());    // 调用 startCurrentClient() 方法
        }
    }

}

9.3 BiometricServiceBase.startCurrentClient()

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

public abstract class BiometricServiceBase extends SystemService
        implements IHwBinder.DeathRecipient {

    private ClientMonitor mCurrentClient;

    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() + ")"
                + " targetUserId: " + mCurrentClient.getTargetUserId()
                + " currentUserId: " + mCurrentUserId
                + " cookie: " + cookie + "/" + mCurrentClient.getCookie());
        if (cookie != mCurrentClient.getCookie()) {
            Slog.e(getTag(), "Mismatched cookie");
            return;
        }
        notifyClientActiveCallbacks(true);
        mCurrentClient.start();    // 调用 EnrollClient 的 start() 方法
    }

}


十、EnrollClient

10.1 EnrollClient.start()

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

// EnrollClient 是为给定的客户端跟踪指纹录制状态
public abstract class EnrollClient extends ClientMonitor {

    // start 方法会调用 fingerprintd,调用底层的指纹库,底层库返回结果后会调用 onEnrollResult 来反馈结果给 receiver,再往上层反馈。
    @Override
    public int start() {
        mEnrollmentStartTimeMs = System.currentTimeMillis();
        try {
            final ArrayList<Integer> disabledFeatures = new ArrayList<>();
            for (int i = 0; i < mDisabledFeatures.length; i++) {
                disabledFeatures.add(mDisabledFeatures[i]);
            }

            // 调用 getDaemonWrapper().enroll() 方法
            final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), mTimeoutSec,
                    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
    }

}

看下 getDaemonWrapper():

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

public abstract class ClientMonitor extends LoggableMonitor implements IBinder.DeathRecipient {

    private final BiometricServiceBase.DaemonWrapper mDaemon;

    public final BiometricServiceBase.DaemonWrapper getDaemonWrapper() {
        return mDaemon;
    }

}

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

public abstract class BiometricServiceBase extends SystemService
        implements IHwBinder.DeathRecipient {

    protected interface DaemonWrapper {
        int ERROR_ESRCH = 3; // Likely HAL is dead. see errno.h.
        int authenticate(long operationId, int groupId) throws RemoteException;
        int cancel() throws RemoteException;
        int remove(int groupId, int biometricId) throws RemoteException;
        int enumerate() throws RemoteException;
        int enroll(byte[] token, int groupId, int timeout,
                ArrayList<Integer> disabledFeatures) throws RemoteException;
        void resetLockout(byte[] token) throws RemoteException;
    }

}

mDamon 是一个 BiometricServiceBase.DaemonWrapper 接口,在 FingerprintService 中做了定义:

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

public class FingerprintService extends BiometricServiceBase {

    private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() {
        ... ...

        @Override
        public int enroll(byte[] cryptoToken, int groupId, int timeout,
                ArrayList<Integer> disabledFeatures) throws RemoteException {
            IBiometricsFingerprint daemon = getFingerprintDaemon();
            if (daemon == null) {
                Slog.w(TAG, "enroll(): no fingerprint HAL!");
                return ERROR_ESRCH;
            }
            return daemon.enroll(cryptoToken, groupId, timeout);
        }
        ... ...

    };

}

getDaemonWrapper().enroll() 最终会走到 fingerprintd,调用底层的指纹库,底层库返回结果后会调用 onEnrollResult 来反馈结果给 receiver,在往上层反馈。这就是指纹的录制流程。

最后,我们再看下 mServiceReceiver 处理信息的流程:

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

public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {

    private Handler mHandler;

    // mServiceReceiver 对象会通过 handler 发送相关消息去调用 EnrollmentCallback 或者 AuthenticationCallback 中方法
    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();
        }
    };

    private class MyHandler extends Handler {
        private MyHandler(Context context) {
            super(context.getMainLooper());
        }

        private MyHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case MSG_ENROLL_RESULT:
                    sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
                    break;
                case MSG_ACQUIRED:
                    sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */,
                            msg.arg2 /* vendorCode */);
                    break;
                case MSG_AUTHENTICATION_SUCCEEDED:
                    sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
                    break;
                case MSG_AUTHENTICATION_FAILED:
                    sendAuthenticatedFailed();
                    break;
                case MSG_ERROR:
                    sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */,
                            msg.arg2 /* vendorCode */);
                    break;
                case MSG_REMOVED:
                    sendRemovedResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
                    break;
                case MSG_ENUMERATED:
                    sendEnumeratedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
                            msg.arg2 /* groupId */);
                    break;
            }
        }
    };
}

看下 MSG_ENROLL_RESULT

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

public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {

    private void sendEnrollResult(Fingerprint fp, int remaining) {
        if (mEnrollmentCallback != null) {
            // 调用 EnrollmentCallback 的 onEnrollmentProgress 方法
            mEnrollmentCallback.onEnrollmentProgress(remaining);
        }
    }

}


# Fingerprint Enroll 流程图

UKXCTS.png