第一部分 指纹模块流程分析
一、Fingerprint模块架构
Fingerprint模块架构主要由application,framework,fingerprintd和FingerprintHal这几个部分,以及涉及到指纹的IC库和驱动这部分,这部分逻辑由指纹厂商来实现。
application层主要涉及到Settings 和 SystemUI
二、指纹录入
1.Settings中重要的指纹相关类
FingerprintEnrollBase.java 指纹录制的基类
FingerprintEnrollFindSensor.java 指纹开始准备录入的activity,继承FingerprintEnrollBase
FingerprintEnrollSidecar.java 注册EnrollmentCallback,监听指纹录入状态,在FingerprintEnrollFindSensor中会new FingerprintEnrollSidecar
FingerprintFindSensorAnimation.java 指纹动画接口
FingerprintLocationAnimationView.java 指纹动画,实现了FingerprintFindSensorAnimation接口
FingerprintEnrollFinish.java 指纹录制结束的activity,同样继承FingerprintEnrollBase
FingerprintEnrollEnrolling.java 指纹正在录制的activity,同样继承FingerprintEnrollBase,同样也 new
FingerprintRemoveSidecar.java 管理指纹删除操作
FingerprintEnrollSidecar() 管理指纹录入
2.准备录入指纹
启动FingerprintEnrollFindSensor(开始准备录入指纹的activity)时,在onCreate()中调用startLookingForFingerprint(),
new FingerprintEnrollSidecar() --->onStart() --->startEnrollment()--->mFingerprintManager.enroll()
FingerprintManager.java --- enroll()
@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()) {
Log.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) {
Log.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(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
}
}
}
FingerprintService.java--- enroll()
@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 int limit = mContext.getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size();
if (enrolled >= limit) {
Slog.w(TAG, "Too many fingerprints registered");
return;
}
// Group ID is arbitrarily set to parent profile user ID. It just represents
// the default fingerprints for the user.
if (!isCurrentUserOrProfile(userId)) {
return;
}
final boolean restricted = isRestricted();
mHandler.post(new Runnable() {
@Override
public void run() {
startEnrollment(token, cryptoToken, userId, receiver, flags,
restricted, opPackageName);
}
});
}
private void startEnrollment(IBinder token, byte [] cryptoToken, int userId,
IFingerprintServiceReceiver receiver, int flags, boolean restricted,
String opPackageName) {
updateActiveGroup(userId, opPackageName);
final int groupId = userId; // default group for fingerprint enrollment
EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver,
userId, groupId, cryptoToken, restricted, opPackageName) {
@Override
public IBiometricsFingerprint getFingerprintDaemon() {
return FingerprintService.this.getFingerprintDaemon();
}
@Override
public void notifyUserActivity() {
FingerprintService.this.userActivity();
}
};
startClient(client, true /* initiatedByClient */);
}
private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
ClientMonitor currentClient = mCurrentClient;
if (currentClient != null) {
if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString());
if (currentClient instanceof InternalEnumerateClient ||
currentClient instanceof InternalRemovalClient) {
// This condition means we're currently running internal diagnostics to
// remove extra fingerprints in the hardware and/or the software
// TODO: design an escape hatch in case client never finishes
}
else {
currentClient.stop(initiatedByClient);
}
mPendingClient = newClient;
mHandler.removeCallbacks(mResetClientState);
mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
} else if (newClient != null) {
mCurrentClient = newClient;
if (DEBUG) Slog.v(TAG, "starting client "
+ newClient.getClass().getSuperclass().getSimpleName()
+ "(" + newClient.getOwnerString() + ")"
+ ", initiatedByClient = " + initiatedByClient + ")");
notifyClientActiveCallbacks(true);
newClient.start();
}
startEnrollment方法中会调用EnrollClient的start方法,EnrollClient是为给定的客户端跟踪指纹录制状态。
/**
* A class to keep track of the enrollment state for a given client.
*/
public abstract class EnrollClient extends ClientMonitor {
......
public EnrollClient(Context context, long halDeviceId, IBinder token,
IFingerprintServiceReceiver receiver, int userId, int groupId, byte [] cryptoToken,
boolean restricted, String owner) {
super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
......
}
@Override
public boolean onEnrollResult(int fingerId, int groupId, int remaining) {
if (remaining == 0) {
FingerprintUtils.getInstance().addFingerprintForUser(getContext(), fingerId,
getTargetUserId());
}
return sendEnrollResult(fingerId, groupId, remaining);
}
/*
* @return true if we're done.
*/
private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
IFingerprintServiceReceiver receiver = getReceiver();
......
receiver.onEnrollResult(getHalDeviceId(), fpId, groupId, remaining);
......
}
@Override
public int start() {
IFingerprintDaemon daemon = getFingerprintDaemon();
......
final int result = daemon.enroll(mCryptoToken, getGroupId(), timeout);
......
return 0; // success
}
start方法会调用fingerprintd,调用底层的指纹库,底层库返回结果后会调用onEnrollResult来反馈结果给receiver,在往上层反馈。这就是指纹的录制流程。在onEnrollResult中当remaining等于0的时候录制完成,调用addFingerprintForUser()
FingerprintManager.java中注册了IFingerprintServiceReceiver,实现onEnrollResult方法发送MSG_ENROLL_RESULT
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();
}
};
@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);
}
}
EnrollmentCallback是FingerprintManager.java的抽象内部类
public static abstract class EnrollmentCallback {
/**
* Called when an unrecoverable error has been encountered and the operation is complete.
* No further callbacks will be made on this object.
* @param errMsgId An integer identifying the error message
* @param errString A human-readable error string that can be shown in UI
*/
public void onEnrollmentError(int errMsgId, CharSequence errString) { }
/**
* Called when a recoverable error has been encountered during enrollment. The help
* string is provided to give the user guidance for what went wrong, such as
* "Sensor dirty, please clean it" or what they need to do next, such as
* "Touch sensor again."
* @param helpMsgId An integer identifying the error message
* @param helpString A human-readable string that can be shown in UI
*/
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { }
/**
* Called as each enrollment step progresses. Enrollment is considered complete when
* remaining reaches 0. This function will not be called if enrollment fails. See
* {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)}
* @param remaining The number of remaining steps
*/
public void onEnrollmentProgress(int remaining) { }
};
再回过头来看Settings
FingerprintEnrollSidecar.java中注册EnrollmentCallback,监听指纹录入状态。并写有一个内部接口Listener
public interface Listener {
void onEnrollmentHelp(int helpMsgId,CharSequence helpString);
//void onEnrollmentHelp(CharSequence helpString);
void onEnrollmentError(int errMsgId, CharSequence errString);
void onEnrollmentProgressChange(int steps, int remaining);
}
一个public方法
public void setListener(Listener listener) {
mListener = listener;
......
}
实现了EnrollmentCallback接口
private FingerprintManager.EnrollmentCallback mEnrollmentCallback
= new FingerprintManager.EnrollmentCallback() {
@Override
public void onEnrollmentProgress(int remaining) {
if (mEnrollmentSteps == -1) {
mEnrollmentSteps = remaining;
}
mEnrollmentRemaining = remaining;
mDone = remaining == 0;
if (mListener != null) {
mListener.onEnrollmentProgressChange(mEnrollmentSteps, remaining);
} else {
mQueuedEvents.add(new QueuedEnrollmentProgress(mEnrollmentSteps, remaining));
}
}
@Override
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
if (mListener != null) {
mListener.onEnrollmentHelp(helpMsgId,helpString);
//mListener.onEnrollmentHelp(helpString);
} else {
mQueuedEvents.add(new QueuedEnrollmentHelp(helpMsgId, helpString));
}
}
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
if (mListener != null) {
mListener.onEnrollmentError(errMsgId, errString);
} else {
mQueuedEvents.add(new QueuedEnrollmentError(errMsgId, errString));
}
mEnrolling = false;
}
};
而FingerprintEnrollFindSensor.java和FingerprintEnrollEnrolling.java 分别implements FingerprintEnrollSidecar.Listener,从而实现了CallBack
三,指纹重命名
弹出重命名框:FingerprintSettings.java--->RenameDialog--->renameFingerPrint()
调用到FingerprintManager.java的rename()方法
@RequiresPermission(MANAGE_FINGERPRINT)
public void rename(int fpId, int userId, String newName) {
// Renames the given fpId
if (mService != null) {
try {
mService.rename(fpId, userId, newName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else {
Log.w(TAG, "rename(): Service not connected!");
}
调用FingerprintService.java的rename()方法
@Override // Binder call
public void rename(final int fingerId, final int groupId, final String name) {
checkPermission(MANAGE_FINGERPRINT);
if (!isCurrentUserOrProfile(groupId)) {
return;
}
mHandler.post(new Runnable() {
@Override
public void run() {
mFingerprintUtils.renameFingerprintForUser(mContext, fingerId,
groupId, name);
}
});
}
再到FingerprintUtils.java的renameFingerprintForUser()
public void renameFingerprintForUser(Context ctx, int fingerId, int userId, CharSequence name) {
if (TextUtils.isEmpty(name)) {
// Don't do the rename if it's empty
return;
}
getStateForUser(ctx, userId).renameFingerprint(fingerId, name);
}
到FingerprintsUserState的renameFingerprint()
public void renameFingerprint(int fingerId, CharSequence name) {
synchronized (this) {
for (int i = 0; i < mFingerprints.size(); i++) {
if (mFingerprints.get(i).getFingerId() == fingerId) {
Fingerprint old = mFingerprints.get(i);
mFingerprints.set(i, new Fingerprint(name, old.getGroupId(), old.getFingerId(),
old.getDeviceId()));
scheduleWriteStateLocked();
break;
}
}
}
}
四,指纹的删除流程
弹出删除确认框FingerprintSettings.java--->DeleteFingerprintDialog--->deleteFingerPrint()
void deleteFingerPrint(Fingerprint fingerPrint) {
mRemovalSidecar.startRemove(fingerPrint, mUserId);
String name = genKey(fingerPrint.getFingerId());
Preference prefToRemove = findPreference(name);
prefToRemove.setEnabled(false);
updateAddPreference();
}
调用FingerprintRemoveSidecar.java的startRemove()
public void startRemove(Fingerprint fingerprint, int userId) {
if (mFingerprintRemoving != null) {
Log.e(TAG, "Remove already in progress");
return;
}
if (userId != UserHandle.USER_NULL) {
mFingerprintManager.setActiveUser(userId);
}
mFingerprintRemoving = fingerprint;
mFingerprintManager.remove(fingerprint, userId, mRemoveCallback);;
}
可以看到调用FingerprintManager的remove方法时传入了一个removeCallback,看下这个Callbcak
private FingerprintManager.RemovalCallback
mRemoveCallback = new FingerprintManager.RemovalCallback() {
@Override
public void onRemovalSucceeded(Fingerprint fingerprint, int remaining) {
if (mListener != null) {
mListener.onRemovalSucceeded(fingerprint);
} else {
mFingerprintsRemoved.add(fingerprint);
};
mFingerprintRemoving = null;
}
@Override
public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) {
if (mListener != null) {
mListener.onRemovalError(fp, errMsgId, errString);
} else {
mFingerprintsRemoved.add(new RemovalError(fp, errMsgId, errString));
}
mFingerprintRemoving = null;
}
};
这个Listener是FingerprintRemoveSidecar的一个内部接口,FingerprintSettings实现了这个接口
public interface Listener {
void onRemovalSucceeded(Fingerprint fingerprint);
void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString);
}
回过头来继续看FingerprintManager的remove方法
public void remove(Fingerprint fp, int userId, RemovalCallback callback) {
if (mService != null) try {
mRemovalCallback = callback;
mRemovalFingerprint = fp;
mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver);
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in remove: ", e);
if (callback != null) {
callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
}
}
}
调用FingerprintService的remove方法
public void remove(final IBinder token, final int fingerId, final int groupId,
final int userId, final IFingerprintServiceReceiver receiver) {
checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
final boolean restricted = isRestricted();
mHandler.post(new Runnable() {
@Override
public void run() {
startRemove(token, fingerId, groupId, userId, receiver,
restricted, false /* internal */);
}
});
}
FingerprintService--->startRemove
void startRemove(IBinder token, int fingerId, int groupId, int userId,
IFingerprintServiceReceiver receiver, boolean restricted, boolean internal) {
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startRemove: no fingerprint HAL!");
return;
}
if (internal) {
Context context = getContext();
InternalRemovalClient client = new InternalRemovalClient(context, mHalDeviceId,
token, receiver, fingerId, groupId, userId, restricted,
context.getOpPackageName()) {
@Override
public void notifyUserActivity() {
}
@Override
public IBiometricsFingerprint getFingerprintDaemon() {
return FingerprintService.this.getFingerprintDaemon();
}
};
startClient(client, true);
}//internal是false,所以调用RemovalClient
else {
RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token,
receiver, fingerId, groupId, userId, restricted, token.toString()) {
@Override
public void notifyUserActivity() {
FingerprintService.this.userActivity();
}
@Override
public IBiometricsFingerprint getFingerprintDaemon() {
return FingerprintService.this.getFingerprintDaemon();
}
};
startClient(client, true);
}
}
RemovalClient和EnrollClient一样都是继承ClientMonitor,start方法会调用fingerprintd,调用底层的指纹库,底层库返回结果后会调用onEnrollResult来反馈结果给onRemoved,在往上层反馈。这就是指纹的删除流程
@Override
public boolean onRemoved(int fingerId, int groupId, int remaining) {
if (fingerId != 0) {
FingerprintUtils.getInstance().removeFingerprintIdForUser(getContext(), fingerId,
getTargetUserId());
}
return sendRemoved(fingerId, getGroupId(), remaining);
}
FingerprintUtils --->removeFingerprintIdForUser
public void removeFingerprintIdForUser(Context ctx, int fingerId, int userId) {
getStateForUser(ctx, userId).removeFingerprint(fingerId);
}
FingerprintsUserState --->removeFingerprint
public void removeFingerprint(int fingerId) {
synchronized (this) {
for (int i = 0; i < mFingerprints.size(); i++) {
if (mFingerprints.get(i).getFingerId() == fingerId) {
mFingerprints.remove(i);
scheduleWriteStateLocked();
break;
}
}
}
}
五,指纹解锁流程
首先分析下灭屏后,如何开始监听指纹解锁的
灭屏后会走到PhoneWindowManager.java-->startedGoingToSleep()方法
// Called on the PowerManager's Notifier thread.
@Override
public void startedGoingToSleep(int why) {
if (DEBUG_WAKEUP) Slog.i(TAG, "Started going to sleep... (why=" + why + ")");
mGoingToSleep = true;
mRequestedOrGoingToSleep = true;
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onStartedGoingToSleep(why);
}
}
KeyguardServiceDelegate.java-->onStartedGoingToSleep()
public void onStartedGoingToSleep(int why) {
if (mKeyguardService != null) {
mKeyguardService.onStartedGoingToSleep(why);
}
mKeyguardState.offReason = why;
mKeyguardState.interactiveState = INTERACTIVE_STATE_GOING_TO_SLEEP;
}
KeyguardServiceWrapper.java-->onStartedGoingToSleep()
@Override
public void onStartedGoingToSleep(int reason) {
try {
mService.onStartedGoingToSleep(reason);
} catch (RemoteException e) {
Slog.w(TAG , "Remote Exception", e);
}
}
KeyguardService.java-->onStartedGoingToSleep()
@Override // Binder interface
public void onStartedGoingToSleep(int reason) {
checkPermission();
mKeyguardViewMediator.onStartedGoingToSleep(reason);
mKeyguardLifecyclesDispatcher.dispatch(
KeyguardLifecyclesDispatcher.STARTED_GOING_TO_SLEEP);
}
KeyguardViewMediator.java-->onStartedGoingToSleep()
public void onStartedGoingToSleep(int why) {
......
KeyguardUpdateMonitor.getInstance(mContext).dispatchStartedGoingToSleep(why);
notifyStartedGoingToSleep();
}
KeyguardUpdateMonitor.java-->dispatchStartedGoingToSleep()
public void dispatchStartedGoingToSleep(int why) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_STARTED_GOING_TO_SLEEP, why, 0));
}
case MSG_STARTED_GOING_TO_SLEEP:
handleStartedGoingToSleep(msg.arg1);
break;
KeyguardUpdateMonitor.java-->handleStartedGoingToSleep()
protected void handleStartedGoingToSleep(int arg1) {
clearFingerprintRecognized();
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;
updateFingerprintListeningState();
}
KeyguardUpdateMonitor.java-->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_FINGERPRINT_AUTHENTICATION_CONTINUE)) {
return;
}
mHandler.removeCallbacks(mRetryFingerprintAuthentication);
boolean shouldListenForFingerprint = shouldListenForFingerprint();
if (mFingerprintRunningState == FINGERPRINT_STATE_RUNNING && !shouldListenForFingerprint) {
stopListeningForFingerprint();
} else if (mFingerprintRunningState != FINGERPRINT_STATE_RUNNING
&& shouldListenForFingerprint) {
startListeningForFingerprint();
}
}
KeyguardUpdateMonitor.java-->startListeningForFingerprint()
private void startListeningForFingerprint() {
if (mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING) {
setFingerprintRunningState(FINGERPRINT_STATE_CANCELLING_RESTARTING);
return;
}
if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
int userId = ActivityManager.getCurrentUser();
if (isUnlockWithFingerprintPossible(userId)) {
if (mFingerprintCancelSignal != null) {
mFingerprintCancelSignal.cancel();
}
mFingerprintCancelSignal = new CancellationSignal();
mFpm.authenticate(null, mFingerprintCancelSignal, 0, mAuthenticationCallback, null, userId);
setFingerprintRunningState(FINGERPRINT_STATE_RUNNING);
}
}
FingerprintManager.java-->authenticate()
@RequiresPermission(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()) {
Log.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;
mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
mContext.getOpPackageName());
} catch (RemoteException e) {
Log.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(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
}
}
}
FingerprintService.java-->authenticate()
@Override // Binder call
public void authenticate(final IBinder token, final long opId, final int groupId,
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
final boolean restricted = isRestricted();
if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
callingUserId)) {
if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
return;
}
mHandler.post(new Runnable() {
@Override
public void run() {
MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
// Get performance stats object for this user.
HashMap
= (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
PerformanceStats stats = pmap.get(mCurrentUserId);
if (stats == null) {
stats = new PerformanceStats();
pmap.put(mCurrentUserId, stats);
}
mPerformanceStats = stats;
startAuthentication(token, opId, callingUserId, groupId, receiver,
flags, restricted, opPackageName);
}
});
}
FingerprintService.java-->startAuthentication()
private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
IFingerprintServiceReceiver receiver, int flags, boolean restricted,
String opPackageName) {
updateActiveGroup(groupId, opPackageName);
if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
receiver, mCurrentUserId, groupId, opId, restricted, opPackageName) {
@Override
public int handleFailedAttempt() {
mFailedAttempts++;
mTimedLockoutCleared = false;
final int lockoutMode = getLockoutMode();
if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
mPerformanceStats.permanentLockout++;
} else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
mPerformanceStats.lockout++;
}
// Failing multiple times will continue to push out the lockout time
if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
scheduleLockoutReset();
return lockoutMode;
}
return AuthenticationClient.LOCKOUT_NONE;
}
@Override
public void resetFailedAttempts() {
FingerprintService.this.resetFailedAttempts(true /* clearAttemptCounter */);
}
@Override
public void notifyUserActivity() {
FingerprintService.this.userActivity();
}
@Override
public IBiometricsFingerprint getFingerprintDaemon() {
return FingerprintService.this.getFingerprintDaemon();
}
};
int lockoutMode = getLockoutMode();
if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
Slog.v(TAG, "In lockout mode(" + lockoutMode +
") ; disallowing authentication");
int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
if (!client.onError(errorCode, 0 /* vendorCode */)) {
Slog.w(TAG, "Cannot send permanent lockout message to client");
}
return;
}
startClient(client, true /* initiatedByClient */);
}
灭屏时开始监听的流程完成,当有指纹解锁时,会执行
AuthenticationClient.java-->onAuthenticated()
@Override
public boolean onAuthenticated(int fingerId, int groupId) {
......
IFingerprintServiceReceiver receiver = getReceiver();
......
receiver.onAuthenticationSucceeded(getHalDeviceId(), fp, getTargetUserId());
}
FingerprintManager.java-->new IFingerprintServiceReceiver.Stub()-->onAuthenticationSucceeded()
private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
@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();
}
}
case MSG_AUTHENTICATION_SUCCEEDED:
sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
break;
FingerprintManager.java-->sendAuthenticatedSucceeded()
private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
if (mAuthenticationCallback != null) {
final AuthenticationResult result =
new AuthenticationResult(mCryptoObject, fp, userId);
mAuthenticationCallback.onAuthenticationSucceeded(result);
}
}
AuthenticationCallback是FpM的一个内部回调接口
public static abstract class 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
*/
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
*/
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.
*/
public void onAuthenticationFailed() { }
/**
* Called when a fingerprint image has been acquired, but wasn't processed yet.
*
* @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants
* @hide
*/
public void onAuthenticationAcquired(int acquireInfo) {}
};
此接口在KeyguardUpdateMonitor.java中实现,用于监听FingerprintService中的指纹解锁状态
private FingerprintManager.AuthenticationCallback mAuthenticationCallback
= 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);
}
};
KeyguardUpdateMonitor.java-->handleFingerprintAuthenticated()
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(FINGERPRINT_STATE_STOPPED);
}
Trace.endSection();
}
KeyguardUpdateMonitor.java-->onFingerprintAuthenticated()
private 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.unlockedByFingerprintForUser(userId);
}
// 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.onFingerprintAuthenticated(userId);
}
}
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_FINGERPRINT_AUTHENTICATION_CONTINUE),
FINGERPRINT_CONTINUE_DELAY_MS);
// Only authenticate fingerprint once when assistant is visible
mAssistantVisible = false;
Trace.endSection();
}
可以看到在onFingerprintAuthenticated()方法中调用了KeyguardUpdateMonitorCallback这个抽象类的onFingerprintAuthenticated()抽象方法,
而FingerprintUnlockController extends KeyguardUpdateMonitorCallback,并注册了回调mUpdateMonitor.registerCallback(this);
所以会调用到
FingerprintUnlockController.java-->onFingerprintAuthenticated()
@Override
public void onFingerprintAuthenticated(int userId) {
Trace.beginSection("FingerprintUnlockController#onFingerprintAuthenticated");
if (mUpdateMonitor.isGoingToSleep()) {
mPendingAuthenticatedUserId = userId;
Trace.endSection();
return;
}
startWakeAndUnlock(calculateMode());
}
FingerprintUnlockController.java-->startWakeAndUnlock()
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.
mStatusBarWindowManager.setForceDozeBrightness(true);
}
if (!wasDeviceInteractive) {
if (DEBUG_FP_WAKELOCK) {
Log.i(TAG, "fp wakelock: Authenticated, waking up...");
}
mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT");
}
Trace.beginSection("release wake-and-unlock");
releaseFingerprintWakeLock();
Trace.endSection();
switch (mMode) {
case MODE_DISMISS_BOUNCER:
Trace.beginSection("MODE_DISMISS");
mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
false /* strongAuth */);
Trace.endSection();
break;
case MODE_UNLOCK:
case MODE_SHOW_BOUNCER:
boolean unlockingAllowed = mUpdateMonitor.getUserCanSkipBouncer(
mUpdateMonitor.getCurrentUser());
//for qq start
if(unlockingAllowed && mStatusBarKeyguardViewManager.isOccluded()){
mKeyguardViewMediator.keyguardDone();
} else {
Trace.beginSection("MODE_UNLOCK or MODE_SHOW_BOUNCER");
if (!wasDeviceInteractive) {
mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
mPendingShowBouncer = true;
} else {
showBouncer();
}
Trace.endSection();
}
//for qq end
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");
mStatusBar.updateMediaMetaData(false /* metaDataChanged */,
true /* allowEnterAnimation */);
} else if (mMode == MODE_WAKE_AND_UNLOCK){
Trace.beginSection("MODE_WAKE_AND_UNLOCK");
mDozeScrimController.abortDoze();
} else {
Trace.beginSection("MODE_WAKE_AND_UNLOCK_FROM_DREAM");
mUpdateMonitor.awakenFromDream();
}
mStatusBarWindowManager.setStatusBarFocusable(false);
mKeyguardViewMediator.onWakeAndUnlocking();
mScrimController.setWakeAndUnlocking();
mDozeScrimController.setWakeAndUnlocking();
if (mStatusBar.getNavigationBarView() != null) {
mStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
}
Trace.endSection();
break;
case MODE_ONLY_WAKE:
case MODE_NONE:
break;
}
mStatusBar.notifyFpAuthModeChanged();
Trace.endSection();
}
KeyguardViewMediator.java-->onWakeAndUnlocking()
public void onWakeAndUnlocking() {
Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking");
mWakeAndUnlocking = true;
keyguardDone();
Trace.endSection();
}
KeyguardViewMediator.java-->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();
}
case KEYGUARD_DONE:
Trace.beginSection("KeyguardViewMediator#handleMessage KEYGUARD_DONE");
handleKeyguardDone();
Trace.endSection();
break;
KeyguardViewMediator.java-->handleKeyguardDone()
private void handleKeyguardDone() {
......
handleHide();
}
KeyguardViewMediator.java-->handleHide()
private void handleHide() {
Trace.beginSection("KeyguardViewMediator#handleHide");
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();
}
KeyguardViewMediator.java-->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) {
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)
///M: fix ALPS01933919 to avoid play unlock sound continuously.
/// also fixes ALPS01940830
if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState) && mShowing) {
playSounds(false);
}
mWakeAndUnlocking = false;
setShowingLocked(false);
mDismissCallbackRegistry.notifyDismissSucceeded();
mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
adjustStatusBarLocked();
sendUserPresentBroadcast();
mUpdateMonitor.setKeyguardGoingAway(false /* goingAway */);
}
Log.d(TAG, "set mKeyguardDoneOnGoing = false");
mKeyguardDoneOnGoing = false;
Trace.endSection();
}
StatusBarKeyguardViewManager.java-->hide()
/**
* Hides the keyguard view
*/
public void hide(long startTime, long fadeoutDuration) {
mShowing = false;
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() {
mStatusBarWindowManager.setKeyguardShowing(false);
mStatusBarWindowManager.setKeyguardFadingAway(true);
hideBouncer(true /* destroyView */);
updateStates();
mScrimController.animateKeyguardFadingOut(
StatusBar.FADE_KEYGUARD_START_DELAY,
StatusBar.FADE_KEYGUARD_DURATION, null,
false /* skipFirstFrame */);
}
}, new Runnable() {
@Override
public void run() {
mStatusBar.hideKeyguard();
mStatusBarWindowManager.setKeyguardFadingAway(false);
mViewMediatorCallback.keyguardGone();
executeAfterKeyguardGoneAction();
}
});
} else {
executeAfterKeyguardGoneAction();
boolean wakeUnlockPulsing =
mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
if (wakeUnlockPulsing) {
delay = 0;
fadeoutDuration = 240;
}
mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
mFingerprintUnlockController.startKeyguardFadingAway();
hideBouncer(true /* destroyView */);
if (wakeUnlockPulsing) {
mStatusBarWindowManager.setKeyguardFadingAway(true);
mStatusBar.fadeKeyguardWhilePulsing();
animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration,
mStatusBar::hideKeyguard, false /* skipFirstFrame */);
} else {
mFingerprintUnlockController.startKeyguardFadingAway();
mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
boolean staying = mStatusBar.hideKeyguard();
if (!staying) {
mStatusBarWindowManager.setKeyguardFadingAway(true);
if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK) {
boolean turnedOnSinceAuth =
mFingerprintUnlockController.hasScreenTurnedOnSinceAuthenticating();
if (!mScreenTurnedOn || mDisplayBlanksAfterDoze && !turnedOnSinceAuth) {
// Not ready to animate yet; either because the screen is not on yet,
// or it is on but will turn off before waking out of doze.
mDeferScrimFadeOut = true;
} else {
// Screen is already on, don't defer with fading out.
animateScrimControllerKeyguardFadingOut(0,
WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS,
true /* skipFirstFrame */);
}
} else {
animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration,
false /* skipFirstFrame */);
}
} else {
mScrimController.animateGoingToFullShade(delay, fadeoutDuration);
mStatusBar.finishKeyguardFadingAway();
mFingerprintUnlockController.finishKeyguardFadingAway();
}
}
updateStates();
mStatusBarWindowManager.setKeyguardShowing(false);
mViewMediatorCallback.keyguardGone();
}
}
StatusBarKeyguardViewManager.java-->hideBouncer()
private void hideBouncer(boolean destroyView) {
mBouncer.hide(destroyView);
cancelPendingWakeupAction();
}
KeyguardBouncer.java-->hide()
public void hide(boolean destroyView) {
if (isShowing()) {
mDismissCallbackRegistry.notifyDismissCancelled();
}
mFalsingManager.onBouncerHidden();
cancelShowRunnable();
if (mKeyguardView != null) {
mKeyguardView.cancelDismissAction();
mKeyguardView.cleanUp();
}
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);
}
}
}
private final Runnable mRemoveViewRunnable = this::removeView;
KeyguardBouncer.java-->removeView()
protected void removeView() {
if (mRoot != null && mRoot.getParent() == mContainer) {
mContainer.removeView(mRoot);
mRoot = null;
}