1 /*
2  * Copyright (C) 2017 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.autofill;
18 
19 import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
20 
21 import static com.android.server.autofill.Helper.sDebug;
22 import static com.android.server.autofill.Helper.sVerbose;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.content.ComponentName;
27 import android.content.Context;
28 import android.content.IntentSender;
29 import android.os.IBinder;
30 import android.os.ICancellationSignal;
31 import android.os.RemoteException;
32 import android.service.autofill.AutofillService;
33 import android.service.autofill.FillRequest;
34 import android.service.autofill.FillResponse;
35 import android.service.autofill.IAutoFillService;
36 import android.service.autofill.IFillCallback;
37 import android.service.autofill.ISaveCallback;
38 import android.service.autofill.SaveRequest;
39 import android.text.format.DateUtils;
40 import android.util.Slog;
41 
42 import com.android.internal.infra.AbstractSinglePendingRequestRemoteService;
43 
44 import java.util.concurrent.CompletableFuture;
45 
46 final class RemoteFillService
47         extends AbstractSinglePendingRequestRemoteService<RemoteFillService, IAutoFillService> {
48 
49     private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
50     private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
51 
52     private final FillServiceCallbacks mCallbacks;
53 
54     public interface FillServiceCallbacks extends VultureCallback<RemoteFillService> {
onFillRequestSuccess(int requestId, @Nullable FillResponse response, @NonNull String servicePackageName, int requestFlags)55         void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
56                 @NonNull String servicePackageName, int requestFlags);
onFillRequestFailure(int requestId, @Nullable CharSequence message)57         void onFillRequestFailure(int requestId, @Nullable CharSequence message);
onFillRequestTimeout(int requestId)58         void onFillRequestTimeout(int requestId);
onSaveRequestSuccess(@onNull String servicePackageName, @Nullable IntentSender intentSender)59         void onSaveRequestSuccess(@NonNull String servicePackageName,
60                 @Nullable IntentSender intentSender);
61         // TODO(b/80093094): add timeout here too?
onSaveRequestFailure(@ullable CharSequence message, @NonNull String servicePackageName)62         void onSaveRequestFailure(@Nullable CharSequence message,
63                 @NonNull String servicePackageName);
64     }
65 
RemoteFillService(Context context, ComponentName componentName, int userId, FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed)66     RemoteFillService(Context context, ComponentName componentName, int userId,
67             FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed) {
68         super(context, AutofillService.SERVICE_INTERFACE, componentName, userId, callbacks,
69                 context.getMainThreadHandler(), Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
70                 | (bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0), sVerbose);
71         mCallbacks = callbacks;
72     }
73 
74     @Override // from AbstractRemoteService
handleOnConnectedStateChanged(boolean state)75     protected void handleOnConnectedStateChanged(boolean state) {
76         if (mService == null) {
77             Slog.w(mTag, "onConnectedStateChanged(): null service");
78             return;
79         }
80         try {
81             mService.onConnectedStateChanged(state);
82         } catch (Exception e) {
83             Slog.w(mTag, "Exception calling onConnectedStateChanged(" + state + "): " + e);
84         }
85     }
86 
87     @Override // from AbstractRemoteService
getServiceInterface(IBinder service)88     protected IAutoFillService getServiceInterface(IBinder service) {
89         return IAutoFillService.Stub.asInterface(service);
90     }
91 
92     @Override // from AbstractRemoteService
getTimeoutIdleBindMillis()93     protected long getTimeoutIdleBindMillis() {
94         return TIMEOUT_IDLE_BIND_MILLIS;
95     }
96 
97     @Override // from AbstractRemoteService
getRemoteRequestMillis()98     protected long getRemoteRequestMillis() {
99         return TIMEOUT_REMOTE_REQUEST_MILLIS;
100     }
101 
102     /**
103      * Cancel the currently pending request.
104      *
105      * <p>This can be used when the request is unnecessary or will be superceeded by a request that
106      * will soon be queued.
107      *
108      * @return the future id of the canceled request, or {@link FillRequest#INVALID_REQUEST_ID} if
109      *          no {@link PendingFillRequest} was canceled.
110      */
cancelCurrentRequest()111     public CompletableFuture<Integer> cancelCurrentRequest() {
112         return CompletableFuture.supplyAsync(() -> {
113             if (isDestroyed()) {
114                 return INVALID_REQUEST_ID;
115             }
116 
117             BasePendingRequest<RemoteFillService, IAutoFillService> canceledRequest =
118                     handleCancelPendingRequest();
119             return canceledRequest instanceof PendingFillRequest
120                     ? ((PendingFillRequest) canceledRequest).mRequest.getId()
121                     : INVALID_REQUEST_ID;
122         }, mHandler::post);
123     }
124 
125     public void onFillRequest(@NonNull FillRequest request) {
126         scheduleRequest(new PendingFillRequest(request, this));
127     }
128 
129     public void onSaveRequest(@NonNull SaveRequest request) {
130         scheduleRequest(new PendingSaveRequest(request, this));
131     }
132 
133     private boolean handleResponseCallbackCommon(
134             @NonNull PendingRequest<RemoteFillService, IAutoFillService> pendingRequest) {
135         if (isDestroyed()) return false;
136 
137         if (mPendingRequest == pendingRequest) {
138             mPendingRequest = null;
139         }
140         return true;
141     }
142 
143     private void dispatchOnFillRequestSuccess(@NonNull PendingFillRequest pendingRequest,
144             @Nullable FillResponse response, int requestFlags) {
145         mHandler.post(() -> {
146             if (handleResponseCallbackCommon(pendingRequest)) {
147                 mCallbacks.onFillRequestSuccess(pendingRequest.mRequest.getId(), response,
148                         mComponentName.getPackageName(), requestFlags);
149             }
150         });
151     }
152 
153     private void dispatchOnFillRequestFailure(@NonNull PendingFillRequest pendingRequest,
154             @Nullable CharSequence message) {
155         mHandler.post(() -> {
156             if (handleResponseCallbackCommon(pendingRequest)) {
157                 mCallbacks.onFillRequestFailure(pendingRequest.mRequest.getId(), message);
158             }
159         });
160     }
161 
162     private void dispatchOnFillRequestTimeout(@NonNull PendingFillRequest pendingRequest) {
163         mHandler.post(() -> {
164             if (handleResponseCallbackCommon(pendingRequest)) {
165                 mCallbacks.onFillRequestTimeout(pendingRequest.mRequest.getId());
166             }
167         });
168     }
169 
170     private void dispatchOnFillTimeout(@NonNull ICancellationSignal cancellationSignal) {
171         mHandler.post(() -> {
172             try {
173                 cancellationSignal.cancel();
174             } catch (RemoteException e) {
175                 Slog.w(mTag, "Error calling cancellation signal: " + e);
176             }
177         });
178     }
179 
180     private void dispatchOnSaveRequestSuccess(PendingSaveRequest pendingRequest,
181             IntentSender intentSender) {
182         mHandler.post(() -> {
183             if (handleResponseCallbackCommon(pendingRequest)) {
184                 mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName(), intentSender);
185             }
186         });
187     }
188 
189     private void dispatchOnSaveRequestFailure(PendingSaveRequest pendingRequest,
190             @Nullable CharSequence message) {
191         mHandler.post(() -> {
192             if (handleResponseCallbackCommon(pendingRequest)) {
193                 mCallbacks.onSaveRequestFailure(message, mComponentName.getPackageName());
194             }
195         });
196     }
197 
198     private static final class PendingFillRequest
199             extends PendingRequest<RemoteFillService, IAutoFillService> {
200         private final FillRequest mRequest;
201         private final IFillCallback mCallback;
202         private ICancellationSignal mCancellation;
203 
204         public PendingFillRequest(FillRequest request, RemoteFillService service) {
205             super(service);
206             mRequest = request;
207 
208             mCallback = new IFillCallback.Stub() {
209                 @Override
210                 public void onCancellable(ICancellationSignal cancellation) {
211                     synchronized (mLock) {
212                         final boolean cancelled;
213                         synchronized (mLock) {
214                             mCancellation = cancellation;
215                             cancelled = isCancelledLocked();
216                         }
217                         if (cancelled) {
218                             try {
219                                 cancellation.cancel();
220                             } catch (RemoteException e) {
221                                 Slog.e(mTag, "Error requesting a cancellation", e);
222                             }
223                         }
224                     }
225                 }
226 
227                 @Override
228                 public void onSuccess(FillResponse response) {
229                     if (!finish()) return;
230 
231                     final RemoteFillService remoteService = getService();
232                     if (remoteService != null) {
233                         remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
234                                 response, request.getFlags());
235                     }
236                 }
237 
238                 @Override
239                 public void onFailure(int requestId, CharSequence message) {
240                     if (!finish()) return;
241 
242                     final RemoteFillService remoteService = getService();
243                     if (remoteService != null) {
244                         remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this,
245                                 message);
246                     }
247                 }
248             };
249         }
250 
251         @Override
252         protected void onTimeout(RemoteFillService remoteService) {
253             // NOTE: Must make these 2 calls asynchronously, because the cancellation signal is
254             // handled by the service, which could block.
255             final ICancellationSignal cancellation;
256             synchronized (mLock) {
257                 cancellation = mCancellation;
258             }
259             if (cancellation != null) {
260                 remoteService.dispatchOnFillTimeout(cancellation);
261             }
262             remoteService.dispatchOnFillRequestTimeout(PendingFillRequest.this);
263         }
264 
265         @Override
266         public void run() {
267             synchronized (mLock) {
268                 if (isCancelledLocked()) {
269                     if (sDebug) Slog.d(mTag, "run() called after canceled: " + mRequest);
270                     return;
271                 }
272             }
273             final RemoteFillService remoteService = getService();
274             if (remoteService != null) {
275                 if (sVerbose) Slog.v(mTag, "calling onFillRequest() for id=" + mRequest.getId());
276                 try {
277                     remoteService.mService.onFillRequest(mRequest, mCallback);
278                 } catch (RemoteException e) {
279                     Slog.e(mTag, "Error calling on fill request", e);
280 
281                     remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
282                 }
283             }
284         }
285 
286         @Override
287         public boolean cancel() {
288             if (!super.cancel()) return false;
289 
290             final ICancellationSignal cancellation;
291             synchronized (mLock) {
292                 cancellation = mCancellation;
293             }
294             if (cancellation != null) {
295                 try {
296                     cancellation.cancel();
297                 } catch (RemoteException e) {
298                     Slog.e(mTag, "Error cancelling a fill request", e);
299                 }
300             }
301             return true;
302         }
303     }
304 
305     private static final class PendingSaveRequest
306             extends PendingRequest<RemoteFillService, IAutoFillService> {
307         private final SaveRequest mRequest;
308         private final ISaveCallback mCallback;
309 
310         public PendingSaveRequest(@NonNull SaveRequest request,
311                 @NonNull RemoteFillService service) {
312             super(service);
313             mRequest = request;
314 
315             mCallback = new ISaveCallback.Stub() {
316                 @Override
317                 public void onSuccess(IntentSender intentSender) {
318                     if (!finish()) return;
319 
320                     final RemoteFillService remoteService = getService();
321                     if (remoteService != null) {
322                         remoteService.dispatchOnSaveRequestSuccess(PendingSaveRequest.this,
323                                 intentSender);
324                     }
325                 }
326 
327                 @Override
328                 public void onFailure(CharSequence message) {
329                     if (!finish()) return;
330 
331                     final RemoteFillService remoteService = getService();
332                     if (remoteService != null) {
333                         remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this,
334                                 message);
335                     }
336                 }
337             };
338         }
339 
340         @Override
341         protected void onTimeout(RemoteFillService remoteService) {
342             remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
343         }
344 
345         @Override
346         public void run() {
347             final RemoteFillService remoteService = getService();
348             if (remoteService != null) {
349                 if (sVerbose) Slog.v(mTag, "calling onSaveRequest()");
350                 try {
351                     remoteService.mService.onSaveRequest(mRequest, mCallback);
352                 } catch (RemoteException e) {
353                     Slog.e(mTag, "Error calling on save request", e);
354 
355                     remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
356                 }
357             }
358         }
359 
360         @Override
361         public boolean isFinal() {
362             return true;
363         }
364     }
365 }
366