地点:FingerprintService.java/AuthenticationClient.java
人物:AuthenticationClient和removeClient()(=null)
AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token, receiver, mCurrentUserId, groupId, opId, restricted, opPackageName, bundle, dialogReceiver, mStatusBarService) {
@Override //p
public void onStart() {
try {
mActivityManager.registerTaskStackListener(mTaskStackListener);
} catch (RemoteException e) {
Slog.e(TAG, "Could not register task stack listener", e);
}
}
@Override //p
public void onStop() {
try {
mActivityManager.unregisterTaskStackListener(mTaskStackListener);
} catch (RemoteException e) {
Slog.e(TAG, "Could not unregister task stack listener", e);
}
}
@Override
public int handleFailedAttempt() {
final int currentUser = ActivityManager.getCurrentUser();
mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), 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) {
scheduleLockoutResetForUser(currentUser);
return lockoutMode;
}
return AuthenticationClient.LOCKOUT_NONE;
}
@Override
public void resetFailedAttempts() {
FingerprintService.this.resetFailedAttemptsForUser(true /* clearAttemptCounter */,
ActivityManager.getCurrentUser());
}
@Override
public void notifyUserActivity() {
FingerprintService.this.userActivity();
}
@Override
public IBiometricsFingerprint getFingerprintDaemon() {
return FingerprintService.this.getFingerprintDaemon();
}
};
理论上说,每调用一次authenticate接口就会创建一次AuthenticationClient对象,每个client之前具有独立性。
1.前面一次识别不成功,还可以继续识别,这个过程中client发生变化了吗?为什么
2.识别成功后,本次的client去哪儿了
3.请面5次识别失败,本次的client去哪儿了?
/**
* Calls fingerprint HAL to switch states to the new task. If there's already a current task,
* it calls cancel() and sets mPendingClient to begin when the current task finishes
* ({@link FingerprintManager#FINGERPRINT_ERROR_CANCELED}).
* @param newClient the new client that wants to connect
* @param initiatedByClient true for authenticate, remove and enroll
*/
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 {//client冲掉了
currentClient.stop(initiatedByClient/*useless*/);//通知底层cancel
}
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();//为 newClient开启sensor扫描
}
}
指纹识别的结果会反馈到这里(调用下面的函数)
protected void handleAuthenticated(long deviceId, int fingerId, int groupId,
ArrayList<Byte> token) {
ClientMonitor client = mCurrentClient;
if (fingerId != 0) {
// Ugh...
final byte[] byteToken = new byte[token.size()];
for (int i = 0; i < token.size(); i++) {
byteToken[i] = token.get(i);
}
// Send to Keystore
KeyStore.getInstance().addAuthToken(byteToken);
}
if (client != null && client.onAuthenticated(fingerId, groupId)) {
removeClient(client);
}
if (fingerId != 0) {
mPerformanceStats.accept++;
} else {
mPerformanceStats.reject++;
}
}
看到removeClient
private void removeClient(ClientMonitor client) {
if (client != null) {
client.destroy();//
if (client != mCurrentClient && mCurrentClient != null) {
Slog.w(TAG, "Unexpected client: " + client.getOwnerString() + "expected: "
+ mCurrentClient != null ? mCurrentClient.getOwnerString() : "null");
}
}
if (mCurrentClient != null) {
if (DEBUG) Slog.v(TAG, "Done with client: " + client.getOwnerString());
if (deviceName.equals("bbb100")) {
/* If there is a pending client, don't turn off the light, because startClient will run soon for it. */
Slog.v(TAG, "FpLight(off) in removeClient\n");
mHandler.removeCallbacks(mRestartFpAnimateRunnable);
requestFpLight(false);
}
mCurrentClient = null;
}
if (mPendingClient == null) {
notifyClientActiveCallbacks(false);
}
}
看到ClientMonitor
public void destroy() {
if (mToken != null) {
try {
mToken.unlinkToDeath(this, 0);
} catch (NoSuchElementException e) {
// TODO: remove when duplicate call bug is found
Slog.e(TAG, "destroy(): " + this + ":", new Exception("here"));
}
mToken = null;
}
mReceiver = null;
}
看到AuthenticationClient
关注返回值情况:
@Override
public boolean onAuthenticated(int fingerId, int groupId) {
boolean result = false;
boolean authenticated = fingerId != 0;
//进入了lockout模式或者识别成功返回true,导致client移除;(没进入lockout)识别失败返回false,不移除client
…...
}
Note:指纹的识别,录入等操作需要同时具备两个条件:
1.指纹底层处于image模式(没有cancel)
2.此时的client非null。(只有在存在的client的基础上才能做识别,录入等操作)
对于lockout模式,第五次识别失败后,调用 handleAuthenticated时,将导致client移除。将无法继续指纹的识别操作。
private IBiometricsFingerprintClientCallback mDaemonCallback =
new IBiometricsFingerprintClientCallback.Stub() {
@Override
public void onAuthenticated(final long deviceId, final int fingerId, final int groupId,
ArrayList<Byte> token) {
mHandler.post(new Runnable() {
@Override
public void run() {
handleAuthenticated(deviceId, fingerId, groupId, token);
}
});
}
@Override
public void onError(final long deviceId, final int error, final int vendorCode) {
mHandler.post(new Runnable() {
@Override
public void run() {
handleError(deviceId, error, vendorCode);
}
});
}
…...
}
从handleAuthenticated,再将目光投向AuthenticationClient,通过逻辑,handleFailedAttempt() 让进入lockout模式,接着stop(false)—>cancel (daemon.cancel())----> handleError–>onError返回值为 true---->removeClient (client)(指纹停止工作,client清除); 同时onAuthenticated返回值为true—>removeClient(client);(client清除) 通过分析可以确定是 handleAuthenticated先将导致removeClient(client)使得client清除,后面的 removeClient由于Client已经为null,,其实将没有任何实际意义的操作。
protected void handleError(long deviceId, int error, int vendorCode) {
ClientMonitor client = mCurrentClient;
if (client instanceof InternalRemovalClient || client instanceof InternalEnumerateClient) {
resetEnumerateState();
}
if (client != null && client.onError(error, vendorCode)) {
removeClient(client);
}
…...
//ClientMonitor.java
public boolean onError(int error, int vendorCode) {
if (mReceiver != null) {
try {
mReceiver.onError(getHalDeviceId(), error, vendorCode);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to invoke sendError:", e);
}
}
return true; // errors always remove current client
}
Note:通过authenticate等API让指纹工作起来后,除非对它cancel,让它停止工作,否则它将一直处于工作状态中。