Loading services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java +68 −19 Original line number Diff line number Diff line Loading @@ -19,27 +19,50 @@ package com.android.server.credentials; import android.credentials.CredentialDescription; import android.credentials.RegisterCredentialDescriptionRequest; import android.credentials.UnregisterCredentialDescriptionRequest; import android.service.credentials.CredentialEntry; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; 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; /** Contains information on what CredentialProvider has what provisioned Credential. */ public class CredentialDescriptionRegistry { public final class CredentialDescriptionRegistry { private static final int MAX_ALLOWED_CREDENTIAL_DESCRIPTIONS = 128; private static final int MAX_ALLOWED_ENTRIES_PER_PROVIDER = 16; private static SparseArray<CredentialDescriptionRegistry> sCredentialDescriptionSessionPerUser; @GuardedBy("sLock") private static final SparseArray<CredentialDescriptionRegistry> sCredentialDescriptionSessionPerUser; private static final ReentrantLock sLock; static { sCredentialDescriptionSessionPerUser = new SparseArray<>(); sLock = new ReentrantLock(); } /** Represents the results of a given query into the registry. */ public static final class FilterResult { final String mPackageName; final List<CredentialEntry> mCredentialEntries; private FilterResult(String packageName, List<CredentialEntry> credentialEntries) { mPackageName = packageName; mCredentialEntries = credentialEntries; } } // TODO(b/265992655): add a way to update CredentialRegistry when a user is removed. /** Get and/or create a {@link CredentialDescription} for the given user id. */ @GuardedBy("sLock") public static CredentialDescriptionRegistry forUser(int userId) { sLock.lock(); try { CredentialDescriptionRegistry session = sCredentialDescriptionSessionPerUser.get(userId, null); Loading @@ -48,6 +71,20 @@ public class CredentialDescriptionRegistry { sCredentialDescriptionSessionPerUser.put(userId, session); } return session; } finally { sLock.unlock(); } } /** Clears an existing session for a given user identifier. */ @GuardedBy("sLock") public static void clearUserSession(int userId) { sLock.lock(); try { sCredentialDescriptionSessionPerUser.remove(userId); } finally { sLock.unlock(); } } private Map<String, Set<CredentialDescription>> mCredentialDescriptions; Loading @@ -74,7 +111,7 @@ public class CredentialDescriptionRegistry { int size = mCredentialDescriptions.get(callingPackageName).size(); mCredentialDescriptions.get(callingPackageName) .addAll(descriptions); mTotalDescriptionCount += size - mCredentialDescriptions.get(callingPackageName).size(); mTotalDescriptionCount += mCredentialDescriptions.get(callingPackageName).size() - size; } } Loading @@ -93,21 +130,33 @@ public class CredentialDescriptionRegistry { } } /** Returns package names of CredentialProviders that can satisfy a given /** Returns package names and entries of a CredentialProviders that can satisfy a given * {@link CredentialDescription}. */ public Set<String> filterCredentials(String flatRequestString) { public Set<FilterResult> getFilteredResultForProvider(String packageName, List<String> flatRequestStrings) { Set<FilterResult> result = new HashSet<>(); Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName); for (CredentialDescription containedDescription: currentSet) { if (flatRequestStrings.contains(containedDescription.getFlattenedRequestString())) { result.add(new FilterResult(packageName, containedDescription .getCredentialEntries())); } } return result; } /** Returns package names of CredentialProviders that can satisfy a given * {@link CredentialDescription}. */ public Set<String> getMatchingProviders(Set<String> flatRequestString) { Set<String> result = new HashSet<>(); for (String componentName: mCredentialDescriptions.keySet()) { Set<CredentialDescription> currentSet = mCredentialDescriptions.get(componentName); for (String packageName: mCredentialDescriptions.keySet()) { Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName); for (CredentialDescription containedDescription : currentSet) { if (flatRequestString.equals(containedDescription.getFlattenedRequestString())) { result.add(componentName); if (flatRequestString.contains(containedDescription.getFlattenedRequestString())) { result.add(packageName); } } } return result; } Loading services/credentials/java/com/android/server/credentials/CredentialManagerService.java +75 −30 Original line number Diff line number Diff line Loading @@ -61,13 +61,11 @@ import com.android.server.infra.AbstractMasterSystemService; import com.android.server.infra.SecureSettingsServiceNameResolver; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; /** * Entry point service for credential management. Loading Loading @@ -236,6 +234,7 @@ public final class CredentialManagerService concatenatedServices.addAll(getOrConstructSystemServiceListLock(userId)); return concatenatedServices; } public static boolean isCredentialDescriptionApiEnabled() { return DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API, false); Loading @@ -244,44 +243,38 @@ public final class CredentialManagerService @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked // to be guarded by 'service.mLock', which is the same as mLock. private List<ProviderSession> initiateProviderSessionsWithActiveContainers( RequestSession session, List<String> requestOptions, Set<ComponentName> activeCredentialContainers) { GetRequestSession session, List<String> requestOptions, Set<String> activeCredentialContainers) { List<ProviderSession> providerSessions = new ArrayList<>(); // Invoke all services of a user to initiate a provider session runForUser((service) -> { if (activeCredentialContainers.contains(service.getComponentName())) { ProviderSession providerSession = service .initiateProviderSessionForRequestLocked(session, requestOptions); if (providerSession != null) { providerSessions.add(providerSession); } for (String packageName: activeCredentialContainers) { providerSessions.add(ProviderRegistryGetSession.createNewSession( mContext, UserHandle.getCallingUserId(), session, packageName, requestOptions)); } }); return providerSessions; } @NonNull private Set<String> getMatchingProviders(GetCredentialRequest request) { private Set<String> getFilteredResultFromRegistry(List<CredentialOption> options) { // Session for active/provisioned credential descriptions; CredentialDescriptionRegistry registry = CredentialDescriptionRegistry .forUser(UserHandle.getCallingUserId()); // All requested credential descriptions based on the given request. Set<String> requestedCredentialDescriptions = request.getCredentialOptions().stream().map( credentialOption -> credentialOption options.stream().map( getCredentialOption -> getCredentialOption .getCredentialRetrievalData() .getString(CredentialOption .FLATTENED_REQUEST)) .collect(Collectors.toSet()); // All requested credential descriptions based on the given request. return requestedCredentialDescriptions.stream() .map(registry::filterCredentials) .flatMap( (Function<Set<String>, Stream<String>>) Collection::stream) .collect(Collectors.toSet()); return registry.getMatchingProviders(requestedCredentialDescriptions); } @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked Loading @@ -304,6 +297,13 @@ public final class CredentialManagerService return providerSessions; } @Override @GuardedBy("CredentialDescriptionRegistry.sLock") public void onUserStopped(@NonNull TargetUser user) { super.onUserStopped(user); CredentialDescriptionRegistry.clearUserSession(user.getUserIdentifier()); } private CallingAppInfo constructCallingAppInfo(String packageName, int userId) { final PackageInfo packageInfo; try { Loading Loading @@ -340,13 +340,57 @@ public final class CredentialManagerService request, constructCallingAppInfo(callingPackage, userId)); List<ProviderSession> providerSessions; if (isCredentialDescriptionApiEnabled()) { List<CredentialOption> optionsThatRequireActiveCredentials = request.getCredentialOptions().stream() .filter(getCredentialOption -> !TextUtils.isEmpty(getCredentialOption .getCredentialRetrievalData().getString( CredentialOption .FLATTENED_REQUEST, null))) .toList(); List<CredentialOption> optionsThatDoNotRequireActiveCredentials = request.getCredentialOptions().stream() .filter(getCredentialOption -> TextUtils.isEmpty(getCredentialOption .getCredentialRetrievalData().getString( CredentialOption .FLATTENED_REQUEST, null))) .toList(); List<ProviderSession> sessionsWithoutRemoteService = initiateProviderSessionsWithActiveContainers(session, optionsThatRequireActiveCredentials .stream().map(getCredentialOption -> getCredentialOption.getCredentialRetrievalData() .getString(CredentialOption .FLATTENED_REQUEST)) .collect(Collectors.toList()), getFilteredResultFromRegistry(optionsThatRequireActiveCredentials)); List<ProviderSession> sessionsWithRemoteService = initiateProviderSessions( session, optionsThatDoNotRequireActiveCredentials.stream() .map(CredentialOption::getType) .collect(Collectors.toList())); Set<ProviderSession> all = new LinkedHashSet<>(); all.addAll(sessionsWithRemoteService); all.addAll(sessionsWithoutRemoteService); providerSessions = new ArrayList<>(all); } else { // Initiate all provider sessions List<ProviderSession> providerSessions = providerSessions = initiateProviderSessions( session, request.getCredentialOptions().stream() .map(CredentialOption::getType) .collect(Collectors.toList())); } if (providerSessions.isEmpty()) { try { Loading @@ -363,6 +407,7 @@ public final class CredentialManagerService // Iterate over all provider sessions and invoke the request providerSessions.forEach(ProviderSession::invokeSession); return cancelTransport; } Loading services/credentials/java/com/android/server/credentials/ProviderClearSession.java +3 −3 Original line number Diff line number Diff line Loading @@ -118,8 +118,8 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS @Override protected void invokeSession() { this.mRemoteCredentialService.onClearCredentialState( this.getProviderRequest(), /*callback=*/this); if (mRemoteCredentialService != null) { mRemoteCredentialService.onClearCredentialState(mProviderRequest, this); } } } services/credentials/java/com/android/server/credentials/ProviderCreateSession.java +5 −3 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ public final class ProviderCreateSession extends ProviderSession< // Key to be used as an entry key for a save entry private static final String SAVE_ENTRY_KEY = "save_entry_key"; // Key to be used as an entry key for a remote entry private static final String REMOTE_ENTRY_KEY = "remote_entry_key"; @NonNull private final Map<String, CreateEntry> mUiSaveEntries = new HashMap<>(); Loading Loading @@ -199,9 +201,9 @@ public final class ProviderCreateSession extends ProviderSession< @Override protected void invokeSession() { this.mRemoteCredentialService.onCreateCredential( this.getProviderRequest(), /*callback=*/this); if (mRemoteCredentialService != null) { mRemoteCredentialService.onCreateCredential(mProviderRequest, this); } } private List<Entry> prepareUiSaveEntries(@NonNull List<CreateEntry> saveEntries) { Loading services/credentials/java/com/android/server/credentials/ProviderGetSession.java +45 −45 Original line number Diff line number Diff line Loading @@ -59,14 +59,14 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential implements RemoteCredentialService.ProviderCallbacks<BeginGetCredentialResponse> { private static final String TAG = "ProviderGetSession"; // Key to be used as an entry key for a credential entry private static final String CREDENTIAL_ENTRY_KEY = "credential_key"; // Key to be used as the entry key for an action entry private static final String ACTION_ENTRY_KEY = "action_key"; // Key to be used as the entry key for the authentication entry private static final String AUTHENTICATION_ACTION_ENTRY_KEY = "authentication_action_key"; // Key to be used as an entry key for a remote entry private static final String REMOTE_ENTRY_KEY = "remote_entry_key"; // Key to be used as an entry key for a credential entry private static final String CREDENTIAL_ENTRY_KEY = "credential_key"; @NonNull private final Map<String, CredentialEntry> mUiCredentialEntries = new HashMap<>(); Loading Loading @@ -101,23 +101,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential return null; } private static BeginGetCredentialRequest constructQueryPhaseRequest( android.credentials.GetCredentialRequest filteredRequest, CallingAppInfo callingAppInfo ) { return new BeginGetCredentialRequest.Builder(callingAppInfo) .setBeginGetCredentialOptions( filteredRequest.getCredentialOptions().stream().map( option -> { return new BeginGetCredentialOption( option.getType(), option.getCandidateQueryData()); }).collect(Collectors.toList())) .build(); } @Nullable private static android.credentials.GetCredentialRequest filterOptions( protected static android.credentials.GetCredentialRequest filterOptions( List<String> providerCapabilities, android.credentials.GetCredentialRequest clientRequest ) { Loading @@ -142,6 +127,21 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential return null; } private static BeginGetCredentialRequest constructQueryPhaseRequest( android.credentials.GetCredentialRequest filteredRequest, CallingAppInfo callingAppInfo ) { return new BeginGetCredentialRequest.Builder(callingAppInfo) .setBeginGetCredentialOptions( filteredRequest.getCredentialOptions().stream().map( option -> { return new BeginGetCredentialOption( option.getType(), option.getCandidateQueryData()); }).collect(Collectors.toList())) .build(); } public ProviderGetSession(Context context, CredentialProviderInfo info, ProviderInternalCallback<GetCredentialResponse> callbacks, Loading Loading @@ -232,9 +232,9 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential @Override protected void invokeSession() { this.mRemoteCredentialService.onBeginGetCredential( this.getProviderRequest(), /*callback=*/this); if (mRemoteCredentialService != null) { mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this); } } @Override // Call from request session to data to be shown on the UI Loading Loading @@ -379,6 +379,28 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential invokeCallbackOnInternalInvalidState(); } @Nullable protected GetCredentialException maybeGetPendingIntentException( ProviderPendingIntentResponse pendingIntentResponse) { if (pendingIntentResponse == null) { Log.i(TAG, "pendingIntentResponse is null"); return null; } if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) { GetCredentialException exception = PendingIntentResultHandler .extractGetCredentialException(pendingIntentResponse.getResultData()); if (exception != null) { Log.i(TAG, "Pending intent contains provider exception"); return exception; } } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) { return new GetCredentialException(GetCredentialException.TYPE_USER_CANCELED); } else { return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL); } return null; } private void onAuthenticationEntrySelected( @Nullable ProviderPendingIntentResponse providerPendingIntentResponse) { //TODO: Other provider intent statuses Loading Loading @@ -431,28 +453,6 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential updateStatusAndInvokeCallback(Status.NO_CREDENTIALS); } @Nullable private GetCredentialException maybeGetPendingIntentException( ProviderPendingIntentResponse pendingIntentResponse) { if (pendingIntentResponse == null) { Log.i(TAG, "pendingIntentResponse is null"); return null; } if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) { GetCredentialException exception = PendingIntentResultHandler .extractGetCredentialException(pendingIntentResponse.getResultData()); if (exception != null) { Log.i(TAG, "Pending intent contains provider exception"); return exception; } } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) { return new GetCredentialException(GetCredentialException.TYPE_USER_CANCELED); } else { return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL); } return null; } /** * When an invalid state occurs, e.g. entry mismatch or no response from provider, * we send back a TYPE_UNKNOWN error as to the developer. Loading Loading
services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java +68 −19 Original line number Diff line number Diff line Loading @@ -19,27 +19,50 @@ package com.android.server.credentials; import android.credentials.CredentialDescription; import android.credentials.RegisterCredentialDescriptionRequest; import android.credentials.UnregisterCredentialDescriptionRequest; import android.service.credentials.CredentialEntry; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; 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; /** Contains information on what CredentialProvider has what provisioned Credential. */ public class CredentialDescriptionRegistry { public final class CredentialDescriptionRegistry { private static final int MAX_ALLOWED_CREDENTIAL_DESCRIPTIONS = 128; private static final int MAX_ALLOWED_ENTRIES_PER_PROVIDER = 16; private static SparseArray<CredentialDescriptionRegistry> sCredentialDescriptionSessionPerUser; @GuardedBy("sLock") private static final SparseArray<CredentialDescriptionRegistry> sCredentialDescriptionSessionPerUser; private static final ReentrantLock sLock; static { sCredentialDescriptionSessionPerUser = new SparseArray<>(); sLock = new ReentrantLock(); } /** Represents the results of a given query into the registry. */ public static final class FilterResult { final String mPackageName; final List<CredentialEntry> mCredentialEntries; private FilterResult(String packageName, List<CredentialEntry> credentialEntries) { mPackageName = packageName; mCredentialEntries = credentialEntries; } } // TODO(b/265992655): add a way to update CredentialRegistry when a user is removed. /** Get and/or create a {@link CredentialDescription} for the given user id. */ @GuardedBy("sLock") public static CredentialDescriptionRegistry forUser(int userId) { sLock.lock(); try { CredentialDescriptionRegistry session = sCredentialDescriptionSessionPerUser.get(userId, null); Loading @@ -48,6 +71,20 @@ public class CredentialDescriptionRegistry { sCredentialDescriptionSessionPerUser.put(userId, session); } return session; } finally { sLock.unlock(); } } /** Clears an existing session for a given user identifier. */ @GuardedBy("sLock") public static void clearUserSession(int userId) { sLock.lock(); try { sCredentialDescriptionSessionPerUser.remove(userId); } finally { sLock.unlock(); } } private Map<String, Set<CredentialDescription>> mCredentialDescriptions; Loading @@ -74,7 +111,7 @@ public class CredentialDescriptionRegistry { int size = mCredentialDescriptions.get(callingPackageName).size(); mCredentialDescriptions.get(callingPackageName) .addAll(descriptions); mTotalDescriptionCount += size - mCredentialDescriptions.get(callingPackageName).size(); mTotalDescriptionCount += mCredentialDescriptions.get(callingPackageName).size() - size; } } Loading @@ -93,21 +130,33 @@ public class CredentialDescriptionRegistry { } } /** Returns package names of CredentialProviders that can satisfy a given /** Returns package names and entries of a CredentialProviders that can satisfy a given * {@link CredentialDescription}. */ public Set<String> filterCredentials(String flatRequestString) { public Set<FilterResult> getFilteredResultForProvider(String packageName, List<String> flatRequestStrings) { Set<FilterResult> result = new HashSet<>(); Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName); for (CredentialDescription containedDescription: currentSet) { if (flatRequestStrings.contains(containedDescription.getFlattenedRequestString())) { result.add(new FilterResult(packageName, containedDescription .getCredentialEntries())); } } return result; } /** Returns package names of CredentialProviders that can satisfy a given * {@link CredentialDescription}. */ public Set<String> getMatchingProviders(Set<String> flatRequestString) { Set<String> result = new HashSet<>(); for (String componentName: mCredentialDescriptions.keySet()) { Set<CredentialDescription> currentSet = mCredentialDescriptions.get(componentName); for (String packageName: mCredentialDescriptions.keySet()) { Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName); for (CredentialDescription containedDescription : currentSet) { if (flatRequestString.equals(containedDescription.getFlattenedRequestString())) { result.add(componentName); if (flatRequestString.contains(containedDescription.getFlattenedRequestString())) { result.add(packageName); } } } return result; } Loading
services/credentials/java/com/android/server/credentials/CredentialManagerService.java +75 −30 Original line number Diff line number Diff line Loading @@ -61,13 +61,11 @@ import com.android.server.infra.AbstractMasterSystemService; import com.android.server.infra.SecureSettingsServiceNameResolver; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; /** * Entry point service for credential management. Loading Loading @@ -236,6 +234,7 @@ public final class CredentialManagerService concatenatedServices.addAll(getOrConstructSystemServiceListLock(userId)); return concatenatedServices; } public static boolean isCredentialDescriptionApiEnabled() { return DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API, false); Loading @@ -244,44 +243,38 @@ public final class CredentialManagerService @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked // to be guarded by 'service.mLock', which is the same as mLock. private List<ProviderSession> initiateProviderSessionsWithActiveContainers( RequestSession session, List<String> requestOptions, Set<ComponentName> activeCredentialContainers) { GetRequestSession session, List<String> requestOptions, Set<String> activeCredentialContainers) { List<ProviderSession> providerSessions = new ArrayList<>(); // Invoke all services of a user to initiate a provider session runForUser((service) -> { if (activeCredentialContainers.contains(service.getComponentName())) { ProviderSession providerSession = service .initiateProviderSessionForRequestLocked(session, requestOptions); if (providerSession != null) { providerSessions.add(providerSession); } for (String packageName: activeCredentialContainers) { providerSessions.add(ProviderRegistryGetSession.createNewSession( mContext, UserHandle.getCallingUserId(), session, packageName, requestOptions)); } }); return providerSessions; } @NonNull private Set<String> getMatchingProviders(GetCredentialRequest request) { private Set<String> getFilteredResultFromRegistry(List<CredentialOption> options) { // Session for active/provisioned credential descriptions; CredentialDescriptionRegistry registry = CredentialDescriptionRegistry .forUser(UserHandle.getCallingUserId()); // All requested credential descriptions based on the given request. Set<String> requestedCredentialDescriptions = request.getCredentialOptions().stream().map( credentialOption -> credentialOption options.stream().map( getCredentialOption -> getCredentialOption .getCredentialRetrievalData() .getString(CredentialOption .FLATTENED_REQUEST)) .collect(Collectors.toSet()); // All requested credential descriptions based on the given request. return requestedCredentialDescriptions.stream() .map(registry::filterCredentials) .flatMap( (Function<Set<String>, Stream<String>>) Collection::stream) .collect(Collectors.toSet()); return registry.getMatchingProviders(requestedCredentialDescriptions); } @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked Loading @@ -304,6 +297,13 @@ public final class CredentialManagerService return providerSessions; } @Override @GuardedBy("CredentialDescriptionRegistry.sLock") public void onUserStopped(@NonNull TargetUser user) { super.onUserStopped(user); CredentialDescriptionRegistry.clearUserSession(user.getUserIdentifier()); } private CallingAppInfo constructCallingAppInfo(String packageName, int userId) { final PackageInfo packageInfo; try { Loading Loading @@ -340,13 +340,57 @@ public final class CredentialManagerService request, constructCallingAppInfo(callingPackage, userId)); List<ProviderSession> providerSessions; if (isCredentialDescriptionApiEnabled()) { List<CredentialOption> optionsThatRequireActiveCredentials = request.getCredentialOptions().stream() .filter(getCredentialOption -> !TextUtils.isEmpty(getCredentialOption .getCredentialRetrievalData().getString( CredentialOption .FLATTENED_REQUEST, null))) .toList(); List<CredentialOption> optionsThatDoNotRequireActiveCredentials = request.getCredentialOptions().stream() .filter(getCredentialOption -> TextUtils.isEmpty(getCredentialOption .getCredentialRetrievalData().getString( CredentialOption .FLATTENED_REQUEST, null))) .toList(); List<ProviderSession> sessionsWithoutRemoteService = initiateProviderSessionsWithActiveContainers(session, optionsThatRequireActiveCredentials .stream().map(getCredentialOption -> getCredentialOption.getCredentialRetrievalData() .getString(CredentialOption .FLATTENED_REQUEST)) .collect(Collectors.toList()), getFilteredResultFromRegistry(optionsThatRequireActiveCredentials)); List<ProviderSession> sessionsWithRemoteService = initiateProviderSessions( session, optionsThatDoNotRequireActiveCredentials.stream() .map(CredentialOption::getType) .collect(Collectors.toList())); Set<ProviderSession> all = new LinkedHashSet<>(); all.addAll(sessionsWithRemoteService); all.addAll(sessionsWithoutRemoteService); providerSessions = new ArrayList<>(all); } else { // Initiate all provider sessions List<ProviderSession> providerSessions = providerSessions = initiateProviderSessions( session, request.getCredentialOptions().stream() .map(CredentialOption::getType) .collect(Collectors.toList())); } if (providerSessions.isEmpty()) { try { Loading @@ -363,6 +407,7 @@ public final class CredentialManagerService // Iterate over all provider sessions and invoke the request providerSessions.forEach(ProviderSession::invokeSession); return cancelTransport; } Loading
services/credentials/java/com/android/server/credentials/ProviderClearSession.java +3 −3 Original line number Diff line number Diff line Loading @@ -118,8 +118,8 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS @Override protected void invokeSession() { this.mRemoteCredentialService.onClearCredentialState( this.getProviderRequest(), /*callback=*/this); if (mRemoteCredentialService != null) { mRemoteCredentialService.onClearCredentialState(mProviderRequest, this); } } }
services/credentials/java/com/android/server/credentials/ProviderCreateSession.java +5 −3 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ public final class ProviderCreateSession extends ProviderSession< // Key to be used as an entry key for a save entry private static final String SAVE_ENTRY_KEY = "save_entry_key"; // Key to be used as an entry key for a remote entry private static final String REMOTE_ENTRY_KEY = "remote_entry_key"; @NonNull private final Map<String, CreateEntry> mUiSaveEntries = new HashMap<>(); Loading Loading @@ -199,9 +201,9 @@ public final class ProviderCreateSession extends ProviderSession< @Override protected void invokeSession() { this.mRemoteCredentialService.onCreateCredential( this.getProviderRequest(), /*callback=*/this); if (mRemoteCredentialService != null) { mRemoteCredentialService.onCreateCredential(mProviderRequest, this); } } private List<Entry> prepareUiSaveEntries(@NonNull List<CreateEntry> saveEntries) { Loading
services/credentials/java/com/android/server/credentials/ProviderGetSession.java +45 −45 Original line number Diff line number Diff line Loading @@ -59,14 +59,14 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential implements RemoteCredentialService.ProviderCallbacks<BeginGetCredentialResponse> { private static final String TAG = "ProviderGetSession"; // Key to be used as an entry key for a credential entry private static final String CREDENTIAL_ENTRY_KEY = "credential_key"; // Key to be used as the entry key for an action entry private static final String ACTION_ENTRY_KEY = "action_key"; // Key to be used as the entry key for the authentication entry private static final String AUTHENTICATION_ACTION_ENTRY_KEY = "authentication_action_key"; // Key to be used as an entry key for a remote entry private static final String REMOTE_ENTRY_KEY = "remote_entry_key"; // Key to be used as an entry key for a credential entry private static final String CREDENTIAL_ENTRY_KEY = "credential_key"; @NonNull private final Map<String, CredentialEntry> mUiCredentialEntries = new HashMap<>(); Loading Loading @@ -101,23 +101,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential return null; } private static BeginGetCredentialRequest constructQueryPhaseRequest( android.credentials.GetCredentialRequest filteredRequest, CallingAppInfo callingAppInfo ) { return new BeginGetCredentialRequest.Builder(callingAppInfo) .setBeginGetCredentialOptions( filteredRequest.getCredentialOptions().stream().map( option -> { return new BeginGetCredentialOption( option.getType(), option.getCandidateQueryData()); }).collect(Collectors.toList())) .build(); } @Nullable private static android.credentials.GetCredentialRequest filterOptions( protected static android.credentials.GetCredentialRequest filterOptions( List<String> providerCapabilities, android.credentials.GetCredentialRequest clientRequest ) { Loading @@ -142,6 +127,21 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential return null; } private static BeginGetCredentialRequest constructQueryPhaseRequest( android.credentials.GetCredentialRequest filteredRequest, CallingAppInfo callingAppInfo ) { return new BeginGetCredentialRequest.Builder(callingAppInfo) .setBeginGetCredentialOptions( filteredRequest.getCredentialOptions().stream().map( option -> { return new BeginGetCredentialOption( option.getType(), option.getCandidateQueryData()); }).collect(Collectors.toList())) .build(); } public ProviderGetSession(Context context, CredentialProviderInfo info, ProviderInternalCallback<GetCredentialResponse> callbacks, Loading Loading @@ -232,9 +232,9 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential @Override protected void invokeSession() { this.mRemoteCredentialService.onBeginGetCredential( this.getProviderRequest(), /*callback=*/this); if (mRemoteCredentialService != null) { mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this); } } @Override // Call from request session to data to be shown on the UI Loading Loading @@ -379,6 +379,28 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential invokeCallbackOnInternalInvalidState(); } @Nullable protected GetCredentialException maybeGetPendingIntentException( ProviderPendingIntentResponse pendingIntentResponse) { if (pendingIntentResponse == null) { Log.i(TAG, "pendingIntentResponse is null"); return null; } if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) { GetCredentialException exception = PendingIntentResultHandler .extractGetCredentialException(pendingIntentResponse.getResultData()); if (exception != null) { Log.i(TAG, "Pending intent contains provider exception"); return exception; } } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) { return new GetCredentialException(GetCredentialException.TYPE_USER_CANCELED); } else { return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL); } return null; } private void onAuthenticationEntrySelected( @Nullable ProviderPendingIntentResponse providerPendingIntentResponse) { //TODO: Other provider intent statuses Loading Loading @@ -431,28 +453,6 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential updateStatusAndInvokeCallback(Status.NO_CREDENTIALS); } @Nullable private GetCredentialException maybeGetPendingIntentException( ProviderPendingIntentResponse pendingIntentResponse) { if (pendingIntentResponse == null) { Log.i(TAG, "pendingIntentResponse is null"); return null; } if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) { GetCredentialException exception = PendingIntentResultHandler .extractGetCredentialException(pendingIntentResponse.getResultData()); if (exception != null) { Log.i(TAG, "Pending intent contains provider exception"); return exception; } } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) { return new GetCredentialException(GetCredentialException.TYPE_USER_CANCELED); } else { return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL); } return null; } /** * When an invalid state occurs, e.g. entry mismatch or no response from provider, * we send back a TYPE_UNKNOWN error as to the developer. Loading