Merge "Listen to live cancellation signal" into udc-dev

This commit is contained in:
Reema Bajwa
2023-04-05 15:27:40 +00:00
committed by Android (Google) Code Review
12 changed files with 171 additions and 41 deletions

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0N
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@@ -74,7 +74,6 @@ class CredentialSelectorActivity : ComponentActivity() {
override fun onNewIntent(intent: Intent) { override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent) super.onNewIntent(intent)
setIntent(intent) setIntent(intent)
Log.d(Constants.LOG_TAG, "Existing activity received new intent")
try { try {
val viewModel: CredentialSelectorViewModel by viewModels() val viewModel: CredentialSelectorViewModel by viewModels()
val (isCancellationRequest, shouldShowCancellationUi, appDisplayName) = val (isCancellationRequest, shouldShowCancellationUi, appDisplayName) =

View File

@@ -40,11 +40,13 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
implements ProviderSession.ProviderInternalCallback<Void> { implements ProviderSession.ProviderInternalCallback<Void> {
private static final String TAG = "GetRequestSession"; private static final String TAG = "GetRequestSession";
public ClearRequestSession(Context context, int userId, int callingUid, public ClearRequestSession(Context context, RequestSession.SessionLifetime sessionCallback,
Object lock, int userId, int callingUid,
IClearCredentialStateCallback callback, ClearCredentialStateRequest request, IClearCredentialStateCallback callback, ClearCredentialStateRequest request,
CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal, CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal,
long startedTimestamp) { long startedTimestamp) {
super(context, userId, callingUid, request, callback, RequestInfo.TYPE_UNDEFINED, super(context, sessionCallback, lock, userId, callingUid, request, callback,
RequestInfo.TYPE_UNDEFINED,
callingAppInfo, cancellationSignal, startedTimestamp); callingAppInfo, cancellationSignal, startedTimestamp);
} }

View File

@@ -49,13 +49,15 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
implements ProviderSession.ProviderInternalCallback<CreateCredentialResponse> { implements ProviderSession.ProviderInternalCallback<CreateCredentialResponse> {
private static final String TAG = "CreateRequestSession"; private static final String TAG = "CreateRequestSession";
CreateRequestSession(@NonNull Context context, int userId, int callingUid, CreateRequestSession(@NonNull Context context, RequestSession.SessionLifetime sessionCallback,
Object lock, int userId, int callingUid,
CreateCredentialRequest request, CreateCredentialRequest request,
ICreateCredentialCallback callback, ICreateCredentialCallback callback,
CallingAppInfo callingAppInfo, CallingAppInfo callingAppInfo,
CancellationSignal cancellationSignal, CancellationSignal cancellationSignal,
long startedTimestamp) { long startedTimestamp) {
super(context, userId, callingUid, request, callback, RequestInfo.TYPE_CREATE, super(context, sessionCallback, lock, userId, callingUid, request, callback,
RequestInfo.TYPE_CREATE,
callingAppInfo, cancellationSignal, startedTimestamp); callingAppInfo, cancellationSignal, startedTimestamp);
} }
@@ -83,6 +85,7 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
@Override @Override
protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) { protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) {
mRequestSessionMetric.collectUiCallStartTime(System.nanoTime()); mRequestSessionMetric.collectUiCallStartTime(System.nanoTime());
mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.USER_INTERACTION);
try { try {
mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent( mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent(
RequestInfo.newCreateRequestInfo( RequestInfo.newCreateRequestInfo(
@@ -93,6 +96,7 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
providerDataList)); providerDataList));
} catch (RemoteException e) { } catch (RemoteException e) {
mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false);
mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED);
respondToClientWithErrorAndFinish( respondToClientWithErrorAndFinish(
CreateCredentialException.TYPE_UNKNOWN, CreateCredentialException.TYPE_UNKNOWN,
"Unable to invoke selector"); "Unable to invoke selector");

View File

@@ -33,7 +33,6 @@ import android.content.pm.PackageManager;
import android.credentials.ClearCredentialStateRequest; import android.credentials.ClearCredentialStateRequest;
import android.credentials.CreateCredentialException; import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialRequest; import android.credentials.CreateCredentialRequest;
import android.credentials.CredentialManager;
import android.credentials.CredentialOption; import android.credentials.CredentialOption;
import android.credentials.CredentialProviderInfo; import android.credentials.CredentialProviderInfo;
import android.credentials.GetCredentialException; import android.credentials.GetCredentialException;
@@ -50,6 +49,7 @@ import android.credentials.UnregisterCredentialDescriptionRequest;
import android.credentials.ui.IntentFactory; import android.credentials.ui.IntentFactory;
import android.os.Binder; import android.os.Binder;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.ICancellationSignal; import android.os.ICancellationSignal;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
@@ -70,9 +70,11 @@ import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.SecureSettingsServiceNameResolver; import com.android.server.infra.SecureSettingsServiceNameResolver;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -102,6 +104,13 @@ public final class CredentialManagerService
private final SparseArray<List<CredentialManagerServiceImpl>> mSystemServicesCacheList = private final SparseArray<List<CredentialManagerServiceImpl>> mSystemServicesCacheList =
new SparseArray<>(); new SparseArray<>();
/** Cache of all ongoing request sessions per user id. */
@GuardedBy("mLock")
private final SparseArray<Map<IBinder, RequestSession>> mRequestSessions =
new SparseArray<>();
private final SessionManager mSessionManager = new SessionManager();
public CredentialManagerService(@NonNull Context context) { public CredentialManagerService(@NonNull Context context) {
super( super(
context, context,
@@ -331,7 +340,7 @@ public final class CredentialManagerService
@NonNull @NonNull
private Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> private Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>>
getFilteredResultFromRegistry(List<CredentialOption> options) { getFilteredResultFromRegistry(List<CredentialOption> options) {
// Session for active/provisioned credential descriptions; // Session for active/provisioned credential descriptions;
CredentialDescriptionRegistry registry = CredentialDescriptionRegistry registry =
CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId()); CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId());
@@ -389,14 +398,6 @@ public final class CredentialManagerService
return providerSessions; return providerSessions;
} }
private List<CredentialProviderInfo> getServicesForCredentialDescription(int userId) {
return CredentialProviderInfoFactory.getCredentialProviderServices(
mContext,
userId,
CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS,
new HashSet<>());
}
@Override @Override
@GuardedBy("CredentialDescriptionRegistry.sLock") @GuardedBy("CredentialDescriptionRegistry.sLock")
public void onUserStopped(@NonNull TargetUser user) { public void onUserStopped(@NonNull TargetUser user) {
@@ -448,6 +449,8 @@ public final class CredentialManagerService
final GetRequestSession session = final GetRequestSession session =
new GetRequestSession( new GetRequestSession(
getContext(), getContext(),
mSessionManager,
mLock,
userId, userId,
callingUid, callingUid,
callback, callback,
@@ -455,6 +458,7 @@ public final class CredentialManagerService
constructCallingAppInfo(callingPackage, userId, request.getOrigin()), constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
CancellationSignal.fromTransport(cancelTransport), CancellationSignal.fromTransport(cancelTransport),
timestampBegan); timestampBegan);
addSessionLocked(userId, session);
List<ProviderSession> providerSessions = List<ProviderSession> providerSessions =
prepareProviderSessions(request, session); prepareProviderSessions(request, session);
@@ -499,6 +503,8 @@ public final class CredentialManagerService
final PrepareGetRequestSession session = final PrepareGetRequestSession session =
new PrepareGetRequestSession( new PrepareGetRequestSession(
getContext(), getContext(),
mSessionManager,
mLock,
userId, userId,
callingUid, callingUid,
getCredentialCallback, getCredentialCallback,
@@ -515,8 +521,8 @@ public final class CredentialManagerService
// TODO: fix // TODO: fix
prepareGetCredentialCallback.onResponse( prepareGetCredentialCallback.onResponse(
new PrepareGetCredentialResponseInternal( new PrepareGetCredentialResponseInternal(
false, null, false, null,
false, false, null)); false, false, null));
} catch (RemoteException e) { } catch (RemoteException e) {
Log.i( Log.i(
TAG, TAG,
@@ -540,10 +546,10 @@ public final class CredentialManagerService
List<CredentialOption> optionsThatRequireActiveCredentials = List<CredentialOption> optionsThatRequireActiveCredentials =
request.getCredentialOptions().stream() request.getCredentialOptions().stream()
.filter(credentialOption -> credentialOption .filter(credentialOption -> credentialOption
.getCredentialRetrievalData() .getCredentialRetrievalData()
.getStringArrayList( .getStringArrayList(
CredentialOption CredentialOption
.SUPPORTED_ELEMENT_KEYS) != null) .SUPPORTED_ELEMENT_KEYS) != null)
.toList(); .toList();
List<CredentialOption> optionsThatDoNotRequireActiveCredentials = List<CredentialOption> optionsThatDoNotRequireActiveCredentials =
@@ -614,6 +620,8 @@ public final class CredentialManagerService
final CreateRequestSession session = final CreateRequestSession session =
new CreateRequestSession( new CreateRequestSession(
getContext(), getContext(),
mSessionManager,
mLock,
userId, userId,
callingUid, callingUid,
request, request,
@@ -621,6 +629,7 @@ public final class CredentialManagerService
constructCallingAppInfo(callingPackage, userId, request.getOrigin()), constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
CancellationSignal.fromTransport(cancelTransport), CancellationSignal.fromTransport(cancelTransport),
timestampBegan); timestampBegan);
addSessionLocked(userId, session);
processCreateCredential(request, callback, session); processCreateCredential(request, callback, session);
return cancelTransport; return cancelTransport;
@@ -815,6 +824,8 @@ public final class CredentialManagerService
final ClearRequestSession session = final ClearRequestSession session =
new ClearRequestSession( new ClearRequestSession(
getContext(), getContext(),
mSessionManager,
mLock,
userId, userId,
callingUid, callingUid,
callback, callback,
@@ -822,6 +833,7 @@ public final class CredentialManagerService
constructCallingAppInfo(callingPackage, userId, null), constructCallingAppInfo(callingPackage, userId, null),
CancellationSignal.fromTransport(cancelTransport), CancellationSignal.fromTransport(cancelTransport),
timestampBegan); timestampBegan);
addSessionLocked(userId, session);
// Initiate all provider sessions // Initiate all provider sessions
// TODO: Determine if provider needs to have clear capability in their manifest // TODO: Determine if provider needs to have clear capability in their manifest
@@ -905,6 +917,13 @@ public final class CredentialManagerService
} }
} }
private void addSessionLocked(@UserIdInt int userId,
RequestSession requestSession) {
synchronized (mLock) {
mSessionManager.addSession(userId, requestSession.mRequestId, requestSession);
}
}
private void enforceCallingPackage(String callingPackage, int callingUid) { private void enforceCallingPackage(String callingPackage, int callingUid) {
int packageUid; int packageUid;
PackageManager pm = mContext.createContextAsUser( PackageManager pm = mContext.createContextAsUser(
@@ -919,4 +938,23 @@ public final class CredentialManagerService
throw new SecurityException(callingPackage + " does not belong to uid " + callingUid); throw new SecurityException(callingPackage + " does not belong to uid " + callingUid);
} }
} }
private class SessionManager implements RequestSession.SessionLifetime {
@Override
@GuardedBy("mLock")
public void onFinishRequestSession(@UserIdInt int userId, IBinder token) {
Log.i(TAG, "In onFinishRequestSession");
if (mRequestSessions.get(userId) != null) {
mRequestSessions.get(userId).remove(token);
}
}
@GuardedBy("mLock")
public void addSession(int userId, IBinder token, RequestSession requestSession) {
if (mRequestSessions.get(userId) == null) {
mRequestSessions.put(userId, new HashMap<>());
}
mRequestSessions.get(userId).put(token, requestSession);
}
}
} }

View File

@@ -30,6 +30,7 @@ import android.credentials.ui.RequestInfo;
import android.credentials.ui.UserSelectionDialogResult; import android.credentials.ui.UserSelectionDialogResult;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.ResultReceiver; import android.os.ResultReceiver;
import android.service.credentials.CredentialProviderInfoFactory; import android.service.credentials.CredentialProviderInfoFactory;
@@ -50,6 +51,20 @@ public class CredentialManagerUi {
@NonNull private final Context mContext; @NonNull private final Context mContext;
// TODO : Use for starting the activity for this user // TODO : Use for starting the activity for this user
private final int mUserId; private final int mUserId;
private UiStatus mStatus;
/** Creates intent that is ot be invoked to cancel an in-progress UI session. */
public Intent createCancelIntent(IBinder requestId, String packageName) {
return IntentFactory.createCancelUiIntent(requestId, /*shouldShowCancellationUi=*/ true,
packageName);
}
enum UiStatus {
IN_PROGRESS,
USER_INTERACTION,
NOT_STARTED, TERMINATED
}
@NonNull private final ResultReceiver mResultReceiver = new ResultReceiver( @NonNull private final ResultReceiver mResultReceiver = new ResultReceiver(
new Handler(Looper.getMainLooper())) { new Handler(Looper.getMainLooper())) {
@Override @Override
@@ -61,6 +76,7 @@ public class CredentialManagerUi {
private void handleUiResult(int resultCode, Bundle resultData) { private void handleUiResult(int resultCode, Bundle resultData) {
switch (resultCode) { switch (resultCode) {
case UserSelectionDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION: case UserSelectionDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION:
mStatus = UiStatus.IN_PROGRESS;
UserSelectionDialogResult selection = UserSelectionDialogResult UserSelectionDialogResult selection = UserSelectionDialogResult
.fromResultData(resultData); .fromResultData(resultData);
if (selection != null) { if (selection != null) {
@@ -70,16 +86,20 @@ public class CredentialManagerUi {
} }
break; break;
case UserSelectionDialogResult.RESULT_CODE_DIALOG_USER_CANCELED: case UserSelectionDialogResult.RESULT_CODE_DIALOG_USER_CANCELED:
mStatus = UiStatus.TERMINATED;
mCallbacks.onUiCancellation(/* isUserCancellation= */ true); mCallbacks.onUiCancellation(/* isUserCancellation= */ true);
break; break;
case UserSelectionDialogResult.RESULT_CODE_CANCELED_AND_LAUNCHED_SETTINGS: case UserSelectionDialogResult.RESULT_CODE_CANCELED_AND_LAUNCHED_SETTINGS:
mStatus = UiStatus.TERMINATED;
mCallbacks.onUiCancellation(/* isUserCancellation= */ false); mCallbacks.onUiCancellation(/* isUserCancellation= */ false);
break; break;
case UserSelectionDialogResult.RESULT_CODE_DATA_PARSING_FAILURE: case UserSelectionDialogResult.RESULT_CODE_DATA_PARSING_FAILURE:
mStatus = UiStatus.TERMINATED;
mCallbacks.onUiSelectorInvocationFailure(); mCallbacks.onUiSelectorInvocationFailure();
break; break;
default: default:
Slog.i(TAG, "Unknown error code returned from the UI"); Slog.i(TAG, "Unknown error code returned from the UI");
mStatus = UiStatus.IN_PROGRESS;
mCallbacks.onUiSelectorInvocationFailure(); mCallbacks.onUiSelectorInvocationFailure();
break; break;
} }
@@ -103,6 +123,17 @@ public class CredentialManagerUi {
mContext = context; mContext = context;
mUserId = userId; mUserId = userId;
mCallbacks = callbacks; mCallbacks = callbacks;
mStatus = UiStatus.IN_PROGRESS;
}
/** Set status for credential manager UI */
public void setStatus(UiStatus status) {
mStatus = status;
}
/** Returns status for credential manager UI */
public UiStatus getStatus() {
return mStatus;
} }
/** /**

View File

@@ -45,12 +45,13 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
IGetCredentialCallback, GetCredentialResponse> IGetCredentialCallback, GetCredentialResponse>
implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> { implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> {
private static final String TAG = "GetRequestSession"; private static final String TAG = "GetRequestSession";
public GetRequestSession(Context context, int userId, int callingUid, public GetRequestSession(Context context, RequestSession.SessionLifetime sessionCallback,
Object lock, int userId, int callingUid,
IGetCredentialCallback callback, GetCredentialRequest request, IGetCredentialCallback callback, GetCredentialRequest request,
CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal, CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal,
long startedTimestamp) { long startedTimestamp) {
super(context, userId, callingUid, request, callback, RequestInfo.TYPE_GET, super(context, sessionCallback, lock, userId, callingUid, request, callback,
callingAppInfo, cancellationSignal, startedTimestamp); RequestInfo.TYPE_GET, callingAppInfo, cancellationSignal, startedTimestamp);
int numTypes = (request.getCredentialOptions().stream() int numTypes = (request.getCredentialOptions().stream()
.map(CredentialOption::getType).collect( .map(CredentialOption::getType).collect(
Collectors.toSet())).size(); // Dedupe type strings Collectors.toSet())).size(); // Dedupe type strings
@@ -81,6 +82,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
@Override @Override
protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) { protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) {
mRequestSessionMetric.collectUiCallStartTime(System.nanoTime()); mRequestSessionMetric.collectUiCallStartTime(System.nanoTime());
mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.USER_INTERACTION);
try { try {
mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent( mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent(
RequestInfo.newGetRequestInfo( RequestInfo.newGetRequestInfo(
@@ -88,6 +90,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
providerDataList)); providerDataList));
} catch (RemoteException e) { } catch (RemoteException e) {
mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false);
mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED);
respondToClientWithErrorAndFinish( respondToClientWithErrorAndFinish(
GetCredentialException.TYPE_UNKNOWN, "Unable to instantiate selector"); GetCredentialException.TYPE_UNKNOWN, "Unable to instantiate selector");
} }

View File

@@ -49,14 +49,13 @@ public class PrepareGetRequestSession extends GetRequestSession {
private final IPrepareGetCredentialCallback mPrepareGetCredentialCallback; private final IPrepareGetCredentialCallback mPrepareGetCredentialCallback;
public PrepareGetRequestSession(Context context, int userId, int callingUid, public PrepareGetRequestSession(Context context,
IGetCredentialCallback callback, RequestSession.SessionLifetime sessionCallback, Object lock, int userId,
GetCredentialRequest request, int callingUid, IGetCredentialCallback getCredCallback, GetCredentialRequest request,
CallingAppInfo callingAppInfo, CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal,
CancellationSignal cancellationSignal, long startedTimestamp, long startedTimestamp, IPrepareGetCredentialCallback prepareGetCredentialCallback) {
IPrepareGetCredentialCallback prepareGetCredentialCallback) { super(context, sessionCallback, lock, userId, callingUid, getCredCallback, request,
super(context, userId, callingUid, callback, request, callingAppInfo, cancellationSignal, callingAppInfo, cancellationSignal, startedTimestamp);
startedTimestamp);
int numTypes = (request.getCredentialOptions().stream() int numTypes = (request.getCredentialOptions().stream()
.map(CredentialOption::getType).collect( .map(CredentialOption::getType).collect(
Collectors.toSet())).size(); // Dedupe type strings Collectors.toSet())).size(); // Dedupe type strings

View File

@@ -126,7 +126,8 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS
protected void invokeSession() { protected void invokeSession() {
if (mRemoteCredentialService != null) { if (mRemoteCredentialService != null) {
startCandidateMetrics(); startCandidateMetrics();
mRemoteCredentialService.onClearCredentialState(mProviderRequest, this); mProviderCancellationSignal =
mRemoteCredentialService.onClearCredentialState(mProviderRequest, this);
} }
} }
} }

View File

@@ -236,7 +236,8 @@ public final class ProviderCreateSession extends ProviderSession<
protected void invokeSession() { protected void invokeSession() {
if (mRemoteCredentialService != null) { if (mRemoteCredentialService != null) {
startCandidateMetrics(); startCandidateMetrics();
mRemoteCredentialService.onCreateCredential(mProviderRequest, this); mProviderCancellationSignal =
mRemoteCredentialService.onCreateCredential(mProviderRequest, this);
} }
} }

View File

@@ -302,7 +302,9 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
protected void invokeSession() { protected void invokeSession() {
if (mRemoteCredentialService != null) { if (mRemoteCredentialService != null) {
startCandidateMetrics(); startCandidateMetrics();
mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this); mProviderCancellationSignal =
mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this);
boolean foundSig = mProviderCancellationSignal == null;
} }
} }

View File

@@ -30,6 +30,7 @@ import android.credentials.ui.ProviderPendingIntentResponse;
import android.os.ICancellationSignal; import android.os.ICancellationSignal;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import android.util.Slog;
import com.android.server.credentials.metrics.ProviderSessionMetric; import com.android.server.credentials.metrics.ProviderSessionMetric;
@@ -189,7 +190,7 @@ public abstract class ProviderSession<T, R>
} }
setStatus(Status.CANCELED); setStatus(Status.CANCELED);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.i(TAG, "Issue while cancelling provider session: " + e.getMessage()); Slog.e(TAG, "Issue while cancelling provider session: ", e);
} }
} }

View File

@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.UserIdInt; import android.annotation.UserIdInt;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.credentials.CredentialProviderInfo; import android.credentials.CredentialProviderInfo;
import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderData;
import android.credentials.ui.UserSelectionDialogResult; import android.credentials.ui.UserSelectionDialogResult;
@@ -29,8 +30,10 @@ import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle;
import android.service.credentials.CallingAppInfo; import android.service.credentials.CallingAppInfo;
import android.util.Log; import android.util.Log;
import android.util.Slog;
import com.android.internal.R; import com.android.internal.R;
import com.android.server.credentials.metrics.ApiName; import com.android.server.credentials.metrics.ApiName;
@@ -39,8 +42,8 @@ import com.android.server.credentials.metrics.ProviderStatusForMetrics;
import com.android.server.credentials.metrics.RequestSessionMetric; import com.android.server.credentials.metrics.RequestSessionMetric;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* Base class of a request session, that listens to UI events. This class must be extended * Base class of a request session, that listens to UI events. This class must be extended
@@ -49,6 +52,11 @@ import java.util.Map;
abstract class RequestSession<T, U, V> implements CredentialManagerUi.CredentialManagerUiCallback { abstract class RequestSession<T, U, V> implements CredentialManagerUi.CredentialManagerUiCallback {
private static final String TAG = "RequestSession"; private static final String TAG = "RequestSession";
public interface SessionLifetime {
/** Called when the user makes a selection. */
void onFinishRequestSession(@UserIdInt int userId, IBinder token);
}
// TODO: Revise access levels of attributes // TODO: Revise access levels of attributes
@NonNull @NonNull
protected final T mClientRequest; protected final T mClientRequest;
@@ -72,10 +80,14 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
@NonNull @NonNull
protected final CancellationSignal mCancellationSignal; protected final CancellationSignal mCancellationSignal;
protected final Map<String, ProviderSession> mProviders = new HashMap<>(); protected final Map<String, ProviderSession> mProviders = new ConcurrentHashMap<>();
protected final RequestSessionMetric mRequestSessionMetric = new RequestSessionMetric(); protected final RequestSessionMetric mRequestSessionMetric = new RequestSessionMetric();
protected final String mHybridService; protected final String mHybridService;
protected final Object mLock;
protected final SessionLifetime mSessionCallback;
@NonNull @NonNull
protected RequestSessionStatus mRequestSessionStatus = protected RequestSessionStatus mRequestSessionStatus =
RequestSessionStatus.IN_PROGRESS; RequestSessionStatus.IN_PROGRESS;
@@ -91,11 +103,15 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
} }
protected RequestSession(@NonNull Context context, protected RequestSession(@NonNull Context context,
@UserIdInt int userId, int callingUid, @NonNull T clientRequest, U clientCallback, RequestSession.SessionLifetime sessionCallback,
Object lock, @UserIdInt int userId, int callingUid,
@NonNull T clientRequest, U clientCallback,
@NonNull String requestType, @NonNull String requestType,
CallingAppInfo callingAppInfo, CallingAppInfo callingAppInfo,
CancellationSignal cancellationSignal, long timestampStarted) { CancellationSignal cancellationSignal, long timestampStarted) {
mContext = context; mContext = context;
mLock = lock;
mSessionCallback = sessionCallback;
mUserId = userId; mUserId = userId;
mCallingUid = callingUid; mCallingUid = callingUid;
mClientRequest = clientRequest; mClientRequest = clientRequest;
@@ -111,6 +127,32 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
R.string.config_defaultCredentialManagerHybridService); R.string.config_defaultCredentialManagerHybridService);
mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted, mRequestId, mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted, mRequestId,
mCallingUid, ApiName.getMetricCodeFromRequestInfo(mRequestType)); mCallingUid, ApiName.getMetricCodeFromRequestInfo(mRequestType));
setCancellationListener();
}
private void setCancellationListener() {
mCancellationSignal.setOnCancelListener(
() -> {
boolean isUiActive = maybeCancelUi();
finishSession(!isUiActive);
}
);
}
private boolean maybeCancelUi() {
if (mCredentialManagerUi.getStatus()
== CredentialManagerUi.UiStatus.USER_INTERACTION) {
final long originalCallingUidToken = Binder.clearCallingIdentity();
try {
mContext.startActivityAsUser(mCredentialManagerUi.createCancelIntent(
mRequestId, mClientAppInfo.getPackageName())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), UserHandle.of(mUserId));
return true;
} finally {
Binder.restoreCallingIdentity(originalCallingUidToken);
}
}
return false;
} }
public abstract ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo, public abstract ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo,
@@ -154,12 +196,19 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
} }
protected void finishSession(boolean propagateCancellation) { protected void finishSession(boolean propagateCancellation) {
Log.i(TAG, "finishing session"); Slog.d(TAG, "finishing session with propagateCancellation " + propagateCancellation);
if (propagateCancellation) { if (propagateCancellation) {
mProviders.values().forEach(ProviderSession::cancelProviderRemoteSession); mProviders.values().forEach(ProviderSession::cancelProviderRemoteSession);
} }
mRequestSessionStatus = RequestSessionStatus.COMPLETE; mRequestSessionStatus = RequestSessionStatus.COMPLETE;
mProviders.clear(); mProviders.clear();
clearRequestSessionLocked();
}
private void clearRequestSessionLocked() {
synchronized (mLock) {
mSessionCallback.onFinishRequestSession(mUserId, mRequestId);
}
} }
protected boolean isAnyProviderPending() { protected boolean isAnyProviderPending() {