Change the flat request matching logic

Currently the flattened request matching logic
does not support subset checks. We need that to
fully support mdoc element matching.

Bug: 272334103
Test: atest FrameworksServicesTests:com.android.server.credentials.CredentialDescriptionRegistryTest
Change-Id: I7904570146426d33dbf8325c01a825787d1648f0
diff --git a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java
index 14c49b3..3b92cc9 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java
@@ -25,17 +25,19 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
-
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
 
 /** Contains information on what CredentialProvider has what provisioned Credential. */
 public class CredentialDescriptionRegistry {
 
+    private static final String FLAT_STRING_SPLIT_REGEX = ";";
     private static final int MAX_ALLOWED_CREDENTIAL_DESCRIPTIONS = 128;
     private static final int MAX_ALLOWED_ENTRIES_PER_PROVIDER = 16;
     @GuardedBy("sLock")
@@ -164,14 +166,16 @@
     /** Returns package names and entries of a CredentialProviders that can satisfy a given
      * {@link CredentialDescription}. */
     public Set<FilterResult> getFilteredResultForProvider(String packageName,
-            String flatRequestStrings) {
+            String flatRequestString) {
         Set<FilterResult> result = new HashSet<>();
         if (!mCredentialDescriptions.containsKey(packageName)) {
             return result;
         }
         Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName);
+        Set<String> unflattenedRequestString = flatStringToSet(flatRequestString);
         for (CredentialDescription containedDescription: currentSet) {
-            if (flatRequestStrings.equals(containedDescription.getFlattenedRequestString())) {
+            if (checkForMatch(flatStringToSet(containedDescription.getFlattenedRequestString()),
+                    unflattenedRequestString)) {
                 result.add(new FilterResult(packageName,
                         containedDescription.getFlattenedRequestString(), containedDescription
                         .getCredentialEntries()));
@@ -182,12 +186,16 @@
 
     /** Returns package names of CredentialProviders that can satisfy a given
      * {@link CredentialDescription}. */
-    public Set<FilterResult> getMatchingProviders(Set<String> flatRequestString) {
+    public Set<FilterResult> getMatchingProviders(Set<String> flatRequestStrings) {
         Set<FilterResult> result = new HashSet<>();
+        Set<Set<String>> unflattenedRequestStrings = flatRequestStrings.stream().map(
+                CredentialDescriptionRegistry::flatStringToSet).collect(Collectors.toSet());
         for (String packageName: mCredentialDescriptions.keySet()) {
             Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName);
             for (CredentialDescription containedDescription : currentSet) {
-                if (flatRequestString.contains(containedDescription.getFlattenedRequestString())) {
+                if (canProviderSatisfyAny(flatStringToSet(containedDescription
+                                .getFlattenedRequestString()),
+                        unflattenedRequestStrings)) {
                     result.add(new FilterResult(packageName,
                             containedDescription.getFlattenedRequestString(), containedDescription
                             .getCredentialEntries()));
@@ -203,4 +211,24 @@
         }
     }
 
+    private static boolean canProviderSatisfyAny(Set<String> registeredUnflattenedStrings,
+            Set<Set<String>> requestedUnflattenedStrings) {
+        for (Set<String> requestedUnflattenedString : requestedUnflattenedStrings) {
+            if (registeredUnflattenedStrings.containsAll(requestedUnflattenedString)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean checkForMatch(Set<String> registeredUnflattenedStrings,
+            Set<String> requestedUnflattenedString) {
+        return registeredUnflattenedStrings.containsAll(requestedUnflattenedString);
+    }
+
+    private static Set<String> flatStringToSet(String flatString) {
+        return new HashSet<>(Arrays
+                .asList(flatString.split(FLAT_STRING_SPLIT_REGEX)));
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java b/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java
index b7085f1..169210f 100644
--- a/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java
+++ b/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java
@@ -52,8 +52,10 @@
     private static final String CALLING_PACKAGE_NAME_2 = "com.credman.app2";
     private static final String MDOC_CREDENTIAL_TYPE = "MDOC";
     private static final String PASSKEY_CREDENTIAL_TYPE = "PASSKEY";
-    private static final String FLATTENED_REQUEST = "FLATTENED_REQ";
-    private static final String FLATTENED_REQUEST_2 = "FLATTENED_REQ_2";
+    private static final String FLATTENED_REGISTRY =
+            "FLATTENED_REQ;FLATTENED_REQ123;FLATTENED_REQa";
+    private static final String FLATTENED_REGISTRY_2 = "FLATTENED_REQ_2";
+    private static final String FLATTENED_REQUEST = "FLATTENED_REQ;FLATTENED_REQ123";
 
     private CredentialDescriptionRegistry mCredentialDescriptionRegistry;
     private CredentialEntry mEntry;
@@ -104,12 +106,12 @@
     @Test
     public void testEvictProvider_existingProviders_succeeds() {
         final CredentialDescription credentialDescription =
-                new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REQUEST,
+                new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REGISTRY,
                         Collections.emptyList());
         final RegisterCredentialDescriptionRequest registerCredentialDescriptionRequest =
                 new RegisterCredentialDescriptionRequest(credentialDescription);
         final CredentialDescription credentialDescription2 =
-                new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REQUEST_2,
+                new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REGISTRY_2,
                         Collections.emptyList());
         final RegisterCredentialDescriptionRequest registerCredentialDescriptionRequest2 =
                 new RegisterCredentialDescriptionRequest(credentialDescription2);
@@ -130,12 +132,12 @@
     @Test
     public void testGetMatchingProviders_existingProviders_succeeds() {
         final CredentialDescription credentialDescription =
-                new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REQUEST,
+                new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REGISTRY,
                         Collections.emptyList());
         final RegisterCredentialDescriptionRequest registerCredentialDescriptionRequest =
                 new RegisterCredentialDescriptionRequest(credentialDescription);
         final CredentialDescription credentialDescription2 =
-                new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REQUEST,
+                new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REGISTRY,
                         Collections.emptyList());
         final RegisterCredentialDescriptionRequest registerCredentialDescriptionRequest2 =
                 new RegisterCredentialDescriptionRequest(credentialDescription2);
@@ -171,11 +173,11 @@
     public void testExecuteRegisterRequest_existingProviders_filterSucceeds() {
         final CredentialDescription credentialDescription =
                 new CredentialDescription(MDOC_CREDENTIAL_TYPE,
-                        FLATTENED_REQUEST,
+                        FLATTENED_REGISTRY,
                         List.of(mEntry, mEntry2));
         final CredentialDescription credentialDescription2 =
                 new CredentialDescription(PASSKEY_CREDENTIAL_TYPE,
-                        FLATTENED_REQUEST_2,
+                        FLATTENED_REGISTRY_2,
                         List.of(mEntry3));
         final RegisterCredentialDescriptionRequest registerCredentialDescriptionRequest =
                 new RegisterCredentialDescriptionRequest(Set.of(credentialDescription,