Merge "Fix cancellation on the provider side" into udc-dev

This commit is contained in:
Reema Bajwa
2023-04-05 22:54:23 +00:00
committed by Android (Google) Code Review
10 changed files with 133 additions and 53 deletions

View File

@@ -231,12 +231,18 @@ public abstract class CredentialProviderService extends Service {
}
private final ICredentialProviderService mInterface = new ICredentialProviderService.Stub() {
public ICancellationSignal onBeginGetCredential(BeginGetCredentialRequest request,
@Override
public void onBeginGetCredential(BeginGetCredentialRequest request,
IBeginGetCredentialCallback callback) {
Objects.requireNonNull(request);
Objects.requireNonNull(callback);
ICancellationSignal transport = CancellationSignal.createTransport();
try {
callback.onCancellable(transport);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
mHandler.sendMessage(obtainMessage(
CredentialProviderService::onBeginGetCredential,
@@ -267,7 +273,6 @@ public abstract class CredentialProviderService extends Service {
}
}
));
return transport;
}
private void enforceRemoteEntryPermission() {
String permission =
@@ -280,12 +285,17 @@ public abstract class CredentialProviderService extends Service {
}
@Override
public ICancellationSignal onBeginCreateCredential(BeginCreateCredentialRequest request,
public void onBeginCreateCredential(BeginCreateCredentialRequest request,
IBeginCreateCredentialCallback callback) {
Objects.requireNonNull(request);
Objects.requireNonNull(callback);
ICancellationSignal transport = CancellationSignal.createTransport();
try {
callback.onCancellable(transport);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
mHandler.sendMessage(obtainMessage(
CredentialProviderService::onBeginCreateCredential,
@@ -316,16 +326,20 @@ public abstract class CredentialProviderService extends Service {
}
}
));
return transport;
}
@Override
public ICancellationSignal onClearCredentialState(ClearCredentialStateRequest request,
public void onClearCredentialState(ClearCredentialStateRequest request,
IClearCredentialStateCallback callback) {
Objects.requireNonNull(request);
Objects.requireNonNull(callback);
ICancellationSignal transport = CancellationSignal.createTransport();
try {
callback.onCancellable(transport);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
mHandler.sendMessage(obtainMessage(
CredentialProviderService::onClearCredentialState,
@@ -350,7 +364,6 @@ public abstract class CredentialProviderService extends Service {
}
}
));
return transport;
}
};

View File

@@ -1,6 +1,7 @@
package android.service.credentials;
import android.service.credentials.BeginCreateCredentialResponse;
import android.os.ICancellationSignal;
/**
* Interface from the system to a credential provider service.
@@ -10,4 +11,5 @@ import android.service.credentials.BeginCreateCredentialResponse;
oneway interface IBeginCreateCredentialCallback {
void onSuccess(in BeginCreateCredentialResponse request);
void onFailure(String errorType, in CharSequence message);
void onCancellable(in ICancellationSignal cancellation);
}

View File

@@ -1,6 +1,8 @@
package android.service.credentials;
import android.service.credentials.BeginGetCredentialResponse;
import android.os.ICancellationSignal;
/**
* Interface from the system to a credential provider service.
@@ -10,4 +12,5 @@ import android.service.credentials.BeginGetCredentialResponse;
oneway interface IBeginGetCredentialCallback {
void onSuccess(in BeginGetCredentialResponse response);
void onFailure(String errorType, in CharSequence message);
void onCancellable(in ICancellationSignal cancellation);
}

View File

@@ -16,12 +16,16 @@
package android.service.credentials;
import android.os.ICancellationSignal;
/**
* Callback for onClearCredentialState request.
*
* @hide
*/
interface IClearCredentialStateCallback {
oneway void onSuccess();
oneway void onFailure(String errorType, CharSequence message);
oneway interface IClearCredentialStateCallback {
void onSuccess();
void onFailure(String errorType, CharSequence message);
void onCancellable(in ICancellationSignal cancellation);
}

View File

@@ -30,8 +30,8 @@ import android.os.ICancellationSignal;
*
* @hide
*/
interface ICredentialProviderService {
ICancellationSignal onBeginGetCredential(in BeginGetCredentialRequest request, in IBeginGetCredentialCallback callback);
ICancellationSignal onBeginCreateCredential(in BeginCreateCredentialRequest request, in IBeginCreateCredentialCallback callback);
ICancellationSignal onClearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback);
oneway interface ICredentialProviderService {
void onBeginGetCredential(in BeginGetCredentialRequest request, in IBeginGetCredentialCallback callback);
void onBeginCreateCredential(in BeginCreateCredentialRequest request, in IBeginCreateCredentialCallback callback);
void onClearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback);
}

View File

@@ -23,6 +23,7 @@ import android.credentials.ClearCredentialStateException;
import android.credentials.CredentialProviderInfo;
import android.credentials.ui.ProviderData;
import android.credentials.ui.ProviderPendingIntentResponse;
import android.os.ICancellationSignal;
import android.service.credentials.CallingAppInfo;
import android.service.credentials.ClearCredentialStateRequest;
import android.util.Log;
@@ -109,6 +110,11 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS
}
}
@Override
public void onProviderCancellable(ICancellationSignal cancellation) {
mProviderCancellationSignal = cancellation;
}
@Nullable
@Override
protected ProviderData prepareUiData() {
@@ -126,8 +132,7 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
mProviderCancellationSignal =
mRemoteCredentialService.onClearCredentialState(mProviderRequest, this);
mRemoteCredentialService.onClearCredentialState(mProviderRequest, this);
}
}
}

View File

@@ -29,6 +29,7 @@ import android.credentials.ui.CreateCredentialProviderData;
import android.credentials.ui.Entry;
import android.credentials.ui.ProviderPendingIntentResponse;
import android.os.Bundle;
import android.os.ICancellationSignal;
import android.service.credentials.BeginCreateCredentialRequest;
import android.service.credentials.BeginCreateCredentialResponse;
import android.service.credentials.CallingAppInfo;
@@ -173,6 +174,11 @@ public final class ProviderCreateSession extends ProviderSession<
}
}
@Override
public void onProviderCancellable(ICancellationSignal cancellation) {
mProviderCancellationSignal = cancellation;
}
private void onSetInitialRemoteResponse(BeginCreateCredentialResponse response) {
Log.i(TAG, "onSetInitialRemoteResponse with save entries");
mProviderResponse = response;
@@ -236,8 +242,7 @@ public final class ProviderCreateSession extends ProviderSession<
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
mProviderCancellationSignal =
mRemoteCredentialService.onCreateCredential(mProviderRequest, this);
mRemoteCredentialService.onBeginCreateCredential(mProviderRequest, this);
}
}

View File

@@ -30,6 +30,7 @@ import android.credentials.ui.AuthenticationEntry;
import android.credentials.ui.Entry;
import android.credentials.ui.GetCredentialProviderData;
import android.credentials.ui.ProviderPendingIntentResponse;
import android.os.ICancellationSignal;
import android.service.credentials.Action;
import android.service.credentials.BeginGetCredentialOption;
import android.service.credentials.BeginGetCredentialRequest;
@@ -235,6 +236,11 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
}
}
@Override
public void onProviderCancellable(ICancellationSignal cancellation) {
mProviderCancellationSignal = cancellation;
}
@Override // Selection call from the request provider
protected void onUiEntrySelected(String entryType, String entryKey,
ProviderPendingIntentResponse providerPendingIntentResponse) {
@@ -302,9 +308,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
mProviderCancellationSignal =
mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this);
boolean foundSig = mProviderCancellationSignal == null;
mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this);
}
}

View File

@@ -29,6 +29,7 @@ import android.credentials.ui.Entry;
import android.credentials.ui.GetCredentialProviderData;
import android.credentials.ui.ProviderData;
import android.credentials.ui.ProviderPendingIntentResponse;
import android.os.ICancellationSignal;
import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialEntry;
import android.service.credentials.CredentialProviderService;
@@ -115,7 +116,7 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption
@NonNull String servicePackageName,
@NonNull CredentialOption requestOption) {
super(context, requestOption, session,
new ComponentName(servicePackageName, servicePackageName) ,
new ComponentName(servicePackageName, servicePackageName),
userId, null);
mCredentialDescriptionRegistry = CredentialDescriptionRegistry.forUser(userId);
mCallingAppInfo = callingAppInfo;
@@ -132,7 +133,7 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption
@NonNull String servicePackageName,
@NonNull CredentialOption requestOption) {
super(context, requestOption, session,
new ComponentName(servicePackageName, servicePackageName) ,
new ComponentName(servicePackageName, servicePackageName),
userId, null);
mCredentialDescriptionRegistry = CredentialDescriptionRegistry.forUser(userId);
mCallingAppInfo = callingAppInfo;
@@ -254,14 +255,19 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption
// No need to do anything since this class does not rely on a remote service.
}
@Override
public void onProviderCancellable(ICancellationSignal cancellation) {
// No need to do anything since this class does not rely on a remote service.
}
@Override
protected void invokeSession() {
mProviderResponse = mCredentialDescriptionRegistry
.getFilteredResultForProvider(mCredentialProviderPackageName,
mElementKeys);
mCredentialEntries = mProviderResponse.stream().flatMap(
(Function<CredentialDescriptionRegistry.FilterResult,
Stream<CredentialEntry>>) filterResult
(Function<CredentialDescriptionRegistry.FilterResult,
Stream<CredentialEntry>>) filterResult
-> filterResult.mCredentialEntries.stream())
.collect(Collectors.toList());
updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED,

View File

@@ -82,6 +82,9 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
/** Called when the remote provider service dies. */
void onProviderServiceDied(RemoteCredentialService service);
/** Called to set the cancellation transport from the remote provider service. */
void onProviderCancellable(ICancellationSignal cancellation);
}
public RemoteCredentialService(@NonNull Context context,
@@ -117,43 +120,56 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
* @param callback the callback to be used to send back the provider response to the
* {@link ProviderGetSession} class that maintains provider state
*/
public ICancellationSignal onBeginGetCredential(@NonNull BeginGetCredentialRequest request,
public void onBeginGetCredential(@NonNull BeginGetCredentialRequest request,
ProviderCallbacks<BeginGetCredentialResponse> callback) {
Log.i(TAG, "In onGetCredentials in RemoteCredentialService");
AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
AtomicReference<CompletableFuture<BeginGetCredentialResponse>> futureRef =
new AtomicReference<>();
CompletableFuture<BeginGetCredentialResponse> connectThenExecute = postAsync(service -> {
CompletableFuture<BeginGetCredentialResponse> getCredentials =
new CompletableFuture<>();
final long originalCallingUidToken = Binder.clearCallingIdentity();
try {
ICancellationSignal cancellationSignal =
service.onBeginGetCredential(request,
new IBeginGetCredentialCallback.Stub() {
@Override
public void onSuccess(BeginGetCredentialResponse response) {
getCredentials.complete(response);
}
service.onBeginGetCredential(request,
new IBeginGetCredentialCallback.Stub() {
@Override
public void onSuccess(BeginGetCredentialResponse response) {
getCredentials.complete(response);
}
@Override
public void onFailure(String errorType, CharSequence message) {
Log.i(TAG, "In onFailure in RemoteCredentialService");
String errorMsg = message == null ? "" : String.valueOf(
message);
getCredentials.completeExceptionally(
new GetCredentialException(errorType, errorMsg));
}
});
cancellationSink.set(cancellationSignal);
@Override
public void onFailure(String errorType, CharSequence message) {
Log.i(TAG, "In onFailure in RemoteCredentialService");
String errorMsg = message == null ? "" : String.valueOf(
message);
getCredentials.completeExceptionally(
new GetCredentialException(errorType, errorMsg));
}
@Override
public void onCancellable(ICancellationSignal cancellation) {
CompletableFuture<BeginGetCredentialResponse> future =
futureRef.get();
if (future != null && future.isCancelled()) {
dispatchCancellationSignal(cancellation);
} else {
cancellationSink.set(cancellation);
callback.onProviderCancellable(cancellation);
}
}
});
return getCredentials;
} finally {
Binder.restoreCallingIdentity(originalCallingUidToken);
}
}).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
futureRef.set(connectThenExecute);
connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() ->
handleExecutionResponse(result, error, cancellationSink, callback)));
return cancellationSink.get();
}
/**
@@ -164,10 +180,12 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
* @param callback the callback to be used to send back the provider response to the
* {@link ProviderCreateSession} class that maintains provider state
*/
public ICancellationSignal onCreateCredential(@NonNull BeginCreateCredentialRequest request,
public void onBeginCreateCredential(@NonNull BeginCreateCredentialRequest request,
ProviderCallbacks<BeginCreateCredentialResponse> callback) {
Log.i(TAG, "In onCreateCredential in RemoteCredentialService");
AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
AtomicReference<CompletableFuture<BeginCreateCredentialResponse>> futureRef =
new AtomicReference<>();
CompletableFuture<BeginCreateCredentialResponse> connectThenExecute =
postAsync(service -> {
@@ -175,7 +193,7 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
new CompletableFuture<>();
final long originalCallingUidToken = Binder.clearCallingIdentity();
try {
ICancellationSignal cancellationSignal = service.onBeginCreateCredential(
service.onBeginCreateCredential(
request, new IBeginCreateCredentialCallback.Stub() {
@Override
public void onSuccess(BeginCreateCredentialResponse response) {
@@ -192,18 +210,28 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
createCredentialFuture.completeExceptionally(
new CreateCredentialException(errorType, errorMsg));
}
@Override
public void onCancellable(ICancellationSignal cancellation) {
CompletableFuture<BeginCreateCredentialResponse> future =
futureRef.get();
if (future != null && future.isCancelled()) {
dispatchCancellationSignal(cancellation);
} else {
cancellationSink.set(cancellation);
callback.onProviderCancellable(cancellation);
}
}
});
cancellationSink.set(cancellationSignal);
return createCredentialFuture;
} finally {
Binder.restoreCallingIdentity(originalCallingUidToken);
}
}).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
futureRef.set(connectThenExecute);
connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() ->
handleExecutionResponse(result, error, cancellationSink, callback)));
return cancellationSink.get();
}
/**
@@ -214,10 +242,11 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
* @param callback the callback to be used to send back the provider response to the
* {@link ProviderClearSession} class that maintains provider state
*/
public ICancellationSignal onClearCredentialState(@NonNull ClearCredentialStateRequest request,
public void onClearCredentialState(@NonNull ClearCredentialStateRequest request,
ProviderCallbacks<Void> callback) {
Log.i(TAG, "In onClearCredentialState in RemoteCredentialService");
AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
AtomicReference<CompletableFuture<Void>> futureRef = new AtomicReference<>();
CompletableFuture<Void> connectThenExecute =
postAsync(service -> {
@@ -225,7 +254,7 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
new CompletableFuture<>();
final long originalCallingUidToken = Binder.clearCallingIdentity();
try {
ICancellationSignal cancellationSignal = service.onClearCredentialState(
service.onClearCredentialState(
request, new IClearCredentialStateCallback.Stub() {
@Override
public void onSuccess() {
@@ -243,18 +272,27 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
new ClearCredentialStateException(errorType,
errorMsg));
}
@Override
public void onCancellable(ICancellationSignal cancellation) {
CompletableFuture<Void> future = futureRef.get();
if (future != null && future.isCancelled()) {
dispatchCancellationSignal(cancellation);
} else {
cancellationSink.set(cancellation);
callback.onProviderCancellable(cancellation);
}
}
});
cancellationSink.set(cancellationSignal);
return clearCredentialFuture;
} finally {
Binder.restoreCallingIdentity(originalCallingUidToken);
}
}).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
futureRef.set(connectThenExecute);
connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() ->
handleExecutionResponse(result, error, cancellationSink, callback)));
return cancellationSink.get();
}
private <T> void handleExecutionResponse(T result,