From f37c7ec77fd1f661df526fec2091698b77bd254d Mon Sep 17 00:00:00 2001 From: Wenhui Yang Date: Mon, 7 Aug 2023 17:19:33 +0000 Subject: [PATCH] [4/n] FRR data cleanup Add logic to delete data when removing a user. Bug: 258872351 Test: AuthenticationStatsPersisterTest Change-Id: I5f89ffbeeb0f01fbaffe22e7a372d05a6e22093d --- .../AuthenticationStatsCollector.java | 22 ++++++++++++++++++ .../AuthenticationStatsPersister.java | 23 +++++++++++++++++++ .../AuthenticationStatsPersisterTest.java | 14 +++++++++++ 3 files changed, 59 insertions(+) diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java index 0380756addeab..c9fb78546c423 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java @@ -18,10 +18,14 @@ package com.android.server.biometrics; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; +import android.os.UserHandle; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -56,6 +60,17 @@ public class AuthenticationStatsCollector { @NonNull private AuthenticationStatsPersister mAuthenticationStatsPersister; @NonNull private BiometricNotification mBiometricNotification; + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(@NonNull Context context, @NonNull Intent intent) { + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); + if (userId != UserHandle.USER_NULL + && intent.getAction().equals(Intent.ACTION_USER_REMOVED)) { + onUserRemoved(userId); + } + } + }; + public AuthenticationStatsCollector(@NonNull Context context, int modality, @NonNull BiometricNotification biometricNotification) { mContext = context; @@ -64,6 +79,8 @@ public class AuthenticationStatsCollector { mUserAuthenticationStatsMap = new HashMap<>(); mModality = modality; mBiometricNotification = biometricNotification; + + context.registerReceiver(mBroadcastReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED)); } private void initializeUserAuthenticationStatsMap() { @@ -146,6 +163,11 @@ public class AuthenticationStatsCollector { } } + private void onUserRemoved(final int userId) { + mUserAuthenticationStatsMap.remove(userId); + mAuthenticationStatsPersister.removeFrrStats(userId); + } + /** * Only being used in tests. Callers should not make any changes to the returned * authentication stats. diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsPersister.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsPersister.java index 96150a6553424..7217956c61a5e 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationStatsPersister.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsPersister.java @@ -93,6 +93,29 @@ public class AuthenticationStatsPersister { return authenticationStatsList; } + /** + * Remove frr data for a specific user. + */ + public void removeFrrStats(int userId) { + try { + // Copy into a new HashSet to avoid iterator exception. + Set frrStatsSet = new HashSet<>(readFrrStats()); + + // Remove the old authentication stat for the user if it exists. + for (Iterator iterator = frrStatsSet.iterator(); iterator.hasNext();) { + String frrStats = iterator.next(); + JSONObject frrStatJson = new JSONObject(frrStats); + if (getValue(frrStatJson, USER_ID).equals(String.valueOf(userId))) { + iterator.remove(); + break; + } + } + + mSharedPreferences.edit().putStringSet(KEY, frrStatsSet).apply(); + } catch (JSONException ignored) { + } + } + /** * Persist frr data for a specific user. */ diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsPersisterTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsPersisterTest.java index 455625cf69ec0..66a8ff31018ac 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsPersisterTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsPersisterTest.java @@ -211,6 +211,20 @@ public class AuthenticationStatsPersisterTest { assertThat(mStringSetArgumentCaptor.getValue()).contains(expectedFrrStats); } + @Test + public void removeFrrStats_existingUser_shouldUpdateRecord() throws JSONException { + AuthenticationStats authenticationStats = new AuthenticationStats(USER_ID_1, + 300 /* totalAttempts */, 10 /* rejectedAttempts */, + 0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FACE); + when(mSharedPreferences.getStringSet(eq(KEY), anySet())).thenReturn( + Set.of(buildFrrStats(authenticationStats))); + + mAuthenticationStatsPersister.removeFrrStats(USER_ID_1); + + verify(mEditor).putStringSet(eq(KEY), mStringSetArgumentCaptor.capture()); + assertThat(mStringSetArgumentCaptor.getValue()).doesNotContain(authenticationStats); + } + private String buildFrrStats(AuthenticationStats authenticationStats) throws JSONException { if (authenticationStats.getModality() == BiometricsProtoEnums.MODALITY_FACE) {