1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.credentials;
18 
19 import android.annotation.Nullable;
20 import android.annotation.UserIdInt;
21 import android.content.Context;
22 import android.credentials.ClearCredentialStateException;
23 import android.credentials.CredentialProviderInfo;
24 import android.credentials.ui.ProviderData;
25 import android.credentials.ui.ProviderPendingIntentResponse;
26 import android.os.ICancellationSignal;
27 import android.service.credentials.CallingAppInfo;
28 import android.service.credentials.ClearCredentialStateRequest;
29 import android.util.Slog;
30 
31 /**
32  * Central provider session that listens for provider callbacks, and maintains provider state.
33  *
34  * @hide
35  */
36 public final class ProviderClearSession extends ProviderSession<ClearCredentialStateRequest,
37         Void>
38         implements
39         RemoteCredentialService.ProviderCallbacks<Void> {
40     private static final String TAG = "ProviderClearSession";
41 
42     private ClearCredentialStateException mProviderException;
43 
44     /** Creates a new provider session to be used by the request session. */
45     @Nullable
createNewSession( Context context, @UserIdInt int userId, CredentialProviderInfo providerInfo, ClearRequestSession clearRequestSession, RemoteCredentialService remoteCredentialService)46     public static ProviderClearSession createNewSession(
47             Context context,
48             @UserIdInt int userId,
49             CredentialProviderInfo providerInfo,
50             ClearRequestSession clearRequestSession,
51             RemoteCredentialService remoteCredentialService) {
52         ClearCredentialStateRequest providerRequest =
53                 createProviderRequest(
54                         clearRequestSession.mClientRequest,
55                         clearRequestSession.mClientAppInfo);
56         return new ProviderClearSession(context, providerInfo, clearRequestSession, userId,
57                 remoteCredentialService, providerRequest);
58     }
59 
60     @Nullable
createProviderRequest( android.credentials.ClearCredentialStateRequest clientRequest, CallingAppInfo callingAppInfo )61     private static ClearCredentialStateRequest createProviderRequest(
62             android.credentials.ClearCredentialStateRequest clientRequest,
63             CallingAppInfo callingAppInfo
64     ) {
65         return new ClearCredentialStateRequest(
66                 callingAppInfo,
67                 clientRequest.getData());
68     }
69 
ProviderClearSession(Context context, CredentialProviderInfo info, ProviderInternalCallback callbacks, int userId, RemoteCredentialService remoteCredentialService, ClearCredentialStateRequest providerRequest)70     public ProviderClearSession(Context context,
71             CredentialProviderInfo info,
72             ProviderInternalCallback callbacks,
73             int userId, RemoteCredentialService remoteCredentialService,
74             ClearCredentialStateRequest providerRequest) {
75         super(context, providerRequest, callbacks, info.getComponentName(),
76                 userId, remoteCredentialService);
77         setStatus(Status.PENDING);
78     }
79 
80     @Override
onProviderResponseSuccess(@ullable Void response)81     public void onProviderResponseSuccess(@Nullable Void response) {
82         Slog.i(TAG, "Remote provider responded with a valid response: " + mComponentName);
83         mProviderResponseSet = true;
84         updateStatusAndInvokeCallback(Status.COMPLETE,
85                 /*source=*/ CredentialsSource.REMOTE_PROVIDER);
86     }
87 
88     /** Called when the provider response resulted in a failure. */
89     @Override // Callback from the remote provider
onProviderResponseFailure(int errorCode, Exception exception)90     public void onProviderResponseFailure(int errorCode, Exception exception) {
91         if (exception instanceof ClearCredentialStateException) {
92             mProviderException = (ClearCredentialStateException) exception;
93             // TODO(b/271135048) : Decide on exception type length
94             mProviderSessionMetric.collectCandidateFrameworkException(mProviderException.getType());
95         }
96         mProviderSessionMetric.collectCandidateExceptionStatus(/*hasException=*/true);
97         updateStatusAndInvokeCallback(Status.CANCELED,
98                 /*source=*/ CredentialsSource.REMOTE_PROVIDER);
99     }
100 
101     /** Called when provider service dies. */
102     @Override // Callback from the remote provider
onProviderServiceDied(RemoteCredentialService service)103     public void onProviderServiceDied(RemoteCredentialService service) {
104         if (service.getComponentName().equals(mComponentName)) {
105             updateStatusAndInvokeCallback(Status.SERVICE_DEAD,
106                     /*source=*/ CredentialsSource.REMOTE_PROVIDER);
107         } else {
108             Slog.w(TAG, "Component names different in onProviderServiceDied - "
109                     + "this should not happen");
110         }
111     }
112 
113     @Override
onProviderCancellable(ICancellationSignal cancellation)114     public void onProviderCancellable(ICancellationSignal cancellation) {
115         mProviderCancellationSignal = cancellation;
116     }
117 
118     @Nullable
119     @Override
prepareUiData()120     protected ProviderData prepareUiData() {
121         //Not applicable for clearCredential as response is not picked by the user
122         return null;
123     }
124 
125     @Override
onUiEntrySelected(String entryType, String entryId, ProviderPendingIntentResponse providerPendingIntentResponse)126     protected void onUiEntrySelected(String entryType, String entryId,
127             ProviderPendingIntentResponse providerPendingIntentResponse) {
128         //Not applicable for clearCredential as response is not picked by the user
129     }
130 
131     @Override
invokeSession()132     protected void invokeSession() {
133         if (mRemoteCredentialService != null) {
134             startCandidateMetrics();
135             mRemoteCredentialService.setCallback(this);
136             mRemoteCredentialService.onClearCredentialState(mProviderRequest);
137         }
138     }
139 }
140