Merge "Propagate cancellations to session" into main
diff --git a/core/java/android/credentials/GetCandidateCredentialsException.java b/core/java/android/credentials/GetCandidateCredentialsException.java
index 40650d0..0ac5f6c 100644
--- a/core/java/android/credentials/GetCandidateCredentialsException.java
+++ b/core/java/android/credentials/GetCandidateCredentialsException.java
@@ -46,6 +46,17 @@
             "android.credentials.GetCandidateCredentialsException.TYPE_NO_CREDENTIAL";
 
     @NonNull
+    public static final String TYPE_USER_CANCELED =
+            "android.credentials.GetCredentialException.TYPE_USER_CANCELED";
+    /**
+     * The error type value for when the given operation failed due to internal interruption.
+     * Retrying the same operation should fix the error.
+     */
+    @NonNull
+    public static final String TYPE_INTERRUPTED =
+            "android.credentials.GetCredentialException.TYPE_INTERRUPTED";
+
+    @NonNull
     private final String mType;
 
     /** Returns the specific exception type. */
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index 69a5e5c..db985fd 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -50,7 +50,8 @@
             long startedTimestamp) {
         super(context, sessionCallback, lock, userId, callingUid, request, callback,
                 RequestInfo.TYPE_UNDEFINED,
-                callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp);
+                callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp,
+                /*shouldBindClientToDeath=*/ true);
     }
 
     /**
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index 31409ab..b24accb 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -63,7 +63,8 @@
             long startedTimestamp) {
         super(context, sessionCallback, lock, userId, callingUid, request, callback,
                 RequestInfo.TYPE_CREATE,
-                callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp);
+                callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp,
+                /*shouldBindClientToDeath=*/ true);
         mRequestSessionMetric.collectCreateFlowInitialMetricInfo(
                 /*origin=*/request.getOrigin() != null, request);
         mPrimaryProviders = primaryProviders;
diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
index 0f914c3..0187ce8 100644
--- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
@@ -65,10 +65,13 @@
             IAutoFillManagerClient autoFillCallback) {
         super(context, sessionCallback, lock, userId, callingUid, request, callback,
                 RequestInfo.TYPE_GET, callingAppInfo, enabledProviders,
-                cancellationSignal, 0L);
+                cancellationSignal, 0L, /*shouldBindClientToDeath=*/ false);
         mAutoFillCallback = autoFillCallback;
         mAutofillSessionId = request.getData().getInt(SESSION_ID_KEY, -1);
         mAutofillRequestId = request.getData().getInt(REQUEST_ID_KEY, -1);
+        if (mAutoFillCallback != null) {
+            setUpClientCallbackListener(mAutoFillCallback.asBinder());
+        }
     }
 
     /**
@@ -144,17 +147,27 @@
     @Override
     public void onFinalErrorReceived(ComponentName componentName, String errorType,
             String message) {
-        // Not applicable for session without UI
+        respondToClientWithErrorAndFinish(errorType, message);
     }
 
     @Override
     public void onUiCancellation(boolean isUserCancellation) {
-        // Not applicable for session without UI
+        String exception = GetCandidateCredentialsException.TYPE_USER_CANCELED;
+        String message = "User cancelled the selector";
+        if (!isUserCancellation) {
+            exception = GetCandidateCredentialsException.TYPE_INTERRUPTED;
+            message = "The UI was interrupted - please try again.";
+        }
+        mRequestSessionMetric.collectFrameworkException(exception);
+        respondToClientWithErrorAndFinish(exception, message);
     }
 
     @Override
     public void onUiSelectorInvocationFailure() {
-        // Not applicable for session without UI
+        String exception = GetCandidateCredentialsException.TYPE_NO_CREDENTIAL;
+        mRequestSessionMetric.collectFrameworkException(exception);
+        respondToClientWithErrorAndFinish(exception,
+                "No credentials available.");
     }
 
     @Override
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index 3f57c80..49ea19a 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -57,7 +57,7 @@
             long startedTimestamp) {
         super(context, sessionCallback, lock, userId, callingUid, request, callback,
                 getRequestInfoFromRequest(request), callingAppInfo, enabledProviders,
-                cancellationSignal, startedTimestamp);
+                cancellationSignal, startedTimestamp, /*shouldBindClientToDeath=*/ true);
         mRequestSessionMetric.collectGetFlowInitialMetricInfo(request);
     }
 
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index da44aac..67c52e6 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -122,7 +122,8 @@
             @NonNull String requestType,
             CallingAppInfo callingAppInfo,
             Set<ComponentName> enabledProviders,
-            CancellationSignal cancellationSignal, long timestampStarted) {
+            CancellationSignal cancellationSignal, long timestampStarted,
+            boolean shouldBindClientToDeath) {
         mContext = context;
         mLock = lock;
         mSessionCallback = sessionCallback;
@@ -146,16 +147,18 @@
         mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted,
                 mCallingUid, ApiName.getMetricCodeFromRequestInfo(mRequestType));
         setCancellationListener();
-        if (Flags.clearSessionEnabled()) {
-            setUpClientCallbackListener();
+        if (shouldBindClientToDeath && Flags.clearSessionEnabled()) {
+            if (mClientCallback != null && mClientCallback instanceof IInterface) {
+                setUpClientCallbackListener(((IInterface) mClientCallback).asBinder());
+            }
         }
     }
 
-    private void setUpClientCallbackListener() {
+    protected void setUpClientCallbackListener(IBinder clientBinder) {
         if (mClientCallback != null && mClientCallback instanceof IInterface) {
             IInterface callback = (IInterface) mClientCallback;
             try {
-                callback.asBinder().linkToDeath(mDeathRecipient, 0);
+                clientBinder.linkToDeath(mDeathRecipient, 0);
             } catch (RemoteException e) {
                 Slog.e(TAG, e.getMessage());
             }