Prevent GC requests from piling up in LockSettingsService

Don't allow an unbounded number of GC requests to be enqueued if
lockscreen credential operations are happening very quickly.

Test: 'atest FrameworksServicesTests:com.android.server.locksettings'
      and checked log.  No longer see any messages that say
      "WaitForGcToComplete blocked Explicit on Explicit".  Note, even
      before this CL only a few such messages appeared with that atest
      command, but apparently it could happen more often in some cases.
Bug: 367713409
Flag: EXEMPT bugfix
Change-Id: I598116754210aa75265a9262e7b63937e2b836c2
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 45885f0..c314ab0 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -347,6 +347,8 @@
 
     private final StorageManagerInternal mStorageManagerInternal;
 
+    private final Object mGcWorkToken = new Object();
+
     // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
     // devices. The most basic of these is to show/hide notifications about missing features until
     // the user unlocks the account and credential-encrypted storage is available.
@@ -3632,11 +3634,19 @@
      * release references to the argument.
      */
     private void scheduleGc() {
+        // Cancel any existing GC request first, so that GC requests don't pile up if lockscreen
+        // credential operations are happening very quickly, e.g. as sometimes happens during tests.
+        //
+        // This delays the already-requested GC, but that is fine in practice where lockscreen
+        // operations don't happen very quickly.  And the precise time that the sanitization happens
+        // isn't very important; doing it within a minute can be fine, for example.
+        mHandler.removeCallbacksAndMessages(mGcWorkToken);
+
         mHandler.postDelayed(() -> {
             System.gc();
             System.runFinalization();
             System.gc();
-        }, 2000);
+        }, mGcWorkToken, 2000);
     }
 
     private class DeviceProvisionedObserver extends ContentObserver {