summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/service/credentials/CredentialProviderInfo.java56
-rw-r--r--core/java/android/service/credentials/CredentialProviderService.java14
-rw-r--r--core/res/AndroidManifest.xml12
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerService.java79
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java17
5 files changed, 155 insertions, 23 deletions
diff --git a/core/java/android/service/credentials/CredentialProviderInfo.java b/core/java/android/service/credentials/CredentialProviderInfo.java
index f89ad8e6e429..6a10a6ac891d 100644
--- a/core/java/android/service/credentials/CredentialProviderInfo.java
+++ b/core/java/android/service/credentials/CredentialProviderInfo.java
@@ -24,6 +24,7 @@ import android.app.AppGlobals;
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;
@@ -58,6 +59,7 @@ public final class CredentialProviderInfo {
private final Drawable mIcon;
@Nullable
private final CharSequence mLabel;
+ private final boolean mIsSystemProvider;
/**
* Constructs an information instance of the credential provider.
@@ -65,13 +67,14 @@ public final class CredentialProviderInfo {
* @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 CredentialProviderInfo(@NonNull Context context,
- @NonNull ComponentName serviceComponent, int userId)
+ @NonNull ComponentName serviceComponent, int userId, boolean isSystemProvider)
throws PackageManager.NameNotFoundException {
- this(context, getServiceInfoOrThrow(serviceComponent, userId));
+ this(context, getServiceInfoOrThrow(serviceComponent, userId), isSystemProvider);
}
/**
@@ -79,8 +82,11 @@ public final class CredentialProviderInfo {
* @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
*/
- public CredentialProviderInfo(@NonNull Context context, @NonNull ServiceInfo serviceInfo) {
+ 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"
@@ -95,6 +101,7 @@ public final class CredentialProviderInfo {
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());
populateProviderCapabilities(context, serviceInfo);
@@ -147,6 +154,42 @@ public final class CredentialProviderInfo {
}
/**
+ * 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) {
+ final List<CredentialProviderInfo> services = new ArrayList<>();
+
+ final List<ResolveInfo> resolveInfos =
+ 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;
+ try {
+ ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
+ serviceInfo.packageName,
+ PackageManager.ApplicationInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY));
+ if (appInfo != null
+ && context.checkPermission(Manifest.permission.SYSTEM_CREDENTIAL_PROVIDER,
+ /*pId=*/-1, appInfo.uid) == PackageManager.PERMISSION_GRANTED) {
+ services.add(new CredentialProviderInfo(context, serviceInfo,
+ /*isSystemProvider=*/true));
+ }
+ } catch (SecurityException e) {
+ Log.i(TAG, "Error getting info for " + serviceInfo + ": " + e);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.i(TAG, "Error getting info for " + serviceInfo + ": " + e);
+ }
+ }
+ return services;
+ }
+
+ /**
* Returns true if the service supports the given {@code credentialType}, false otherwise.
*/
@NonNull
@@ -160,6 +203,10 @@ public final class CredentialProviderInfo {
return mServiceInfo;
}
+ public boolean isSystemProvider() {
+ return mIsSystemProvider;
+ }
+
/** Returns the service icon. */
@Nullable
public Drawable getServiceIcon() {
@@ -195,7 +242,8 @@ public final class CredentialProviderInfo {
for (ResolveInfo resolveInfo : resolveInfos) {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
try {
- services.add(new CredentialProviderInfo(context, serviceInfo));
+ services.add(new CredentialProviderInfo(context,
+ serviceInfo, false));
} catch (SecurityException e) {
Log.w(TAG, "Error getting info for " + serviceInfo + ": " + e);
}
diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java
index 41d20f26b381..a70659552543 100644
--- a/core/java/android/service/credentials/CredentialProviderService.java
+++ b/core/java/android/service/credentials/CredentialProviderService.java
@@ -140,6 +140,20 @@ public abstract class CredentialProviderService extends Service {
public static final String SERVICE_INTERFACE =
"android.service.credentials.CredentialProviderService";
+ /**
+ * The {@link Intent} that must be declared as handled by a system credential provider
+ * service.
+ *
+ * <p>The service must also require the
+ * {android.Manifest.permission#BIND_CREDENTIAL_PROVIDER_SERVICE} permission
+ * so that only the system can bind to it.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SYSTEM_SERVICE_INTERFACE =
+ "android.service.credentials.system.CredentialProviderService";
+
@CallSuper
@Override
public void onCreate() {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index bfa530143380..6953a467f54b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3906,6 +3906,18 @@
<permission android:name="android.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS"
android:protectionLevel="signature|privileged" />
+ <!-- Allows a system application to be registered with credential manager without
+ having to be enabled by the user.
+ @hide -->
+ <permission android:name="android.permission.SYSTEM_CREDENTIAL_PROVIDER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to be able to store and retrieve credentials from a remote
+ device.
+ @hide -->
+ <permission android:name="android.permission.HYBRID_CREDENTIAL_PROVIDER"
+ android:protectionLevel="signature|privileged" />
+
<!-- ========================================= -->
<!-- Permissions for special development tools -->
<!-- ========================================= -->
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 25e205b459d9..a1ae0263ba1b 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -48,6 +48,7 @@ import android.service.credentials.CredentialProviderInfo;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.server.infra.AbstractMasterSystemService;
@@ -71,6 +72,16 @@ public final class CredentialManagerService
private static final String TAG = "CredManSysService";
+ private final Context mContext;
+
+ /**
+ * Cache of system service list per user id.
+ */
+ @GuardedBy("mLock")
+ private final SparseArray<List<CredentialManagerServiceImpl>> mSystemServicesCacheList =
+ new SparseArray<>();
+
+
public CredentialManagerService(@NonNull Context context) {
super(
context,
@@ -78,6 +89,20 @@ public final class CredentialManagerService
context, Settings.Secure.CREDENTIAL_SERVICE, /* isMultipleMode= */ true),
null,
PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
+ mContext = context;
+ }
+
+ @NonNull
+ @GuardedBy("mLock")
+ private List<CredentialManagerServiceImpl> constructSystemServiceListLocked(
+ int resolvedUserId) {
+ List<CredentialManagerServiceImpl> services = new ArrayList<>();
+ List<CredentialProviderInfo> credentialProviderInfos =
+ CredentialProviderInfo.getAvailableSystemServices(mContext, resolvedUserId);
+ credentialProviderInfos.forEach(info -> {
+ services.add(new CredentialManagerServiceImpl(this, mLock, resolvedUserId, info));
+ });
+ return services;
}
@Override
@@ -103,8 +128,10 @@ public final class CredentialManagerService
}
@Override // from AbstractMasterSystemService
+ @GuardedBy("mLock")
protected List<CredentialManagerServiceImpl> newServiceListLocked(
int resolvedUserId, boolean disabled, String[] serviceNames) {
+ getOrConstructSystemServiceListLock(resolvedUserId);
if (serviceNames == null || serviceNames.length == 0) {
Slog.i(TAG, "serviceNames sent in newServiceListLocked is null, or empty");
return new ArrayList<>();
@@ -153,13 +180,24 @@ public final class CredentialManagerService
// TODO("Iterate over system services and remove if needed")
}
+ @GuardedBy("mLock")
+ private List<CredentialManagerServiceImpl> getOrConstructSystemServiceListLock(
+ int resolvedUserId) {
+ List<CredentialManagerServiceImpl> services = mSystemServicesCacheList.get(resolvedUserId);
+ if (services == null || services.size() == 0) {
+ services = constructSystemServiceListLocked(resolvedUserId);
+ mSystemServicesCacheList.put(resolvedUserId, services);
+ }
+ return services;
+ }
+
private void runForUser(@NonNull final Consumer<CredentialManagerServiceImpl> c) {
final int userId = UserHandle.getCallingUserId();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
final List<CredentialManagerServiceImpl> services =
- getServiceListForUserLocked(userId);
+ getAllCredentialProviderServicesLocked(userId);
for (CredentialManagerServiceImpl s : services) {
c.accept(s);
}
@@ -169,6 +207,19 @@ public final class CredentialManagerService
}
}
+ @GuardedBy("mLock")
+ private List<CredentialManagerServiceImpl> getAllCredentialProviderServicesLocked(
+ int userId) {
+ List<CredentialManagerServiceImpl> concatenatedServices = new ArrayList<>();
+ List<CredentialManagerServiceImpl> userConfigurableServices =
+ getServiceListForUserLocked(userId);
+ if (userConfigurableServices != null && !userConfigurableServices.isEmpty()) {
+ concatenatedServices.addAll(userConfigurableServices);
+ }
+ concatenatedServices.addAll(getOrConstructSystemServiceListLock(userId));
+ return concatenatedServices;
+ }
+
@SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked
// to be guarded by 'service.mLock', which is the same as mLock.
private List<ProviderSession> initiateProviderSessions(
@@ -231,14 +282,10 @@ public final class CredentialManagerService
// Iterate over all provider sessions and invoke the request
providerSessions.forEach(
- providerGetSession -> {
- providerGetSession
- .getRemoteCredentialService()
- .onBeginGetCredential(
- (BeginGetCredentialRequest)
- providerGetSession.getProviderRequest(),
- /* callback= */ providerGetSession);
- });
+ providerGetSession -> providerGetSession
+ .getRemoteCredentialService().onBeginGetCredential(
+ (BeginGetCredentialRequest) providerGetSession.getProviderRequest(),
+ /*callback=*/providerGetSession));
return cancelTransport;
}
@@ -279,14 +326,12 @@ public final class CredentialManagerService
// Iterate over all provider sessions and invoke the request
providerSessions.forEach(
- providerCreateSession -> {
- providerCreateSession
- .getRemoteCredentialService()
- .onCreateCredential(
- (BeginCreateCredentialRequest)
- providerCreateSession.getProviderRequest(),
- /* callback= */ providerCreateSession);
- });
+ providerCreateSession -> providerCreateSession
+ .getRemoteCredentialService()
+ .onCreateCredential(
+ (BeginCreateCredentialRequest)
+ providerCreateSession.getProviderRequest(),
+ /* callback= */ providerCreateSession));
return cancelTransport;
}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
index 0fd1f1929cae..546c48fe05f4 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
@@ -58,7 +58,18 @@ public final class CredentialManagerServiceImpl extends
return mInfo.getServiceInfo().getComponentName();
}
- @Override // from PerUserSystemService
+ CredentialManagerServiceImpl(
+ @NonNull CredentialManagerService master,
+ @NonNull Object lock, int userId, CredentialProviderInfo providerInfo) {
+ super(master, lock, userId);
+ Log.i(TAG, "in CredentialManagerServiceImpl constructed with system constructor: "
+ + providerInfo.isSystemProvider()
+ + " , " + providerInfo.getServiceInfo() == null ? "" :
+ providerInfo.getServiceInfo().getComponentName().flattenToString());
+ mInfo = providerInfo;
+ }
+
+ @Override // from PerUserSystemService when a new setting based service is to be created
@GuardedBy("mLock")
protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
throws PackageManager.NameNotFoundException {
@@ -71,7 +82,9 @@ public final class CredentialManagerServiceImpl extends
Log.i(TAG, "newServiceInfoLocked with null mInfo , "
+ serviceComponent.getPackageName());
}
- mInfo = new CredentialProviderInfo(getContext(), serviceComponent, mUserId);
+ mInfo = new CredentialProviderInfo(
+ getContext(), serviceComponent,
+ mUserId, /*isSystemProvider=*/false);
return mInfo.getServiceInfo();
}