Capture fingerprint statistics for estimating FRR

Fixes bug 29258254

Change-Id: I10620c9bf07e4cdd7df456548b6516b5e1f1f5ee
This commit is contained in:
Jim Miller
2016-07-06 14:16:49 -07:00
parent c7b1d74ae8
commit bcc100aae9

View File

@@ -72,6 +72,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
/**
@@ -90,10 +91,17 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private static final String ACTION_LOCKOUT_RESET =
"com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
private class PerformanceStats {
int accept; // number of accepted fingerprints
int reject; // number of rejected fingerprints
int acquire; // total number of acquisitions. Should be >= accept+reject due to poor image
// acquisition in some cases (too fast, too slow, dirty sensor, etc.)
int lockout; // total number of lockouts
}
private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
new ArrayList<>();
private final AppOpsManager mAppOps;
private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
private static final int MAX_FAILED_ATTEMPTS = 5;
private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
@@ -110,6 +118,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private ClientMonitor mCurrentClient;
private ClientMonitor mPendingClient;
private long mCurrentAuthenticatorId;
private PerformanceStats mPerformanceStats;
// Normal fingerprint authentications are tracked by mPerformanceMap.
private HashMap<Integer, PerformanceStats> mPerformanceMap
= new HashMap<Integer, PerformanceStats>();
// Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
private HashMap<Integer, PerformanceStats> mCryptoPerformanceMap
= new HashMap<Integer, PerformanceStats>();
private Handler mHandler = new Handler() {
@Override
@@ -246,6 +263,11 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
if (client != null && client.onAuthenticated(fingerId, groupId)) {
removeClient(client);
}
if (fingerId != 0) {
mPerformanceStats.accept++;
} else {
mPerformanceStats.reject++;
}
}
protected void handleAcquired(long deviceId, int acquiredInfo) {
@@ -253,6 +275,11 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
if (client != null && client.onAcquired(acquiredInfo)) {
removeClient(client);
}
if (mPerformanceStats != null && !inLockoutMode()
&& client instanceof AuthenticationClient) {
// ignore enrollment acquisitions or acquisitions when we're locked out
mPerformanceStats.acquire++;
}
}
protected void handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
@@ -505,6 +532,9 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
@Override
public boolean handleFailedAttempt() {
mFailedAttempts++;
if (mFailedAttempts == MAX_FAILED_ATTEMPTS) {
mPerformanceStats.lockout++;
}
if (inLockoutMode()) {
// Failing multiple times will continue to push out the lockout time.
scheduleLockoutReset();
@@ -742,12 +772,24 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
mHandler.post(new Runnable() {
@Override
public void run() {
MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
if (!canUseFingerprint(opPackageName, true /* foregroundOnly */,
callingUid, pid)) {
if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
return;
}
MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
// Get performance stats object for this user.
HashMap<Integer, PerformanceStats> pmap
= (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);
}
@@ -924,9 +966,21 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
for (UserInfo user : UserManager.get(getContext()).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
final int N = mFingerprintUtils.getFingerprintsForUser(mContext, userId).size();
PerformanceStats stats = mPerformanceMap.get(userId);
PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId);
JSONObject set = new JSONObject();
set.put("id", userId);
set.put("count", N);
set.put("accept", (stats != null) ? stats.accept : 0);
set.put("reject", (stats != null) ? stats.reject : 0);
set.put("acquire", (stats != null) ? stats.acquire : 0);
set.put("lockout", (stats != null) ? stats.lockout : 0);
// cryptoStats measures statistics about secure fingerprint transactions
// (e.g. to unlock password storage, make secure purchases, etc.)
set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0);
set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0);
set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0);
sets.put(set);
}
@@ -947,6 +1001,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private void updateActiveGroup(int userId, String clientPackage) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon != null) {
try {
userId = getUserOrWorkProfileId(clientPackage, userId);