Merge "Listen to live cancellation signal" into udc-dev
This commit is contained in:
@@ -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) =
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user