Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit edbcdce2 authored by Reema Bajwa's avatar Reema Bajwa Committed by Android (Google) Code Review
Browse files

Merge "Cancel session when client callback dies" into main

parents 77869c4f 1d08d49e
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
@@ -23,12 +23,14 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.credentials.CredentialProviderInfo;
import android.credentials.flags.Flags;
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.IInterface;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -94,6 +96,9 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential

    private final Set<ComponentName> mEnabledProviders;

    private final RequestSessionDeathRecipient mDeathRecipient =
            new RequestSessionDeathRecipient();

    protected PendingIntent mPendingIntent;

    @NonNull
@@ -141,11 +146,26 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
        mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted,
                mCallingUid, ApiName.getMetricCodeFromRequestInfo(mRequestType));
        setCancellationListener();
        if (Flags.clearSessionEnabled()) {
            setUpClientCallbackListener();
        }
    }

    private void setUpClientCallbackListener() {
        if (mClientCallback != null && mClientCallback instanceof IInterface) {
            IInterface callback = (IInterface) mClientCallback;
            try {
                callback.asBinder().linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
                Slog.e(TAG, e.getMessage());
            }
        }
    }

    private void setCancellationListener() {
        mCancellationSignal.setOnCancelListener(
                () -> {
                    Slog.d(TAG, "Cancellation invoked from the client - clearing session");
                    boolean isUiActive = maybeCancelUi();
                    finishSession(!isUiActive);
                }
@@ -168,6 +188,17 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
        return false;
    }

    private boolean isUiWaitingForData() {
        // Technically, the status can also be IN_PROGRESS when the user has made a selection
        // so this an over estimation, but safe to do so as it is used for cancellation
        // propagation to the provider in a very narrow time frame. If provider has
        // already responded, cancellation is not an issue as the cancellation listener
        // is independent of the service binding.
        // TODO(b/313512500): Do not propagate cancelation if provider has responded in
        // query phase.
        return mCredentialManagerUi.getStatus() == CredentialManagerUi.UiStatus.IN_PROGRESS;
    }

    public abstract ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo,
            RemoteCredentialService remoteCredentialService);

@@ -373,4 +404,12 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
        return chosenProviderSession != null && chosenProviderSession.mProviderInfo != null
                && chosenProviderSession.mProviderInfo.isPrimary();
    }

    private class RequestSessionDeathRecipient implements IBinder.DeathRecipient {
        @Override
        public void binderDied() {
            Slog.d(TAG, "Client binder died - clearing session");
            finishSession(isUiWaitingForData());
        }
    }
}