Loading core/java/android/credentials/CredentialManager.java +73 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN; import static java.util.Objects.requireNonNull; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; Loading @@ -30,6 +31,7 @@ import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.IntentSender; import android.content.pm.ServiceInfo; import android.os.CancellationSignal; import android.os.ICancellationSignal; import android.os.OutcomeReceiver; Loading @@ -37,6 +39,8 @@ import android.os.RemoteException; import android.provider.DeviceConfig; import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.concurrent.Executor; Loading @@ -54,6 +58,39 @@ import java.util.concurrent.Executor; public final class CredentialManager { private static final String TAG = "CredentialManager"; /** @hide */ @IntDef( flag = true, prefix = {"PROVIDER_FILTER_"}, value = { PROVIDER_FILTER_ALL_PROVIDERS, PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY, PROVIDER_FILTER_USER_PROVIDERS_ONLY, }) @Retention(RetentionPolicy.SOURCE) public @interface ProviderFilter {} /** * Returns both system and user credential providers. * * @hide */ public static final int PROVIDER_FILTER_ALL_PROVIDERS = 0; /** * Returns system credential providers only. * * @hide */ public static final int PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY = 1; /** * Returns user credential providers only. * * @hide */ public static final int PROVIDER_FILTER_USER_PROVIDERS_ONLY = 2; private final Context mContext; private final ICredentialManager mService; Loading Loading @@ -404,6 +441,42 @@ public final class CredentialManager { } } /** * Returns the list of ServiceInfo for all discovered credential providers on this device. * * @hide */ @NonNull @RequiresPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS) public List<ServiceInfo> getCredentialProviderServicesForTesting( @ProviderFilter int providerFilter) { try { return mService.getCredentialProviderServices( mContext.getUserId(), /* disableSystemAppVerificationForTests= */ true, providerFilter); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns the list of ServiceInfo for all discovered credential providers on this device. * * @hide */ @NonNull @RequiresPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS) public List<ServiceInfo> getCredentialProviderServices( int userId, @ProviderFilter int providerFilter) { try { return mService.getCredentialProviderServices( userId, /* disableSystemAppVerificationForTests= */ false, providerFilter); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns whether the service is enabled. * Loading core/java/android/credentials/ICredentialManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.credentials; import java.util.List; import android.content.pm.ServiceInfo; import android.credentials.ClearCredentialStateRequest; import android.credentials.CreateCredentialRequest; import android.credentials.GetCredentialRequest; Loading Loading @@ -57,5 +58,7 @@ interface ICredentialManager { void unregisterCredentialDescription(in UnregisterCredentialDescriptionRequest request, String callingPackage); boolean isEnabledCredentialProviderService(in ComponentName componentName, String callingPackage); List<ServiceInfo> getCredentialProviderServices(in int userId, in boolean disableSystemAppVerificationForTests, in int providerFilter); } core/java/android/service/credentials/CredentialProviderInfo.java +307 −68 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppGlobals; import android.app.admin.DevicePolicyManager; import android.app.admin.PackagePolicy; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading @@ -29,6 +31,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.credentials.CredentialManager; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.RemoteException; Loading @@ -38,7 +41,10 @@ import android.util.Slog; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; /** * {@link ServiceInfo} and meta-data about a credential provider. Loading Loading @@ -74,39 +80,124 @@ public final class CredentialProviderInfo { public CredentialProviderInfo(@NonNull Context context, @NonNull ComponentName serviceComponent, int userId, boolean isSystemProvider) throws PackageManager.NameNotFoundException { this(context, getServiceInfoOrThrow(serviceComponent, userId), isSystemProvider); this( context, getServiceInfoOrThrow(serviceComponent, userId), isSystemProvider, /* disableSystemAppVerificationForTests= */ false); } /** * Constructs an information instance of the credential provider. * * @param context the context object * @param serviceInfo the service info for the provider app. This must be retrieved from the * {@code PackageManager} * @param isSystemProvider whether the provider is a system app or not * @param isSystemProvider whether the provider app is a system provider * @param disableSystemAppVerificationForTests whether to disable system app permission * verification so that tests can install system providers * @throws SecurityException If provider does not require the relevant permission */ public CredentialProviderInfo(@NonNull Context context, public CredentialProviderInfo( @NonNull Context context, @NonNull ServiceInfo serviceInfo, boolean isSystemProvider) { if (!Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE.equals(serviceInfo.permission)) { Log.i(TAG, "Credential Provider Service from : " + serviceInfo.packageName + "does not require permission" + Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE); throw new SecurityException("Service does not require the expected permission : " + Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE); boolean isSystemProvider, boolean disableSystemAppVerificationForTests) { verifyProviderPermission(serviceInfo); if (isSystemProvider) { if (!isValidSystemProvider( context, serviceInfo, disableSystemAppVerificationForTests)) { Slog.e(TAG, "Provider is not a valid system provider: " + serviceInfo); throw new SecurityException( "Provider is not a valid system provider: " + serviceInfo); } } mIsSystemProvider = isSystemProvider; mContext = context; mServiceInfo = serviceInfo; mCapabilities = new ArrayList<>(); mIcon = mServiceInfo.loadIcon(mContext.getPackageManager()); mLabel = mServiceInfo.loadSafeLabel( mContext.getPackageManager(), 0 /* do not ellipsize */, mLabel = mServiceInfo.loadSafeLabel( mContext.getPackageManager(), 0 /* do not ellipsize */, TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM); mIsSystemProvider = isSystemProvider; Log.i(TAG, "mLabel is : " + mLabel + ", for: " + mServiceInfo.getComponentName() .flattenToString()); Log.i( TAG, "mLabel is : " + mLabel + ", for: " + mServiceInfo.getComponentName().flattenToString()); populateProviderCapabilities(context, serviceInfo); } private static void verifyProviderPermission(ServiceInfo serviceInfo) throws SecurityException { final String permission = Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE; if (permission.equals(serviceInfo.permission)) { return; } Slog.e( TAG, "Credential Provider Service from : " + serviceInfo.packageName + "does not require permission" + permission); throw new SecurityException( "Service does not require the expected permission : " + permission); } private static boolean isSystemProviderWithValidPermission( ServiceInfo serviceInfo, Context context) { final String permission = Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE; try { ApplicationInfo appInfo = context.getPackageManager() .getApplicationInfo( serviceInfo.packageName, PackageManager.ApplicationInfoFlags.of( PackageManager.MATCH_SYSTEM_ONLY)); if (appInfo != null && context.checkPermission(permission, /* pid= */ -1, appInfo.uid) == PackageManager.PERMISSION_GRANTED) { Slog.i(TAG, "SYS permission granted for: " + serviceInfo.packageName); return true; } else { Slog.i(TAG, "SYS permission failed for: " + serviceInfo.packageName); } } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); } return false; } private static boolean isValidSystemProvider( Context context, ServiceInfo serviceInfo, boolean disableSystemAppVerificationForTests) { boolean isValidSystemTestProvider = isTestSystemProvider(serviceInfo, disableSystemAppVerificationForTests); if (isValidSystemTestProvider) { return true; } return isSystemProviderWithValidPermission(serviceInfo, context); } private static boolean isTestSystemProvider( ServiceInfo serviceInfo, boolean disableSystemAppVerificationForTests) { if (!disableSystemAppVerificationForTests) { return false; } Bundle metadata = serviceInfo.metaData; if (metadata == null) { Slog.e(TAG, "metadata is null: " + serviceInfo); return false; } return metadata.getBoolean(CredentialProviderService.TEST_SYSTEM_PROVIDER_META_DATA_KEY); } private void populateProviderCapabilities(@NonNull Context context, ServiceInfo serviceInfo) { final PackageManager pm = context.getPackageManager(); try { Loading @@ -133,7 +224,9 @@ public final class CredentialProviderInfo { mCapabilities.add(capability); } } catch (PackageManager.NameNotFoundException e) { Slog.i(TAG, e.getMessage()); Slog.e(TAG, e.getMessage()); } catch (Resources.NotFoundException e) { Slog.e(TAG, e.getMessage()); } } Loading @@ -154,42 +247,82 @@ public final class CredentialProviderInfo { } /** * Returns the valid credential provider services available for the user with the * given {@code userId}. * Returns the valid credential provider services available for the user with the given {@code * userId}. */ @NonNull public static List<CredentialProviderInfo> getAvailableSystemServices( private static List<ServiceInfo> getAvailableSystemServiceInfos( @NonNull Context context, @UserIdInt int userId) { final List<CredentialProviderInfo> services = new ArrayList<>(); @UserIdInt int userId, boolean disableSystemAppVerificationForTests) { final List<ServiceInfo> services = new ArrayList<>(); final List<ResolveInfo> resolveInfos = new ArrayList<>(); final List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentServicesAsUser( resolveInfos.addAll( context.getPackageManager() .queryIntentServicesAsUser( new Intent(CredentialProviderService.SYSTEM_SERVICE_INTERFACE), PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA), userId); userId)); for (ResolveInfo resolveInfo : resolveInfos) { final ServiceInfo serviceInfo = resolveInfo.serviceInfo; try { ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo( serviceInfo.packageName, PackageManager.ApplicationInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY)); if (appInfo != null && context.checkPermission( Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE, /*pId=*/-1, appInfo.uid) == PackageManager.PERMISSION_GRANTED) { services.add(new CredentialProviderInfo(context, serviceInfo, /*isSystemProvider=*/true)); PackageManager.ApplicationInfoFlags appInfoFlags = disableSystemAppVerificationForTests ? PackageManager.ApplicationInfoFlags.of(0) : PackageManager.ApplicationInfoFlags.of( PackageManager.MATCH_SYSTEM_ONLY); ApplicationInfo appInfo = context.getPackageManager() .getApplicationInfo(serviceInfo.packageName, appInfoFlags); if (appInfo == null || serviceInfo == null) { continue; } services.add(serviceInfo); } catch (SecurityException e) { Log.i(TAG, "Error getting info for " + serviceInfo + ": " + e); Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); } catch (PackageManager.NameNotFoundException e) { Log.i(TAG, "Error getting info for " + serviceInfo + ": " + e); Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); } } return services; } /** * Returns the valid credential provider services available for the user with the given {@code * userId}. */ @NonNull public static List<CredentialProviderInfo> getAvailableSystemServices( @NonNull Context context, @UserIdInt int userId, boolean disableSystemAppVerificationForTests) { final List<CredentialProviderInfo> providerInfos = new ArrayList<>(); for (ServiceInfo si : getAvailableSystemServiceInfos( context, userId, disableSystemAppVerificationForTests)) { try { CredentialProviderInfo cpi = new CredentialProviderInfo( context, si, /* isSystemProvider= */ true, disableSystemAppVerificationForTests); if (cpi.isSystemProvider()) { providerInfos.add(cpi); } else { Slog.e(TAG, "Non system provider was in system provider list."); } } catch (SecurityException e) { Slog.e(TAG, "Failed to create CredentialProviderInfo: " + e); } } return providerInfos; } /** * Returns true if the service supports the given {@code credentialType}, false otherwise. */ Loading Loading @@ -226,47 +359,153 @@ public final class CredentialProviderInfo { return Collections.unmodifiableList(mCapabilities); } private static @Nullable PackagePolicy getDeviceManagerPolicy(@NonNull Context context) { try { DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); return dpm.getCredentialManagerPolicy(); } catch (SecurityException e) { // If the current user is not enrolled in DPM then this can throw a security error. Log.e(TAG, "Failed to get device policy: " + e); } return null; } /** * Returns the valid credential provider services available for the user with the * given {@code userId}. * Returns the valid credential provider services available for the user with the given {@code * userId}. */ @NonNull public static List<CredentialProviderInfo> getAvailableServices(@NonNull Context context, @UserIdInt int userId) { final List<CredentialProviderInfo> services = new ArrayList<>(); public static List<CredentialProviderInfo> getCredentialProviderServices( @NonNull Context context, int userId, boolean disableSystemAppVerificationForTests, int providerFilter) { // Get the device policy. PackagePolicy pp = getDeviceManagerPolicy(context); // Generate the provider list. ProviderGenerator generator = new ProviderGenerator( context, pp, disableSystemAppVerificationForTests, providerFilter); generator.addUserProviders( getUserProviders(context, userId, disableSystemAppVerificationForTests)); generator.addSystemProviders( getAvailableSystemServices(context, userId, disableSystemAppVerificationForTests)); return generator.getProviders(); } private static class ProviderGenerator { private final Context mContext; private final PackagePolicy mPp; private final boolean mDisableSystemAppVerificationForTests; private final Map<String, CredentialProviderInfo> mServices = new HashMap(); private final int mProviderFilter; ProviderGenerator( Context context, PackagePolicy pp, boolean disableSystemAppVerificationForTests, int providerFilter) { this.mContext = context; this.mPp = pp; this.mDisableSystemAppVerificationForTests = disableSystemAppVerificationForTests; this.mProviderFilter = providerFilter; } private boolean isPackageAllowed(boolean isSystemProvider, String packageName) { if (mPp == null) { return true; } if (isSystemProvider) { return mPp.getPolicyType() == PackagePolicy.PACKAGE_POLICY_ALLOWLIST_AND_SYSTEM; } return mPp.isPackageAllowed(packageName, new HashSet<>()); } public List<CredentialProviderInfo> getProviders() { return new ArrayList<>(mServices.values()); } public void addUserProviders(List<CredentialProviderInfo> providers) { for (CredentialProviderInfo cpi : providers) { if (!cpi.isSystemProvider()) { addProvider(cpi); } } } public void addSystemProviders(List<CredentialProviderInfo> providers) { for (CredentialProviderInfo cpi : providers) { if (cpi.isSystemProvider()) { addProvider(cpi); } } } private boolean isProviderAllowedWithFilter(CredentialProviderInfo cpi) { if (mProviderFilter == CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS) { return true; } if (cpi.isSystemProvider()) { return mProviderFilter == CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY; } else { return mProviderFilter == CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY; } } private void addProvider(CredentialProviderInfo cpi) { final String componentNameString = cpi.getServiceInfo().getComponentName().flattenToString(); if (!isProviderAllowedWithFilter(cpi)) { return; } if (!isPackageAllowed(cpi.isSystemProvider(), cpi.getServiceInfo().packageName)) { return; } mServices.put(componentNameString, cpi); } } /** * Returns the valid credential provider services available for the user with the given {@code * userId}. */ @NonNull private static List<CredentialProviderInfo> getUserProviders( @NonNull Context context, @UserIdInt int userId, boolean disableSystemAppVerificationForTests) { final List<CredentialProviderInfo> services = new ArrayList<>(); final List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentServicesAsUser( context.getPackageManager() .queryIntentServicesAsUser( new Intent(CredentialProviderService.SERVICE_INTERFACE), PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA), userId); for (ResolveInfo resolveInfo : resolveInfos) { final ServiceInfo serviceInfo = resolveInfo.serviceInfo; try { services.add(new CredentialProviderInfo(context, serviceInfo, false)); CredentialProviderInfo cpi = new CredentialProviderInfo( context, serviceInfo, /* isSystemProvider= */ false, disableSystemAppVerificationForTests); if (!cpi.isSystemProvider()) { services.add(cpi); } } catch (SecurityException e) { Log.w(TAG, "Error getting info for " + serviceInfo + ": " + e); Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); } catch (Exception e) { Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); } } return services; } /** * Returns the valid credential provider services available for the user, that can * support the given {@code credentialType}. */ @NonNull public static List<CredentialProviderInfo> getAvailableServicesForCapability( @NonNull Context context, @UserIdInt int userId, @NonNull String credentialType) { List<CredentialProviderInfo> servicesForCapability = new ArrayList<>(); final List<CredentialProviderInfo> services = getAvailableServices(context, userId); for (CredentialProviderInfo service : services) { if (service.hasCapability(credentialType)) { servicesForCapability.add(service); } } return servicesForCapability; } } core/java/android/service/credentials/CredentialProviderService.java +4 −0 Original line number Diff line number Diff line Loading @@ -157,6 +157,10 @@ public abstract class CredentialProviderService extends Service { public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities"; /** @hide */ public static final String TEST_SYSTEM_PROVIDER_META_DATA_KEY = "android.credentials.testsystemprovider"; private Handler mHandler; /** Loading services/credentials/java/com/android/server/credentials/CredentialManagerService.java +48 −11 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/credentials/CredentialManager.java +73 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN; import static java.util.Objects.requireNonNull; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; Loading @@ -30,6 +31,7 @@ import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.IntentSender; import android.content.pm.ServiceInfo; import android.os.CancellationSignal; import android.os.ICancellationSignal; import android.os.OutcomeReceiver; Loading @@ -37,6 +39,8 @@ import android.os.RemoteException; import android.provider.DeviceConfig; import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.concurrent.Executor; Loading @@ -54,6 +58,39 @@ import java.util.concurrent.Executor; public final class CredentialManager { private static final String TAG = "CredentialManager"; /** @hide */ @IntDef( flag = true, prefix = {"PROVIDER_FILTER_"}, value = { PROVIDER_FILTER_ALL_PROVIDERS, PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY, PROVIDER_FILTER_USER_PROVIDERS_ONLY, }) @Retention(RetentionPolicy.SOURCE) public @interface ProviderFilter {} /** * Returns both system and user credential providers. * * @hide */ public static final int PROVIDER_FILTER_ALL_PROVIDERS = 0; /** * Returns system credential providers only. * * @hide */ public static final int PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY = 1; /** * Returns user credential providers only. * * @hide */ public static final int PROVIDER_FILTER_USER_PROVIDERS_ONLY = 2; private final Context mContext; private final ICredentialManager mService; Loading Loading @@ -404,6 +441,42 @@ public final class CredentialManager { } } /** * Returns the list of ServiceInfo for all discovered credential providers on this device. * * @hide */ @NonNull @RequiresPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS) public List<ServiceInfo> getCredentialProviderServicesForTesting( @ProviderFilter int providerFilter) { try { return mService.getCredentialProviderServices( mContext.getUserId(), /* disableSystemAppVerificationForTests= */ true, providerFilter); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns the list of ServiceInfo for all discovered credential providers on this device. * * @hide */ @NonNull @RequiresPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS) public List<ServiceInfo> getCredentialProviderServices( int userId, @ProviderFilter int providerFilter) { try { return mService.getCredentialProviderServices( userId, /* disableSystemAppVerificationForTests= */ false, providerFilter); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns whether the service is enabled. * Loading
core/java/android/credentials/ICredentialManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.credentials; import java.util.List; import android.content.pm.ServiceInfo; import android.credentials.ClearCredentialStateRequest; import android.credentials.CreateCredentialRequest; import android.credentials.GetCredentialRequest; Loading Loading @@ -57,5 +58,7 @@ interface ICredentialManager { void unregisterCredentialDescription(in UnregisterCredentialDescriptionRequest request, String callingPackage); boolean isEnabledCredentialProviderService(in ComponentName componentName, String callingPackage); List<ServiceInfo> getCredentialProviderServices(in int userId, in boolean disableSystemAppVerificationForTests, in int providerFilter); }
core/java/android/service/credentials/CredentialProviderInfo.java +307 −68 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppGlobals; import android.app.admin.DevicePolicyManager; import android.app.admin.PackagePolicy; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading @@ -29,6 +31,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.credentials.CredentialManager; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.RemoteException; Loading @@ -38,7 +41,10 @@ import android.util.Slog; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; /** * {@link ServiceInfo} and meta-data about a credential provider. Loading Loading @@ -74,39 +80,124 @@ public final class CredentialProviderInfo { public CredentialProviderInfo(@NonNull Context context, @NonNull ComponentName serviceComponent, int userId, boolean isSystemProvider) throws PackageManager.NameNotFoundException { this(context, getServiceInfoOrThrow(serviceComponent, userId), isSystemProvider); this( context, getServiceInfoOrThrow(serviceComponent, userId), isSystemProvider, /* disableSystemAppVerificationForTests= */ false); } /** * Constructs an information instance of the credential provider. * * @param context the context object * @param serviceInfo the service info for the provider app. This must be retrieved from the * {@code PackageManager} * @param isSystemProvider whether the provider is a system app or not * @param isSystemProvider whether the provider app is a system provider * @param disableSystemAppVerificationForTests whether to disable system app permission * verification so that tests can install system providers * @throws SecurityException If provider does not require the relevant permission */ public CredentialProviderInfo(@NonNull Context context, public CredentialProviderInfo( @NonNull Context context, @NonNull ServiceInfo serviceInfo, boolean isSystemProvider) { if (!Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE.equals(serviceInfo.permission)) { Log.i(TAG, "Credential Provider Service from : " + serviceInfo.packageName + "does not require permission" + Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE); throw new SecurityException("Service does not require the expected permission : " + Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE); boolean isSystemProvider, boolean disableSystemAppVerificationForTests) { verifyProviderPermission(serviceInfo); if (isSystemProvider) { if (!isValidSystemProvider( context, serviceInfo, disableSystemAppVerificationForTests)) { Slog.e(TAG, "Provider is not a valid system provider: " + serviceInfo); throw new SecurityException( "Provider is not a valid system provider: " + serviceInfo); } } mIsSystemProvider = isSystemProvider; mContext = context; mServiceInfo = serviceInfo; mCapabilities = new ArrayList<>(); mIcon = mServiceInfo.loadIcon(mContext.getPackageManager()); mLabel = mServiceInfo.loadSafeLabel( mContext.getPackageManager(), 0 /* do not ellipsize */, mLabel = mServiceInfo.loadSafeLabel( mContext.getPackageManager(), 0 /* do not ellipsize */, TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM); mIsSystemProvider = isSystemProvider; Log.i(TAG, "mLabel is : " + mLabel + ", for: " + mServiceInfo.getComponentName() .flattenToString()); Log.i( TAG, "mLabel is : " + mLabel + ", for: " + mServiceInfo.getComponentName().flattenToString()); populateProviderCapabilities(context, serviceInfo); } private static void verifyProviderPermission(ServiceInfo serviceInfo) throws SecurityException { final String permission = Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE; if (permission.equals(serviceInfo.permission)) { return; } Slog.e( TAG, "Credential Provider Service from : " + serviceInfo.packageName + "does not require permission" + permission); throw new SecurityException( "Service does not require the expected permission : " + permission); } private static boolean isSystemProviderWithValidPermission( ServiceInfo serviceInfo, Context context) { final String permission = Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE; try { ApplicationInfo appInfo = context.getPackageManager() .getApplicationInfo( serviceInfo.packageName, PackageManager.ApplicationInfoFlags.of( PackageManager.MATCH_SYSTEM_ONLY)); if (appInfo != null && context.checkPermission(permission, /* pid= */ -1, appInfo.uid) == PackageManager.PERMISSION_GRANTED) { Slog.i(TAG, "SYS permission granted for: " + serviceInfo.packageName); return true; } else { Slog.i(TAG, "SYS permission failed for: " + serviceInfo.packageName); } } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); } return false; } private static boolean isValidSystemProvider( Context context, ServiceInfo serviceInfo, boolean disableSystemAppVerificationForTests) { boolean isValidSystemTestProvider = isTestSystemProvider(serviceInfo, disableSystemAppVerificationForTests); if (isValidSystemTestProvider) { return true; } return isSystemProviderWithValidPermission(serviceInfo, context); } private static boolean isTestSystemProvider( ServiceInfo serviceInfo, boolean disableSystemAppVerificationForTests) { if (!disableSystemAppVerificationForTests) { return false; } Bundle metadata = serviceInfo.metaData; if (metadata == null) { Slog.e(TAG, "metadata is null: " + serviceInfo); return false; } return metadata.getBoolean(CredentialProviderService.TEST_SYSTEM_PROVIDER_META_DATA_KEY); } private void populateProviderCapabilities(@NonNull Context context, ServiceInfo serviceInfo) { final PackageManager pm = context.getPackageManager(); try { Loading @@ -133,7 +224,9 @@ public final class CredentialProviderInfo { mCapabilities.add(capability); } } catch (PackageManager.NameNotFoundException e) { Slog.i(TAG, e.getMessage()); Slog.e(TAG, e.getMessage()); } catch (Resources.NotFoundException e) { Slog.e(TAG, e.getMessage()); } } Loading @@ -154,42 +247,82 @@ public final class CredentialProviderInfo { } /** * Returns the valid credential provider services available for the user with the * given {@code userId}. * Returns the valid credential provider services available for the user with the given {@code * userId}. */ @NonNull public static List<CredentialProviderInfo> getAvailableSystemServices( private static List<ServiceInfo> getAvailableSystemServiceInfos( @NonNull Context context, @UserIdInt int userId) { final List<CredentialProviderInfo> services = new ArrayList<>(); @UserIdInt int userId, boolean disableSystemAppVerificationForTests) { final List<ServiceInfo> services = new ArrayList<>(); final List<ResolveInfo> resolveInfos = new ArrayList<>(); final List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentServicesAsUser( resolveInfos.addAll( context.getPackageManager() .queryIntentServicesAsUser( new Intent(CredentialProviderService.SYSTEM_SERVICE_INTERFACE), PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA), userId); userId)); for (ResolveInfo resolveInfo : resolveInfos) { final ServiceInfo serviceInfo = resolveInfo.serviceInfo; try { ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo( serviceInfo.packageName, PackageManager.ApplicationInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY)); if (appInfo != null && context.checkPermission( Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE, /*pId=*/-1, appInfo.uid) == PackageManager.PERMISSION_GRANTED) { services.add(new CredentialProviderInfo(context, serviceInfo, /*isSystemProvider=*/true)); PackageManager.ApplicationInfoFlags appInfoFlags = disableSystemAppVerificationForTests ? PackageManager.ApplicationInfoFlags.of(0) : PackageManager.ApplicationInfoFlags.of( PackageManager.MATCH_SYSTEM_ONLY); ApplicationInfo appInfo = context.getPackageManager() .getApplicationInfo(serviceInfo.packageName, appInfoFlags); if (appInfo == null || serviceInfo == null) { continue; } services.add(serviceInfo); } catch (SecurityException e) { Log.i(TAG, "Error getting info for " + serviceInfo + ": " + e); Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); } catch (PackageManager.NameNotFoundException e) { Log.i(TAG, "Error getting info for " + serviceInfo + ": " + e); Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); } } return services; } /** * Returns the valid credential provider services available for the user with the given {@code * userId}. */ @NonNull public static List<CredentialProviderInfo> getAvailableSystemServices( @NonNull Context context, @UserIdInt int userId, boolean disableSystemAppVerificationForTests) { final List<CredentialProviderInfo> providerInfos = new ArrayList<>(); for (ServiceInfo si : getAvailableSystemServiceInfos( context, userId, disableSystemAppVerificationForTests)) { try { CredentialProviderInfo cpi = new CredentialProviderInfo( context, si, /* isSystemProvider= */ true, disableSystemAppVerificationForTests); if (cpi.isSystemProvider()) { providerInfos.add(cpi); } else { Slog.e(TAG, "Non system provider was in system provider list."); } } catch (SecurityException e) { Slog.e(TAG, "Failed to create CredentialProviderInfo: " + e); } } return providerInfos; } /** * Returns true if the service supports the given {@code credentialType}, false otherwise. */ Loading Loading @@ -226,47 +359,153 @@ public final class CredentialProviderInfo { return Collections.unmodifiableList(mCapabilities); } private static @Nullable PackagePolicy getDeviceManagerPolicy(@NonNull Context context) { try { DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); return dpm.getCredentialManagerPolicy(); } catch (SecurityException e) { // If the current user is not enrolled in DPM then this can throw a security error. Log.e(TAG, "Failed to get device policy: " + e); } return null; } /** * Returns the valid credential provider services available for the user with the * given {@code userId}. * Returns the valid credential provider services available for the user with the given {@code * userId}. */ @NonNull public static List<CredentialProviderInfo> getAvailableServices(@NonNull Context context, @UserIdInt int userId) { final List<CredentialProviderInfo> services = new ArrayList<>(); public static List<CredentialProviderInfo> getCredentialProviderServices( @NonNull Context context, int userId, boolean disableSystemAppVerificationForTests, int providerFilter) { // Get the device policy. PackagePolicy pp = getDeviceManagerPolicy(context); // Generate the provider list. ProviderGenerator generator = new ProviderGenerator( context, pp, disableSystemAppVerificationForTests, providerFilter); generator.addUserProviders( getUserProviders(context, userId, disableSystemAppVerificationForTests)); generator.addSystemProviders( getAvailableSystemServices(context, userId, disableSystemAppVerificationForTests)); return generator.getProviders(); } private static class ProviderGenerator { private final Context mContext; private final PackagePolicy mPp; private final boolean mDisableSystemAppVerificationForTests; private final Map<String, CredentialProviderInfo> mServices = new HashMap(); private final int mProviderFilter; ProviderGenerator( Context context, PackagePolicy pp, boolean disableSystemAppVerificationForTests, int providerFilter) { this.mContext = context; this.mPp = pp; this.mDisableSystemAppVerificationForTests = disableSystemAppVerificationForTests; this.mProviderFilter = providerFilter; } private boolean isPackageAllowed(boolean isSystemProvider, String packageName) { if (mPp == null) { return true; } if (isSystemProvider) { return mPp.getPolicyType() == PackagePolicy.PACKAGE_POLICY_ALLOWLIST_AND_SYSTEM; } return mPp.isPackageAllowed(packageName, new HashSet<>()); } public List<CredentialProviderInfo> getProviders() { return new ArrayList<>(mServices.values()); } public void addUserProviders(List<CredentialProviderInfo> providers) { for (CredentialProviderInfo cpi : providers) { if (!cpi.isSystemProvider()) { addProvider(cpi); } } } public void addSystemProviders(List<CredentialProviderInfo> providers) { for (CredentialProviderInfo cpi : providers) { if (cpi.isSystemProvider()) { addProvider(cpi); } } } private boolean isProviderAllowedWithFilter(CredentialProviderInfo cpi) { if (mProviderFilter == CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS) { return true; } if (cpi.isSystemProvider()) { return mProviderFilter == CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY; } else { return mProviderFilter == CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY; } } private void addProvider(CredentialProviderInfo cpi) { final String componentNameString = cpi.getServiceInfo().getComponentName().flattenToString(); if (!isProviderAllowedWithFilter(cpi)) { return; } if (!isPackageAllowed(cpi.isSystemProvider(), cpi.getServiceInfo().packageName)) { return; } mServices.put(componentNameString, cpi); } } /** * Returns the valid credential provider services available for the user with the given {@code * userId}. */ @NonNull private static List<CredentialProviderInfo> getUserProviders( @NonNull Context context, @UserIdInt int userId, boolean disableSystemAppVerificationForTests) { final List<CredentialProviderInfo> services = new ArrayList<>(); final List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentServicesAsUser( context.getPackageManager() .queryIntentServicesAsUser( new Intent(CredentialProviderService.SERVICE_INTERFACE), PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA), userId); for (ResolveInfo resolveInfo : resolveInfos) { final ServiceInfo serviceInfo = resolveInfo.serviceInfo; try { services.add(new CredentialProviderInfo(context, serviceInfo, false)); CredentialProviderInfo cpi = new CredentialProviderInfo( context, serviceInfo, /* isSystemProvider= */ false, disableSystemAppVerificationForTests); if (!cpi.isSystemProvider()) { services.add(cpi); } } catch (SecurityException e) { Log.w(TAG, "Error getting info for " + serviceInfo + ": " + e); Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); } catch (Exception e) { Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); } } return services; } /** * Returns the valid credential provider services available for the user, that can * support the given {@code credentialType}. */ @NonNull public static List<CredentialProviderInfo> getAvailableServicesForCapability( @NonNull Context context, @UserIdInt int userId, @NonNull String credentialType) { List<CredentialProviderInfo> servicesForCapability = new ArrayList<>(); final List<CredentialProviderInfo> services = getAvailableServices(context, userId); for (CredentialProviderInfo service : services) { if (service.hasCapability(credentialType)) { servicesForCapability.add(service); } } return servicesForCapability; } }
core/java/android/service/credentials/CredentialProviderService.java +4 −0 Original line number Diff line number Diff line Loading @@ -157,6 +157,10 @@ public abstract class CredentialProviderService extends Service { public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities"; /** @hide */ public static final String TEST_SYSTEM_PROVIDER_META_DATA_KEY = "android.credentials.testsystemprovider"; private Handler mHandler; /** Loading
services/credentials/java/com/android/server/credentials/CredentialManagerService.java +48 −11 File changed.Preview size limit exceeded, changes collapsed. Show changes