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