Loading core/java/android/credentials/ui/RequestInfo.java +2 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ public class RequestInfo implements Parcelable { public static final @NonNull String EXTRA_REQUEST_INFO = "android.credentials.ui.extra.REQUEST_INFO"; /** Type value for any request that does not require UI. */ public static final @NonNull String TYPE_UNDEFINED = "android.credentials.ui.TYPE_UNDEFINED"; /** Type value for an executeGetCredential request. */ public static final @NonNull String TYPE_GET = "android.credentials.ui.TYPE_GET"; /** Type value for an executeCreateCredential request. */ Loading services/credentials/java/com/android/server/credentials/ClearRequestSession.java 0 → 100644 +142 −0 Original line number Diff line number Diff line /* * 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 com.android.server.credentials; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.credentials.ClearCredentialStateRequest; import android.credentials.IClearCredentialStateCallback; import android.credentials.ui.ProviderData; import android.credentials.ui.RequestInfo; import android.os.RemoteException; import android.service.credentials.CredentialProviderInfo; import android.util.Log; import java.util.ArrayList; /** * Central session for a single clearCredentialState request. This class listens to the * responses from providers, and updates the provider(S) state. */ public final class ClearRequestSession extends RequestSession<ClearCredentialStateRequest, IClearCredentialStateCallback> implements ProviderSession.ProviderInternalCallback<Void> { private static final String TAG = "GetRequestSession"; public ClearRequestSession(Context context, int userId, IClearCredentialStateCallback callback, ClearCredentialStateRequest request, String callingPackage) { super(context, userId, request, callback, RequestInfo.TYPE_UNDEFINED, callingPackage); } /** * Creates a new provider session, and adds it list of providers that are contributing to * this session. * @return the provider session created within this request session, for the given provider * info. */ @Override @Nullable public ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo, RemoteCredentialService remoteCredentialService) { ProviderClearSession providerClearSession = ProviderClearSession .createNewSession(mContext, mUserId, providerInfo, this, remoteCredentialService); if (providerClearSession != null) { Log.i(TAG, "In startProviderSession - provider session created and being added"); mProviders.put(providerClearSession.getComponentName().flattenToString(), providerClearSession); } return providerClearSession; } @Override // from provider session public void onProviderStatusChanged(ProviderSession.Status status, ComponentName componentName) { Log.i(TAG, "in onStatusChanged with status: " + status); if (ProviderSession.isTerminatingStatus(status)) { Log.i(TAG, "in onStatusChanged terminating status"); onProviderTerminated(componentName); } else if (ProviderSession.isCompletionStatus(status)) { Log.i(TAG, "in onStatusChanged isCompletionStatus status"); onProviderResponseComplete(componentName); } } @Override public void onFinalResponseReceived(ComponentName componentName, Void response) { respondToClientWithResponseAndFinish(); } @Override protected void onProviderResponseComplete(ComponentName componentName) { if (!isAnyProviderPending()) { onFinalResponseReceived(componentName, null); } } @Override protected void onProviderTerminated(ComponentName componentName) { if (!isAnyProviderPending()) { processResponses(); } } @Override protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) { //Not applicable for clearCredential as UI is not needed } @Override public void onFinalErrorReceived(ComponentName componentName, String errorType, String message) { //Not applicable for clearCredential as response is not picked by the user } private void respondToClientWithResponseAndFinish() { Log.i(TAG, "respondToClientWithResponseAndFinish"); try { mClientCallback.onSuccess(); } catch (RemoteException e) { Log.i(TAG, "Issue while propagating the response to the client"); } finishSession(); } private void respondToClientWithErrorAndFinish(String errorType, String errorMsg) { Log.i(TAG, "respondToClientWithErrorAndFinish"); try { mClientCallback.onError(errorType, errorMsg); } catch (RemoteException e) { e.printStackTrace(); } finishSession(); } private void processResponses() { for (ProviderSession session: mProviders.values()) { if (session.isProviderResponseSet()) { // If even one provider responded successfully, send back the response // TODO: Aggregate other exceptions respondToClientWithResponseAndFinish(); return; } } // TODO: Replace with properly defined error type respondToClientWithErrorAndFinish("unknown", "All providers failed"); } } services/credentials/java/com/android/server/credentials/CredentialManagerService.java +38 −2 Original line number Diff line number Diff line Loading @@ -314,9 +314,45 @@ public final class CredentialManagerService @Override public ICancellationSignal clearCredentialState(ClearCredentialStateRequest request, IClearCredentialStateCallback callback, String callingPackage) { // TODO: implement. Log.i(TAG, "clearCredentialSession"); Log.i(TAG, "starting clearCredentialState with callingPackage: " + callingPackage); // TODO : Implement cancellation ICancellationSignal cancelTransport = CancellationSignal.createTransport(); // New request session, scoped for this request only. final ClearRequestSession session = new ClearRequestSession( getContext(), UserHandle.getCallingUserId(), callback, request, callingPackage); // Initiate all provider sessions // TODO: Determine if provider needs to have clear capability in their manifest List<ProviderSession> providerSessions = initiateProviderSessions(session, List.of()); 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 IClearCredentialStateCallback " + "callback: " + e.getMessage()); } } // Iterate over all provider sessions and invoke the request providerSessions.forEach( providerClearSession -> { providerClearSession .getRemoteCredentialService() .onClearCredentialState( (android.service.credentials.ClearCredentialStateRequest) providerClearSession.getProviderRequest(), /* callback= */ providerClearSession); }); return cancelTransport; } } Loading services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java +2 −4 Original line number Diff line number Diff line Loading @@ -76,7 +76,7 @@ public final class CredentialManagerServiceImpl extends @GuardedBy("mLock") public ProviderSession initiateProviderSessionForRequestLocked( RequestSession requestSession, List<String> requestOptions) { if (!isServiceCapableLocked(requestOptions)) { if (!requestOptions.isEmpty() && !isServiceCapableLocked(requestOptions)) { Log.i(TAG, "Service is not capable"); return null; } Loading @@ -88,9 +88,7 @@ public final class CredentialManagerServiceImpl extends } final RemoteCredentialService remoteService = new RemoteCredentialService( getContext(), mInfo.getServiceInfo().getComponentName(), mUserId); ProviderSession providerSession = requestSession.initiateProviderSession(mInfo, remoteService); return providerSession; return requestSession.initiateProviderSession(mInfo, remoteService); } /** Return true if at least one capability found. */ Loading services/credentials/java/com/android/server/credentials/ProviderClearSession.java 0 → 100644 +119 −0 Original line number Diff line number Diff line /* * 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 com.android.server.credentials; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; import android.credentials.ClearCredentialStateException; import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderPendingIntentResponse; import android.service.credentials.CallingAppInfo; import android.service.credentials.ClearCredentialStateRequest; import android.service.credentials.CredentialProviderInfo; import android.util.ArraySet; import android.util.Log; import android.util.Slog; /** * Central provider session that listens for provider callbacks, and maintains provider state. * * @hide */ public final class ProviderClearSession extends ProviderSession<ClearCredentialStateRequest, Void> implements RemoteCredentialService.ProviderCallbacks<Void> { private static final String TAG = "ProviderClearSession"; private ClearCredentialStateException mProviderException; /** Creates a new provider session to be used by the request session. */ @Nullable public static ProviderClearSession createNewSession( Context context, @UserIdInt int userId, CredentialProviderInfo providerInfo, ClearRequestSession clearRequestSession, RemoteCredentialService remoteCredentialService) { ClearCredentialStateRequest providerRequest = createProviderRequest( clearRequestSession.mClientRequest, clearRequestSession.mClientCallingPackage); return new ProviderClearSession(context, providerInfo, clearRequestSession, userId, remoteCredentialService, providerRequest); } @Nullable private static ClearCredentialStateRequest createProviderRequest( android.credentials.ClearCredentialStateRequest clientRequest, String clientCallingPackage ) { // TODO: Determine if provider needs to declare clear capability in manifest return new ClearCredentialStateRequest( new CallingAppInfo(clientCallingPackage, new ArraySet<>()), clientRequest.getData()); } public ProviderClearSession(Context context, CredentialProviderInfo info, ProviderInternalCallback callbacks, int userId, RemoteCredentialService remoteCredentialService, ClearCredentialStateRequest providerRequest) { super(context, info, providerRequest, callbacks, userId, remoteCredentialService); setStatus(Status.PENDING); } @Override public void onProviderResponseSuccess(@Nullable Void response) { Log.i(TAG, "in onProviderResponseSuccess"); mProviderResponseSet = true; updateStatusAndInvokeCallback(Status.COMPLETE); } /** Called when the provider response resulted in a failure. */ @Override // Callback from the remote provider public void onProviderResponseFailure(int errorCode, Exception exception) { if (exception instanceof ClearCredentialStateException) { mProviderException = (ClearCredentialStateException) exception; } updateStatusAndInvokeCallback(toStatus(errorCode)); } /** Called when provider service dies. */ @Override // Callback from the remote provider public void onProviderServiceDied(RemoteCredentialService service) { if (service.getComponentName().equals(mProviderInfo.getServiceInfo().getComponentName())) { updateStatusAndInvokeCallback(Status.SERVICE_DEAD); } else { Slog.i(TAG, "Component names different in onProviderServiceDied - " + "this should not happen"); } } @Nullable @Override protected ProviderData prepareUiData() { //Not applicable for clearCredential as response is not picked by the user return null; } @Override protected void onUiEntrySelected(String entryType, String entryId, ProviderPendingIntentResponse providerPendingIntentResponse) { //Not applicable for clearCredential as response is not picked by the user } } Loading
core/java/android/credentials/ui/RequestInfo.java +2 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ public class RequestInfo implements Parcelable { public static final @NonNull String EXTRA_REQUEST_INFO = "android.credentials.ui.extra.REQUEST_INFO"; /** Type value for any request that does not require UI. */ public static final @NonNull String TYPE_UNDEFINED = "android.credentials.ui.TYPE_UNDEFINED"; /** Type value for an executeGetCredential request. */ public static final @NonNull String TYPE_GET = "android.credentials.ui.TYPE_GET"; /** Type value for an executeCreateCredential request. */ Loading
services/credentials/java/com/android/server/credentials/ClearRequestSession.java 0 → 100644 +142 −0 Original line number Diff line number Diff line /* * 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 com.android.server.credentials; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.credentials.ClearCredentialStateRequest; import android.credentials.IClearCredentialStateCallback; import android.credentials.ui.ProviderData; import android.credentials.ui.RequestInfo; import android.os.RemoteException; import android.service.credentials.CredentialProviderInfo; import android.util.Log; import java.util.ArrayList; /** * Central session for a single clearCredentialState request. This class listens to the * responses from providers, and updates the provider(S) state. */ public final class ClearRequestSession extends RequestSession<ClearCredentialStateRequest, IClearCredentialStateCallback> implements ProviderSession.ProviderInternalCallback<Void> { private static final String TAG = "GetRequestSession"; public ClearRequestSession(Context context, int userId, IClearCredentialStateCallback callback, ClearCredentialStateRequest request, String callingPackage) { super(context, userId, request, callback, RequestInfo.TYPE_UNDEFINED, callingPackage); } /** * Creates a new provider session, and adds it list of providers that are contributing to * this session. * @return the provider session created within this request session, for the given provider * info. */ @Override @Nullable public ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo, RemoteCredentialService remoteCredentialService) { ProviderClearSession providerClearSession = ProviderClearSession .createNewSession(mContext, mUserId, providerInfo, this, remoteCredentialService); if (providerClearSession != null) { Log.i(TAG, "In startProviderSession - provider session created and being added"); mProviders.put(providerClearSession.getComponentName().flattenToString(), providerClearSession); } return providerClearSession; } @Override // from provider session public void onProviderStatusChanged(ProviderSession.Status status, ComponentName componentName) { Log.i(TAG, "in onStatusChanged with status: " + status); if (ProviderSession.isTerminatingStatus(status)) { Log.i(TAG, "in onStatusChanged terminating status"); onProviderTerminated(componentName); } else if (ProviderSession.isCompletionStatus(status)) { Log.i(TAG, "in onStatusChanged isCompletionStatus status"); onProviderResponseComplete(componentName); } } @Override public void onFinalResponseReceived(ComponentName componentName, Void response) { respondToClientWithResponseAndFinish(); } @Override protected void onProviderResponseComplete(ComponentName componentName) { if (!isAnyProviderPending()) { onFinalResponseReceived(componentName, null); } } @Override protected void onProviderTerminated(ComponentName componentName) { if (!isAnyProviderPending()) { processResponses(); } } @Override protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) { //Not applicable for clearCredential as UI is not needed } @Override public void onFinalErrorReceived(ComponentName componentName, String errorType, String message) { //Not applicable for clearCredential as response is not picked by the user } private void respondToClientWithResponseAndFinish() { Log.i(TAG, "respondToClientWithResponseAndFinish"); try { mClientCallback.onSuccess(); } catch (RemoteException e) { Log.i(TAG, "Issue while propagating the response to the client"); } finishSession(); } private void respondToClientWithErrorAndFinish(String errorType, String errorMsg) { Log.i(TAG, "respondToClientWithErrorAndFinish"); try { mClientCallback.onError(errorType, errorMsg); } catch (RemoteException e) { e.printStackTrace(); } finishSession(); } private void processResponses() { for (ProviderSession session: mProviders.values()) { if (session.isProviderResponseSet()) { // If even one provider responded successfully, send back the response // TODO: Aggregate other exceptions respondToClientWithResponseAndFinish(); return; } } // TODO: Replace with properly defined error type respondToClientWithErrorAndFinish("unknown", "All providers failed"); } }
services/credentials/java/com/android/server/credentials/CredentialManagerService.java +38 −2 Original line number Diff line number Diff line Loading @@ -314,9 +314,45 @@ public final class CredentialManagerService @Override public ICancellationSignal clearCredentialState(ClearCredentialStateRequest request, IClearCredentialStateCallback callback, String callingPackage) { // TODO: implement. Log.i(TAG, "clearCredentialSession"); Log.i(TAG, "starting clearCredentialState with callingPackage: " + callingPackage); // TODO : Implement cancellation ICancellationSignal cancelTransport = CancellationSignal.createTransport(); // New request session, scoped for this request only. final ClearRequestSession session = new ClearRequestSession( getContext(), UserHandle.getCallingUserId(), callback, request, callingPackage); // Initiate all provider sessions // TODO: Determine if provider needs to have clear capability in their manifest List<ProviderSession> providerSessions = initiateProviderSessions(session, List.of()); 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 IClearCredentialStateCallback " + "callback: " + e.getMessage()); } } // Iterate over all provider sessions and invoke the request providerSessions.forEach( providerClearSession -> { providerClearSession .getRemoteCredentialService() .onClearCredentialState( (android.service.credentials.ClearCredentialStateRequest) providerClearSession.getProviderRequest(), /* callback= */ providerClearSession); }); return cancelTransport; } } Loading
services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java +2 −4 Original line number Diff line number Diff line Loading @@ -76,7 +76,7 @@ public final class CredentialManagerServiceImpl extends @GuardedBy("mLock") public ProviderSession initiateProviderSessionForRequestLocked( RequestSession requestSession, List<String> requestOptions) { if (!isServiceCapableLocked(requestOptions)) { if (!requestOptions.isEmpty() && !isServiceCapableLocked(requestOptions)) { Log.i(TAG, "Service is not capable"); return null; } Loading @@ -88,9 +88,7 @@ public final class CredentialManagerServiceImpl extends } final RemoteCredentialService remoteService = new RemoteCredentialService( getContext(), mInfo.getServiceInfo().getComponentName(), mUserId); ProviderSession providerSession = requestSession.initiateProviderSession(mInfo, remoteService); return providerSession; return requestSession.initiateProviderSession(mInfo, remoteService); } /** Return true if at least one capability found. */ Loading
services/credentials/java/com/android/server/credentials/ProviderClearSession.java 0 → 100644 +119 −0 Original line number Diff line number Diff line /* * 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 com.android.server.credentials; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; import android.credentials.ClearCredentialStateException; import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderPendingIntentResponse; import android.service.credentials.CallingAppInfo; import android.service.credentials.ClearCredentialStateRequest; import android.service.credentials.CredentialProviderInfo; import android.util.ArraySet; import android.util.Log; import android.util.Slog; /** * Central provider session that listens for provider callbacks, and maintains provider state. * * @hide */ public final class ProviderClearSession extends ProviderSession<ClearCredentialStateRequest, Void> implements RemoteCredentialService.ProviderCallbacks<Void> { private static final String TAG = "ProviderClearSession"; private ClearCredentialStateException mProviderException; /** Creates a new provider session to be used by the request session. */ @Nullable public static ProviderClearSession createNewSession( Context context, @UserIdInt int userId, CredentialProviderInfo providerInfo, ClearRequestSession clearRequestSession, RemoteCredentialService remoteCredentialService) { ClearCredentialStateRequest providerRequest = createProviderRequest( clearRequestSession.mClientRequest, clearRequestSession.mClientCallingPackage); return new ProviderClearSession(context, providerInfo, clearRequestSession, userId, remoteCredentialService, providerRequest); } @Nullable private static ClearCredentialStateRequest createProviderRequest( android.credentials.ClearCredentialStateRequest clientRequest, String clientCallingPackage ) { // TODO: Determine if provider needs to declare clear capability in manifest return new ClearCredentialStateRequest( new CallingAppInfo(clientCallingPackage, new ArraySet<>()), clientRequest.getData()); } public ProviderClearSession(Context context, CredentialProviderInfo info, ProviderInternalCallback callbacks, int userId, RemoteCredentialService remoteCredentialService, ClearCredentialStateRequest providerRequest) { super(context, info, providerRequest, callbacks, userId, remoteCredentialService); setStatus(Status.PENDING); } @Override public void onProviderResponseSuccess(@Nullable Void response) { Log.i(TAG, "in onProviderResponseSuccess"); mProviderResponseSet = true; updateStatusAndInvokeCallback(Status.COMPLETE); } /** Called when the provider response resulted in a failure. */ @Override // Callback from the remote provider public void onProviderResponseFailure(int errorCode, Exception exception) { if (exception instanceof ClearCredentialStateException) { mProviderException = (ClearCredentialStateException) exception; } updateStatusAndInvokeCallback(toStatus(errorCode)); } /** Called when provider service dies. */ @Override // Callback from the remote provider public void onProviderServiceDied(RemoteCredentialService service) { if (service.getComponentName().equals(mProviderInfo.getServiceInfo().getComponentName())) { updateStatusAndInvokeCallback(Status.SERVICE_DEAD); } else { Slog.i(TAG, "Component names different in onProviderServiceDied - " + "this should not happen"); } } @Nullable @Override protected ProviderData prepareUiData() { //Not applicable for clearCredential as response is not picked by the user return null; } @Override protected void onUiEntrySelected(String entryType, String entryId, ProviderPendingIntentResponse providerPendingIntentResponse) { //Not applicable for clearCredential as response is not picked by the user } }