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 android.service.credentials; 18 19 import static java.util.Objects.requireNonNull; 20 21 import android.Manifest; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.UserIdInt; 25 import android.app.AppGlobals; 26 import android.app.admin.DevicePolicyManager; 27 import android.app.admin.PackagePolicy; 28 import android.content.ComponentName; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.pm.ApplicationInfo; 32 import android.content.pm.PackageManager; 33 import android.content.pm.ResolveInfo; 34 import android.content.pm.ServiceInfo; 35 import android.content.res.Resources; 36 import android.content.res.TypedArray; 37 import android.content.res.XmlResourceParser; 38 import android.credentials.CredentialManager; 39 import android.credentials.CredentialProviderInfo; 40 import android.os.Bundle; 41 import android.os.RemoteException; 42 import android.os.UserHandle; 43 import android.text.TextUtils; 44 import android.util.AttributeSet; 45 import android.util.Slog; 46 import android.util.Xml; 47 48 import com.android.internal.R; 49 import com.android.internal.annotations.VisibleForTesting; 50 51 import org.xmlpull.v1.XmlPullParser; 52 import org.xmlpull.v1.XmlPullParserException; 53 54 import java.io.IOException; 55 import java.util.ArrayList; 56 import java.util.HashMap; 57 import java.util.HashSet; 58 import java.util.List; 59 import java.util.Map; 60 import java.util.Set; 61 62 /** 63 * {@link CredentialProviderInfo} generator. 64 * 65 * @hide 66 */ 67 public final class CredentialProviderInfoFactory { 68 private static final String TAG = CredentialManager.TAG; 69 70 private static final String TAG_CREDENTIAL_PROVIDER = "credential-provider"; 71 private static final String TAG_CAPABILITIES = "capabilities"; 72 private static final String TAG_CAPABILITY = "capability"; 73 private static final String ATTR_NAME = "name"; 74 75 /** 76 * Constructs an information instance of the credential provider. 77 * 78 * @param context the context object 79 * @param serviceComponent the serviceComponent of the provider service 80 * @param userId the android userId for which the current process is running 81 * @param isSystemProvider whether this provider is a system provider 82 * @throws PackageManager.NameNotFoundException If provider service is not found 83 * @throws SecurityException If provider does not require the relevant permission 84 */ create( @onNull Context context, @NonNull ComponentName serviceComponent, int userId, boolean isSystemProvider, boolean isPrimary)85 public static CredentialProviderInfo create( 86 @NonNull Context context, 87 @NonNull ComponentName serviceComponent, 88 int userId, 89 boolean isSystemProvider, 90 boolean isPrimary) 91 throws PackageManager.NameNotFoundException { 92 return create( 93 context, 94 getServiceInfoOrThrow(serviceComponent, userId), 95 isSystemProvider, 96 /* disableSystemAppVerificationForTests= */ false, 97 /* isEnabled= */ false, 98 isPrimary); 99 } 100 101 /** 102 * Constructs an information instance of the credential provider. 103 * 104 * @param context the context object 105 * @param serviceInfo the service info for the provider app. This must be retrieved from the 106 * {@code PackageManager} 107 * @param isSystemProvider whether the provider app is a system provider 108 * @param disableSystemAppVerificationForTests whether to disable system app permission 109 * verification so that tests can install system providers 110 * @param isEnabled whether the user enabled this provider 111 * @throws SecurityException If provider does not require the relevant permission 112 */ create( @onNull Context context, @NonNull ServiceInfo serviceInfo, boolean isSystemProvider, boolean disableSystemAppVerificationForTests, boolean isEnabled, boolean isPrimary)113 public static CredentialProviderInfo create( 114 @NonNull Context context, 115 @NonNull ServiceInfo serviceInfo, 116 boolean isSystemProvider, 117 boolean disableSystemAppVerificationForTests, 118 boolean isEnabled, 119 boolean isPrimary) 120 throws SecurityException { 121 verifyProviderPermission(serviceInfo); 122 if (isSystemProvider) { 123 if (!isValidSystemProvider( 124 context, serviceInfo, disableSystemAppVerificationForTests)) { 125 Slog.e(TAG, "Provider is not a valid system provider: " + serviceInfo); 126 throw new SecurityException( 127 "Provider is not a valid system provider: " + serviceInfo); 128 } 129 } 130 131 return populateMetadata(context, serviceInfo) 132 .setSystemProvider(isSystemProvider) 133 .setEnabled(isEnabled) 134 .setPrimary(isPrimary) 135 .build(); 136 } 137 138 /** 139 * Constructs an information instance of the credential provider for testing purposes. Does not 140 * run any verifications and passes parameters as is. 141 */ 142 @VisibleForTesting createForTests( @onNull ServiceInfo serviceInfo, @NonNull CharSequence overrideLabel, boolean isSystemProvider, boolean isEnabled, @NonNull List<String> capabilities)143 public static CredentialProviderInfo createForTests( 144 @NonNull ServiceInfo serviceInfo, 145 @NonNull CharSequence overrideLabel, 146 boolean isSystemProvider, 147 boolean isEnabled, 148 @NonNull List<String> capabilities) { 149 return new CredentialProviderInfo.Builder(serviceInfo) 150 .setEnabled(isEnabled) 151 .setOverrideLabel(overrideLabel) 152 .setSystemProvider(isSystemProvider) 153 .addCapabilities(capabilities) 154 .build(); 155 } 156 verifyProviderPermission(ServiceInfo serviceInfo)157 private static void verifyProviderPermission(ServiceInfo serviceInfo) throws SecurityException { 158 final String permission = Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE; 159 if (permission.equals(serviceInfo.permission)) { 160 return; 161 } 162 throw new SecurityException( 163 "Service does not require the expected permission : " + permission); 164 } 165 isSystemProviderWithValidPermission( ServiceInfo serviceInfo, Context context)166 private static boolean isSystemProviderWithValidPermission( 167 ServiceInfo serviceInfo, Context context) { 168 if (context == null) { 169 Slog.w(TAG, "Context is null in isSystemProviderWithValidPermission"); 170 return false; 171 } 172 return PermissionUtils.hasPermission( 173 context, 174 serviceInfo.packageName, 175 Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE); 176 } 177 isValidSystemProvider( Context context, ServiceInfo serviceInfo, boolean disableSystemAppVerificationForTests)178 private static boolean isValidSystemProvider( 179 Context context, 180 ServiceInfo serviceInfo, 181 boolean disableSystemAppVerificationForTests) { 182 requireNonNull(context, "context must not be null"); 183 184 if (disableSystemAppVerificationForTests) { 185 Bundle metadata = serviceInfo.metaData; 186 if (metadata == null) { 187 Slog.w( 188 TAG, 189 "metadata is null while reading " 190 + "TEST_SYSTEM_PROVIDER_META_DATA_KEY: " 191 + serviceInfo); 192 return false; 193 } 194 return metadata.getBoolean( 195 CredentialProviderService.TEST_SYSTEM_PROVIDER_META_DATA_KEY); 196 } 197 198 return isSystemProviderWithValidPermission(serviceInfo, context); 199 } 200 populateMetadata( @onNull Context context, ServiceInfo serviceInfo)201 private static CredentialProviderInfo.Builder populateMetadata( 202 @NonNull Context context, ServiceInfo serviceInfo) { 203 requireNonNull(context, "context must not be null"); 204 final PackageManager pm = context.getPackageManager(); 205 CredentialProviderInfo.Builder builder = new CredentialProviderInfo.Builder(serviceInfo); 206 207 // 1. Get the metadata for the service. 208 final Bundle metadata = serviceInfo.metaData; 209 if (metadata == null) { 210 Slog.w(TAG, "Metadata is null for provider: " + serviceInfo.getComponentName()); 211 return builder; 212 } 213 214 // 2. Get the resources for the application. 215 Resources resources = null; 216 try { 217 resources = pm.getResourcesForApplication(serviceInfo.applicationInfo); 218 } catch (PackageManager.NameNotFoundException e) { 219 Slog.e(TAG, "Failed to get app resources", e); 220 } 221 222 // 3. Stop if we are missing data. 223 if (resources == null) { 224 Slog.w( 225 TAG, 226 "Resources are null for the serviceInfo being processed: " 227 + serviceInfo.getComponentName()); 228 return builder; 229 } 230 231 // 4. Extract the XML metadata. 232 try { 233 builder = extractXmlMetadata(context, serviceInfo, pm, resources); 234 } catch (Exception e) { 235 Slog.e(TAG, "Failed to get XML metadata", e); 236 } 237 238 return builder; 239 } 240 extractXmlMetadata( @onNull Context context, @NonNull ServiceInfo serviceInfo, @NonNull PackageManager pm, @NonNull Resources resources)241 private static CredentialProviderInfo.Builder extractXmlMetadata( 242 @NonNull Context context, 243 @NonNull ServiceInfo serviceInfo, 244 @NonNull PackageManager pm, 245 @NonNull Resources resources) { 246 final CredentialProviderInfo.Builder builder = 247 new CredentialProviderInfo.Builder(serviceInfo); 248 final XmlResourceParser parser = 249 serviceInfo.loadXmlMetaData(pm, CredentialProviderService.SERVICE_META_DATA); 250 if (parser == null) { 251 return builder; 252 } 253 254 try { 255 int type = 0; 256 while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { 257 type = parser.next(); 258 } 259 260 // This is matching a <credential-provider /> tag in the XML. 261 if (TAG_CREDENTIAL_PROVIDER.equals(parser.getName())) { 262 final AttributeSet allAttributes = Xml.asAttributeSet(parser); 263 TypedArray afsAttributes = null; 264 try { 265 afsAttributes = 266 resources.obtainAttributes( 267 allAttributes, 268 com.android.internal.R.styleable.CredentialProvider); 269 builder.setSettingsSubtitle( 270 getAfsAttributeSafe( 271 afsAttributes, 272 R.styleable.CredentialProvider_settingsSubtitle)); 273 builder.setSettingsActivity( 274 getAfsAttributeSafe( 275 afsAttributes, 276 R.styleable.CredentialProvider_settingsActivity)); 277 } catch (Exception e) { 278 Slog.w(TAG, "Failed to get XML attr for metadata", e); 279 } finally { 280 if (afsAttributes != null) { 281 afsAttributes.recycle(); 282 } 283 } 284 285 builder.addCapabilities(parseXmlProviderOuterCapabilities(parser, resources)); 286 } else { 287 Slog.w(TAG, "Meta-data does not start with credential-provider-service tag"); 288 } 289 } catch (IOException | XmlPullParserException e) { 290 Slog.e(TAG, "Error parsing credential provider service meta-data", e); 291 } 292 293 return builder; 294 } 295 getAfsAttributeSafe( @ullable TypedArray afsAttributes, int resId)296 private static @Nullable String getAfsAttributeSafe( 297 @Nullable TypedArray afsAttributes, int resId) { 298 if (afsAttributes == null) { 299 return null; 300 } 301 302 try { 303 return afsAttributes.getString(resId); 304 } catch (Exception e) { 305 Slog.w(TAG, "Failed to get XML attr from afs attributes", e); 306 } 307 308 return null; 309 } 310 parseXmlProviderOuterCapabilities( XmlPullParser parser, Resources resources)311 private static List<String> parseXmlProviderOuterCapabilities( 312 XmlPullParser parser, Resources resources) throws IOException, XmlPullParserException { 313 final List<String> capabilities = new ArrayList<>(); 314 final int outerDepth = parser.getDepth(); 315 int type; 316 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 317 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 318 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 319 continue; 320 } 321 322 if (TAG_CAPABILITIES.equals(parser.getName())) { 323 capabilities.addAll(parseXmlProviderInnerCapabilities(parser, resources)); 324 } 325 } 326 327 return capabilities; 328 } 329 parseXmlProviderInnerCapabilities( XmlPullParser parser, Resources resources)330 private static List<String> parseXmlProviderInnerCapabilities( 331 XmlPullParser parser, Resources resources) throws IOException, XmlPullParserException { 332 List<String> capabilities = new ArrayList<>(); 333 334 final int outerDepth = parser.getDepth(); 335 int type; 336 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 337 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 338 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 339 continue; 340 } 341 342 if (TAG_CAPABILITY.equals(parser.getName())) { 343 String name = parser.getAttributeValue(null, ATTR_NAME); 344 if (name != null && !TextUtils.isEmpty(name)) { 345 capabilities.add(name); 346 } 347 } 348 } 349 350 return capabilities; 351 } 352 getServiceInfoOrThrow( @onNull ComponentName serviceComponent, int userId)353 private static ServiceInfo getServiceInfoOrThrow( 354 @NonNull ComponentName serviceComponent, int userId) 355 throws PackageManager.NameNotFoundException { 356 try { 357 ServiceInfo si = 358 AppGlobals.getPackageManager() 359 .getServiceInfo(serviceComponent, PackageManager.GET_META_DATA, userId); 360 if (si != null) { 361 return si; 362 } 363 } catch (RemoteException e) { 364 Slog.e(TAG, "Unable to get serviceInfo", e); 365 } 366 throw new PackageManager.NameNotFoundException(serviceComponent.toString()); 367 } 368 369 /** 370 * Returns the valid credential provider services available for the user with the given {@code 371 * userId}. 372 */ 373 @NonNull getAvailableSystemServiceInfos( @onNull Context context, @UserIdInt int userId, boolean disableSystemAppVerificationForTests)374 private static List<ServiceInfo> getAvailableSystemServiceInfos( 375 @NonNull Context context, 376 @UserIdInt int userId, 377 boolean disableSystemAppVerificationForTests) { 378 requireNonNull(context, "context must not be null"); 379 380 final List<ServiceInfo> services = new ArrayList<>(); 381 final List<ResolveInfo> resolveInfos = new ArrayList<>(); 382 383 resolveInfos.addAll( 384 context.getPackageManager() 385 .queryIntentServicesAsUser( 386 new Intent(CredentialProviderService.SYSTEM_SERVICE_INTERFACE), 387 PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA), 388 userId)); 389 390 for (ResolveInfo resolveInfo : resolveInfos) { 391 final ServiceInfo serviceInfo = resolveInfo.serviceInfo; 392 if (disableSystemAppVerificationForTests) { 393 if (serviceInfo != null) { 394 services.add(serviceInfo); 395 } 396 continue; 397 } 398 399 try { 400 ApplicationInfo appInfo = 401 context.getPackageManager() 402 .getApplicationInfo( 403 serviceInfo.packageName, 404 PackageManager.ApplicationInfoFlags.of( 405 PackageManager.MATCH_SYSTEM_ONLY)); 406 407 if (appInfo == null || serviceInfo == null) { 408 continue; 409 } 410 services.add(serviceInfo); 411 } catch (SecurityException | PackageManager.NameNotFoundException e) { 412 Slog.e(TAG, "Error getting info for " + serviceInfo, e); 413 } 414 } 415 return services; 416 } 417 418 /** 419 * Returns the valid credential provider services available for the user with the given {@code 420 * userId}. 421 */ 422 @NonNull getAvailableSystemServices( @onNull Context context, @UserIdInt int userId, boolean disableSystemAppVerificationForTests, Set<ComponentName> enabledServices)423 public static List<CredentialProviderInfo> getAvailableSystemServices( 424 @NonNull Context context, 425 @UserIdInt int userId, 426 boolean disableSystemAppVerificationForTests, 427 Set<ComponentName> enabledServices) { 428 requireNonNull(context, "context must not be null"); 429 430 final List<CredentialProviderInfo> providerInfos = new ArrayList<>(); 431 for (ServiceInfo si : 432 getAvailableSystemServiceInfos( 433 context, userId, disableSystemAppVerificationForTests)) { 434 try { 435 CredentialProviderInfo cpi = 436 CredentialProviderInfoFactory.create( 437 context, 438 si, 439 /* isSystemProvider= */ true, 440 disableSystemAppVerificationForTests, 441 enabledServices.contains(si.getComponentName()), 442 false); 443 if (cpi.isSystemProvider()) { 444 providerInfos.add(cpi); 445 } else { 446 Slog.e(TAG, "Non system provider was in system provider list."); 447 } 448 } catch (SecurityException e) { 449 Slog.e(TAG, "Failed to create CredentialProviderInfo: " + e); 450 } 451 } 452 return providerInfos; 453 } 454 getDeviceManagerPolicy( @onNull Context context, int userId)455 private static @Nullable PackagePolicy getDeviceManagerPolicy( 456 @NonNull Context context, int userId) { 457 Context newContext = context.createContextAsUser(UserHandle.of(userId), 0); 458 459 try { 460 DevicePolicyManager dpm = newContext.getSystemService(DevicePolicyManager.class); 461 PackagePolicy pp = dpm.getCredentialManagerPolicy(); 462 return pp; 463 } catch (SecurityException e) { 464 // If the current user is not enrolled in DPM then this can throw a security error. 465 Slog.e(TAG, "Failed to get device policy: " + e); 466 } 467 468 return null; 469 } 470 471 /** 472 * Returns the valid credential provider services available for the user with the given {@code 473 * userId}. 474 */ 475 @NonNull getCredentialProviderServices( @onNull Context context, int userId, int providerFilter, Set<ComponentName> enabledServices, Set<ComponentName> primaryServices)476 public static List<CredentialProviderInfo> getCredentialProviderServices( 477 @NonNull Context context, 478 int userId, 479 int providerFilter, 480 Set<ComponentName> enabledServices, 481 Set<ComponentName> primaryServices) { 482 requireNonNull(context, "context must not be null"); 483 484 // Get the device policy. If the client has asked for all providers then we 485 // should ignore the device policy. 486 PackagePolicy pp = 487 providerFilter != CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN 488 ? getDeviceManagerPolicy(context, userId) 489 : null; 490 491 // Generate the provider list. 492 final boolean disableSystemAppVerificationForTests = false; 493 ProviderGenerator generator = 494 new ProviderGenerator( 495 context, pp, disableSystemAppVerificationForTests, providerFilter); 496 generator.addUserProviders( 497 getUserProviders( 498 context, 499 userId, 500 disableSystemAppVerificationForTests, 501 enabledServices, 502 primaryServices)); 503 generator.addSystemProviders( 504 getAvailableSystemServices( 505 context, userId, disableSystemAppVerificationForTests, enabledServices)); 506 return generator.getProviders(); 507 } 508 509 /** 510 * Returns the valid credential provider services available for the user with the given {@code 511 * userId}. Includes test providers. 512 */ 513 @NonNull getCredentialProviderServicesForTesting( @onNull Context context, int userId, int providerFilter, Set<ComponentName> enabledServices, Set<ComponentName> primaryServices)514 public static List<CredentialProviderInfo> getCredentialProviderServicesForTesting( 515 @NonNull Context context, 516 int userId, 517 int providerFilter, 518 Set<ComponentName> enabledServices, 519 Set<ComponentName> primaryServices) { 520 requireNonNull(context, "context must not be null"); 521 522 // Get the device policy. If the client has asked for all providers then we 523 // should ignore the device policy. 524 PackagePolicy pp = 525 providerFilter != CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN 526 ? getDeviceManagerPolicy(context, userId) 527 : null; 528 529 // Generate the provider list. 530 final boolean disableSystemAppVerificationForTests = true; 531 ProviderGenerator generator = 532 new ProviderGenerator( 533 context, pp, disableSystemAppVerificationForTests, providerFilter); 534 generator.addUserProviders( 535 getUserProviders( 536 context, 537 userId, 538 disableSystemAppVerificationForTests, 539 enabledServices, 540 primaryServices)); 541 generator.addSystemProviders( 542 getAvailableSystemServices( 543 context, userId, disableSystemAppVerificationForTests, enabledServices)); 544 return generator.getProviders(); 545 } 546 547 private static class ProviderGenerator { 548 private final Context mContext; 549 private final PackagePolicy mPp; 550 private final boolean mDisableSystemAppVerificationForTests; 551 private final Map<String, CredentialProviderInfo> mServices = new HashMap(); 552 private final int mProviderFilter; 553 ProviderGenerator( Context context, PackagePolicy pp, boolean disableSystemAppVerificationForTests, int providerFilter)554 ProviderGenerator( 555 Context context, 556 PackagePolicy pp, 557 boolean disableSystemAppVerificationForTests, 558 int providerFilter) { 559 this.mContext = context; 560 this.mPp = pp; 561 this.mDisableSystemAppVerificationForTests = disableSystemAppVerificationForTests; 562 this.mProviderFilter = providerFilter; 563 } 564 isPackageAllowed(boolean isSystemProvider, String packageName)565 private boolean isPackageAllowed(boolean isSystemProvider, String packageName) { 566 if (mPp == null) { 567 return true; 568 } 569 570 if (isSystemProvider) { 571 return mPp.getPolicyType() == PackagePolicy.PACKAGE_POLICY_ALLOWLIST_AND_SYSTEM; 572 } 573 574 return mPp.isPackageAllowed(packageName, new HashSet<>()); 575 } 576 getProviders()577 public List<CredentialProviderInfo> getProviders() { 578 return new ArrayList<>(mServices.values()); 579 } 580 addUserProviders(List<CredentialProviderInfo> providers)581 public void addUserProviders(List<CredentialProviderInfo> providers) { 582 for (CredentialProviderInfo cpi : providers) { 583 if (!cpi.isSystemProvider()) { 584 addProvider(cpi); 585 } 586 } 587 } 588 addSystemProviders(List<CredentialProviderInfo> providers)589 public void addSystemProviders(List<CredentialProviderInfo> providers) { 590 for (CredentialProviderInfo cpi : providers) { 591 if (cpi.isSystemProvider()) { 592 addProvider(cpi); 593 } 594 } 595 } 596 isProviderAllowedWithFilter(CredentialProviderInfo cpi)597 private boolean isProviderAllowedWithFilter(CredentialProviderInfo cpi) { 598 if (mProviderFilter == CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS) { 599 return true; 600 } 601 602 if (cpi.isSystemProvider()) { 603 return mProviderFilter == CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY; 604 } else { 605 return mProviderFilter == CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY 606 || mProviderFilter 607 == CredentialManager 608 .PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN; 609 } 610 } 611 addProvider(CredentialProviderInfo cpi)612 private void addProvider(CredentialProviderInfo cpi) { 613 final String componentNameString = 614 cpi.getServiceInfo().getComponentName().flattenToString(); 615 if (!isProviderAllowedWithFilter(cpi)) { 616 return; 617 } 618 619 if (!isPackageAllowed(cpi.isSystemProvider(), cpi.getServiceInfo().packageName)) { 620 return; 621 } 622 623 mServices.put(componentNameString, cpi); 624 } 625 } 626 627 /** 628 * Returns the valid credential provider services available for the user with the given {@code 629 * userId}. 630 */ 631 @NonNull getUserProviders( @onNull Context context, @UserIdInt int userId, boolean disableSystemAppVerificationForTests, Set<ComponentName> enabledServices, Set<ComponentName> primaryServices)632 private static List<CredentialProviderInfo> getUserProviders( 633 @NonNull Context context, 634 @UserIdInt int userId, 635 boolean disableSystemAppVerificationForTests, 636 Set<ComponentName> enabledServices, 637 Set<ComponentName> primaryServices) { 638 final List<CredentialProviderInfo> services = new ArrayList<>(); 639 final List<ResolveInfo> resolveInfos = 640 context.getPackageManager() 641 .queryIntentServicesAsUser( 642 new Intent(CredentialProviderService.SERVICE_INTERFACE), 643 PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA), 644 userId); 645 for (ResolveInfo resolveInfo : resolveInfos) { 646 final ServiceInfo serviceInfo = resolveInfo.serviceInfo; 647 if (serviceInfo == null) { 648 Slog.d(TAG, "No serviceInfo found for resolveInfo, so skipping provider"); 649 continue; 650 } 651 652 try { 653 CredentialProviderInfo cpi = 654 CredentialProviderInfoFactory.create( 655 context, 656 serviceInfo, 657 /* isSystemProvider= */ false, 658 disableSystemAppVerificationForTests, 659 enabledServices.contains(serviceInfo.getComponentName()), 660 primaryServices.contains(serviceInfo.getComponentName())); 661 if (!cpi.isSystemProvider()) { 662 services.add(cpi); 663 } 664 } catch (Exception e) { 665 Slog.e(TAG, "Error getting info for " + serviceInfo, e); 666 } 667 } 668 return services; 669 } 670 } 671