Add KeyChain Test API for the credential manager

* Add setCredentialManagementApp and
  removeCredentialManagementApp
  to KeyChain
* Add permission to manage credential
  management app, which is to be used in
  CTS tests

Bug: 165641221
Test: atest android.devicepolicy.cts.CredentialManagementAppTest
Change-Id: I8487ebc13758a31639d55c8e380faa51d1cfd843
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1086577..23897bb 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1585,6 +1585,11 @@
 
 package android.security {
 
+  public final class KeyChain {
+    method @RequiresPermission("android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP") public static boolean removeCredentialManagementApp(@NonNull android.content.Context);
+    method @RequiresPermission("android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP") public static boolean setCredentialManagementApp(@NonNull android.content.Context, @NonNull String, @NonNull android.security.AppUriAuthenticationPolicy);
+  }
+
   public class KeyStoreException extends java.lang.Exception {
     ctor public KeyStoreException(int, String);
     method public int getErrorCode();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8682fea..c1e93e7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3147,6 +3147,11 @@
     <permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to set, update and remove the credential management app.
+         @hide -->
+    <permission android:name="android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP"
+        android:protectionLevel="signature" />
+
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
     <!-- ========================================= -->
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 2f444b3..97819c5 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -17,10 +17,13 @@
 
 import static android.security.Credentials.ACTION_MANAGE_CREDENTIALS;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.TestApi;
 import android.annotation.WorkerThread;
 import android.app.Activity;
 import android.app.PendingIntent;
@@ -41,6 +44,7 @@
 import android.security.keystore.AndroidKeyStoreProvider;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
 import android.security.keystore.KeyProperties;
+import android.util.Log;
 
 import com.android.org.conscrypt.TrustedCertificateStore;
 
@@ -105,6 +109,11 @@
 public final class KeyChain {
 
     /**
+     * @hide
+     */
+    public static final String LOG = "KeyChain";
+
+    /**
      * @hide Also used by KeyChainService implementation
      */
     public static final String ACCOUNT_TYPE = "com.android.keychain";
@@ -579,6 +588,55 @@
         activity.startActivity(intent);
     }
 
+    /**
+     * Set a credential management app. The credential management app has the ability to manage
+     * the user's KeyChain credentials on unmanaged devices.
+     *
+     * <p>There can only be one credential management on the device. If another app requests to
+     * become the credential management app, then the existing credential management app will
+     * no longer be able to manage credentials.
+     *
+     * @param packageName The package name of the credential management app
+     * @param authenticationPolicy The authentication policy of the credential management app. This
+     *                             policy determines which alias for a private key and certificate
+     *                             pair should be used for authentication.
+     * @return {@code true} if the credential management app was successfully added.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP)
+    public static boolean setCredentialManagementApp(@NonNull Context context,
+            @NonNull String packageName, @NonNull AppUriAuthenticationPolicy authenticationPolicy) {
+        try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) {
+            keyChainConnection.getService()
+                    .setCredentialManagementApp(packageName, authenticationPolicy);
+            return true;
+        } catch (RemoteException | InterruptedException e) {
+            Log.w(LOG, "Set credential management app failed", e);
+            Thread.currentThread().interrupt();
+            return false;
+        }
+    }
+
+    /**
+     * Remove the user's KeyChain credentials on unmanaged devices.
+     *
+     * @return {@code true} if the credential management app was successfully removed.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP)
+    public static boolean removeCredentialManagementApp(@NonNull Context context) {
+        try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) {
+            keyChainConnection.getService().removeCredentialManagementApp();
+            return true;
+        } catch (RemoteException | InterruptedException e) {
+            Log.w(LOG, "Remove credential management app failed", e);
+            Thread.currentThread().interrupt();
+            return false;
+        }
+    }
+
     private static class AliasResponse extends IKeyChainAliasCallback.Stub {
         private final KeyChainAliasCallback keyChainAliasResponse;
         private AliasResponse(KeyChainAliasCallback keyChainAliasResponse) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index f83f670..d221819 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -119,6 +119,7 @@
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.CREATE_USERS" />
+    <uses-permission android:name="android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP" />
     <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
     <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
     <uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE"/>