diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java index be60946dc6550..447c67fa44f8f 100644 --- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java @@ -23,6 +23,7 @@ import android.credentials.ClearCredentialStateRequest; import android.credentials.IClearCredentialStateCallback; import android.credentials.ui.ProviderData; import android.credentials.ui.RequestInfo; +import android.os.CancellationSignal; import android.os.RemoteException; import android.service.credentials.CallingAppInfo; import android.service.credentials.CredentialProviderInfo; @@ -41,9 +42,9 @@ public final class ClearRequestSession extends RequestSession getOrConstructSystemServiceListLock( int resolvedUserId) { @@ -338,7 +337,8 @@ public final class CredentialManagerService callingUid, callback, request, - constructCallingAppInfo(callingPackage, userId)); + constructCallingAppInfo(callingPackage, userId), + CancellationSignal.fromTransport(cancelTransport)); // Initiate all provider sessions List providerSessions = @@ -360,8 +360,6 @@ public final class CredentialManagerService + e.getMessage()); } } - - // Iterate over all provider sessions and invoke the request providerSessions.forEach(ProviderSession::invokeSession); return cancelTransport; } @@ -385,7 +383,8 @@ public final class CredentialManagerService callingUid, request, callback, - constructCallingAppInfo(callingPackage, userId)); + constructCallingAppInfo(callingPackage, userId), + CancellationSignal.fromTransport(cancelTransport)); // Initiate all provider sessions List providerSessions = @@ -405,8 +404,7 @@ public final class CredentialManagerService } // Iterate over all provider sessions and invoke the request - providerSessions.forEach( - ProviderSession::invokeSession); + providerSessions.forEach(ProviderSession::invokeSession); return cancelTransport; } @@ -497,7 +495,8 @@ public final class CredentialManagerService callingUid, callback, request, - constructCallingAppInfo(callingPackage, userId)); + constructCallingAppInfo(callingPackage, userId), + CancellationSignal.fromTransport(cancelTransport)); // Initiate all provider sessions // TODO: Determine if provider needs to have clear capability in their manifest @@ -518,8 +517,7 @@ public final class CredentialManagerService } // Iterate over all provider sessions and invoke the request - providerSessions.forEach( - ProviderSession::invokeSession); + providerSessions.forEach(ProviderSession::invokeSession); return cancelTransport; } diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java index e3a27ecebd317..e732c23ca2d90 100644 --- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java @@ -25,6 +25,7 @@ import android.credentials.GetCredentialResponse; import android.credentials.IGetCredentialCallback; import android.credentials.ui.ProviderData; import android.credentials.ui.RequestInfo; +import android.os.CancellationSignal; import android.os.RemoteException; import android.service.credentials.CallingAppInfo; import android.service.credentials.CredentialProviderInfo; @@ -43,8 +44,9 @@ public final class GetRequestSession extends RequestSession @NonNull protected Status mStatus = Status.NOT_STARTED; @NonNull protected final ProviderInternalCallback mCallbacks; @Nullable protected Credential mFinalCredentialResponse; + @Nullable protected ICancellationSignal mProviderCancellationSignal; @NonNull protected final T mProviderRequest; @Nullable protected R mProviderResponse; @NonNull protected Boolean mProviderResponseSet = false; @@ -151,6 +155,18 @@ public abstract class ProviderSession return mFinalCredentialResponse; } + /** Propagates cancellation signal to the remote provider service. */ + public void cancelProviderRemoteSession() { + try { + if (mProviderCancellationSignal != null) { + mProviderCancellationSignal.cancel(); + } + setStatus(Status.CANCELED); + } catch (RemoteException e) { + Log.i(TAG, "Issue while cancelling provider session: " + e.getMessage()); + } + } + protected void setStatus(@NonNull Status status) { mStatus = status; } diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java index 8cad6acebc4a1..2dea8bda78d52 100644 --- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java +++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java @@ -110,7 +110,7 @@ public class RemoteCredentialService extends ServiceConnector.Impl callback) { Log.i(TAG, "In onGetCredentials in RemoteCredentialService"); AtomicReference cancellationSink = new AtomicReference<>(); @@ -149,6 +149,8 @@ public class RemoteCredentialService extends ServiceConnector.Impl Handler.getMain().post(() -> handleExecutionResponse(result, error, cancellationSink, callback))); + + return cancellationSink.get(); } /** Main entry point to be called for executing a beginCreateCredential call on the remote @@ -157,7 +159,7 @@ public class RemoteCredentialService extends ServiceConnector.Impl callback) { Log.i(TAG, "In onCreateCredential in RemoteCredentialService"); AtomicReference cancellationSink = new AtomicReference<>(); @@ -196,6 +198,8 @@ public class RemoteCredentialService extends ServiceConnector.Impl Handler.getMain().post(() -> handleExecutionResponse(result, error, cancellationSink, callback))); + + return cancellationSink.get(); } /** Main entry point to be called for executing a clearCredentialState call on the remote @@ -204,7 +208,7 @@ public class RemoteCredentialService extends ServiceConnector.Impl callback) { Log.i(TAG, "In onClearCredentialState in RemoteCredentialService"); AtomicReference cancellationSink = new AtomicReference<>(); @@ -243,6 +247,8 @@ public class RemoteCredentialService extends ServiceConnector.Impl Handler.getMain().post(() -> handleExecutionResponse(result, error, cancellationSink, callback))); + + return cancellationSink.get(); } private void handleExecutionResponse(T result, diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java index f92ffe208cf40..9f1bd8f69ddec 100644 --- a/services/credentials/java/com/android/server/credentials/RequestSession.java +++ b/services/credentials/java/com/android/server/credentials/RequestSession.java @@ -29,6 +29,7 @@ import android.content.Context; import android.credentials.ui.ProviderData; import android.credentials.ui.UserSelectionDialogResult; import android.os.Binder; +import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -83,13 +84,16 @@ abstract class RequestSession implements CredentialManagerUi.CredentialMan private final int mCallingUid; @NonNull protected final CallingAppInfo mClientAppInfo; + @NonNull + protected final CancellationSignal mCancellationSignal; protected final Map mProviders = new HashMap<>(); protected RequestSession(@NonNull Context context, @UserIdInt int userId, int callingUid, @NonNull T clientRequest, U clientCallback, @NonNull String requestType, - CallingAppInfo callingAppInfo) { + CallingAppInfo callingAppInfo, + CancellationSignal cancellationSignal) { mContext = context; mUserId = userId; mCallingUid = callingUid; @@ -97,6 +101,7 @@ abstract class RequestSession implements CredentialManagerUi.CredentialMan mClientCallback = clientCallback; mRequestType = requestType; mClientAppInfo = callingAppInfo; + mCancellationSignal = cancellationSignal; mHandler = new Handler(Looper.getMainLooper(), null, true); mRequestId = new Binder(); mCredentialManagerUi = new CredentialManagerUi(mContext, @@ -112,6 +117,10 @@ abstract class RequestSession implements CredentialManagerUi.CredentialMan @Override // from CredentialManagerUiCallbacks public void onUiSelection(UserSelectionDialogResult selection) { + if (isSessionCancelled()) { + finishSession(/*propagateCancellation=*/true); + return; + } String providerId = selection.getProviderId(); Log.i(TAG, "onUiSelection, providerId: " + providerId); ProviderSession providerSession = mProviders.get(providerId); @@ -127,18 +136,19 @@ abstract class RequestSession implements CredentialManagerUi.CredentialMan @Override // from CredentialManagerUiCallbacks public void onUiCancellation(boolean isUserCancellation) { Log.i(TAG, "Ui canceled. Canceled by user: " + isUserCancellation); + if (isSessionCancelled()) { + finishSession(/*propagateCancellation=*/true); + return; + } // User canceled the activity - finishSession(); + finishSession(/*propagateCancellation=*/false); } - protected void finishSession() { + protected void finishSession(boolean propagateCancellation) { Log.i(TAG, "finishing session"); - clearProviderSessions(); - } - - protected void clearProviderSessions() { - Log.i(TAG, "Clearing sessions"); - //TODO: Implement + if (propagateCancellation) { + mProviders.values().forEach(ProviderSession::cancelProviderRemoteSession); + } mProviders.clear(); } @@ -178,6 +188,10 @@ abstract class RequestSession implements CredentialManagerUi.CredentialMan isSuccessful ? METRICS_API_STATUS_SUCCESS : METRICS_API_STATUS_FAILURE); } + protected boolean isSessionCancelled() { + return mCancellationSignal.isCanceled(); + } + /** * Returns true if at least one provider is ready for UI invocation, and no * provider is pending a response. @@ -197,6 +211,11 @@ abstract class RequestSession implements CredentialManagerUi.CredentialMan Log.i(TAG, "In getProviderDataAndInitiateUi"); Log.i(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size()); + if (isSessionCancelled()) { + finishSession(/*propagateCancellation=*/true); + return; + } + ArrayList providerDataList = new ArrayList<>(); for (ProviderSession session : mProviders.values()) { Log.i(TAG, "preparing data for : " + session.getComponentName()); @@ -208,7 +227,11 @@ abstract class RequestSession implements CredentialManagerUi.CredentialMan } if (!providerDataList.isEmpty()) { Log.i(TAG, "provider list not empty about to initiate ui"); - launchUiWithProviderData(providerDataList); + if (isSessionCancelled()) { + Log.i(TAG, "In getProviderDataAndInitiateUi but session has been cancelled"); + } else { + launchUiWithProviderData(providerDataList); + } } } }