• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.credentials;
18 
19 import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS;
20 import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN;
21 import static android.content.Context.CREDENTIAL_SERVICE;
22 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
23 
24 import android.Manifest;
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.annotation.UserIdInt;
28 import android.app.ActivityManager;
29 import android.content.ComponentName;
30 import android.content.ContentResolver;
31 import android.content.Context;
32 import android.content.pm.PackageInfo;
33 import android.content.pm.PackageManager;
34 import android.content.res.Resources;
35 import android.credentials.ClearCredentialStateRequest;
36 import android.credentials.CreateCredentialException;
37 import android.credentials.CreateCredentialRequest;
38 import android.credentials.CredentialManager;
39 import android.credentials.CredentialOption;
40 import android.credentials.CredentialProviderInfo;
41 import android.credentials.GetCandidateCredentialsException;
42 import android.credentials.GetCredentialException;
43 import android.credentials.GetCredentialRequest;
44 import android.credentials.IClearCredentialStateCallback;
45 import android.credentials.ICreateCredentialCallback;
46 import android.credentials.ICredentialManager;
47 import android.credentials.IGetCandidateCredentialsCallback;
48 import android.credentials.IGetCredentialCallback;
49 import android.credentials.IPrepareGetCredentialCallback;
50 import android.credentials.ISetEnabledProvidersCallback;
51 import android.credentials.PrepareGetCredentialResponseInternal;
52 import android.credentials.RegisterCredentialDescriptionRequest;
53 import android.credentials.UnregisterCredentialDescriptionRequest;
54 import android.os.Binder;
55 import android.os.CancellationSignal;
56 import android.os.IBinder;
57 import android.os.ICancellationSignal;
58 import android.os.RemoteException;
59 import android.os.UserHandle;
60 import android.provider.DeviceConfig;
61 import android.provider.Settings;
62 import android.service.credentials.CallingAppInfo;
63 import android.service.credentials.CredentialProviderInfoFactory;
64 import android.service.credentials.PermissionUtils;
65 import android.text.TextUtils;
66 import android.util.Pair;
67 import android.util.Slog;
68 import android.util.SparseArray;
69 
70 import com.android.internal.R;
71 import com.android.internal.annotations.GuardedBy;
72 import com.android.server.credentials.metrics.ApiName;
73 import com.android.server.credentials.metrics.ApiStatus;
74 import com.android.server.infra.AbstractMasterSystemService;
75 import com.android.server.infra.SecureSettingsServiceNameResolver;
76 
77 import java.util.ArrayList;
78 import java.util.HashMap;
79 import java.util.HashSet;
80 import java.util.LinkedHashSet;
81 import java.util.List;
82 import java.util.Map;
83 import java.util.Objects;
84 import java.util.Set;
85 import java.util.function.Consumer;
86 import java.util.stream.Collectors;
87 
88 /**
89  * Entry point service for credential management.
90  *
91  * <p>This service provides the {@link ICredentialManager} implementation and keeps a list of {@link
92  * CredentialManagerServiceImpl} per user; the real work is done by {@link
93  * CredentialManagerServiceImpl} itself.
94  */
95 public final class CredentialManagerService
96         extends AbstractMasterSystemService<
97         CredentialManagerService, CredentialManagerServiceImpl> {
98 
99     private static final String TAG = CredentialManager.TAG;
100     private static final String PERMISSION_DENIED_ERROR = "permission_denied";
101     private static final String PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR =
102             "Caller is missing WRITE_SECURE_SETTINGS permission";
103     private static final String DEVICE_CONFIG_ENABLE_CREDENTIAL_MANAGER =
104             "enable_credential_manager";
105 
106     private static final String DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API =
107             "enable_credential_description_api";
108 
109     /**
110      * Value stored in autofill pref when credential provider is primary. This is
111      * used as a placeholder since a credman only provider will not have an
112      * autofill service.
113      */
114     public static final String AUTOFILL_PLACEHOLDER_VALUE = "credential-provider";
115 
116     private final Context mContext;
117 
118     /** Cache of system service list per user id. */
119     @GuardedBy("mLock")
120     private final SparseArray<List<CredentialManagerServiceImpl>> mSystemServicesCacheList =
121             new SparseArray<>();
122 
123     /** Cache of all ongoing request sessions per user id. */
124     @GuardedBy("mLock")
125     private final SparseArray<Map<IBinder, RequestSession>> mRequestSessions =
126             new SparseArray<>();
127 
128     private final SessionManager mSessionManager = new SessionManager();
129 
CredentialManagerService(@onNull Context context)130     public CredentialManagerService(@NonNull Context context) {
131         super(
132                 context,
133                 new SecureSettingsServiceNameResolver(
134                         context, Settings.Secure.CREDENTIAL_SERVICE, /* isMultipleMode= */ true),
135                 null,
136                 PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
137         mContext = context;
138     }
139 
140     @NonNull
141     @GuardedBy("mLock")
constructSystemServiceListLocked( int resolvedUserId)142     private List<CredentialManagerServiceImpl> constructSystemServiceListLocked(
143             int resolvedUserId) {
144         List<CredentialManagerServiceImpl> services = new ArrayList<>();
145         List<CredentialProviderInfo> serviceInfos =
146                 CredentialProviderInfoFactory.getAvailableSystemServices(
147                         mContext,
148                         resolvedUserId,
149                         /* disableSystemAppVerificationForTests= */ false,
150                         new HashSet<>());
151         serviceInfos.forEach(
152                 info -> {
153                     services.add(
154                             new CredentialManagerServiceImpl(this, mLock, resolvedUserId,
155                                     info));
156                 });
157         return services;
158     }
159 
160     @Override
getServiceSettingsProperty()161     protected String getServiceSettingsProperty() {
162         return Settings.Secure.CREDENTIAL_SERVICE;
163     }
164 
165     @Override // from AbstractMasterSystemService
newServiceLocked( @serIdInt int resolvedUserId, boolean disabled)166     protected CredentialManagerServiceImpl newServiceLocked(
167             @UserIdInt int resolvedUserId, boolean disabled) {
168         // This method should not be called for CredentialManagerService as it is configured to use
169         // multiple services.
170         Slog.w(
171                 TAG,
172                 "Should not be here - CredentialManagerService is configured to use "
173                         + "multiple services");
174         return null;
175     }
176 
177     @Override // from SystemService
onStart()178     public void onStart() {
179         publishBinderService(CREDENTIAL_SERVICE, new CredentialManagerServiceStub());
180     }
181 
182     @Override // from AbstractMasterSystemService
183     @GuardedBy("mLock")
newServiceListLocked( int resolvedUserId, boolean disabled, String[] serviceNames)184     protected List<CredentialManagerServiceImpl> newServiceListLocked(
185             int resolvedUserId, boolean disabled, String[] serviceNames) {
186         getOrConstructSystemServiceListLock(resolvedUserId);
187         if (serviceNames == null || serviceNames.length == 0) {
188             return new ArrayList<>();
189         }
190         List<CredentialManagerServiceImpl> serviceList = new ArrayList<>(serviceNames.length);
191         for (String serviceName : serviceNames) {
192             if (TextUtils.isEmpty(serviceName)) {
193                 continue;
194             }
195             try {
196                 serviceList.add(
197                         new CredentialManagerServiceImpl(this, mLock, resolvedUserId, serviceName));
198             } catch (PackageManager.NameNotFoundException | SecurityException e) {
199                 Slog.e(TAG, "Unable to add serviceInfo : ", e);
200             }
201         }
202         return serviceList;
203     }
204 
205     @GuardedBy("mLock")
206     @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same
207     // this.mLock
handlePackageRemovedMultiModeLocked(String packageName, int userId)208     protected void handlePackageRemovedMultiModeLocked(String packageName, int userId) {
209         updateProvidersWhenPackageRemoved(new SettingsWrapper(mContext), packageName, userId);
210 
211         List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId);
212         if (services == null) {
213             return;
214         }
215 
216         List<CredentialManagerServiceImpl> servicesToBeRemoved = new ArrayList<>();
217         for (CredentialManagerServiceImpl service : services) {
218             if (service != null) {
219                 CredentialProviderInfo credentialProviderInfo = service.getCredentialProviderInfo();
220                 ComponentName componentName =
221                         credentialProviderInfo.getServiceInfo().getComponentName();
222                 if (packageName.equals(componentName.getPackageName())) {
223                     servicesToBeRemoved.add(service);
224                 }
225             }
226         }
227 
228         // Iterate over all the services to be removed, and remove them from the user configurable
229         // services cache, the system services cache as well as the setting key-value pair.
230         for (CredentialManagerServiceImpl serviceToBeRemoved : servicesToBeRemoved) {
231             removeServiceFromCache(serviceToBeRemoved, userId);
232             removeServiceFromSystemServicesCache(serviceToBeRemoved, userId);
233             CredentialDescriptionRegistry.forUser(userId)
234                     .evictProviderWithPackageName(serviceToBeRemoved.getServicePackageName());
235         }
236     }
237 
238     @GuardedBy("mLock")
239     @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same
240     // this.mLock
handleServiceRemovedMultiModeLocked(ComponentName componentName, int userId)241     protected void handleServiceRemovedMultiModeLocked(ComponentName componentName, int userId) {
242         updateProvidersWhenServiceRemoved(new SettingsWrapper(mContext), componentName, userId);
243 
244         List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId);
245         if (services == null) {
246             return;
247         }
248 
249         List<CredentialManagerServiceImpl> servicesToBeRemoved = new ArrayList<>();
250         for (CredentialManagerServiceImpl service : services) {
251             if (service != null) {
252                 CredentialProviderInfo credentialProviderInfo = service.getCredentialProviderInfo();
253                 ComponentName serviceComponentName =
254                         credentialProviderInfo.getServiceInfo().getComponentName();
255                 if (serviceComponentName != null && serviceComponentName.equals(componentName)) {
256                     servicesToBeRemoved.add(service);
257                 }
258             }
259         }
260 
261         removeServicesLocked(servicesToBeRemoved, userId);
262     }
263 
264     @GuardedBy("mLock")
265     @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same
266     // this.mLock
removeServicesLocked( List<CredentialManagerServiceImpl> servicesToBeRemoved, int userId)267     private void removeServicesLocked(
268             List<CredentialManagerServiceImpl> servicesToBeRemoved, int userId) {
269         // Iterate over all the services to be removed, and remove them from the user configurable
270         // services cache, the system services cache as well as the setting key-value pair.
271         for (CredentialManagerServiceImpl serviceToBeRemoved : servicesToBeRemoved) {
272             removeServiceFromCache(serviceToBeRemoved, userId);
273             removeServiceFromSystemServicesCache(serviceToBeRemoved, userId);
274             CredentialDescriptionRegistry.forUser(userId)
275                     .evictProviderWithPackageName(serviceToBeRemoved.getServicePackageName());
276         }
277     }
278 
279     @GuardedBy("mLock")
removeServiceFromSystemServicesCache( CredentialManagerServiceImpl serviceToBeRemoved, int userId)280     private void removeServiceFromSystemServicesCache(
281             CredentialManagerServiceImpl serviceToBeRemoved, int userId) {
282         if (mSystemServicesCacheList.get(userId) != null) {
283             mSystemServicesCacheList.get(userId).remove(serviceToBeRemoved);
284         }
285     }
286 
287     @GuardedBy("mLock")
getOrConstructSystemServiceListLock( int resolvedUserId)288     private List<CredentialManagerServiceImpl> getOrConstructSystemServiceListLock(
289             int resolvedUserId) {
290         List<CredentialManagerServiceImpl> services = mSystemServicesCacheList.get(resolvedUserId);
291         if (services == null || services.size() == 0) {
292             services = constructSystemServiceListLocked(resolvedUserId);
293             mSystemServicesCacheList.put(resolvedUserId, services);
294         }
295         return services;
296     }
297 
hasWriteSecureSettingsPermission()298     private boolean hasWriteSecureSettingsPermission() {
299         return hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS);
300     }
301 
verifyGetProvidersPermission()302     private void verifyGetProvidersPermission() throws SecurityException {
303         if (hasPermission(android.Manifest.permission.QUERY_ALL_PACKAGES)) {
304             return;
305         }
306 
307         if (hasPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS)) {
308             return;
309         }
310 
311         throw new SecurityException(
312                 "Caller is missing permission: QUERY_ALL_PACKAGES or "
313                         + "LIST_ENABLED_CREDENTIAL_PROVIDERS");
314     }
315 
hasPermission(String permission)316     private boolean hasPermission(String permission) {
317         final boolean result =
318                 mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
319         if (!result) {
320             Slog.e(TAG, "Caller does not have permission: " + permission);
321         }
322         return result;
323     }
324 
runForUser(@onNull final Consumer<CredentialManagerServiceImpl> c)325     private void runForUser(@NonNull final Consumer<CredentialManagerServiceImpl> c) {
326         final int userId = UserHandle.getCallingUserId();
327         final long origId = Binder.clearCallingIdentity();
328         try {
329             synchronized (mLock) {
330                 final List<CredentialManagerServiceImpl> services =
331                         getCredentialProviderServicesLocked(userId);
332                 for (CredentialManagerServiceImpl s : services) {
333                     c.accept(s);
334                 }
335             }
336         } finally {
337             Binder.restoreCallingIdentity(origId);
338         }
339     }
340 
getPrimaryProvidersForUserId(Context context, int userId)341     static Set<ComponentName> getPrimaryProvidersForUserId(Context context, int userId) {
342         final int resolvedUserId = ActivityManager.handleIncomingUser(
343                 Binder.getCallingPid(), Binder.getCallingUid(),
344                 userId, false, false,
345                 "getPrimaryProvidersForUserId", null);
346         SecureSettingsServiceNameResolver resolver = new SecureSettingsServiceNameResolver(
347                 context, Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
348                 /* isMultipleMode= */ true);
349         String[] serviceNames = resolver.readServiceNameList(resolvedUserId);
350         if (serviceNames == null) {
351             return new HashSet<ComponentName>();
352         }
353 
354         Set<ComponentName> services = new HashSet<>();
355         for (String serviceName : serviceNames) {
356             ComponentName compName = ComponentName.unflattenFromString(serviceName);
357             if (compName == null) {
358                 Slog.w(
359                         TAG,
360                         "Primary provider component name unflatten from string error: "
361                                 + serviceName);
362                 continue;
363             }
364             services.add(compName);
365         }
366         return services;
367     }
368 
369     @GuardedBy("mLock")
getCredentialProviderServicesLocked(int userId)370     private List<CredentialManagerServiceImpl> getCredentialProviderServicesLocked(int userId) {
371         List<CredentialManagerServiceImpl> concatenatedServices = new ArrayList<>();
372         List<CredentialManagerServiceImpl> userConfigurableServices =
373                 getServiceListForUserLocked(userId);
374         if (userConfigurableServices != null && !userConfigurableServices.isEmpty()) {
375             concatenatedServices.addAll(userConfigurableServices);
376         }
377         concatenatedServices.addAll(getOrConstructSystemServiceListLock(userId));
378         return concatenatedServices;
379     }
380 
isCredentialDescriptionApiEnabled()381     public static boolean isCredentialDescriptionApiEnabled() {
382         final long origId = Binder.clearCallingIdentity();
383         try {
384             return DeviceConfig.getBoolean(
385                     DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API,
386                     false);
387         } finally {
388             Binder.restoreCallingIdentity(origId);
389         }
390     }
391 
392     @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked
393     // to be guarded by 'service.mLock', which is the same as mLock.
initiateProviderSessionsWithActiveContainers( GetRequestSession session, Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> activeCredentialContainers)394     private List<ProviderSession> initiateProviderSessionsWithActiveContainers(
395             GetRequestSession session,
396             Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>>
397                     activeCredentialContainers) {
398         List<ProviderSession> providerSessions = new ArrayList<>();
399         for (Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult> result :
400                 activeCredentialContainers) {
401             ProviderSession providerSession = ProviderRegistryGetSession.createNewSession(
402                     mContext,
403                     UserHandle.getCallingUserId(),
404                     session,
405                     session.mClientAppInfo,
406                     result.second.mPackageName,
407                     result.first);
408             providerSessions.add(providerSession);
409             session.addProviderSession(providerSession.getComponentName(), providerSession);
410         }
411         return providerSessions;
412     }
413 
414     @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked
415     // to be guarded by 'service.mLock', which is the same as mLock.
initiateProviderSessionsWithActiveContainers( PrepareGetRequestSession session, Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> activeCredentialContainers)416     private List<ProviderSession> initiateProviderSessionsWithActiveContainers(
417             PrepareGetRequestSession session,
418             Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>>
419                     activeCredentialContainers) {
420         List<ProviderSession> providerSessions = new ArrayList<>();
421         for (Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult> result :
422                 activeCredentialContainers) {
423             ProviderSession providerSession = ProviderRegistryGetSession.createNewSession(
424                     mContext,
425                     UserHandle.getCallingUserId(),
426                     session,
427                     session.mClientAppInfo,
428                     result.second.mPackageName,
429                     result.first);
430             providerSessions.add(providerSession);
431             session.addProviderSession(providerSession.getComponentName(), providerSession);
432         }
433         return providerSessions;
434     }
435 
436 
437     @NonNull
438     private Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>>
getFilteredResultFromRegistry(List<CredentialOption> options)439     getFilteredResultFromRegistry(List<CredentialOption> options) {
440         // Session for active/provisioned credential descriptions;
441         CredentialDescriptionRegistry registry =
442                 CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId());
443 
444         // All requested credential descriptions based on the given request.
445         Set<Set<String>> requestedCredentialDescriptions =
446                 options.stream()
447                         .map(
448                                 getCredentialOption ->
449                                         new HashSet<>(getCredentialOption
450                                                 .getCredentialRetrievalData()
451                                                 .getStringArrayList(
452                                                         CredentialOption.SUPPORTED_ELEMENT_KEYS)))
453                         .collect(Collectors.toSet());
454 
455         // All requested credential descriptions based on the given request.
456         Set<CredentialDescriptionRegistry.FilterResult> filterResults =
457                 registry.getMatchingProviders(requestedCredentialDescriptions);
458 
459         Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> result =
460                 new HashSet<>();
461 
462         for (CredentialDescriptionRegistry.FilterResult filterResult : filterResults) {
463             for (CredentialOption credentialOption : options) {
464                 Set<String> requestedElementKeys = new HashSet<>(
465                         credentialOption
466                                 .getCredentialRetrievalData()
467                                 .getStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS));
468                 if (CredentialDescriptionRegistry.checkForMatch(filterResult.mElementKeys,
469                         requestedElementKeys)) {
470                     result.add(new Pair<>(credentialOption, filterResult));
471                 }
472             }
473         }
474         return result;
475     }
476 
477     @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked
478     // to be guarded by 'service.mLock', which is the same as mLock.
initiateProviderSessions( RequestSession session, List<String> requestOptions)479     private List<ProviderSession> initiateProviderSessions(
480             RequestSession session, List<String> requestOptions) {
481         List<ProviderSession> providerSessions = new ArrayList<>();
482         // Invoke all services of a user to initiate a provider session
483         runForUser(
484                 (service) -> {
485                     synchronized (mLock) {
486                         ProviderSession providerSession =
487                                 service.initiateProviderSessionForRequestLocked(
488                                         session, requestOptions);
489                         if (providerSession != null) {
490                             providerSessions.add(providerSession);
491                         }
492                     }
493                 });
494         return providerSessions;
495     }
496 
497     @Override
498     @GuardedBy("CredentialDescriptionRegistry.sLock")
onUserStopped(@onNull TargetUser user)499     public void onUserStopped(@NonNull TargetUser user) {
500         super.onUserStopped(user);
501         CredentialDescriptionRegistry.clearUserSession(user.getUserIdentifier());
502     }
503 
constructCallingAppInfo( String realPackageName, int userId, @Nullable String origin)504     private CallingAppInfo constructCallingAppInfo(
505             String realPackageName,
506             int userId,
507             @Nullable String origin) {
508         final PackageInfo packageInfo;
509         CallingAppInfo callingAppInfo;
510         try {
511             packageInfo =
512                     getContext()
513                             .getPackageManager()
514                             .getPackageInfoAsUser(
515                                     realPackageName,
516                                     PackageManager.PackageInfoFlags.of(
517                                             PackageManager.GET_SIGNING_CERTIFICATES),
518                                     userId);
519             callingAppInfo = new CallingAppInfo(realPackageName, packageInfo.signingInfo, origin);
520         } catch (PackageManager.NameNotFoundException e) {
521             Slog.e(TAG, "Issue while retrieving signatureInfo : ", e);
522             callingAppInfo = new CallingAppInfo(realPackageName, null, origin);
523         }
524         return callingAppInfo;
525     }
526 
527     final class CredentialManagerServiceStub extends ICredentialManager.Stub {
528         @Override
getCandidateCredentials( GetCredentialRequest request, IGetCandidateCredentialsCallback callback, IBinder clientBinder, final String callingPackage)529         public ICancellationSignal getCandidateCredentials(
530                 GetCredentialRequest request,
531                 IGetCandidateCredentialsCallback callback,
532                 IBinder clientBinder,
533                 final String callingPackage) {
534             Slog.i(TAG, "starting getCandidateCredentials with callingPackage: "
535                     + callingPackage);
536             ICancellationSignal cancelTransport = CancellationSignal.createTransport();
537 
538             final int userId = UserHandle.getCallingUserId();
539             final int callingUid = Binder.getCallingUid();
540             try {
541                 String credentialManagerAutofillCompName = mContext.getResources().getString(
542                         R.string.config_defaultCredentialManagerAutofillService);
543                 ComponentName componentName = ComponentName.unflattenFromString(
544                         credentialManagerAutofillCompName);
545                 if (componentName == null) {
546                     throw new SecurityException(
547                             "Credential Autofill service does not exist on this device.");
548                 }
549                 PackageManager pm = mContext.createContextAsUser(
550                         UserHandle.getUserHandleForUid(callingUid), 0).getPackageManager();
551                 String callingProcessPackage = pm.getNameForUid(callingUid);
552                 if (callingProcessPackage == null) {
553                     throw new SecurityException(
554                             "Couldn't determine the identity of the caller.");
555                 }
556                 if (!Objects.equals(componentName.getPackageName(), callingProcessPackage)) {
557                     throw new SecurityException(callingProcessPackage
558                             + " is not the device's credential autofill package.");
559                 }
560             } catch (Resources.NotFoundException e) {
561                 throw new SecurityException(
562                         "Credential Autofill service does not exist on this device.");
563             }
564 
565             // New request session, scoped for this request only.
566             final GetCandidateRequestSession session =
567                     new GetCandidateRequestSession(
568                             getContext(),
569                             mSessionManager,
570                             mLock,
571                             userId,
572                             callingUid,
573                             callback,
574                             request,
575                             constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
576                             getEnabledProvidersForUser(userId),
577                             CancellationSignal.fromTransport(cancelTransport),
578                             clientBinder
579                     );
580             addSessionLocked(userId, session);
581 
582             List<ProviderSession> providerSessions =
583                     initiateProviderSessions(
584                             session,
585                             request.getCredentialOptions().stream()
586                                     .map(CredentialOption::getType)
587                                     .collect(Collectors.toList()));
588 
589             finalizeAndEmitInitialPhaseMetric(session);
590 
591             if (providerSessions.isEmpty()) {
592                 try {
593                     callback.onError(
594                             GetCandidateCredentialsException.TYPE_NO_CREDENTIAL,
595                             "No credentials available on this device.");
596                 } catch (RemoteException e) {
597                     Slog.i(
598                             TAG,
599                             "Issue invoking onError on IGetCredentialCallback "
600                                     + "callback: "
601                                     + e.getMessage());
602                 }
603             }
604 
605             invokeProviderSessions(providerSessions);
606             return cancelTransport;
607         }
608 
609         @Override
executeGetCredential( GetCredentialRequest request, IGetCredentialCallback callback, final String callingPackage)610         public ICancellationSignal executeGetCredential(
611                 GetCredentialRequest request,
612                 IGetCredentialCallback callback,
613                 final String callingPackage) {
614             final long timestampBegan = System.nanoTime();
615             Slog.i(TAG, "starting executeGetCredential with callingPackage: "
616                     + callingPackage);
617             ICancellationSignal cancelTransport = CancellationSignal.createTransport();
618 
619             final int userId = UserHandle.getCallingUserId();
620             final int callingUid = Binder.getCallingUid();
621             enforceCallingPackage(callingPackage, callingUid);
622 
623             validateGetCredentialRequest(request);
624 
625             // New request session, scoped for this request only.
626             final GetRequestSession session =
627                     new GetRequestSession(
628                             getContext(),
629                             mSessionManager,
630                             mLock,
631                             userId,
632                             callingUid,
633                             callback,
634                             request,
635                             constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
636                             getEnabledProvidersForUser(userId),
637                             CancellationSignal.fromTransport(cancelTransport),
638                             timestampBegan);
639             addSessionLocked(userId, session);
640 
641             List<ProviderSession> providerSessions =
642                     prepareProviderSessions(request, session);
643 
644             if (providerSessions.isEmpty()) {
645                 try {
646                     callback.onError(
647                             GetCredentialException.TYPE_NO_CREDENTIAL,
648                             "No credentials available on this device.");
649                 } catch (RemoteException e) {
650                     Slog.e(
651                             TAG,
652                             "Issue invoking onError on IGetCredentialCallback "
653                                     + "callback: "
654                                     + e.getMessage());
655                 }
656             }
657 
658             invokeProviderSessions(providerSessions);
659             return cancelTransport;
660         }
661 
662         @Override
executePrepareGetCredential( GetCredentialRequest request, IPrepareGetCredentialCallback prepareGetCredentialCallback, IGetCredentialCallback getCredentialCallback, final String callingPackage)663         public ICancellationSignal executePrepareGetCredential(
664                 GetCredentialRequest request,
665                 IPrepareGetCredentialCallback prepareGetCredentialCallback,
666                 IGetCredentialCallback getCredentialCallback,
667                 final String callingPackage) {
668             final long timestampBegan = System.nanoTime();
669             ICancellationSignal cancelTransport = CancellationSignal.createTransport();
670 
671             if (request.getOrigin() != null) {
672                 // Check privileged permissions
673                 mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null);
674             }
675             enforcePermissionForAllowedProviders(request);
676 
677             final int userId = UserHandle.getCallingUserId();
678             final int callingUid = Binder.getCallingUid();
679             enforceCallingPackage(callingPackage, callingUid);
680 
681             final PrepareGetRequestSession session =
682                     new PrepareGetRequestSession(
683                             getContext(),
684                             mSessionManager,
685                             mLock,
686                             userId,
687                             callingUid,
688                             getCredentialCallback,
689                             request,
690                             constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
691                             getEnabledProvidersForUser(userId),
692                             CancellationSignal.fromTransport(cancelTransport),
693                             timestampBegan,
694                             prepareGetCredentialCallback);
695 
696             List<ProviderSession> providerSessions = prepareProviderSessions(request, session);
697 
698             if (providerSessions.isEmpty()) {
699                 try {
700                     prepareGetCredentialCallback.onResponse(
701                             new PrepareGetCredentialResponseInternal(PermissionUtils.hasPermission(
702                                     mContext,
703                                     callingPackage,
704                                     Manifest.permission
705                                             .CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS),
706                                     /*credentialResultTypes=*/null,
707                                     /*hasAuthenticationResults=*/false,
708                                     /*hasRemoteResults=*/false,
709                                     /*pendingIntent=*/null));
710                 } catch (RemoteException e) {
711                     Slog.e(
712                             TAG,
713                             "Issue invoking onError on IGetCredentialCallback "
714                                     + "callback: "
715                                     + e.getMessage());
716                 }
717             }
718 
719             invokeProviderSessions(providerSessions);
720 
721             return cancelTransport;
722         }
723 
prepareProviderSessions( GetCredentialRequest request, GetRequestSession session)724         private List<ProviderSession> prepareProviderSessions(
725                 GetCredentialRequest request,
726                 GetRequestSession session) {
727             List<ProviderSession> providerSessions;
728 
729             if (isCredentialDescriptionApiEnabled()) {
730                 List<CredentialOption> optionsThatRequireActiveCredentials =
731                         request.getCredentialOptions().stream()
732                                 .filter(credentialOption -> credentialOption
733                                         .getCredentialRetrievalData()
734                                         .getStringArrayList(
735                                                 CredentialOption
736                                                         .SUPPORTED_ELEMENT_KEYS) != null)
737                                 .toList();
738 
739                 List<CredentialOption> optionsThatDoNotRequireActiveCredentials =
740                         request.getCredentialOptions().stream()
741                                 .filter(credentialOption -> credentialOption
742                                         .getCredentialRetrievalData()
743                                         .getStringArrayList(
744                                                 CredentialOption
745                                                         .SUPPORTED_ELEMENT_KEYS) == null)
746                                 .toList();
747 
748                 List<ProviderSession> sessionsWithoutRemoteService =
749                         initiateProviderSessionsWithActiveContainers(
750                                 session,
751                                 getFilteredResultFromRegistry(optionsThatRequireActiveCredentials));
752 
753                 List<ProviderSession> sessionsWithRemoteService =
754                         initiateProviderSessions(
755                                 session,
756                                 optionsThatDoNotRequireActiveCredentials.stream()
757                                         .map(CredentialOption::getType)
758                                         .collect(Collectors.toList()));
759 
760                 Set<ProviderSession> all = new LinkedHashSet<>();
761                 all.addAll(sessionsWithRemoteService);
762                 all.addAll(sessionsWithoutRemoteService);
763 
764                 providerSessions = new ArrayList<>(all);
765             } else {
766                 // Initiate all provider sessions
767                 providerSessions =
768                         initiateProviderSessions(
769                                 session,
770                                 request.getCredentialOptions().stream()
771                                         .map(CredentialOption::getType)
772                                         .collect(Collectors.toList()));
773             }
774 
775             finalizeAndEmitInitialPhaseMetric(session);
776             // TODO(b/271135048) - May still be worth emitting in the empty cases above.
777             return providerSessions;
778         }
779 
invokeProviderSessions(List<ProviderSession> providerSessions)780         private void invokeProviderSessions(List<ProviderSession> providerSessions) {
781             providerSessions.forEach(ProviderSession::invokeSession);
782         }
783 
784         @Override
executeCreateCredential( CreateCredentialRequest request, ICreateCredentialCallback callback, String callingPackage)785         public ICancellationSignal executeCreateCredential(
786                 CreateCredentialRequest request,
787                 ICreateCredentialCallback callback,
788                 String callingPackage) {
789             final long timestampBegan = System.nanoTime();
790             Slog.i(TAG, "starting executeCreateCredential with callingPackage: "
791                     + callingPackage);
792             ICancellationSignal cancelTransport = CancellationSignal.createTransport();
793 
794             if (request.getOrigin() != null) {
795                 // Check privileged permissions
796                 mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null);
797             }
798 
799             final int userId = UserHandle.getCallingUserId();
800             final int callingUid = Binder.getCallingUid();
801             enforceCallingPackage(callingPackage, callingUid);
802 
803             // New request session, scoped for this request only.
804             final CreateRequestSession session =
805                     new CreateRequestSession(
806                             getContext(),
807                             mSessionManager,
808                             mLock,
809                             userId,
810                             callingUid,
811                             request,
812                             callback,
813                             constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
814                             getEnabledProvidersForUser(userId),
815                             getPrimaryProvidersForUserId(getContext(), userId),
816                             CancellationSignal.fromTransport(cancelTransport),
817                             timestampBegan);
818             addSessionLocked(userId, session);
819 
820             processCreateCredential(request, callback, session);
821             return cancelTransport;
822         }
823 
processCreateCredential( CreateCredentialRequest request, ICreateCredentialCallback callback, CreateRequestSession session)824         private void processCreateCredential(
825                 CreateCredentialRequest request,
826                 ICreateCredentialCallback callback,
827                 CreateRequestSession session) {
828             // Initiate all provider sessions
829             List<ProviderSession> providerSessions =
830                     initiateProviderSessions(session, List.of(request.getType()));
831 
832             if (providerSessions.isEmpty()) {
833                 try {
834                     callback.onError(
835                             CreateCredentialException.TYPE_NO_CREATE_OPTIONS,
836                             "No create options available.");
837                 } catch (RemoteException e) {
838                     Slog.e(
839                             TAG,
840                             "Issue invoking onError on ICreateCredentialCallback "
841                                     + "callback: ", e);
842                 }
843             }
844 
845             finalizeAndEmitInitialPhaseMetric(session);
846             // Iterate over all provider sessions and invoke the request
847             providerSessions.forEach(ProviderSession::invokeSession);
848         }
849 
finalizeAndEmitInitialPhaseMetric(GetCandidateRequestSession session)850         private void finalizeAndEmitInitialPhaseMetric(GetCandidateRequestSession session) {
851             var initMetric = session.mRequestSessionMetric.getInitialPhaseMetric();
852             initMetric.setAutofillSessionId(session.getAutofillSessionId());
853             initMetric.setAutofillRequestId(session.getAutofillRequestId());
854             finalizeAndEmitInitialPhaseMetric((RequestSession) session);
855         }
856 
finalizeAndEmitInitialPhaseMetric(RequestSession session)857         private void finalizeAndEmitInitialPhaseMetric(RequestSession session) {
858             try {
859                 var initMetric = session.mRequestSessionMetric.getInitialPhaseMetric();
860                 initMetric.setCredentialServiceBeginQueryTimeNanoseconds(System.nanoTime());
861                 MetricUtilities.logApiCalledInitialPhase(initMetric,
862                         session.mRequestSessionMetric.returnIncrementSequence());
863             } catch (Exception e) {
864                 Slog.i(TAG, "Unexpected error during metric logging: ", e);
865             }
866         }
867 
868         @Override
setEnabledProviders( List<String> primaryProviders, List<String> providers, int userId, ISetEnabledProvidersCallback callback)869         public void setEnabledProviders(
870                 List<String> primaryProviders, List<String> providers, int userId,
871                 ISetEnabledProvidersCallback callback) {
872             final int callingUid = Binder.getCallingUid();
873             if (!hasWriteSecureSettingsPermission()) {
874                 try {
875                     MetricUtilities.logApiCalledSimpleV2(
876                             ApiName.SET_ENABLED_PROVIDERS,
877                             ApiStatus.FAILURE, callingUid);
878                     callback.onError(
879                             PERMISSION_DENIED_ERROR, PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR);
880                 } catch (RemoteException e) {
881                     MetricUtilities.logApiCalledSimpleV2(
882                             ApiName.SET_ENABLED_PROVIDERS,
883                             ApiStatus.FAILURE, callingUid);
884                     Slog.e(TAG, "Issue with invoking response: ", e);
885                 }
886                 return;
887             }
888 
889             userId =
890                     ActivityManager.handleIncomingUser(
891                             Binder.getCallingPid(),
892                             Binder.getCallingUid(),
893                             userId,
894                             false,
895                             false,
896                             "setEnabledProviders",
897                             null);
898 
899             Set<String> enableProvider = new HashSet<>(providers);
900             enableProvider.addAll(primaryProviders);
901 
902             boolean writeEnabledStatus =
903                     Settings.Secure.putStringForUser(getContext().getContentResolver(),
904                             Settings.Secure.CREDENTIAL_SERVICE,
905                             String.join(":", enableProvider),
906                             userId);
907 
908             boolean writePrimaryStatus =
909                     Settings.Secure.putStringForUser(getContext().getContentResolver(),
910                             Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
911                             String.join(":", primaryProviders),
912                             userId);
913 
914             if (!writeEnabledStatus || !writePrimaryStatus) {
915                 Slog.e(TAG, "Failed to store setting containing enabled or primary providers");
916                 try {
917                     MetricUtilities.logApiCalledSimpleV2(
918                             ApiName.SET_ENABLED_PROVIDERS,
919                             ApiStatus.FAILURE, callingUid);
920                     callback.onError(
921                             "failed_setting_store",
922                             "Failed to store setting containing enabled or primary providers");
923                 } catch (RemoteException e) {
924                     MetricUtilities.logApiCalledSimpleV2(
925                             ApiName.SET_ENABLED_PROVIDERS,
926                             ApiStatus.FAILURE, callingUid);
927                     Slog.e(TAG, "Issue with invoking error response: ", e);
928                     return;
929                 }
930             }
931 
932             // Call the callback.
933             try {
934                 MetricUtilities.logApiCalledSimpleV2(
935                         ApiName.SET_ENABLED_PROVIDERS,
936                         ApiStatus.SUCCESS, callingUid);
937                 callback.onResponse();
938             } catch (RemoteException e) {
939                 MetricUtilities.logApiCalledSimpleV2(
940                         ApiName.SET_ENABLED_PROVIDERS,
941                         ApiStatus.FAILURE, callingUid);
942                 Slog.e(TAG, "Issue with invoking response: ", e);
943                 // TODO: Propagate failure
944             }
945         }
946 
947         @Override
isEnabledCredentialProviderService( ComponentName componentName, String callingPackage)948         public boolean isEnabledCredentialProviderService(
949                 ComponentName componentName, String callingPackage) {
950             Slog.i(TAG, "isEnabledCredentialProviderService with componentName: "
951                     + componentName.flattenToString());
952 
953             final int userId = UserHandle.getCallingUserId();
954             final int callingUid = Binder.getCallingUid();
955             enforceCallingPackage(callingPackage, callingUid);
956 
957             if (componentName == null) {
958                 Slog.w(TAG, "isEnabledCredentialProviderService componentName is null");
959                 // If the component name was not specified then throw an error and
960                 // record a failure because the request failed due to invalid input.
961                 MetricUtilities.logApiCalledSimpleV2(
962                       ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE,
963                       ApiStatus.FAILURE, callingUid);
964                 return false;
965             }
966 
967             if (!componentName.getPackageName().equals(callingPackage)) {
968                 Slog.w(TAG, "isEnabledCredentialProviderService component name"
969                         + " does not match requested component");
970                 // If the requested component name package name does not match
971                 // the calling package then throw an error and record a failure
972                 // metric (because the request failed due to invalid input).
973                 MetricUtilities.logApiCalledSimpleV2(
974                       ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE,
975                       ApiStatus.FAILURE, callingUid);
976                 throw new IllegalArgumentException("provided component name does not match"
977                         + " does not match requesting component");
978             }
979 
980             final Set<ComponentName> enabledProviders = getEnabledProvidersForUser(userId);
981             MetricUtilities.logApiCalledSimpleV2(
982                 ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE,
983                 ApiStatus.SUCCESS, callingUid);
984             if (enabledProviders == null) {
985                 return false;
986             }
987             return enabledProviders.contains(componentName);
988         }
989 
990         @Override
getCredentialProviderServices( int userId, int providerFilter)991         public List<CredentialProviderInfo> getCredentialProviderServices(
992                 int userId, int providerFilter) {
993             verifyGetProvidersPermission();
994             final int callingUid = Binder.getCallingUid();
995             MetricUtilities.logApiCalledSimpleV2(
996                     ApiName.GET_CREDENTIAL_PROVIDER_SERVICES,
997                     ApiStatus.SUCCESS, callingUid);
998             return CredentialProviderInfoFactory
999                     .getCredentialProviderServices(
1000                             mContext, userId, providerFilter, getEnabledProvidersForUser(userId),
1001                             getPrimaryProvidersForUserId(mContext, userId));
1002 
1003         }
1004 
1005         @Override
getCredentialProviderServicesForTesting( int providerFilter)1006         public List<CredentialProviderInfo> getCredentialProviderServicesForTesting(
1007                 int providerFilter) {
1008             verifyGetProvidersPermission();
1009 
1010             final int userId = UserHandle.getCallingUserId();
1011             return CredentialProviderInfoFactory.getCredentialProviderServicesForTesting(
1012                     mContext, userId, providerFilter, getEnabledProvidersForUser(userId),
1013                     getPrimaryProvidersForUserId(mContext, userId));
1014         }
1015 
1016         @Override
isServiceEnabled()1017         public boolean isServiceEnabled() {
1018             final long origId = Binder.clearCallingIdentity();
1019             try {
1020                 return DeviceConfig.getBoolean(
1021                         DeviceConfig.NAMESPACE_CREDENTIAL,
1022                         DEVICE_CONFIG_ENABLE_CREDENTIAL_MANAGER,
1023                         true);
1024             } finally {
1025                 Binder.restoreCallingIdentity(origId);
1026             }
1027         }
1028 
getEnabledProvidersForUser(int userId)1029         private Set<ComponentName> getEnabledProvidersForUser(int userId) {
1030             final int resolvedUserId = ActivityManager.handleIncomingUser(
1031                     Binder.getCallingPid(), Binder.getCallingUid(),
1032                     userId, false, false,
1033                     "getEnabledProvidersForUser", null);
1034 
1035             Set<ComponentName> enabledProviders = new HashSet<>();
1036             String directValue = Settings.Secure.getStringForUser(
1037                     mContext.getContentResolver(), Settings.Secure.CREDENTIAL_SERVICE,
1038                     resolvedUserId);
1039 
1040             if (!TextUtils.isEmpty(directValue)) {
1041                 String[] components = directValue.split(":");
1042                 for (String componentString : components) {
1043                     ComponentName component = ComponentName.unflattenFromString(componentString);
1044                     if (component != null) {
1045                         enabledProviders.add(component);
1046                     }
1047                 }
1048             }
1049 
1050             return enabledProviders;
1051         }
1052 
1053         @Override
clearCredentialState( ClearCredentialStateRequest request, IClearCredentialStateCallback callback, String callingPackage)1054         public ICancellationSignal clearCredentialState(
1055                 ClearCredentialStateRequest request,
1056                 IClearCredentialStateCallback callback,
1057                 String callingPackage) {
1058             final long timestampBegan = System.nanoTime();
1059             Slog.i(TAG, "starting clearCredentialState with callingPackage: "
1060                     + callingPackage);
1061             final int userId = UserHandle.getCallingUserId();
1062             int callingUid = Binder.getCallingUid();
1063             enforceCallingPackage(callingPackage, callingUid);
1064 
1065             // TODO : Implement cancellation
1066             ICancellationSignal cancelTransport = CancellationSignal.createTransport();
1067 
1068             // New request session, scoped for this request only.
1069             final ClearRequestSession session =
1070                     new ClearRequestSession(
1071                             getContext(),
1072                             mSessionManager,
1073                             mLock,
1074                             userId,
1075                             callingUid,
1076                             callback,
1077                             request,
1078                             constructCallingAppInfo(callingPackage, userId, null),
1079                             getEnabledProvidersForUser(userId),
1080                             CancellationSignal.fromTransport(cancelTransport),
1081                             timestampBegan);
1082             addSessionLocked(userId, session);
1083 
1084             // Initiate all provider sessions
1085             // TODO: Determine if provider needs to have clear capability in their manifest
1086             List<ProviderSession> providerSessions = initiateProviderSessions(session, List.of());
1087 
1088             if (providerSessions.isEmpty()) {
1089                 try {
1090                     // TODO("Replace with properly defined error type")
1091                     callback.onError("UNKNOWN", "No credentials available on "
1092                             + "this device");
1093                 } catch (RemoteException e) {
1094                     Slog.e(
1095                             TAG,
1096                             "Issue invoking onError on IClearCredentialStateCallback "
1097                                     + "callback: ", e);
1098                 }
1099             }
1100 
1101             finalizeAndEmitInitialPhaseMetric(session);
1102 
1103             // Iterate over all provider sessions and invoke the request
1104             providerSessions.forEach(ProviderSession::invokeSession);
1105             return cancelTransport;
1106         }
1107 
1108         @Override
registerCredentialDescription( RegisterCredentialDescriptionRequest request, String callingPackage)1109         public void registerCredentialDescription(
1110                 RegisterCredentialDescriptionRequest request, String callingPackage)
1111                 throws IllegalArgumentException, NonCredentialProviderCallerException {
1112             Slog.i(TAG, "registerCredentialDescription with callingPackage: " + callingPackage);
1113 
1114             if (!isCredentialDescriptionApiEnabled()) {
1115                 throw new UnsupportedOperationException("Feature not supported");
1116             }
1117 
1118             enforceCallingPackage(callingPackage, Binder.getCallingUid());
1119 
1120             CredentialDescriptionRegistry session =
1121                     CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId());
1122 
1123             session.executeRegisterRequest(request, callingPackage);
1124         }
1125 
1126         @Override
unregisterCredentialDescription( UnregisterCredentialDescriptionRequest request, String callingPackage)1127         public void unregisterCredentialDescription(
1128                 UnregisterCredentialDescriptionRequest request, String callingPackage)
1129                 throws IllegalArgumentException {
1130             Slog.i(TAG, "unregisterCredentialDescription with callingPackage: "
1131                     + callingPackage);
1132 
1133 
1134             if (!isCredentialDescriptionApiEnabled()) {
1135                 throw new UnsupportedOperationException("Feature not supported");
1136             }
1137 
1138             enforceCallingPackage(callingPackage, Binder.getCallingUid());
1139 
1140             CredentialDescriptionRegistry session =
1141                     CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId());
1142 
1143             session.executeUnregisterRequest(request, callingPackage);
1144         }
1145     }
1146 
validateGetCredentialRequest(GetCredentialRequest request)1147     private void validateGetCredentialRequest(GetCredentialRequest request) {
1148         if (request.getOrigin() != null) {
1149             // Check privileged permissions
1150             mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null);
1151         }
1152         enforcePermissionForAllowedProviders(request);
1153     }
1154 
enforcePermissionForAllowedProviders(GetCredentialRequest request)1155     private void enforcePermissionForAllowedProviders(GetCredentialRequest request) {
1156         boolean containsAllowedProviders = request.getCredentialOptions()
1157                 .stream()
1158                 .anyMatch(option -> option.getAllowedProviders() != null
1159                         && !option.getAllowedProviders().isEmpty());
1160         if (containsAllowedProviders) {
1161             mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS,
1162                     null);
1163         }
1164     }
1165 
addSessionLocked(@serIdInt int userId, RequestSession requestSession)1166     private void addSessionLocked(@UserIdInt int userId,
1167             RequestSession requestSession) {
1168         synchronized (mLock) {
1169             mSessionManager.addSession(userId, requestSession.mRequestId, requestSession);
1170         }
1171     }
1172 
enforceCallingPackage(String callingPackage, int callingUid)1173     private void enforceCallingPackage(String callingPackage, int callingUid) {
1174         int packageUid;
1175         PackageManager pm = mContext.createContextAsUser(
1176                 UserHandle.getUserHandleForUid(callingUid), 0).getPackageManager();
1177         try {
1178             packageUid = pm.getPackageUid(callingPackage,
1179                     PackageManager.PackageInfoFlags.of(0));
1180         } catch (PackageManager.NameNotFoundException e) {
1181             throw new SecurityException(callingPackage + " not found");
1182         }
1183         if (packageUid != callingUid) {
1184             throw new SecurityException(callingPackage + " does not belong to uid " + callingUid);
1185         }
1186     }
1187 
1188     private class SessionManager implements RequestSession.SessionLifetime {
1189         @Override
1190         @GuardedBy("mLock")
onFinishRequestSession(@serIdInt int userId, IBinder token)1191         public void onFinishRequestSession(@UserIdInt int userId, IBinder token) {
1192             if (mRequestSessions.get(userId) != null) {
1193                 mRequestSessions.get(userId).remove(token);
1194             }
1195         }
1196 
1197         @GuardedBy("mLock")
addSession(int userId, IBinder token, RequestSession requestSession)1198         public void addSession(int userId, IBinder token, RequestSession requestSession) {
1199             if (mRequestSessions.get(userId) == null) {
1200                 mRequestSessions.put(userId, new HashMap<>());
1201             }
1202             mRequestSessions.get(userId).put(token, requestSession);
1203         }
1204     }
1205 
1206     /** Updates the list of providers when a particular service within an app is to be removed. */
updateProvidersWhenServiceRemoved( SettingsWrapper settingsWrapper, ComponentName componentName, int userId)1207     public static void updateProvidersWhenServiceRemoved(
1208             SettingsWrapper settingsWrapper, ComponentName componentName, int userId) {
1209         Slog.i(TAG, "updateProvidersWhenServiceRemoved for: "
1210                 + componentName.flattenToString());
1211 
1212         // Get the current primary providers.
1213         String rawPrimaryProviders =
1214                 settingsWrapper.getStringForUser(
1215                         Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, userId);
1216         if (TextUtils.isEmpty(rawPrimaryProviders)) {
1217             Slog.w(TAG, "primary settings key is null");
1218         } else {
1219             // Remove any service from the primary setting that matches with the service
1220             // being removed, and set the filtered list back to the settings key.
1221             Set<String> filteredPrimaryProviders = getStoredProvidersExceptService(
1222                     rawPrimaryProviders, componentName);
1223 
1224             // If there are no more primary providers AND there is no autofill provider either,
1225             // that means all providers must be cleared as that is what the Settings UI app
1226             // displays to the user.If the autofill provider is present then UI shows that as the
1227             // preferred service and other credential provider services can continue to work.
1228             if (filteredPrimaryProviders.isEmpty()
1229                     && !isAutofillProviderPresent(settingsWrapper, userId)) {
1230                 Slog.d(TAG, "Clearing all credential providers");
1231                 if (clearAllCredentialProviders(settingsWrapper, userId)) {
1232                     return;
1233                 }
1234                 Slog.e(TAG, "Failed to clear all credential providers");
1235             }
1236 
1237             // Set the filtered primary providers to the settings key
1238             if (!settingsWrapper.putStringForUser(
1239                     Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
1240                     String.join(":", filteredPrimaryProviders),
1241                     UserHandle.myUserId(),
1242                     /* overrideableByRestore= */ true)) {
1243                 Slog.e(TAG, "Failed to remove primary service: " + componentName);
1244                 return;
1245             }
1246         }
1247 
1248         // Read the credential providers to remove any reference of the removed service.
1249         String rawCredentialProviders =
1250                 settingsWrapper.getStringForUser(
1251                         Settings.Secure.CREDENTIAL_SERVICE, UserHandle.myUserId());
1252 
1253         // Remove any provider services that are same as the one being removed.
1254         Set<String> filteredCredentialProviders = getStoredProvidersExceptService(
1255                 rawCredentialProviders, componentName);
1256         if (!settingsWrapper.putStringForUser(
1257                 Settings.Secure.CREDENTIAL_SERVICE,
1258                 String.join(":", filteredCredentialProviders),
1259                 UserHandle.myUserId(),
1260                 /* overrideableByRestore= */ true)) {
1261             Slog.e(TAG, "Failed to remove secondary service: " + componentName);
1262         }
1263     }
1264 
isAutofillProviderPresent(SettingsWrapper settingsWrapper, int userId)1265     private static boolean isAutofillProviderPresent(SettingsWrapper settingsWrapper, int userId) {
1266         // Read the autofill provider so we don't accidentally erase it.
1267         String autofillProvider =
1268                 settingsWrapper.getStringForUser(
1269                         Settings.Secure.AUTOFILL_SERVICE, userId);
1270 
1271         return autofillProvider != null && !autofillProvider.isEmpty()
1272                 && !isPlaceholderAutofillProvider(autofillProvider, settingsWrapper);
1273     }
1274 
isPlaceholderAutofillProvider(String autofillProvider, SettingsWrapper settingsWrapper)1275     private static boolean isPlaceholderAutofillProvider(String autofillProvider,
1276             SettingsWrapper settingsWrapper) {
1277 
1278         // If there is an autofill provider and it is the credential autofill service indicating
1279         // that the currently selected primary provider does not support autofill
1280         // then we should keep as is
1281         String credentialAutofillService = settingsWrapper.mContext.getResources().getString(
1282                 R.string.config_defaultCredentialManagerAutofillService);
1283         return autofillProvider != null && TextUtils.equals(
1284                 autofillProvider, credentialAutofillService);
1285     }
1286 
clearAllCredentialProviders(SettingsWrapper settingsWrapper, int userId)1287     private static boolean clearAllCredentialProviders(SettingsWrapper settingsWrapper,
1288             int userId) {
1289         if (!settingsWrapper.putStringForUser(
1290                 Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
1291                 null,
1292                 userId,
1293                 /* overrideableByRestore= */ true)) {
1294             return false;
1295         }
1296         return settingsWrapper.putStringForUser(
1297                 Settings.Secure.CREDENTIAL_SERVICE,
1298                 null,
1299                 userId,
1300                 /* overrideableByRestore= */ true);
1301     }
1302 
1303     /** Updates the list of providers when an app is uninstalled. */
updateProvidersWhenPackageRemoved( SettingsWrapper settingsWrapper, String packageName, int userId)1304     public static void updateProvidersWhenPackageRemoved(
1305             SettingsWrapper settingsWrapper, String packageName, int userId) {
1306         Slog.i(TAG, "updateProvidersWhenPackageRemoved");
1307 
1308         // Get the current providers.
1309         String rawProviders =
1310                 settingsWrapper.getStringForUser(
1311                         Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, userId);
1312         if (rawProviders == null) {
1313             Slog.w(TAG, "settings key is null");
1314         } else {
1315             // Remove any providers from the primary setting that contain the package name
1316             // being removed.
1317             Set<String> primaryProviders = getStoredProvidersExceptPackage(rawProviders,
1318                     packageName);
1319             if (!settingsWrapper.putStringForUser(
1320                     Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
1321                     String.join(":", primaryProviders),
1322                     userId,
1323                     /* overrideableByRestore= */ true)) {
1324                 Slog.e(TAG, "Failed to remove primary package: " + packageName);
1325                 return;
1326             }
1327 
1328             // Read the autofill provider so we don't accidentally erase it.
1329             String autofillProvider =
1330                     settingsWrapper.getStringForUser(
1331                             Settings.Secure.AUTOFILL_SERVICE, userId);
1332 
1333             // If there is an autofill provider and it is the credential autofill service indicating
1334             // that the currently selected primary provider does not support autofill
1335             // then we should keep as is
1336             String credentialAutofillService = settingsWrapper.mContext.getResources().getString(
1337                     R.string.config_defaultCredentialManagerAutofillService);
1338             if (autofillProvider != null && primaryProviders.isEmpty() && !TextUtils.equals(
1339                     autofillProvider, credentialAutofillService)) {
1340                 // If the existing autofill provider is from the app being removed
1341                 // then erase the autofill service setting.
1342                 ComponentName cn = ComponentName.unflattenFromString(autofillProvider);
1343                 if (cn != null && cn.getPackageName().equals(packageName)) {
1344                     if (!settingsWrapper.putStringForUser(
1345                             Settings.Secure.AUTOFILL_SERVICE,
1346                             "",
1347                             userId,
1348                             /* overrideableByRestore= */ true)) {
1349                         Slog.e(TAG, "Failed to remove autofill package: " + packageName);
1350                     }
1351                 }
1352             }
1353 
1354             // If there are no more primary providers AND there is no autofill provider either,
1355             // that means all providers must be cleared as that is what the Settings UI app
1356             // displays to the user.If the autofill provider is present then UI shows that as the
1357             // preferred service and other credential provider services can continue to work.
1358             if (primaryProviders.isEmpty() && !isAutofillProviderPresent(settingsWrapper, userId)) {
1359                 Slog.d(TAG, "Clearing all credential providers");
1360                 if (clearAllCredentialProviders(settingsWrapper, userId)) {
1361                     return;
1362                 }
1363                 Slog.e(TAG, "Failed to clear all credential providers");
1364             }
1365         }
1366 
1367         // Read the credential providers to remove any reference of the removed app.
1368         String rawCredentialProviders =
1369                 settingsWrapper.getStringForUser(
1370                         Settings.Secure.CREDENTIAL_SERVICE, userId);
1371 
1372         // Remove any providers that belong to the removed app.
1373         Set<String> credentialProviders = getStoredProvidersExceptPackage(
1374                 rawCredentialProviders, packageName);
1375         if (!settingsWrapper.putStringForUser(
1376                 Settings.Secure.CREDENTIAL_SERVICE,
1377                 String.join(":", credentialProviders),
1378                 userId,
1379                 /* overrideableByRestore= */ true)) {
1380             Slog.e(TAG, "Failed to remove secondary package: " + packageName);
1381         }
1382     }
1383 
1384     /** Gets the list of stored providers from a string removing any mention of package name. */
getStoredProvidersExceptService(String rawProviders, ComponentName componentName)1385     public static Set<String> getStoredProvidersExceptService(String rawProviders,
1386             ComponentName componentName) {
1387         // If the app being removed matches any of the package names from
1388         // this list then don't add it in the output.
1389         Set<String> providers = new HashSet<>();
1390         if (rawProviders == null || componentName == null) {
1391             return providers;
1392         }
1393         for (String rawComponentName : rawProviders.split(":")) {
1394             if (TextUtils.isEmpty(rawComponentName) || rawComponentName.equals("null")) {
1395                 Slog.d(TAG, "provider component name is empty or null");
1396                 continue;
1397             }
1398 
1399             ComponentName cn = ComponentName.unflattenFromString(rawComponentName);
1400             if (cn != null && !cn.equals(componentName)) {
1401                 providers.add(cn.flattenToString());
1402             }
1403         }
1404 
1405         return providers;
1406     }
1407 
1408     /** Gets the list of stored providers from a string removing any mention of package name. */
getStoredProvidersExceptPackage( String rawProviders, String packageName)1409     public static Set<String> getStoredProvidersExceptPackage(
1410             String rawProviders, String packageName) {
1411         // If the app being removed matches any of the package names from
1412         // this list then don't add it in the output.
1413         Set<String> providers = new HashSet<>();
1414         if (rawProviders == null || packageName == null) {
1415             return providers;
1416         }
1417         for (String rawComponentName : rawProviders.split(":")) {
1418             if (TextUtils.isEmpty(rawComponentName) || rawComponentName.equals("null")) {
1419                 Slog.d(TAG, "provider component name is empty or null");
1420                 continue;
1421             }
1422 
1423             ComponentName cn = ComponentName.unflattenFromString(rawComponentName);
1424             if (cn != null && !cn.getPackageName().equals(packageName)) {
1425                 providers.add(cn.flattenToString());
1426             }
1427         }
1428 
1429         return providers;
1430     }
1431 
1432     /** A wrapper class that can be used by tests for intercepting reads/writes. */
1433     public static class SettingsWrapper {
1434         private final Context mContext;
1435 
SettingsWrapper(@onNull Context context)1436         public SettingsWrapper(@NonNull Context context) {
1437             this.mContext = context;
1438         }
1439 
getContentResolver()1440         ContentResolver getContentResolver() {
1441             return mContext.getContentResolver();
1442         }
1443 
1444         /** Retrieves the string value of a system setting */
getStringForUser(String name, int userHandle)1445         public String getStringForUser(String name, int userHandle) {
1446             return Settings.Secure.getStringForUser(getContentResolver(), name, userHandle);
1447         }
1448 
1449         /** Updates the string value of a system setting */
putStringForUser( String name, String value, int userHandle, boolean overrideableByRestore)1450         public boolean putStringForUser(
1451                 String name,
1452                 String value,
1453                 int userHandle,
1454                 boolean overrideableByRestore) {
1455             return Settings.Secure.putStringForUser(
1456                     getContentResolver(),
1457                     name,
1458                     value,
1459                     null,
1460                     false,
1461                     userHandle,
1462                     overrideableByRestore);
1463         }
1464     }
1465 }
1466