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

Commit 9e5bee14 authored by Reema Bajwa's avatar Reema Bajwa Committed by Automerger Merge Worker
Browse files

Merge "Check query permission and populate attributes" into udc-dev am: fbb43217 am: 22c22364

parents b788a88b 22c22364
Loading
Loading
Loading
Loading
+89 −22
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.server.credentials;
package com.android.server.credentials;


import android.Manifest;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.ComponentName;
@@ -28,17 +29,20 @@ import android.credentials.GetCredentialResponse;
import android.credentials.IGetCredentialCallback;
import android.credentials.IGetCredentialCallback;
import android.credentials.IPrepareGetCredentialCallback;
import android.credentials.IPrepareGetCredentialCallback;
import android.credentials.PrepareGetCredentialResponseInternal;
import android.credentials.PrepareGetCredentialResponseInternal;
import android.credentials.ui.GetCredentialProviderData;
import android.credentials.ui.ProviderData;
import android.credentials.ui.ProviderData;
import android.credentials.ui.RequestInfo;
import android.credentials.ui.RequestInfo;
import android.os.CancellationSignal;
import android.os.CancellationSignal;
import android.os.RemoteException;
import android.os.RemoteException;
import android.service.credentials.CallingAppInfo;
import android.service.credentials.CallingAppInfo;
import android.service.credentials.PermissionUtils;
import android.util.Log;
import android.util.Log;


import com.android.server.credentials.metrics.ApiName;
import com.android.server.credentials.metrics.ApiName;
import com.android.server.credentials.metrics.ProviderStatusForMetrics;
import com.android.server.credentials.metrics.ProviderStatusForMetrics;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Collectors;


/**
/**
@@ -222,38 +226,101 @@ public class PrepareGetRequestSession extends RequestSession<GetCredentialReques
            // If all provider responses have been received, we can either need the UI,
            // If all provider responses have been received, we can either need the UI,
            // or we need to respond with error. The only other case is the entry being
            // or we need to respond with error. The only other case is the entry being
            // selected after the UI has been invoked which has a separate code path.
            // selected after the UI has been invoked which has a separate code path.
            if (isUiInvocationNeeded()) {
            if (mIsInitialQuery) {
            if (mIsInitialQuery) {
                // First time in this state. UI shouldn't be invoked because developer wants to
                // punt it for later
                boolean hasQueryCandidatePermission = PermissionUtils.hasPermission(
                        mContext,
                        mClientAppInfo.getPackageName(),
                        Manifest.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS);
                if (isUiInvocationNeeded()) {
                    ArrayList<ProviderData> providerData = getProviderDataForUi();
                    if (!providerData.isEmpty()) {
                        constructPendingResponseAndInvokeCallback(hasQueryCandidatePermission,
                                getCredentialResultTypes(hasQueryCandidatePermission),
                                hasAuthenticationResults(providerData, hasQueryCandidatePermission),
                                hasRemoteResults(providerData, hasQueryCandidatePermission),
                                getUiIntent());
                    } else {
                        constructEmptyPendingResponseAndInvokeCallback(hasQueryCandidatePermission);
                    }
                } else {
                    constructEmptyPendingResponseAndInvokeCallback(hasQueryCandidatePermission);
                }
                mIsInitialQuery = false;
            } else {
                // Not the first time. This could be a result of a user selection leading to a UI
                // invocation again.
                if (isUiInvocationNeeded()) {
                    getProviderDataAndInitiateUi();
                } else {
                    respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL,
                            "No credentials available");
                }
            }
        }
    }

    private void constructPendingResponseAndInvokeCallback(boolean hasPermission,
            Set<String> credentialTypes,
            boolean hasAuthenticationResults, boolean hasRemoteResults, PendingIntent uiIntent) {
        try {
        try {
            mPrepareGetCredentialCallback.onResponse(
            mPrepareGetCredentialCallback.onResponse(
                    new PrepareGetCredentialResponseInternal(
                    new PrepareGetCredentialResponseInternal(
                                        false, null,
                            hasPermission,
                                        false, false,
                            credentialTypes, hasAuthenticationResults, hasRemoteResults, uiIntent));
                                        getUiIntent()));
        } catch (RemoteException e) {
                    } catch (Exception e) {
            Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e);
            Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e);
        }
        }
                    mIsInitialQuery = false;
                } else {
                    getProviderDataAndInitiateUi();
    }
    }
            } else {

                if (mIsInitialQuery) {
    private void constructEmptyPendingResponseAndInvokeCallback(
            boolean hasQueryCandidatePermission) {
        try {
        try {
            mPrepareGetCredentialCallback.onResponse(
            mPrepareGetCredentialCallback.onResponse(
                    new PrepareGetCredentialResponseInternal(
                    new PrepareGetCredentialResponseInternal(
                                        false, null, false, false, null));
                            hasQueryCandidatePermission,
                    } catch (Exception e) {
                            /*credentialResultTypes=*/ null,
                            /*hasAuthenticationResults=*/false,
                            /*hasRemoteResults=*/ false,
                            /*pendingIntent=*/ null));
        } catch (RemoteException e) {
            Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e);
            Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e);
        }
        }
                    mIsInitialQuery = false;
                    // TODO(273308895): should also clear session here
                } else {
                    respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL,
                            "No credentials available");
    }
    }

    private boolean hasRemoteResults(ArrayList<ProviderData> providerData,
            boolean hasQueryCandidatePermission) {
        if (!hasQueryCandidatePermission) {
            return false;
        }
        return providerData.stream()
                .map(data -> (GetCredentialProviderData) data)
                .anyMatch(getCredentialProviderData ->
                        getCredentialProviderData.getRemoteEntry() != null);
    }

    private boolean hasAuthenticationResults(ArrayList<ProviderData> providerData,
            boolean hasQueryCandidatePermission) {
        if (!hasQueryCandidatePermission) {
            return false;
        }
        return providerData.stream()
                .map(data -> (GetCredentialProviderData) data)
                .anyMatch(getCredentialProviderData ->
                        !getCredentialProviderData.getAuthenticationEntries().isEmpty());
    }
    }

    @Nullable
    private Set<String> getCredentialResultTypes(boolean hasQueryCandidatePermission) {
        if (!hasQueryCandidatePermission) {
            return null;
        }
        }
        return mProviders.values().stream()
                .map(session -> (ProviderGetSession) session)
                .flatMap(providerGetSession -> providerGetSession
                        .getCredentialEntryTypes().stream())
                .collect(Collectors.toSet());
    }
    }


    private PendingIntent getUiIntent() {
    private PendingIntent getUiIntent() {
+16 −0
Original line number Original line Diff line number Diff line
@@ -47,9 +47,11 @@ import com.android.server.credentials.metrics.EntryEnum;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Optional;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Collectors;


/**
/**
@@ -338,6 +340,11 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
        }
        }
    }
    }


    @NonNull
    protected Set<String> getCredentialEntryTypes() {
        return mProviderResponseDataHandler.getCredentialEntryTypes();
    }

    @Override // Call from request session to data to be shown on the UI
    @Override // Call from request session to data to be shown on the UI
    @Nullable
    @Nullable
    protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException {
    protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException {
@@ -575,6 +582,9 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
        private final Map<String, Pair<Action, AuthenticationEntry>> mUiAuthenticationEntries =
        private final Map<String, Pair<Action, AuthenticationEntry>> mUiAuthenticationEntries =
                new HashMap<>();
                new HashMap<>();


        @NonNull
        private final Set<String> mCredentialEntryTypes = new HashSet<>();

        @Nullable
        @Nullable
        private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null;
        private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null;


@@ -607,6 +617,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
                    id, credentialEntry.getSlice(),
                    id, credentialEntry.getSlice(),
                    setUpFillInIntent(credentialEntry.getBeginGetCredentialOptionId()));
                    setUpFillInIntent(credentialEntry.getBeginGetCredentialOptionId()));
            mUiCredentialEntries.put(id, new Pair<>(credentialEntry, entry));
            mUiCredentialEntries.put(id, new Pair<>(credentialEntry, entry));
            mCredentialEntryTypes.add(credentialEntry.getType());
        }
        }


        public void addAction(Action action) {
        public void addAction(Action action) {
@@ -703,6 +714,11 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
                    && response.getRemoteCredentialEntry() == null;
                    && response.getRemoteCredentialEntry() == null;
        }
        }


        @NonNull
        public Set<String> getCredentialEntryTypes() {
            return mCredentialEntryTypes;
        }

        @Nullable
        @Nullable
        public Action getAuthenticationAction(String entryKey) {
        public Action getAuthenticationAction(String entryKey) {
            return mUiAuthenticationEntries.get(entryKey) == null ? null :
            return mUiAuthenticationEntries.get(entryKey) == null ? null :
+13 −7
Original line number Original line Diff line number Diff line
@@ -236,16 +236,26 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
    }
    }


    void getProviderDataAndInitiateUi() {
    void getProviderDataAndInitiateUi() {
        ArrayList<ProviderData> providerDataList = getProviderDataForUi();
        if (!providerDataList.isEmpty()) {
            Log.i(TAG, "provider list not empty about to initiate ui");
            MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter);
            launchUiWithProviderData(providerDataList);
        }
    }

    @NonNull
    protected ArrayList<ProviderData> getProviderDataForUi() {
        Log.i(TAG, "In getProviderDataAndInitiateUi");
        Log.i(TAG, "In getProviderDataAndInitiateUi");
        Log.i(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size());
        Log.i(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size());
        ArrayList<ProviderData> providerDataList = new ArrayList<>();


        if (isSessionCancelled()) {
        if (isSessionCancelled()) {
            MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter);
            MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter);
            finishSession(/*propagateCancellation=*/true);
            finishSession(/*propagateCancellation=*/true);
            return;
            return providerDataList;
        }
        }


        ArrayList<ProviderData> providerDataList = new ArrayList<>();
        for (ProviderSession session : mProviders.values()) {
        for (ProviderSession session : mProviders.values()) {
            Log.i(TAG, "preparing data for : " + session.getComponentName());
            Log.i(TAG, "preparing data for : " + session.getComponentName());
            ProviderData providerData = session.prepareUiData();
            ProviderData providerData = session.prepareUiData();
@@ -254,11 +264,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
                providerDataList.add(providerData);
                providerDataList.add(providerData);
            }
            }
        }
        }
        if (!providerDataList.isEmpty()) {
        return providerDataList;
            Log.i(TAG, "provider list not empty about to initiate ui");
            MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter);
            launchUiWithProviderData(providerDataList);
        }
    }
    }


    protected void collectFinalPhaseMetricStatus(boolean hasException,
    protected void collectFinalPhaseMetricStatus(boolean hasException,