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