671 lines
26 KiB
Java
671 lines
26 KiB
Java
/*
|
|
* Copyright (C) 2022 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.service.credentials;
|
|
|
|
import static java.util.Objects.requireNonNull;
|
|
|
|
import android.Manifest;
|
|
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;
|
|
import android.content.pm.ApplicationInfo;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.ResolveInfo;
|
|
import android.content.pm.ServiceInfo;
|
|
import android.content.res.Resources;
|
|
import android.content.res.TypedArray;
|
|
import android.content.res.XmlResourceParser;
|
|
import android.credentials.CredentialManager;
|
|
import android.credentials.CredentialProviderInfo;
|
|
import android.os.Bundle;
|
|
import android.os.RemoteException;
|
|
import android.os.UserHandle;
|
|
import android.text.TextUtils;
|
|
import android.util.AttributeSet;
|
|
import android.util.Slog;
|
|
import android.util.Xml;
|
|
|
|
import com.android.internal.R;
|
|
import com.android.internal.annotations.VisibleForTesting;
|
|
|
|
import org.xmlpull.v1.XmlPullParser;
|
|
import org.xmlpull.v1.XmlPullParserException;
|
|
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* {@link CredentialProviderInfo} generator.
|
|
*
|
|
* @hide
|
|
*/
|
|
public final class CredentialProviderInfoFactory {
|
|
private static final String TAG = CredentialManager.TAG;
|
|
|
|
private static final String TAG_CREDENTIAL_PROVIDER = "credential-provider";
|
|
private static final String TAG_CAPABILITIES = "capabilities";
|
|
private static final String TAG_CAPABILITY = "capability";
|
|
private static final String ATTR_NAME = "name";
|
|
|
|
/**
|
|
* Constructs an information instance of the credential provider.
|
|
*
|
|
* @param context the context object
|
|
* @param serviceComponent the serviceComponent of the provider service
|
|
* @param userId the android userId for which the current process is running
|
|
* @param isSystemProvider whether this provider is a system provider
|
|
* @throws PackageManager.NameNotFoundException If provider service is not found
|
|
* @throws SecurityException If provider does not require the relevant permission
|
|
*/
|
|
public static CredentialProviderInfo create(
|
|
@NonNull Context context,
|
|
@NonNull ComponentName serviceComponent,
|
|
int userId,
|
|
boolean isSystemProvider,
|
|
boolean isPrimary)
|
|
throws PackageManager.NameNotFoundException {
|
|
return create(
|
|
context,
|
|
getServiceInfoOrThrow(serviceComponent, userId),
|
|
isSystemProvider,
|
|
/* disableSystemAppVerificationForTests= */ false,
|
|
/* isEnabled= */ false,
|
|
isPrimary);
|
|
}
|
|
|
|
/**
|
|
* 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 app is a system provider
|
|
* @param disableSystemAppVerificationForTests whether to disable system app permission
|
|
* verification so that tests can install system providers
|
|
* @param isEnabled whether the user enabled this provider
|
|
* @throws SecurityException If provider does not require the relevant permission
|
|
*/
|
|
public static CredentialProviderInfo create(
|
|
@NonNull Context context,
|
|
@NonNull ServiceInfo serviceInfo,
|
|
boolean isSystemProvider,
|
|
boolean disableSystemAppVerificationForTests,
|
|
boolean isEnabled,
|
|
boolean isPrimary)
|
|
throws SecurityException {
|
|
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);
|
|
}
|
|
}
|
|
|
|
return populateMetadata(context, serviceInfo)
|
|
.setSystemProvider(isSystemProvider)
|
|
.setEnabled(isEnabled)
|
|
.setPrimary(isPrimary)
|
|
.build();
|
|
}
|
|
|
|
/**
|
|
* Constructs an information instance of the credential provider for testing purposes. Does not
|
|
* run any verifications and passes parameters as is.
|
|
*/
|
|
@VisibleForTesting
|
|
public static CredentialProviderInfo createForTests(
|
|
@NonNull ServiceInfo serviceInfo,
|
|
@NonNull CharSequence overrideLabel,
|
|
boolean isSystemProvider,
|
|
boolean isEnabled,
|
|
@NonNull List<String> capabilities) {
|
|
return new CredentialProviderInfo.Builder(serviceInfo)
|
|
.setEnabled(isEnabled)
|
|
.setOverrideLabel(overrideLabel)
|
|
.setSystemProvider(isSystemProvider)
|
|
.addCapabilities(capabilities)
|
|
.build();
|
|
}
|
|
|
|
private static void verifyProviderPermission(ServiceInfo serviceInfo) throws SecurityException {
|
|
final String permission = Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE;
|
|
if (permission.equals(serviceInfo.permission)) {
|
|
return;
|
|
}
|
|
throw new SecurityException(
|
|
"Service does not require the expected permission : " + permission);
|
|
}
|
|
|
|
private static boolean isSystemProviderWithValidPermission(
|
|
ServiceInfo serviceInfo, Context context) {
|
|
if (context == null) {
|
|
Slog.w(TAG, "Context is null in isSystemProviderWithValidPermission");
|
|
return false;
|
|
}
|
|
return PermissionUtils.hasPermission(
|
|
context,
|
|
serviceInfo.packageName,
|
|
Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE);
|
|
}
|
|
|
|
private static boolean isValidSystemProvider(
|
|
Context context,
|
|
ServiceInfo serviceInfo,
|
|
boolean disableSystemAppVerificationForTests) {
|
|
requireNonNull(context, "context must not be null");
|
|
|
|
if (disableSystemAppVerificationForTests) {
|
|
Bundle metadata = serviceInfo.metaData;
|
|
if (metadata == null) {
|
|
Slog.w(
|
|
TAG,
|
|
"metadata is null while reading "
|
|
+ "TEST_SYSTEM_PROVIDER_META_DATA_KEY: "
|
|
+ serviceInfo);
|
|
return false;
|
|
}
|
|
return metadata.getBoolean(
|
|
CredentialProviderService.TEST_SYSTEM_PROVIDER_META_DATA_KEY);
|
|
}
|
|
|
|
return isSystemProviderWithValidPermission(serviceInfo, context);
|
|
}
|
|
|
|
private static CredentialProviderInfo.Builder populateMetadata(
|
|
@NonNull Context context, ServiceInfo serviceInfo) {
|
|
requireNonNull(context, "context must not be null");
|
|
final PackageManager pm = context.getPackageManager();
|
|
CredentialProviderInfo.Builder builder = new CredentialProviderInfo.Builder(serviceInfo);
|
|
|
|
// 1. Get the metadata for the service.
|
|
final Bundle metadata = serviceInfo.metaData;
|
|
if (metadata == null) {
|
|
Slog.w(TAG, "Metadata is null for provider: " + serviceInfo.getComponentName());
|
|
return builder;
|
|
}
|
|
|
|
// 2. Get the resources for the application.
|
|
Resources resources = null;
|
|
try {
|
|
resources = pm.getResourcesForApplication(serviceInfo.applicationInfo);
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
Slog.e(TAG, "Failed to get app resources", e);
|
|
}
|
|
|
|
// 3. Stop if we are missing data.
|
|
if (resources == null) {
|
|
Slog.w(
|
|
TAG,
|
|
"Resources are null for the serviceInfo being processed: "
|
|
+ serviceInfo.getComponentName());
|
|
return builder;
|
|
}
|
|
|
|
// 4. Extract the XML metadata.
|
|
try {
|
|
builder = extractXmlMetadata(context, serviceInfo, pm, resources);
|
|
} catch (Exception e) {
|
|
Slog.e(TAG, "Failed to get XML metadata", e);
|
|
}
|
|
|
|
return builder;
|
|
}
|
|
|
|
private static CredentialProviderInfo.Builder extractXmlMetadata(
|
|
@NonNull Context context,
|
|
@NonNull ServiceInfo serviceInfo,
|
|
@NonNull PackageManager pm,
|
|
@NonNull Resources resources) {
|
|
final CredentialProviderInfo.Builder builder =
|
|
new CredentialProviderInfo.Builder(serviceInfo);
|
|
final XmlResourceParser parser =
|
|
serviceInfo.loadXmlMetaData(pm, CredentialProviderService.SERVICE_META_DATA);
|
|
if (parser == null) {
|
|
return builder;
|
|
}
|
|
|
|
try {
|
|
int type = 0;
|
|
while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
|
|
type = parser.next();
|
|
}
|
|
|
|
// This is matching a <credential-provider /> tag in the XML.
|
|
if (TAG_CREDENTIAL_PROVIDER.equals(parser.getName())) {
|
|
final AttributeSet allAttributes = Xml.asAttributeSet(parser);
|
|
TypedArray afsAttributes = null;
|
|
try {
|
|
afsAttributes =
|
|
resources.obtainAttributes(
|
|
allAttributes,
|
|
com.android.internal.R.styleable.CredentialProvider);
|
|
builder.setSettingsSubtitle(
|
|
getAfsAttributeSafe(
|
|
afsAttributes,
|
|
R.styleable.CredentialProvider_settingsSubtitle));
|
|
builder.setSettingsActivity(
|
|
getAfsAttributeSafe(
|
|
afsAttributes,
|
|
R.styleable.CredentialProvider_settingsActivity));
|
|
} catch (Exception e) {
|
|
Slog.w(TAG, "Failed to get XML attr for metadata", e);
|
|
} finally {
|
|
if (afsAttributes != null) {
|
|
afsAttributes.recycle();
|
|
}
|
|
}
|
|
|
|
builder.addCapabilities(parseXmlProviderOuterCapabilities(parser, resources));
|
|
} else {
|
|
Slog.w(TAG, "Meta-data does not start with credential-provider-service tag");
|
|
}
|
|
} catch (IOException | XmlPullParserException e) {
|
|
Slog.e(TAG, "Error parsing credential provider service meta-data", e);
|
|
}
|
|
|
|
return builder;
|
|
}
|
|
|
|
private static @Nullable String getAfsAttributeSafe(
|
|
@Nullable TypedArray afsAttributes, int resId) {
|
|
if (afsAttributes == null) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return afsAttributes.getString(resId);
|
|
} catch (Exception e) {
|
|
Slog.w(TAG, "Failed to get XML attr from afs attributes", e);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static List<String> parseXmlProviderOuterCapabilities(
|
|
XmlPullParser parser, Resources resources) throws IOException, XmlPullParserException {
|
|
final List<String> capabilities = new ArrayList<>();
|
|
final int outerDepth = parser.getDepth();
|
|
int type;
|
|
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
|
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
|
|
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
|
|
continue;
|
|
}
|
|
|
|
if (TAG_CAPABILITIES.equals(parser.getName())) {
|
|
capabilities.addAll(parseXmlProviderInnerCapabilities(parser, resources));
|
|
}
|
|
}
|
|
|
|
return capabilities;
|
|
}
|
|
|
|
private static List<String> parseXmlProviderInnerCapabilities(
|
|
XmlPullParser parser, Resources resources) throws IOException, XmlPullParserException {
|
|
List<String> capabilities = new ArrayList<>();
|
|
|
|
final int outerDepth = parser.getDepth();
|
|
int type;
|
|
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
|
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
|
|
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
|
|
continue;
|
|
}
|
|
|
|
if (TAG_CAPABILITY.equals(parser.getName())) {
|
|
String name = parser.getAttributeValue(null, ATTR_NAME);
|
|
if (name != null && !TextUtils.isEmpty(name)) {
|
|
capabilities.add(name);
|
|
}
|
|
}
|
|
}
|
|
|
|
return capabilities;
|
|
}
|
|
|
|
private static ServiceInfo getServiceInfoOrThrow(
|
|
@NonNull ComponentName serviceComponent, int userId)
|
|
throws PackageManager.NameNotFoundException {
|
|
try {
|
|
ServiceInfo si =
|
|
AppGlobals.getPackageManager()
|
|
.getServiceInfo(serviceComponent, PackageManager.GET_META_DATA, userId);
|
|
if (si != null) {
|
|
return si;
|
|
}
|
|
} catch (RemoteException e) {
|
|
Slog.e(TAG, "Unable to get serviceInfo", e);
|
|
}
|
|
throw new PackageManager.NameNotFoundException(serviceComponent.toString());
|
|
}
|
|
|
|
/**
|
|
* Returns the valid credential provider services available for the user with the given {@code
|
|
* userId}.
|
|
*/
|
|
@NonNull
|
|
private static List<ServiceInfo> getAvailableSystemServiceInfos(
|
|
@NonNull Context context,
|
|
@UserIdInt int userId,
|
|
boolean disableSystemAppVerificationForTests) {
|
|
requireNonNull(context, "context must not be null");
|
|
|
|
final List<ServiceInfo> services = new ArrayList<>();
|
|
final List<ResolveInfo> resolveInfos = new ArrayList<>();
|
|
|
|
resolveInfos.addAll(
|
|
context.getPackageManager()
|
|
.queryIntentServicesAsUser(
|
|
new Intent(CredentialProviderService.SYSTEM_SERVICE_INTERFACE),
|
|
PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA),
|
|
userId));
|
|
|
|
for (ResolveInfo resolveInfo : resolveInfos) {
|
|
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
|
|
if (disableSystemAppVerificationForTests) {
|
|
if (serviceInfo != null) {
|
|
services.add(serviceInfo);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
ApplicationInfo appInfo =
|
|
context.getPackageManager()
|
|
.getApplicationInfo(
|
|
serviceInfo.packageName,
|
|
PackageManager.ApplicationInfoFlags.of(
|
|
PackageManager.MATCH_SYSTEM_ONLY));
|
|
|
|
if (appInfo == null || serviceInfo == null) {
|
|
continue;
|
|
}
|
|
services.add(serviceInfo);
|
|
} catch (SecurityException | PackageManager.NameNotFoundException 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,
|
|
Set<ComponentName> enabledServices) {
|
|
requireNonNull(context, "context must not be null");
|
|
|
|
final List<CredentialProviderInfo> providerInfos = new ArrayList<>();
|
|
for (ServiceInfo si :
|
|
getAvailableSystemServiceInfos(
|
|
context, userId, disableSystemAppVerificationForTests)) {
|
|
try {
|
|
CredentialProviderInfo cpi =
|
|
CredentialProviderInfoFactory.create(
|
|
context,
|
|
si,
|
|
/* isSystemProvider= */ true,
|
|
disableSystemAppVerificationForTests,
|
|
enabledServices.contains(si.getComponentName()),
|
|
false);
|
|
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;
|
|
}
|
|
|
|
private static @Nullable PackagePolicy getDeviceManagerPolicy(
|
|
@NonNull Context context, int userId) {
|
|
Context newContext = context.createContextAsUser(UserHandle.of(userId), 0);
|
|
|
|
try {
|
|
DevicePolicyManager dpm = newContext.getSystemService(DevicePolicyManager.class);
|
|
PackagePolicy pp = dpm.getCredentialManagerPolicy();
|
|
return pp;
|
|
} catch (SecurityException e) {
|
|
// If the current user is not enrolled in DPM then this can throw a security error.
|
|
Slog.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}.
|
|
*/
|
|
@NonNull
|
|
public static List<CredentialProviderInfo> getCredentialProviderServices(
|
|
@NonNull Context context,
|
|
int userId,
|
|
int providerFilter,
|
|
Set<ComponentName> enabledServices,
|
|
Set<ComponentName> primaryServices) {
|
|
requireNonNull(context, "context must not be null");
|
|
|
|
// Get the device policy. If the client has asked for all providers then we
|
|
// should ignore the device policy.
|
|
PackagePolicy pp =
|
|
providerFilter != CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN
|
|
? getDeviceManagerPolicy(context, userId)
|
|
: null;
|
|
|
|
// Generate the provider list.
|
|
final boolean disableSystemAppVerificationForTests = false;
|
|
ProviderGenerator generator =
|
|
new ProviderGenerator(
|
|
context, pp, disableSystemAppVerificationForTests, providerFilter);
|
|
generator.addUserProviders(
|
|
getUserProviders(
|
|
context,
|
|
userId,
|
|
disableSystemAppVerificationForTests,
|
|
enabledServices,
|
|
primaryServices));
|
|
generator.addSystemProviders(
|
|
getAvailableSystemServices(
|
|
context, userId, disableSystemAppVerificationForTests, enabledServices));
|
|
return generator.getProviders();
|
|
}
|
|
|
|
/**
|
|
* Returns the valid credential provider services available for the user with the given {@code
|
|
* userId}. Includes test providers.
|
|
*/
|
|
@NonNull
|
|
public static List<CredentialProviderInfo> getCredentialProviderServicesForTesting(
|
|
@NonNull Context context,
|
|
int userId,
|
|
int providerFilter,
|
|
Set<ComponentName> enabledServices,
|
|
Set<ComponentName> primaryServices) {
|
|
requireNonNull(context, "context must not be null");
|
|
|
|
// Get the device policy. If the client has asked for all providers then we
|
|
// should ignore the device policy.
|
|
PackagePolicy pp =
|
|
providerFilter != CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN
|
|
? getDeviceManagerPolicy(context, userId)
|
|
: null;
|
|
|
|
// Generate the provider list.
|
|
final boolean disableSystemAppVerificationForTests = true;
|
|
ProviderGenerator generator =
|
|
new ProviderGenerator(
|
|
context, pp, disableSystemAppVerificationForTests, providerFilter);
|
|
generator.addUserProviders(
|
|
getUserProviders(
|
|
context,
|
|
userId,
|
|
disableSystemAppVerificationForTests,
|
|
enabledServices,
|
|
primaryServices));
|
|
generator.addSystemProviders(
|
|
getAvailableSystemServices(
|
|
context, userId, disableSystemAppVerificationForTests, enabledServices));
|
|
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
|
|
|| mProviderFilter
|
|
== CredentialManager
|
|
.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN;
|
|
}
|
|
}
|
|
|
|
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,
|
|
Set<ComponentName> enabledServices,
|
|
Set<ComponentName> primaryServices) {
|
|
final List<CredentialProviderInfo> services = new ArrayList<>();
|
|
final List<ResolveInfo> resolveInfos =
|
|
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;
|
|
if (serviceInfo == null) {
|
|
Slog.d(TAG, "No serviceInfo found for resolveInfo, so skipping provider");
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
CredentialProviderInfo cpi =
|
|
CredentialProviderInfoFactory.create(
|
|
context,
|
|
serviceInfo,
|
|
/* isSystemProvider= */ false,
|
|
disableSystemAppVerificationForTests,
|
|
enabledServices.contains(serviceInfo.getComponentName()),
|
|
primaryServices.contains(serviceInfo.getComponentName()));
|
|
if (!cpi.isSystemProvider()) {
|
|
services.add(cpi);
|
|
}
|
|
} catch (Exception e) {
|
|
Slog.e(TAG, "Error getting info for " + serviceInfo, e);
|
|
}
|
|
}
|
|
return services;
|
|
}
|
|
}
|