Merge "Move CredentialProviderInfo for test/settings (framework)" into udc-dev

This commit is contained in:
Becca Hughes
2023-03-07 22:40:46 +00:00
committed by Android (Google) Code Review
18 changed files with 537 additions and 385 deletions

View File

@@ -1072,6 +1072,40 @@ package android.content.rollback {
} }
package android.credentials {
public final class CredentialManager {
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.QUERY_ALL_PACKAGES, "android.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS"}) public java.util.List<android.credentials.CredentialProviderInfo> getCredentialProviderServicesForTesting(int);
method public static boolean isServiceEnabled(@NonNull android.content.Context);
field public static final int PROVIDER_FILTER_ALL_PROVIDERS = 0; // 0x0
field public static final int PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY = 1; // 0x1
field public static final int PROVIDER_FILTER_USER_PROVIDERS_ONLY = 2; // 0x2
}
public final class CredentialProviderInfo implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<java.lang.String> getCapabilities();
method @NonNull public android.content.ComponentName getComponentName();
method @Nullable public CharSequence getLabel(@NonNull android.content.Context);
method @Nullable public android.graphics.drawable.Drawable getServiceIcon(@NonNull android.content.Context);
method @NonNull public android.content.pm.ServiceInfo getServiceInfo();
method @NonNull public boolean hasCapability(@NonNull String);
method public boolean isEnabled();
method public boolean isSystemProvider();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.credentials.CredentialProviderInfo> CREATOR;
}
public static final class CredentialProviderInfo.Builder {
ctor public CredentialProviderInfo.Builder(@NonNull android.content.pm.ServiceInfo);
method @NonNull public android.credentials.CredentialProviderInfo.Builder addCapabilities(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.credentials.CredentialProviderInfo build();
method @NonNull public android.credentials.CredentialProviderInfo.Builder setEnabled(boolean);
method @NonNull public android.credentials.CredentialProviderInfo.Builder setSystemProvider(boolean);
}
}
package android.credentials.ui { package android.credentials.ui {
public final class AuthenticationEntry implements android.os.Parcelable { public final class AuthenticationEntry implements android.os.Parcelable {

View File

@@ -26,12 +26,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
import android.annotation.SystemService; import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.Activity; import android.app.Activity;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.IntentSender; import android.content.IntentSender;
import android.content.pm.ServiceInfo;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.ICancellationSignal; import android.os.ICancellationSignal;
import android.os.OutcomeReceiver; import android.os.OutcomeReceiver;
@@ -75,21 +75,21 @@ public final class CredentialManager {
* *
* @hide * @hide
*/ */
public static final int PROVIDER_FILTER_ALL_PROVIDERS = 0; @TestApi public static final int PROVIDER_FILTER_ALL_PROVIDERS = 0;
/** /**
* Returns system credential providers only. * Returns system credential providers only.
* *
* @hide * @hide
*/ */
public static final int PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY = 1; @TestApi public static final int PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY = 1;
/** /**
* Returns user credential providers only. * Returns user credential providers only.
* *
* @hide * @hide
*/ */
public static final int PROVIDER_FILTER_USER_PROVIDERS_ONLY = 2; @TestApi public static final int PROVIDER_FILTER_USER_PROVIDERS_ONLY = 2;
private final Context mContext; private final Context mContext;
private final ICredentialManager mService; private final ICredentialManager mService;
@@ -262,44 +262,6 @@ public final class CredentialManager {
} }
} }
/**
* Gets a list of all user configurable credential providers registered on the system. This API
* is intended for browsers and settings apps.
*
* @param cancellationSignal an optional signal that allows for cancelling this call
* @param executor the callback will take place on this {@link Executor}
* @param callback the callback invoked when the request succeeds or fails
* @hide
*/
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public void listEnabledProviders(
@Nullable CancellationSignal cancellationSignal,
@CallbackExecutor @NonNull Executor executor,
@NonNull
OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>
callback) {
requireNonNull(executor, "executor must not be null");
requireNonNull(callback, "callback must not be null");
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
Log.w(TAG, "listEnabledProviders already canceled");
return;
}
ICancellationSignal cancelRemote = null;
try {
cancelRemote =
mService.listEnabledProviders(
new ListEnabledProvidersTransport(executor, callback));
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
if (cancellationSignal != null && cancelRemote != null) {
cancellationSignal.setRemote(cancelRemote);
}
}
/** /**
* Sets a list of all user configurable credential providers registered on the system. This API * Sets a list of all user configurable credential providers registered on the system. This API
* is intended for settings apps. * is intended for settings apps.
@@ -348,36 +310,43 @@ public final class CredentialManager {
} }
/** /**
* Returns the list of ServiceInfo for all discovered credential providers on this device. * Returns the list of CredentialProviderInfo for all discovered credential providers on this
* device but will include test system providers as well.
* *
* @hide * @hide
*/ */
@NonNull @NonNull
@RequiresPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS) @TestApi
public List<ServiceInfo> getCredentialProviderServicesForTesting( @RequiresPermission(
@ProviderFilter int providerFilter) { anyOf = {
android.Manifest.permission.QUERY_ALL_PACKAGES,
android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS
})
public List<CredentialProviderInfo> getCredentialProviderServicesForTesting(
@ProviderFilter int providerFilter) {
try { try {
return mService.getCredentialProviderServices( return mService.getCredentialProviderServicesForTesting(providerFilter);
mContext.getUserId(),
/* disableSystemAppVerificationForTests= */ true,
providerFilter);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
} }
/** /**
* Returns the list of ServiceInfo for all discovered credential providers on this device. * Returns the list of CredentialProviderInfo for all discovered credential providers on this
* device.
* *
* @hide * @hide
*/ */
@NonNull @NonNull
@RequiresPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS) @RequiresPermission(
public List<ServiceInfo> getCredentialProviderServices( anyOf = {
android.Manifest.permission.QUERY_ALL_PACKAGES,
android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS
})
public List<CredentialProviderInfo> getCredentialProviderServices(
int userId, @ProviderFilter int providerFilter) { int userId, @ProviderFilter int providerFilter) {
try { try {
return mService.getCredentialProviderServices( return mService.getCredentialProviderServices(userId, providerFilter);
userId, /* disableSystemAppVerificationForTests= */ false, providerFilter);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
@@ -388,7 +357,9 @@ public final class CredentialManager {
* *
* @hide * @hide
*/ */
public static boolean isServiceEnabled(Context context) { @TestApi
public static boolean isServiceEnabled(@NonNull Context context) {
requireNonNull(context, "context must not be null");
if (context == null) { if (context == null) {
return false; return false;
} }
@@ -578,33 +549,6 @@ public final class CredentialManager {
} }
} }
private static class ListEnabledProvidersTransport extends IListEnabledProvidersCallback.Stub {
// TODO: listen for cancellation to release callback.
private final Executor mExecutor;
private final OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>
mCallback;
private ListEnabledProvidersTransport(
Executor executor,
OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>
callback) {
mExecutor = executor;
mCallback = callback;
}
@Override
public void onResponse(ListEnabledProvidersResponse response) {
mExecutor.execute(() -> mCallback.onResult(response));
}
@Override
public void onError(String errorType, String message) {
mExecutor.execute(
() -> mCallback.onError(new ListEnabledProvidersException(errorType, message)));
}
}
private static class SetEnabledProvidersTransport extends ISetEnabledProvidersCallback.Stub { private static class SetEnabledProvidersTransport extends ISetEnabledProvidersCallback.Stub {
// TODO: listen for cancellation to release callback. // TODO: listen for cancellation to release callback.

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2022 The Android Open Source Project * Copyright 2023 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,14 +16,4 @@
package android.credentials; package android.credentials;
import android.credentials.ListEnabledProvidersResponse; parcelable CredentialProviderInfo;
/**
* Listener for an listEnabledProviders request.
*
* @hide
*/
interface IListEnabledProvidersCallback {
oneway void onResponse(in ListEnabledProvidersResponse response);
oneway void onError(String errorType, String message);
}

View File

@@ -0,0 +1,215 @@
/*
* Copyright (C) 2023 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.credentials;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* {@link ServiceInfo} and meta-data about a credential provider.
*
* @hide
*/
@TestApi
public final class CredentialProviderInfo implements Parcelable {
@NonNull private final ServiceInfo mServiceInfo;
@NonNull private final List<String> mCapabilities = new ArrayList<>();
@Nullable private final CharSequence mOverrideLabel;
private final boolean mIsSystemProvider;
private final boolean mIsEnabled;
/**
* Constructs an information instance of the credential provider.
*
* @param builder the builder object.
*/
private CredentialProviderInfo(@NonNull Builder builder) {
mServiceInfo = builder.mServiceInfo;
mCapabilities.addAll(builder.mCapabilities);
mIsSystemProvider = builder.mIsSystemProvider;
mIsEnabled = builder.mIsEnabled;
mOverrideLabel = builder.mOverrideLabel;
}
/** Returns true if the service supports the given {@code credentialType}, false otherwise. */
@NonNull
public boolean hasCapability(@NonNull String credentialType) {
return mCapabilities.contains(credentialType);
}
/** Returns the service info. */
@NonNull
public ServiceInfo getServiceInfo() {
return mServiceInfo;
}
/** Returns whether it is a system provider. */
public boolean isSystemProvider() {
return mIsSystemProvider;
}
/** Returns the service icon. */
@Nullable
public Drawable getServiceIcon(@NonNull Context context) {
return mServiceInfo.loadIcon(context.getPackageManager());
}
/** Returns the service label. */
@Nullable
public CharSequence getLabel(@NonNull Context context) {
if (mOverrideLabel != null) {
return mOverrideLabel;
}
return mServiceInfo.loadSafeLabel(context.getPackageManager());
}
/** Returns a list of capabilities this provider service can support. */
@NonNull
public List<String> getCapabilities() {
return Collections.unmodifiableList(mCapabilities);
}
/** Returns whether the provider is enabled by the user. */
public boolean isEnabled() {
return mIsEnabled;
}
/** Returns the component name for the service. */
@NonNull
public ComponentName getComponentName() {
return mServiceInfo.getComponentName();
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedObject(mServiceInfo, flags);
dest.writeBoolean(mIsSystemProvider);
dest.writeStringList(mCapabilities);
dest.writeBoolean(mIsEnabled);
TextUtils.writeToParcel(mOverrideLabel, dest, flags);
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
return "CredentialProviderInfo {"
+ "serviceInfo="
+ mServiceInfo
+ ", "
+ "isSystemProvider="
+ mIsSystemProvider
+ ", "
+ "isEnabled="
+ mIsEnabled
+ ", "
+ "overrideLabel="
+ mOverrideLabel
+ ", "
+ "capabilities="
+ String.join(",", mCapabilities)
+ "}";
}
private CredentialProviderInfo(@NonNull Parcel in) {
mServiceInfo = in.readTypedObject(ServiceInfo.CREATOR);
mIsSystemProvider = in.readBoolean();
in.readStringList(mCapabilities);
mIsEnabled = in.readBoolean();
mOverrideLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
}
public static final @NonNull Parcelable.Creator<CredentialProviderInfo> CREATOR =
new Parcelable.Creator<CredentialProviderInfo>() {
@Override
public CredentialProviderInfo[] newArray(int size) {
return new CredentialProviderInfo[size];
}
@Override
public CredentialProviderInfo createFromParcel(@NonNull Parcel in) {
return new CredentialProviderInfo(in);
}
};
/** A builder for {@link CredentialProviderInfo} objects. */
public static final class Builder {
@NonNull private ServiceInfo mServiceInfo;
@NonNull private List<String> mCapabilities = new ArrayList<>();
private boolean mIsSystemProvider = false;
private boolean mIsEnabled = false;
@Nullable private CharSequence mOverrideLabel = null;
/**
* Creates a new builder.
*
* @param serviceInfo the service info of the credential provider service.
*/
public Builder(@NonNull ServiceInfo serviceInfo) {
mServiceInfo = serviceInfo;
}
/** Sets whether it is a system provider. */
public @NonNull Builder setSystemProvider(boolean isSystemProvider) {
mIsSystemProvider = isSystemProvider;
return this;
}
/**
* Sets the label to be used instead of getting from the system (for unit tests).
*
* @hide
*/
public @NonNull Builder setOverrideLabel(@NonNull CharSequence overrideLabel) {
mOverrideLabel = overrideLabel;
return this;
}
/** Sets a list of capabilities this provider service can support. */
public @NonNull Builder addCapabilities(@NonNull List<String> capabilities) {
mCapabilities.addAll(capabilities);
return this;
}
/** Sets whether it is enabled by the user. */
public @NonNull Builder setEnabled(boolean isEnabled) {
mIsEnabled = isEnabled;
return this;
}
/** Builds a new {@link CredentialProviderInfo} instance. */
public @NonNull CredentialProviderInfo build() {
return new CredentialProviderInfo(this);
}
}
}

View File

@@ -18,7 +18,7 @@ package android.credentials;
import java.util.List; import java.util.List;
import android.content.pm.ServiceInfo; import android.credentials.CredentialProviderInfo;
import android.credentials.ClearCredentialStateRequest; import android.credentials.ClearCredentialStateRequest;
import android.credentials.CreateCredentialRequest; import android.credentials.CreateCredentialRequest;
import android.credentials.GetCredentialRequest; import android.credentials.GetCredentialRequest;
@@ -27,7 +27,6 @@ import android.credentials.UnregisterCredentialDescriptionRequest;
import android.credentials.IClearCredentialStateCallback; import android.credentials.IClearCredentialStateCallback;
import android.credentials.ICreateCredentialCallback; import android.credentials.ICreateCredentialCallback;
import android.credentials.IGetCredentialCallback; import android.credentials.IGetCredentialCallback;
import android.credentials.IListEnabledProvidersCallback;
import android.credentials.ISetEnabledProvidersCallback; import android.credentials.ISetEnabledProvidersCallback;
import android.content.ComponentName; import android.content.ComponentName;
import android.os.ICancellationSignal; import android.os.ICancellationSignal;
@@ -45,8 +44,6 @@ interface ICredentialManager {
@nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage); @nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage);
@nullable ICancellationSignal listEnabledProviders(in IListEnabledProvidersCallback callback);
void setEnabledProviders(in List<String> providers, in int userId, in ISetEnabledProvidersCallback callback); void setEnabledProviders(in List<String> providers, in int userId, in ISetEnabledProvidersCallback callback);
void registerCredentialDescription(in RegisterCredentialDescriptionRequest request, String callingPackage); void registerCredentialDescription(in RegisterCredentialDescriptionRequest request, String callingPackage);
@@ -55,6 +52,8 @@ interface ICredentialManager {
boolean isEnabledCredentialProviderService(in ComponentName componentName, String callingPackage); boolean isEnabledCredentialProviderService(in ComponentName componentName, String callingPackage);
List<ServiceInfo> getCredentialProviderServices(in int userId, in boolean disableSystemAppVerificationForTests, in int providerFilter); List<CredentialProviderInfo> getCredentialProviderServices(in int userId, in int providerFilter);
List<CredentialProviderInfo> getCredentialProviderServicesForTesting(in int providerFilter);
} }

View File

@@ -34,40 +34,27 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.content.res.Resources; import android.content.res.Resources;
import android.credentials.CredentialManager; import android.credentials.CredentialManager;
import android.graphics.drawable.Drawable; import android.credentials.CredentialProviderInfo;
import android.os.Bundle; import android.os.Bundle;
import android.os.RemoteException; import android.os.RemoteException;
import android.text.TextUtils; import android.os.UserHandle;
import android.util.Log; import android.util.Log;
import android.util.Slog; import android.util.Slog;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* {@link ServiceInfo} and meta-data about a credential provider. * {@link CredentialProviderInfo} generator.
* *
* @hide * @hide
*/ */
public final class CredentialProviderInfo { public final class CredentialProviderInfoFactory {
private static final String TAG = "CredentialProviderInfo"; private static final String TAG = "CredentialProviderInfoFactory";
@NonNull
private final ServiceInfo mServiceInfo;
@NonNull
private final List<String> mCapabilities;
@NonNull
private final Context mContext;
@Nullable
private final Drawable mIcon;
@Nullable
private final CharSequence mLabel;
private final boolean mIsSystemProvider;
/** /**
* Constructs an information instance of the credential provider. * Constructs an information instance of the credential provider.
@@ -79,14 +66,18 @@ public final class CredentialProviderInfo {
* @throws PackageManager.NameNotFoundException If provider service is not found * @throws PackageManager.NameNotFoundException If provider service is not found
* @throws SecurityException If provider does not require the relevant permission * @throws SecurityException If provider does not require the relevant permission
*/ */
public CredentialProviderInfo(@NonNull Context context, public static CredentialProviderInfo create(
@NonNull ComponentName serviceComponent, int userId, boolean isSystemProvider) @NonNull Context context,
@NonNull ComponentName serviceComponent,
int userId,
boolean isSystemProvider)
throws PackageManager.NameNotFoundException { throws PackageManager.NameNotFoundException {
this( return create(
context, context,
getServiceInfoOrThrow(serviceComponent, userId), getServiceInfoOrThrow(serviceComponent, userId),
isSystemProvider, isSystemProvider,
/* disableSystemAppVerificationForTests= */ false); /* disableSystemAppVerificationForTests= */ false,
/* isEnabled= */ false);
} }
/** /**
@@ -98,13 +89,16 @@ public final class CredentialProviderInfo {
* @param isSystemProvider whether the provider app is a system provider * @param isSystemProvider whether the provider app is a system provider
* @param disableSystemAppVerificationForTests whether to disable system app permission * @param disableSystemAppVerificationForTests whether to disable system app permission
* verification so that tests can install system providers * 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 * @throws SecurityException If provider does not require the relevant permission
*/ */
public CredentialProviderInfo( public static CredentialProviderInfo create(
@NonNull Context context, @NonNull Context context,
@NonNull ServiceInfo serviceInfo, @NonNull ServiceInfo serviceInfo,
boolean isSystemProvider, boolean isSystemProvider,
boolean disableSystemAppVerificationForTests) { boolean disableSystemAppVerificationForTests,
boolean isEnabled)
throws SecurityException {
verifyProviderPermission(serviceInfo); verifyProviderPermission(serviceInfo);
if (isSystemProvider) { if (isSystemProvider) {
if (!isValidSystemProvider( if (!isValidSystemProvider(
@@ -114,23 +108,11 @@ public final class CredentialProviderInfo {
"Provider is not a valid system provider: " + serviceInfo); "Provider is not a valid system provider: " + serviceInfo);
} }
} }
mIsSystemProvider = isSystemProvider;
mContext = requireNonNull(context, "context must not be null"); return populateMetadata(context, serviceInfo)
mServiceInfo = requireNonNull(serviceInfo, "serviceInfo must not be null"); .setSystemProvider(isSystemProvider)
mCapabilities = new ArrayList<>(); .setEnabled(isEnabled)
mIcon = mServiceInfo.loadIcon(mContext.getPackageManager()); .build();
mLabel =
mServiceInfo.loadSafeLabel(
mContext.getPackageManager(),
0 /* do not ellipsize */,
TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM);
Log.i(
TAG,
"mLabel is : "
+ mLabel
+ ", for: "
+ mServiceInfo.getComponentName().flattenToString());
populateProviderCapabilities(context, serviceInfo);
} }
private static void verifyProviderPermission(ServiceInfo serviceInfo) throws SecurityException { private static void verifyProviderPermission(ServiceInfo serviceInfo) throws SecurityException {
@@ -138,19 +120,14 @@ public final class CredentialProviderInfo {
if (permission.equals(serviceInfo.permission)) { if (permission.equals(serviceInfo.permission)) {
return; return;
} }
Slog.e(
TAG,
"Credential Provider Service from : "
+ serviceInfo.packageName
+ "does not require permission"
+ permission);
throw new SecurityException( throw new SecurityException(
"Service does not require the expected permission : " + permission); "Service does not require the expected permission : " + permission);
} }
private static boolean isSystemProviderWithValidPermission( private static boolean isSystemProviderWithValidPermission(
ServiceInfo serviceInfo, Context context) { ServiceInfo serviceInfo, Context context) {
requireNonNull(context, "context must not be null");
final String permission = Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE; final String permission = Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE;
try { try {
ApplicationInfo appInfo = ApplicationInfo appInfo =
@@ -177,67 +154,88 @@ public final class CredentialProviderInfo {
Context context, Context context,
ServiceInfo serviceInfo, ServiceInfo serviceInfo,
boolean disableSystemAppVerificationForTests) { boolean disableSystemAppVerificationForTests) {
boolean isValidSystemTestProvider = requireNonNull(context, "context must not be null");
isTestSystemProvider(serviceInfo, disableSystemAppVerificationForTests);
if (isValidSystemTestProvider) { if (disableSystemAppVerificationForTests) {
return true; Bundle metadata = serviceInfo.metaData;
if (metadata == null) {
Slog.e(TAG, "isValidSystemProvider - metadata is null: " + serviceInfo);
return false;
}
return metadata.getBoolean(
CredentialProviderService.TEST_SYSTEM_PROVIDER_META_DATA_KEY);
} }
return isSystemProviderWithValidPermission(serviceInfo, context); return isSystemProviderWithValidPermission(serviceInfo, context);
} }
private static boolean isTestSystemProvider( private static CredentialProviderInfo.Builder populateMetadata(
ServiceInfo serviceInfo, boolean disableSystemAppVerificationForTests) { @NonNull Context context, ServiceInfo serviceInfo) {
if (!disableSystemAppVerificationForTests) { requireNonNull(context, "context must not be null");
return false;
}
Bundle metadata = serviceInfo.metaData; final CredentialProviderInfo.Builder builder =
if (metadata == null) { new CredentialProviderInfo.Builder(serviceInfo);
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(); final PackageManager pm = context.getPackageManager();
// 1. Get the metadata for the service.
final Bundle metadata = serviceInfo.metaData;
if (metadata == null) {
Log.i(TAG, "populateMetadata - metadata is null");
return builder;
}
// 2. Extract the capabilities from the bundle.
try { try {
Bundle metadata = serviceInfo.metaData;
Resources resources = pm.getResourcesForApplication(serviceInfo.applicationInfo); Resources resources = pm.getResourcesForApplication(serviceInfo.applicationInfo);
if (metadata == null || resources == null) { if (metadata == null || resources == null) {
Log.i(TAG, "populateProviderCapabilities - metadata or resources is null"); Log.i(TAG, "populateMetadata - resources is null");
return; return builder;
} }
String[] capabilities = resources.getStringArray(metadata.getInt( builder.addCapabilities(populateProviderCapabilities(resources, metadata, serviceInfo));
CredentialProviderService.CAPABILITY_META_DATA_KEY));
if (capabilities == null || capabilities.length == 0) {
Slog.i(TAG, "No capabilities found for provider:" + serviceInfo.packageName);
return;
}
for (String capability : capabilities) {
if (capability.isEmpty()) {
Slog.i(TAG, "Skipping empty capability");
continue;
}
Slog.i(TAG, "Capabilities found for provider: " + capability);
mCapabilities.add(capability);
}
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, e.getMessage()); Slog.e(TAG, e.getMessage());
} catch (Resources.NotFoundException e) {
Slog.e(TAG, e.getMessage());
} }
return builder;
} }
private static ServiceInfo getServiceInfoOrThrow(@NonNull ComponentName serviceComponent, private static List<String> populateProviderCapabilities(
int userId) throws PackageManager.NameNotFoundException { Resources resources, Bundle metadata, ServiceInfo serviceInfo) {
List<String> output = new ArrayList<>();
String[] capabilities = new String[0];
try { try {
ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo( capabilities =
serviceComponent, resources.getStringArray(
PackageManager.GET_META_DATA, metadata.getInt(CredentialProviderService.CAPABILITY_META_DATA_KEY));
userId); } catch (Resources.NotFoundException e) {
Slog.e(TAG, "Failed to get capabilities: " + e.getMessage());
}
if (capabilities == null || capabilities.length == 0) {
Slog.e(TAG, "No capabilities found for provider:" + serviceInfo.packageName);
return output;
}
for (String capability : capabilities) {
if (capability.isEmpty()) {
Slog.e(TAG, "Skipping empty capability");
continue;
}
Slog.e(TAG, "Capabilities found for provider: " + capability);
output.add(capability);
}
return output;
}
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) { if (si != null) {
return si; return si;
} }
@@ -256,6 +254,8 @@ public final class CredentialProviderInfo {
@NonNull Context context, @NonNull Context context,
@UserIdInt int userId, @UserIdInt int userId,
boolean disableSystemAppVerificationForTests) { boolean disableSystemAppVerificationForTests) {
requireNonNull(context, "context must not be null");
final List<ServiceInfo> services = new ArrayList<>(); final List<ServiceInfo> services = new ArrayList<>();
final List<ResolveInfo> resolveInfos = new ArrayList<>(); final List<ResolveInfo> resolveInfos = new ArrayList<>();
@@ -268,15 +268,20 @@ public final class CredentialProviderInfo {
for (ResolveInfo resolveInfo : resolveInfos) { for (ResolveInfo resolveInfo : resolveInfos) {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo; final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
if (disableSystemAppVerificationForTests) {
if (serviceInfo != null) {
services.add(serviceInfo);
}
continue;
}
try { try {
PackageManager.ApplicationInfoFlags appInfoFlags =
disableSystemAppVerificationForTests
? PackageManager.ApplicationInfoFlags.of(0)
: PackageManager.ApplicationInfoFlags.of(
PackageManager.MATCH_SYSTEM_ONLY);
ApplicationInfo appInfo = ApplicationInfo appInfo =
context.getPackageManager() context.getPackageManager()
.getApplicationInfo(serviceInfo.packageName, appInfoFlags); .getApplicationInfo(
serviceInfo.packageName,
PackageManager.ApplicationInfoFlags.of(
PackageManager.MATCH_SYSTEM_ONLY));
if (appInfo == null || serviceInfo == null) { if (appInfo == null || serviceInfo == null) {
continue; continue;
@@ -300,19 +305,22 @@ public final class CredentialProviderInfo {
public static List<CredentialProviderInfo> getAvailableSystemServices( public static List<CredentialProviderInfo> getAvailableSystemServices(
@NonNull Context context, @NonNull Context context,
@UserIdInt int userId, @UserIdInt int userId,
boolean disableSystemAppVerificationForTests) { boolean disableSystemAppVerificationForTests,
Set<ServiceInfo> enabledServices) {
requireNonNull(context, "context must not be null"); requireNonNull(context, "context must not be null");
final List<CredentialProviderInfo> providerInfos = new ArrayList<>(); final List<CredentialProviderInfo> providerInfos = new ArrayList<>();
for (ServiceInfo si : for (ServiceInfo si :
getAvailableSystemServiceInfos( getAvailableSystemServiceInfos(
context, userId, disableSystemAppVerificationForTests)) { context, userId, disableSystemAppVerificationForTests)) {
try { try {
CredentialProviderInfo cpi = CredentialProviderInfo cpi =
new CredentialProviderInfo( CredentialProviderInfoFactory.create(
context, context,
si, si,
/* isSystemProvider= */ true, /* isSystemProvider= */ true,
disableSystemAppVerificationForTests); disableSystemAppVerificationForTests,
enabledServices.contains(si));
if (cpi.isSystemProvider()) { if (cpi.isSystemProvider()) {
providerInfos.add(cpi); providerInfos.add(cpi);
} else { } else {
@@ -325,45 +333,12 @@ public final class CredentialProviderInfo {
return providerInfos; return providerInfos;
} }
/** private static @Nullable PackagePolicy getDeviceManagerPolicy(
* Returns true if the service supports the given {@code credentialType}, false otherwise. @NonNull Context context, int userId) {
*/ Context newContext = context.createContextAsUser(UserHandle.of(userId), 0);
@NonNull
public boolean hasCapability(@NonNull String credentialType) {
return mCapabilities.contains(credentialType);
}
/** Returns the service info. */
@NonNull
public ServiceInfo getServiceInfo() {
return mServiceInfo;
}
public boolean isSystemProvider() {
return mIsSystemProvider;
}
/** Returns the service icon. */
@Nullable
public Drawable getServiceIcon() {
return mIcon;
}
/** Returns the service label. */
@Nullable
public CharSequence getServiceLabel() {
return mLabel;
}
/** Returns an immutable list of capabilities this provider service can support. */
@NonNull
public List<String> getCapabilities() {
return Collections.unmodifiableList(mCapabilities);
}
private static @Nullable PackagePolicy getDeviceManagerPolicy(@NonNull Context context) {
try { try {
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); DevicePolicyManager dpm = newContext.getSystemService(DevicePolicyManager.class);
return dpm.getCredentialManagerPolicy(); return dpm.getCredentialManagerPolicy();
} catch (SecurityException e) { } catch (SecurityException e) {
// If the current user is not enrolled in DPM then this can throw a security error. // If the current user is not enrolled in DPM then this can throw a security error.
@@ -381,21 +356,53 @@ public final class CredentialProviderInfo {
public static List<CredentialProviderInfo> getCredentialProviderServices( public static List<CredentialProviderInfo> getCredentialProviderServices(
@NonNull Context context, @NonNull Context context,
int userId, int userId,
boolean disableSystemAppVerificationForTests, int providerFilter,
int providerFilter) { Set<ServiceInfo> enabledServices) {
requireNonNull(context, "context must not be null"); requireNonNull(context, "context must not be null");
// Get the device policy. // Get the device policy.
PackagePolicy pp = getDeviceManagerPolicy(context); PackagePolicy pp = getDeviceManagerPolicy(context, userId);
// Generate the provider list. // Generate the provider list.
final boolean disableSystemAppVerificationForTests = false;
ProviderGenerator generator = ProviderGenerator generator =
new ProviderGenerator( new ProviderGenerator(
context, pp, disableSystemAppVerificationForTests, providerFilter); context, pp, disableSystemAppVerificationForTests, providerFilter);
generator.addUserProviders( generator.addUserProviders(
getUserProviders(context, userId, disableSystemAppVerificationForTests)); getUserProviders(
context, userId, disableSystemAppVerificationForTests, enabledServices));
generator.addSystemProviders( generator.addSystemProviders(
getAvailableSystemServices(context, userId, disableSystemAppVerificationForTests)); 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<ServiceInfo> enabledServices) {
requireNonNull(context, "context must not be null");
// Get the device policy.
PackagePolicy pp = getDeviceManagerPolicy(context, userId);
// Generate the provider list.
final boolean disableSystemAppVerificationForTests = true;
ProviderGenerator generator =
new ProviderGenerator(
context, pp, disableSystemAppVerificationForTests, providerFilter);
generator.addUserProviders(
getUserProviders(
context, userId, disableSystemAppVerificationForTests, enabledServices));
generator.addSystemProviders(
getAvailableSystemServices(
context, userId, disableSystemAppVerificationForTests, enabledServices));
return generator.getProviders(); return generator.getProviders();
} }
@@ -484,7 +491,8 @@ public final class CredentialProviderInfo {
private static List<CredentialProviderInfo> getUserProviders( private static List<CredentialProviderInfo> getUserProviders(
@NonNull Context context, @NonNull Context context,
@UserIdInt int userId, @UserIdInt int userId,
boolean disableSystemAppVerificationForTests) { boolean disableSystemAppVerificationForTests,
Set<ServiceInfo> enabledServices) {
final List<CredentialProviderInfo> services = new ArrayList<>(); final List<CredentialProviderInfo> services = new ArrayList<>();
final List<ResolveInfo> resolveInfos = final List<ResolveInfo> resolveInfos =
context.getPackageManager() context.getPackageManager()
@@ -496,11 +504,12 @@ public final class CredentialProviderInfo {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo; final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
try { try {
CredentialProviderInfo cpi = CredentialProviderInfo cpi =
new CredentialProviderInfo( CredentialProviderInfoFactory.create(
context, context,
serviceInfo, serviceInfo,
/* isSystemProvider= */ false, /* isSystemProvider= */ false,
disableSystemAppVerificationForTests); disableSystemAppVerificationForTests,
enabledServices.contains(serviceInfo));
if (!cpi.isSystemProvider()) { if (!cpi.isSystemProvider()) {
services.add(cpi); services.add(cpi);
} }

View File

@@ -30,6 +30,7 @@ import static org.mockito.Mockito.when;
import android.app.Activity; import android.app.Activity;
import android.app.slice.Slice; import android.app.slice.Slice;
import android.content.Context; import android.content.Context;
import android.content.pm.ServiceInfo;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.CancellationSignal; import android.os.CancellationSignal;
@@ -47,6 +48,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -59,6 +61,17 @@ public class CredentialManagerTest {
@Mock @Mock
private Activity mMockActivity; private Activity mMockActivity;
private static final int TEST_USER_ID = 1;
private static final CredentialProviderInfo TEST_CREDENTIAL_PROVIDER_INFO =
new CredentialProviderInfo.Builder(new ServiceInfo())
.setSystemProvider(true)
.setOverrideLabel("test")
.addCapabilities(Arrays.asList("passkey"))
.setEnabled(true)
.build();
private static final List<CredentialProviderInfo> TEST_CREDENTIAL_PROVIDER_INFO_LIST =
Arrays.asList(TEST_CREDENTIAL_PROVIDER_INFO);
private GetCredentialRequest mGetRequest; private GetCredentialRequest mGetRequest;
private CreateCredentialRequest mCreateRequest; private CreateCredentialRequest mCreateRequest;
@@ -438,95 +451,53 @@ public class CredentialManagerTest {
} }
@Test @Test
public void testListEnabledProviders_nullExecutor() { public void testGetCredentialProviderServices_allProviders() throws RemoteException {
assertThrows(NullPointerException.class, verifyGetCredentialProviderServices(CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS);
() -> mCredentialManager.listEnabledProviders(null, null, result -> {
}));
} }
@Test @Test
public void testListEnabledProviders_nullCallback() { public void testGetCredentialProviderServices_userProviders() throws RemoteException {
assertThrows(NullPointerException.class, verifyGetCredentialProviderServices(CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
() -> mCredentialManager.listEnabledProviders(null, mExecutor, null));
} }
@Test @Test
public void testListEnabledProviders_alreadyCancelled() throws RemoteException { public void testGetCredentialProviderServices_systemProviders() throws RemoteException {
final CancellationSignal cancellation = new CancellationSignal(); verifyGetCredentialProviderServices(CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY);
cancellation.cancel();
mCredentialManager.listEnabledProviders(cancellation, mExecutor, result -> {
});
verify(mMockCredentialManagerService, never()).listEnabledProviders(any());
} }
@Test @Test
public void testListEnabledProviders_cancel() throws RemoteException { public void testGetCredentialProviderServicesForTesting_allProviders() throws RemoteException {
final ICancellationSignal serviceSignal = mock(ICancellationSignal.class); verifyGetCredentialProviderServicesForTesting(CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS);
final CancellationSignal cancellation = new CancellationSignal();
OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException> callback =
mock(OutcomeReceiver.class);
when(mMockCredentialManagerService.listEnabledProviders(any())).thenReturn(serviceSignal);
mCredentialManager.listEnabledProviders(cancellation, mExecutor, callback);
verify(mMockCredentialManagerService).listEnabledProviders(any());
cancellation.cancel();
verify(serviceSignal).cancel();
} }
@Test @Test
public void testListEnabledProviders_failed() throws RemoteException { public void testGetCredentialProviderServicesForTesting_userProviders() throws RemoteException {
ArgumentCaptor<IListEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass( verifyGetCredentialProviderServicesForTesting(CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
IListEnabledProvidersCallback.class);
ArgumentCaptor<ListEnabledProvidersException> errorCaptor = ArgumentCaptor.forClass(
ListEnabledProvidersException.class);
OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException> callback =
mock(OutcomeReceiver.class);
when(mMockCredentialManagerService.listEnabledProviders(
callbackCaptor.capture())).thenReturn(mock(ICancellationSignal.class));
mCredentialManager.listEnabledProviders(null, mExecutor, callback);
verify(mMockCredentialManagerService).listEnabledProviders(any());
final String errorType = "type";
callbackCaptor.getValue().onError("type", "unknown error");
verify(callback).onError(errorCaptor.capture());
assertThat(errorCaptor.getValue().getType()).isEqualTo(errorType);
} }
@Test @Test
public void testListEnabledProviders_success() throws RemoteException { public void testGetCredentialProviderServicesForTesting_systemProviders() throws RemoteException {
ListEnabledProvidersResponse response = ListEnabledProvidersResponse.create( verifyGetCredentialProviderServicesForTesting(CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY);
List.of("foo", "bar", "baz")); }
OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException> callback = private void verifyGetCredentialProviderServices(int testFilter) throws RemoteException {
mock(OutcomeReceiver.class); when(mMockCredentialManagerService.getCredentialProviderServices(
TEST_USER_ID, testFilter)).thenReturn(TEST_CREDENTIAL_PROVIDER_INFO_LIST);
ArgumentCaptor<IListEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass( List<CredentialProviderInfo> output =
IListEnabledProvidersCallback.class); mCredentialManager.getCredentialProviderServices(TEST_USER_ID, testFilter);
ArgumentCaptor<ListEnabledProvidersResponse> responseCaptor = ArgumentCaptor.forClass(
ListEnabledProvidersResponse.class);
when(mMockCredentialManagerService.listEnabledProviders( assertThat(output).containsExactlyElementsIn(TEST_CREDENTIAL_PROVIDER_INFO_LIST);
callbackCaptor.capture())).thenReturn(mock(ICancellationSignal.class)); }
mCredentialManager.listEnabledProviders(null, mExecutor, callback);
verify(mMockCredentialManagerService).listEnabledProviders(any()); private void verifyGetCredentialProviderServicesForTesting(int testFilter) throws RemoteException {
when(mMockCredentialManagerService.getCredentialProviderServicesForTesting(
testFilter)).thenReturn(TEST_CREDENTIAL_PROVIDER_INFO_LIST);
callbackCaptor.getValue().onResponse(response); List<CredentialProviderInfo> output =
mCredentialManager.getCredentialProviderServicesForTesting(testFilter);
verify(callback).onResult(responseCaptor.capture()); assertThat(output).containsExactlyElementsIn(TEST_CREDENTIAL_PROVIDER_INFO_LIST);
assertThat(responseCaptor.getValue().getProviderComponentNames()).containsExactlyElementsIn(
response.getProviderComponentNames());
} }
@Test @Test

View File

@@ -20,13 +20,13 @@ import android.annotation.Nullable;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.credentials.ClearCredentialStateRequest; import android.credentials.ClearCredentialStateRequest;
import android.credentials.CredentialProviderInfo;
import android.credentials.IClearCredentialStateCallback; import android.credentials.IClearCredentialStateCallback;
import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderData;
import android.credentials.ui.RequestInfo; import android.credentials.ui.RequestInfo;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.RemoteException; import android.os.RemoteException;
import android.service.credentials.CallingAppInfo; import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialProviderInfo;
import android.util.Log; import android.util.Log;
import com.android.server.credentials.metrics.ApiName; import com.android.server.credentials.metrics.ApiName;

View File

@@ -24,13 +24,13 @@ import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialRequest; import android.credentials.CreateCredentialRequest;
import android.credentials.CreateCredentialResponse; import android.credentials.CreateCredentialResponse;
import android.credentials.CredentialManager; import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
import android.credentials.ICreateCredentialCallback; import android.credentials.ICreateCredentialCallback;
import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderData;
import android.credentials.ui.RequestInfo; import android.credentials.ui.RequestInfo;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.RemoteException; import android.os.RemoteException;
import android.service.credentials.CallingAppInfo; import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialProviderInfo;
import android.util.Log; import android.util.Log;
import com.android.server.credentials.metrics.ApiName; import com.android.server.credentials.metrics.ApiName;

View File

@@ -36,15 +36,14 @@ import android.credentials.CreateCredentialRequest;
import android.credentials.CredentialDescription; import android.credentials.CredentialDescription;
import android.credentials.CredentialManager; import android.credentials.CredentialManager;
import android.credentials.CredentialOption; import android.credentials.CredentialOption;
import android.credentials.CredentialProviderInfo;
import android.credentials.GetCredentialException; import android.credentials.GetCredentialException;
import android.credentials.GetCredentialRequest; import android.credentials.GetCredentialRequest;
import android.credentials.IClearCredentialStateCallback; import android.credentials.IClearCredentialStateCallback;
import android.credentials.ICreateCredentialCallback; import android.credentials.ICreateCredentialCallback;
import android.credentials.ICredentialManager; import android.credentials.ICredentialManager;
import android.credentials.IGetCredentialCallback; import android.credentials.IGetCredentialCallback;
import android.credentials.IListEnabledProvidersCallback;
import android.credentials.ISetEnabledProvidersCallback; import android.credentials.ISetEnabledProvidersCallback;
import android.credentials.ListEnabledProvidersResponse;
import android.credentials.RegisterCredentialDescriptionRequest; import android.credentials.RegisterCredentialDescriptionRequest;
import android.credentials.UnregisterCredentialDescriptionRequest; import android.credentials.UnregisterCredentialDescriptionRequest;
import android.credentials.ui.IntentFactory; import android.credentials.ui.IntentFactory;
@@ -56,7 +55,7 @@ import android.os.UserHandle;
import android.provider.DeviceConfig; import android.provider.DeviceConfig;
import android.provider.Settings; import android.provider.Settings;
import android.service.credentials.CallingAppInfo; import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialProviderInfo; import android.service.credentials.CredentialProviderInfoFactory;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@@ -118,10 +117,11 @@ public final class CredentialManagerService
int resolvedUserId) { int resolvedUserId) {
List<CredentialManagerServiceImpl> services = new ArrayList<>(); List<CredentialManagerServiceImpl> services = new ArrayList<>();
List<CredentialProviderInfo> serviceInfos = List<CredentialProviderInfo> serviceInfos =
CredentialProviderInfo.getAvailableSystemServices( CredentialProviderInfoFactory.getAvailableSystemServices(
mContext, mContext,
resolvedUserId, resolvedUserId,
/* disableSystemAppVerificationForTests= */ false); /* disableSystemAppVerificationForTests= */ false,
new HashSet<>());
serviceInfos.forEach( serviceInfos.forEach(
info -> { info -> {
services.add( services.add(
@@ -222,10 +222,16 @@ public final class CredentialManagerService
return hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS); return hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS);
} }
private void verifyPermission(String permission) throws SecurityException { private void verifyGetProvidersPermission() throws SecurityException {
if (!hasPermission(permission)) { if (hasPermission(android.Manifest.permission.QUERY_ALL_PACKAGES)) {
throw new SecurityException("Caller is missing permission: " + permission); return;
} }
if (hasPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS)) {
return;
}
throw new SecurityException("Caller is missing permission: QUERY_ALL_PACKAGES or LIST_ENABLED_CREDENTIAL_PROVIDERS");
} }
private boolean hasPermission(String permission) { private boolean hasPermission(String permission) {
@@ -550,40 +556,6 @@ public final class CredentialManagerService
providerSessions.forEach(ProviderSession::invokeSession); providerSessions.forEach(ProviderSession::invokeSession);
} }
@SuppressWarnings("GuardedBy") // ErrorProne requires listEnabledProviders
// to be guarded by 'service.mLock', which is the same as mLock.
@Override
public ICancellationSignal listEnabledProviders(IListEnabledProvidersCallback callback) {
Log.i(TAG, "listEnabledProviders");
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
if (!hasWriteSecureSettingsPermission()) {
try {
callback.onError(
PERMISSION_DENIED_ERROR, PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR);
} catch (RemoteException e) {
Log.e(TAG, "Issue with invoking response: " + e.getMessage());
}
return cancelTransport;
}
List<String> enabledProviders = new ArrayList<>();
runForUser(
(service) -> {
enabledProviders.add(service.getComponentName().flattenToString());
});
// Call the callback.
try {
callback.onResponse(ListEnabledProvidersResponse.create(enabledProviders));
} catch (RemoteException e) {
Log.i(TAG, "Issue with invoking response: " + e.getMessage());
// TODO: Propagate failure
}
return cancelTransport;
}
@Override @Override
public void setEnabledProviders( public void setEnabledProviders(
List<String> providers, int userId, ISetEnabledProvidersCallback callback) { List<String> providers, int userId, ISetEnabledProvidersCallback callback) {
@@ -677,20 +649,35 @@ public final class CredentialManagerService
} }
@Override @Override
public List<ServiceInfo> getCredentialProviderServices( public List<CredentialProviderInfo> getCredentialProviderServices(
int userId, boolean disableSystemAppVerificationForTests, int providerFilter) { int userId, int providerFilter) {
Log.i(TAG, "getCredentialProviderServices"); Log.i(TAG, "getCredentialProviderServices");
verifyPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS); verifyGetProvidersPermission();
List<ServiceInfo> services = new ArrayList<>(); return CredentialProviderInfoFactory.getCredentialProviderServices(
List<CredentialProviderInfo> providers = mContext, userId, providerFilter, getEnabledProviders());
CredentialProviderInfo.getCredentialProviderServices( }
mContext, userId, disableSystemAppVerificationForTests, providerFilter);
for (CredentialProviderInfo p : providers) { @Override
services.add(p.getServiceInfo()); public List<CredentialProviderInfo> getCredentialProviderServicesForTesting(
int providerFilter) {
Log.i(TAG, "getCredentialProviderServicesForTesting");
verifyGetProvidersPermission();
final int userId = UserHandle.getCallingUserId();
return CredentialProviderInfoFactory.getCredentialProviderServicesForTesting(
mContext, userId, providerFilter, getEnabledProviders());
}
private Set<ServiceInfo> getEnabledProviders() {
Set<ServiceInfo> enabledProviders = new HashSet<>();
synchronized (mLock) {
runForUser(
(service) -> {
enabledProviders.add(service.getCredentialProviderInfo().getServiceInfo());
});
} }
return enabledProviders;
return services;
} }
@Override @Override
@@ -828,11 +815,11 @@ public final class CredentialManagerService
} }
private List<CredentialProviderInfo> getServicesForCredentialDescription(int userId) { private List<CredentialProviderInfo> getServicesForCredentialDescription(int userId) {
return CredentialProviderInfo.getCredentialProviderServices( return CredentialProviderInfoFactory.getCredentialProviderServices(
mContext, mContext,
userId, userId,
/* disableSystemAppVerificationForTests= */ false, CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS,
CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS); new HashSet<>());
} }
} }

View File

@@ -21,7 +21,8 @@ import android.annotation.Nullable;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.service.credentials.CredentialProviderInfo; import android.credentials.CredentialProviderInfo;
import android.service.credentials.CredentialProviderInfoFactory;
import android.util.Log; import android.util.Log;
import android.util.Slog; import android.util.Slog;
@@ -82,7 +83,7 @@ public final class CredentialManagerServiceImpl extends
Log.i(TAG, "newServiceInfoLocked with null mInfo , " Log.i(TAG, "newServiceInfoLocked with null mInfo , "
+ serviceComponent.getPackageName()); + serviceComponent.getPackageName());
} }
mInfo = new CredentialProviderInfo( mInfo = CredentialProviderInfoFactory.create(
getContext(), serviceComponent, getContext(), serviceComponent,
mUserId, /*isSystemProvider=*/false); mUserId, /*isSystemProvider=*/false);
return mInfo.getServiceInfo(); return mInfo.getServiceInfo();

View File

@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.credentials.CredentialManager; import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
import android.credentials.ui.DisabledProviderData; import android.credentials.ui.DisabledProviderData;
import android.credentials.ui.IntentFactory; import android.credentials.ui.IntentFactory;
import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderData;
@@ -31,11 +32,12 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.ResultReceiver; import android.os.ResultReceiver;
import android.service.credentials.CredentialProviderInfo; import android.service.credentials.CredentialProviderInfoFactory;
import android.util.Log; import android.util.Log;
import android.util.Slog; import android.util.Slog;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -118,11 +120,11 @@ public class CredentialManagerUi {
.map(ProviderData::getProviderFlattenedComponentName) .map(ProviderData::getProviderFlattenedComponentName)
.collect(Collectors.toUnmodifiableSet()); .collect(Collectors.toUnmodifiableSet());
Set<String> allProviders = Set<String> allProviders =
CredentialProviderInfo.getCredentialProviderServices( CredentialProviderInfoFactory.getCredentialProviderServices(
mContext, mContext,
mUserId, mUserId,
/* disableSystemAppVerificationForTests= */ false, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY,
CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY) new HashSet<>())
.stream() .stream()
.map(CredentialProviderInfo::getServiceInfo) .map(CredentialProviderInfo::getServiceInfo)
.map(ServiceInfo::getComponentName) .map(ServiceInfo::getComponentName)

View File

@@ -19,6 +19,7 @@ package com.android.server.credentials;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.credentials.CredentialProviderInfo;
import android.credentials.GetCredentialException; import android.credentials.GetCredentialException;
import android.credentials.GetCredentialRequest; import android.credentials.GetCredentialRequest;
import android.credentials.GetCredentialResponse; import android.credentials.GetCredentialResponse;
@@ -28,7 +29,6 @@ import android.credentials.ui.RequestInfo;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.RemoteException; import android.os.RemoteException;
import android.service.credentials.CallingAppInfo; import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialProviderInfo;
import android.util.Log; import android.util.Log;
import com.android.server.credentials.metrics.ApiName; import com.android.server.credentials.metrics.ApiName;

View File

@@ -20,11 +20,11 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt; import android.annotation.UserIdInt;
import android.content.Context; import android.content.Context;
import android.credentials.ClearCredentialStateException; import android.credentials.ClearCredentialStateException;
import android.credentials.CredentialProviderInfo;
import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderData;
import android.credentials.ui.ProviderPendingIntentResponse; import android.credentials.ui.ProviderPendingIntentResponse;
import android.service.credentials.CallingAppInfo; import android.service.credentials.CallingAppInfo;
import android.service.credentials.ClearCredentialStateRequest; import android.service.credentials.ClearCredentialStateRequest;
import android.service.credentials.CredentialProviderInfo;
import android.util.Log; import android.util.Log;
import android.util.Slog; import android.util.Slog;

View File

@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.credentials.CreateCredentialException; import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialResponse; import android.credentials.CreateCredentialResponse;
import android.credentials.CredentialProviderInfo;
import android.credentials.ui.CreateCredentialProviderData; import android.credentials.ui.CreateCredentialProviderData;
import android.credentials.ui.Entry; import android.credentials.ui.Entry;
import android.credentials.ui.ProviderPendingIntentResponse; import android.credentials.ui.ProviderPendingIntentResponse;
@@ -33,7 +34,6 @@ import android.service.credentials.BeginCreateCredentialResponse;
import android.service.credentials.CallingAppInfo; import android.service.credentials.CallingAppInfo;
import android.service.credentials.CreateCredentialRequest; import android.service.credentials.CreateCredentialRequest;
import android.service.credentials.CreateEntry; import android.service.credentials.CreateEntry;
import android.service.credentials.CredentialProviderInfo;
import android.service.credentials.CredentialProviderService; import android.service.credentials.CredentialProviderService;
import android.service.credentials.RemoteEntry; import android.service.credentials.RemoteEntry;
import android.util.Log; import android.util.Log;

View File

@@ -23,6 +23,7 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.credentials.CredentialOption; import android.credentials.CredentialOption;
import android.credentials.CredentialProviderInfo;
import android.credentials.GetCredentialException; import android.credentials.GetCredentialException;
import android.credentials.GetCredentialResponse; import android.credentials.GetCredentialResponse;
import android.credentials.ui.AuthenticationEntry; import android.credentials.ui.AuthenticationEntry;
@@ -35,7 +36,6 @@ import android.service.credentials.BeginGetCredentialRequest;
import android.service.credentials.BeginGetCredentialResponse; import android.service.credentials.BeginGetCredentialResponse;
import android.service.credentials.CallingAppInfo; import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialEntry; import android.service.credentials.CredentialEntry;
import android.service.credentials.CredentialProviderInfo;
import android.service.credentials.CredentialProviderService; import android.service.credentials.CredentialProviderService;
import android.service.credentials.GetCredentialRequest; import android.service.credentials.GetCredentialRequest;
import android.service.credentials.RemoteEntry; import android.service.credentials.RemoteEntry;

View File

@@ -24,11 +24,11 @@ import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.credentials.Credential; import android.credentials.Credential;
import android.credentials.CredentialProviderInfo;
import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderData;
import android.credentials.ui.ProviderPendingIntentResponse; import android.credentials.ui.ProviderPendingIntentResponse;
import android.os.ICancellationSignal; import android.os.ICancellationSignal;
import android.os.RemoteException; import android.os.RemoteException;
import android.service.credentials.CredentialProviderInfo;
import android.util.Log; import android.util.Log;
import com.android.server.credentials.metrics.CandidateProviderMetric; import com.android.server.credentials.metrics.CandidateProviderMetric;

View File

@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.UserIdInt; import android.annotation.UserIdInt;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.credentials.CredentialProviderInfo;
import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderData;
import android.credentials.ui.UserSelectionDialogResult; import android.credentials.ui.UserSelectionDialogResult;
import android.os.Binder; import android.os.Binder;
@@ -30,7 +31,6 @@ import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.service.credentials.CallingAppInfo; import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialProviderInfo;
import android.util.Log; import android.util.Log;
import com.android.internal.R; import com.android.internal.R;