Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d6d6d774 authored by Tej Singh's avatar Tej Singh
Browse files

FingerprintStats Westworld Migration

Adds 4 fingerprint atoms: NumFingerprints,
FingerprintAcquired, FingerprintAuthenticated, and
FingerprintErrorOccurred. Right now, these should have a 1-1 mapping
with dumpsys fingerprint. More acquire and error codes can be added
pending Metrics Council approval.

Note: I do not know how to test crypto fingerprints,
Note: Most of the logging likely fits better in BiometricService, but
given that it shares code with FaceService and we do not have approval
to log FaceService, I had to put the logic in FingerprintService.

Bug: b/113129470
Bug: b/113129210
Bug: b/113128442
Bug: b/72342203

Test: manually tested adding fingerprints and acquire/accept/reject/lockout with multiple users
Test: will make cts test

Change-Id: Ia8ca703bd4090f0f3612c6415785288517073117
parent c8c13295
Loading
Loading
Loading
Loading
+71 −0
Original line number Diff line number Diff line
@@ -133,6 +133,9 @@ message Atom {
        VibratorStateChanged vibrator_state_changed = 84;
        DeferredJobStatsReported deferred_job_stats_reported = 85;
        ThermalThrottlingStateChanged thermal_throttling = 86;
        FingerprintAcquired fingerprint_acquired = 87;
        FingerprintAuthenticated fingerprint_authenticated = 88;
        FingerprintErrorOccurred fingerprint_error_occurred = 89;
    }

    // Pulled events will start at field 10000.
@@ -169,6 +172,7 @@ message Atom {
        CategorySize category_size = 10028;
        android.service.procstats.ProcessStatsSectionProto proc_stats = 10029;
        BatteryVoltage battery_voltage = 10030;
        NumFingerprints num_fingerprints = 10031;
    }

    // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above
@@ -1832,6 +1836,60 @@ message GenericAtom {
    optional android.os.statsd.EventType event_id = 2;
}

/**
 * Logs when a fingerprint acquire event occurs.
 *
 * Logged from:
 *   frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
 */
message FingerprintAcquired {
    // The associated user. Eg: 0 for owners, 10+ for others.
    // Defined in android/os/UserHandle.java
    optional int32 user = 1;
    // If this acquire is for a crypto fingerprint.
    // e.g. Secure purchases, unlock password storage.
    optional bool is_crypto = 2;
}

/**
 * Logs when a fingerprint authentication event occurs.
 *
 * Logged from:
 *   frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
 */
message FingerprintAuthenticated {
    // The associated user. Eg: 0 for owners, 10+ for others.
    // Defined in android/os/UserHandle.java
    optional int32 user = 1;
    // If this authentication is for a crypto fingerprint.
    // e.g. Secure purchases, unlock password storage.
    optional bool is_crypto = 2;
    // Whether or not this authentication was successful.
    optional bool is_authenticated = 3;
}

/**
 * Logs when a fingerprint error occurs.
 *
 * Logged from:
 *   frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
 */
message FingerprintErrorOccurred {
    // The associated user. Eg: 0 for owners, 10+ for others.
    // Defined in android/os/UserHandle.java
    optional int32 user = 1;
    // If this error is for a crypto fingerprint.
    // e.g. Secure purchases, unlock password storage.
    optional bool is_crypto = 2;

    enum Error {
        UNKNOWN = 0;
        LOCKOUT = 1;
        PERMANENT_LOCKOUT = 2;
    }
    // The type of error.
    optional Error error = 3;
}
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
@@ -2408,3 +2466,16 @@ message CategorySize {
    // Uses System.currentTimeMillis(), which is wall clock time.
    optional int64 cache_time_millis = 3;
}

/**
 * Pulls the number of fingerprints for each user.
 *
 * Pulled from StatsCompanionService, which queries FingerprintManager.
 */
message NumFingerprints {
    // The associated user. Eg: 0 for owners, 10+ for others.
    // Defined in android/os/UserHandle.java
    optional int32 user = 1;
    // Number of fingerprints registered to that user.
    optional int32 num_fingerprints = 2;
}
+6 −0
Original line number Diff line number Diff line
@@ -217,6 +217,12 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
          {},
          1 * NS_PER_SEC,
          new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
        // Number of fingerprints registered to each user.
        {android::util::NUM_FINGERPRINTS,
         {{},
          {},
          1 * NS_PER_SEC,
          new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}},
        };

StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
+4 −1
Original line number Diff line number Diff line
@@ -108,6 +108,8 @@ public abstract class BiometricService extends SystemService implements IHwBinde
    private ClientMonitor mPendingClient;
    private PerformanceStats mPerformanceStats;
    protected int mCurrentUserId = UserHandle.USER_NULL;
    // Tracks if the current authentication makes use of CryptoObjects.
    protected boolean mIsCrypto;
    // Normal authentications are tracked by mPerformanceMap.
    protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
    // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
@@ -715,6 +717,7 @@ public abstract class BiometricService extends SystemService implements IHwBinde
                pmap.put(mCurrentUserId, stats);
            }
            mPerformanceStats = stats;
            mIsCrypto = (opId != 0);

            startAuthentication(client, opPackageName);
        });
@@ -847,7 +850,7 @@ public abstract class BiometricService extends SystemService implements IHwBinde
        return mKeyguardPackage.equals(clientPackage);
    }

    private int getLockoutMode() {
    protected int getLockoutMode() {
        final int currentUser = ActivityManager.getCurrentUser();
        final int failedAttempts = mFailedAttempts.get(currentUser, 0);
        if (failedAttempts >= getFailedAttemptsLockoutPermanent()) {
+23 −0
Original line number Diff line number Diff line
@@ -50,12 +50,14 @@ import android.os.SELinux;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
import android.util.StatsLog;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.biometrics.AuthenticationClient;
import com.android.server.biometrics.BiometricService;
import com.android.server.biometrics.BiometricUtils;
import com.android.server.biometrics.ClientMonitor;
@@ -590,6 +592,11 @@ public class FingerprintService extends BiometricService {
        public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
            mHandler.post(() -> {
                FingerprintService.super.handleAcquired(deviceId, acquiredInfo, vendorCode);
                if (getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
                        && getCurrentClient() instanceof AuthenticationClient) {
                    // Ignore enrollment acquisitions or acquisitions when we are locked out.
                    StatsLog.write(StatsLog.FINGERPRINT_ACQUIRED, mCurrentUserId, mIsCrypto);
                }
            });
        }

@@ -599,6 +606,22 @@ public class FingerprintService extends BiometricService {
            mHandler.post(() -> {
                Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
                FingerprintService.super.handleAuthenticated(fp, token);
                // Send authentication to statsd.
                final boolean authenticated = fingerId != 0;
                StatsLog.write(StatsLog.FINGERPRINT_AUTHENTICATED, mCurrentUserId, mIsCrypto,
                        authenticated);
                if (!authenticated) {
                    // If we failed to authenticate because of a lockout, inform statsd.
                    final int lockoutMode = getLockoutMode();
                    if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
                        StatsLog.write(StatsLog.FINGERPRINT_ERROR_OCCURRED, mCurrentUserId,
                                mIsCrypto, StatsLog.FINGERPRINT_ERROR_OCCURRED__ERROR__LOCKOUT);
                    } else if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
                        StatsLog.write(StatsLog.FINGERPRINT_ERROR_OCCURRED, mCurrentUserId,
                                mIsCrypto,
                                StatsLog.FINGERPRINT_ERROR_OCCURRED__ERROR__PERMANENT_LOCKOUT);
                    }
                }
            });
        }

+27 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.content.IntentSender;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.hardware.fingerprint.FingerprintManager;
import android.net.NetworkStats;
import android.net.wifi.IWifiManager;
import android.net.wifi.WifiActivityEnergyInfo;
@@ -1171,6 +1172,28 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
        }
    }

    private void pullNumFingerprints(int tagId, List<StatsLogEventWrapper> pulledData) {
        FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
        if (fingerprintManager == null) {
            return;
        }
        UserManager userManager = mContext.getSystemService(UserManager.class);
        if (userManager == null) {
            return;
        }
        final long token = Binder.clearCallingIdentity();
        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
        for (UserInfo user : userManager.getUsers()) {
            final int userId = user.getUserHandle().getIdentifier();
            final int numFingerprints = fingerprintManager.getEnrolledFingerprints(userId).size();
            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 2 /* fields */);
            e.writeInt(userId);
            e.writeInt(numFingerprints);
            pulledData.add(e);
        }
        Binder.restoreCallingIdentity(token);
    }

    /**
     * Pulls various data.
     */
@@ -1277,6 +1300,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
                pullCategorySize(tagId, ret);
                break;
            }
            case StatsLog.NUM_FINGERPRINTS: {
                pullNumFingerprints(tagId, ret);
                break;
            }
            default:
                Slog.w(TAG, "No such tagId data as " + tagId);
                return null;