From 61ae713373b74a50154fb850da68cbafb6f95b7a Mon Sep 17 00:00:00 2001 From: Reema Bajwa Date: Fri, 25 Nov 2022 07:06:45 +0000 Subject: [PATCH] Add error propagation piping for get & create Test: Built & deployed locally Change-Id: I67b57b228722ffce8a10e9269ef53ffa35fc18fc --- .../credentials/CredentialProviderErrors.java | 51 +++++++ .../CredentialProviderException.java | 96 ------------- .../credentials/CreateRequestSession.java | 51 +++++-- .../credentials/CredentialManagerService.java | 32 ++++- .../server/credentials/GetRequestSession.java | 37 ++++- .../PendingIntentResultHandler.java | 28 +++- .../credentials/ProviderCreateSession.java | 72 ++++++++-- .../credentials/ProviderGetSession.java | 133 +++++++++++++----- .../server/credentials/ProviderSession.java | 13 +- .../credentials/RemoteCredentialService.java | 30 ++-- .../server/credentials/RequestSession.java | 6 + 11 files changed, 357 insertions(+), 192 deletions(-) create mode 100644 core/java/android/service/credentials/CredentialProviderErrors.java delete mode 100644 core/java/android/service/credentials/CredentialProviderException.java diff --git a/core/java/android/service/credentials/CredentialProviderErrors.java b/core/java/android/service/credentials/CredentialProviderErrors.java new file mode 100644 index 0000000000000..e9dc35bc1062c --- /dev/null +++ b/core/java/android/service/credentials/CredentialProviderErrors.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.credentials; + +/** + * Contains custom error codes to be used internally for various credential + * provider error states. + * + * @hide + */ +public class CredentialProviderErrors { + public static final int ERROR_UNKNOWN = 0; + + /** + * For internal use only. + * Error code to be used when the provider request times out. + * + * @hide + */ + public static final int ERROR_TIMEOUT = 1; + + /** + * For internal use only. + * Error code to be used when the async task is canceled internally. + * + * @hide + */ + public static final int ERROR_TASK_CANCELED = 2; + + /** + * For internal use only. + * Error code to be used when an exception is received from the provider. + * + * @hide + */ + public static final int ERROR_PROVIDER_FAILURE = 3; +} diff --git a/core/java/android/service/credentials/CredentialProviderException.java b/core/java/android/service/credentials/CredentialProviderException.java deleted file mode 100644 index 969bcb57ff906..0000000000000 --- a/core/java/android/service/credentials/CredentialProviderException.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.service.credentials; - -import android.annotation.IntDef; -import android.annotation.NonNull; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Contains custom exceptions to be used by credential providers on failure. - * - * @hide - */ -public class CredentialProviderException extends Exception { - public static final int ERROR_UNKNOWN = 0; - - /** - * For internal use only. - * Error code to be used when the provider request times out. - * - * @hide - */ - public static final int ERROR_TIMEOUT = 1; - - /** - * For internal use only. - * Error code to be used when the async task is canceled internally. - * - * @hide - */ - public static final int ERROR_TASK_CANCELED = 2; - - /** - * For internal use only. - * Error code to be used when the provider encounters a failure while processing the request. - * - * @hide - */ - public static final int ERROR_PROVIDER_FAILURE = 3; - - private final int mErrorCode; - - /** - * @hide - */ - @IntDef(prefix = {"ERROR_"}, value = { - ERROR_UNKNOWN, - ERROR_TIMEOUT, - ERROR_TASK_CANCELED - }) - @Retention(RetentionPolicy.SOURCE) - public @interface CredentialProviderError { } - - public CredentialProviderException(@CredentialProviderError int errorCode, - @NonNull String message, @NonNull Throwable cause) { - super(message, cause); - mErrorCode = errorCode; - } - - public CredentialProviderException(@CredentialProviderError int errorCode, - @NonNull String message) { - super(message); - mErrorCode = errorCode; - } - - public CredentialProviderException(@CredentialProviderError int errorCode, - @NonNull Throwable cause) { - super(cause); - mErrorCode = errorCode; - } - - public CredentialProviderException(@CredentialProviderError int errorCode) { - super(); - mErrorCode = errorCode; - } - - public @CredentialProviderError int getErrorCode() { - return mErrorCode; - } -} diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java index 3d337b896bb7b..d9dc4ed6c7665 100644 --- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java @@ -83,16 +83,6 @@ public final class CreateRequestSession extends RequestSession providerSessions = - initiateProviderSessions( - session, - request.getGetCredentialOptions().stream() - .map(GetCredentialOption::getType) - .collect(Collectors.toList())); - // TODO : Return error when no providers available + initiateProviderSessions(session, request.getGetCredentialOptions() + .stream().map(GetCredentialOption::getType) + .collect(Collectors.toList())); + + if (providerSessions.isEmpty()) { + try { + // TODO("Replace with properly defined error type") + callback.onError("unknown_type", + "No providers available to fulfill request."); + } catch (RemoteException e) { + Log.i(TAG, "Issue invoking onError on IGetCredentialCallback " + + "callback: " + e.getMessage()); + } + } // Iterate over all provider sessions and invoke the request providerSessions.forEach(providerGetSession -> { @@ -212,7 +220,17 @@ public final class CredentialManagerService // Initiate all provider sessions List providerSessions = initiateProviderSessions(session, List.of(request.getType())); - // TODO : Return error when no providers available + + if (providerSessions.isEmpty()) { + try { + // TODO("Replace with properly defined error type") + callback.onError("unknown_type", + "No providers available to fulfill request."); + } catch (RemoteException e) { + Log.i(TAG, "Issue invoking onError on ICreateCredentialCallback " + + "callback: " + e.getMessage()); + } + } // Iterate over all provider sessions and invoke the request providerSessions.forEach( diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java index c092b3af9699a..6e070f940060f 100644 --- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java @@ -88,15 +88,27 @@ public final class GetRequestSession extends RequestSession())).setGetCredentialOptions( + new ArraySet<>())).setGetCredentialOptions( filteredOptions).build(); } Log.i(TAG, "In createProviderRequest - returning null"); @@ -164,8 +166,10 @@ public final class ProviderGetSession extends ProviderSession implements RemoteCredentialService.ProviderCallbacks { + + private static final String TAG = "ProviderSession"; // Key to be used as an entry key for a remote entry protected static final String REMOTE_ENTRY_KEY = "remote_entry_key"; @@ -52,6 +53,7 @@ public abstract class ProviderSession @Nullable protected R mProviderResponse; @Nullable protected Pair mUiRemoteEntry; + /** * Returns true if the given status reflects that the provider state is ready to be shown * on the credMan UI. @@ -95,8 +97,12 @@ public abstract class ProviderSession /** Called when status changes. */ void onProviderStatusChanged(Status status, ComponentName componentName); - /** Called when the final credential to be returned to the client has been received. */ + /** Called when the final credential is received through an entry selection. */ void onFinalResponseReceived(ComponentName componentName, V response); + + /** Called when an error is received through an entry selection. */ + void onFinalErrorReceived(ComponentName componentName, String errorType, + @Nullable String message); } protected ProviderSession(@NonNull Context context, @NonNull CredentialProviderInfo info, @@ -129,8 +135,7 @@ public abstract class ProviderSession /** Converts exception to a provider session status. */ @NonNull - public static Status toStatus( - @CredentialProviderException.CredentialProviderError int errorCode) { + public static Status toStatus(int errorCode) { // TODO : Add more mappings as more flows are supported return Status.CANCELED; } diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java index 307d96a3bded4..6049fd9a4a214 100644 --- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java +++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java @@ -30,7 +30,7 @@ import android.service.credentials.BeginCreateCredentialRequest; import android.service.credentials.BeginCreateCredentialResponse; import android.service.credentials.BeginGetCredentialRequest; import android.service.credentials.BeginGetCredentialResponse; -import android.service.credentials.CredentialProviderException; +import android.service.credentials.CredentialProviderErrors; import android.service.credentials.CredentialProviderService; import android.service.credentials.IBeginCreateCredentialCallback; import android.service.credentials.IBeginGetCredentialCallback; @@ -72,8 +72,7 @@ public class RemoteCredentialService extends ServiceConnector.Impl implements CredentialManagerUi.CredentialMan @Override // from CredentialManagerUiCallbacks public void onUiCancellation() { + Log.i(TAG, "Ui canceled"); // User canceled the activity finishSession(); } @@ -133,10 +134,12 @@ abstract class RequestSession implements CredentialManagerUi.CredentialMan } protected void finishSession() { + Log.i(TAG, "finishing session"); clearProviderSessions(); } protected void clearProviderSessions() { + Log.i(TAG, "Clearing sessions"); //TODO: Implement mProviders.clear(); } @@ -151,6 +154,9 @@ abstract class RequestSession implements CredentialManagerUi.CredentialMan } private void getProviderDataAndInitiateUi() { + Log.i(TAG, "In getProviderDataAndInitiateUi"); + Log.i(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size()); + ArrayList providerDataList = new ArrayList<>(); for (ProviderSession session : mProviders.values()) { Log.i(TAG, "preparing data for : " + session.getComponentName());