• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Intent;
29 import android.content.ServiceConnection;
30 import android.os.Handler;
31 import android.os.IBinder;
32 import android.os.IBinder.DeathRecipient;
33 import android.os.ICancellationSignal;
34 import android.os.Message;
35 import android.os.RemoteException;
36 import android.os.SystemClock;
37 import android.os.UserHandle;
38 import android.service.autofill.AutofillService;
39 import android.service.autofill.FillRequest;
40 import android.service.autofill.FillResponse;
41 import android.service.autofill.IAutoFillService;
42 import android.service.autofill.IFillCallback;
43 import android.service.autofill.ISaveCallback;
44 import android.service.autofill.SaveRequest;
45 import android.text.format.DateUtils;
46 import android.util.Slog;
47 
48 import com.android.internal.annotations.GuardedBy;
49 import com.android.internal.os.HandlerCaller;
50 import com.android.server.FgThread;
51 
52 import java.io.PrintWriter;
53 import java.lang.ref.WeakReference;
54 
55 /**
56  * This class represents a remote fill service. It abstracts away the binding
57  * and unbinding from the remote implementation.
58  *
59  * <p>Clients can call methods of this class without worrying about when and
60  * how to bind/unbind/timeout. All state of this class is modified on a handler
61  * thread.
62  */
63 final class RemoteFillService implements DeathRecipient {
64     private static final String LOG_TAG = "RemoteFillService";
65 
66     // How long after the last interaction with the service we would unbind
67     private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
68 
69     // How long after we make a remote request to a fill service we timeout
70     private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
71 
72     private final Context mContext;
73 
74     private final ComponentName mComponentName;
75 
76     private final Intent mIntent;
77 
78     private final FillServiceCallbacks mCallbacks;
79 
80     private final int mUserId;
81 
82     private final ServiceConnection mServiceConnection = new RemoteServiceConnection();
83 
84     private final HandlerCaller mHandler;
85 
86     private IAutoFillService mAutoFillService;
87 
88     private boolean mBinding;
89 
90     private boolean mDestroyed;
91 
92     private boolean mServiceDied;
93 
94     private boolean mCompleted;
95 
96     private PendingRequest mPendingRequest;
97 
98     public interface FillServiceCallbacks {
onFillRequestSuccess(int requestFlags, @Nullable FillResponse response, int serviceUid, @NonNull String servicePackageName)99         void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response, int serviceUid,
100                 @NonNull String servicePackageName);
onFillRequestFailure(@ullable CharSequence message, @NonNull String servicePackageName)101         void onFillRequestFailure(@Nullable CharSequence message,
102                 @NonNull String servicePackageName);
onSaveRequestSuccess(@onNull String servicePackageName)103         void onSaveRequestSuccess(@NonNull String servicePackageName);
onSaveRequestFailure(@ullable CharSequence message, @NonNull String servicePackageName)104         void onSaveRequestFailure(@Nullable CharSequence message,
105                 @NonNull String servicePackageName);
onServiceDied(RemoteFillService service)106         void onServiceDied(RemoteFillService service);
107     }
108 
RemoteFillService(Context context, ComponentName componentName, int userId, FillServiceCallbacks callbacks)109     public RemoteFillService(Context context, ComponentName componentName,
110             int userId, FillServiceCallbacks callbacks) {
111         mContext = context;
112         mCallbacks = callbacks;
113         mComponentName = componentName;
114         mIntent = new Intent(AutofillService.SERVICE_INTERFACE).setComponent(mComponentName);
115         mUserId = userId;
116         mHandler = new MyHandler(context);
117     }
118 
destroy()119     public void destroy() {
120         mHandler.obtainMessage(MyHandler.MSG_DESTROY).sendToTarget();
121     }
122 
handleDestroy()123     private void handleDestroy() {
124         if (mPendingRequest != null) {
125             mPendingRequest.cancel();
126             mPendingRequest = null;
127         }
128         ensureUnbound();
129         mDestroyed = true;
130     }
131 
132     @Override
binderDied()133     public void binderDied() {
134         mHandler.obtainMessage(MyHandler.MSG_BINDER_DIED).sendToTarget();
135     }
136 
handleBinderDied()137     private void handleBinderDied() {
138         if (mAutoFillService != null) {
139             mAutoFillService.asBinder().unlinkToDeath(this, 0);
140         }
141         mAutoFillService = null;
142         mServiceDied = true;
143         mCallbacks.onServiceDied(this);
144     }
145 
146     /**
147      * Cancel the currently pending request.
148      *
149      * <p>This can be used when the request is unnecessary or will be superceeded by a request that
150      * will soon be queued.
151      *
152      * @return the id of the canceled request, or {@link FillRequest#INVALID_REQUEST_ID} if no
153      *         {@link PendingFillRequest} was canceled.
154      */
cancelCurrentRequest()155     public int cancelCurrentRequest() {
156         if (mDestroyed) {
157             return INVALID_REQUEST_ID;
158         }
159 
160         int requestId = INVALID_REQUEST_ID;
161         if (mPendingRequest != null) {
162             if (mPendingRequest instanceof PendingFillRequest) {
163                 requestId = ((PendingFillRequest) mPendingRequest).mRequest.getId();
164             }
165 
166             mPendingRequest.cancel();
167             mPendingRequest = null;
168         }
169 
170         return requestId;
171     }
172 
onFillRequest(@onNull FillRequest request)173     public void onFillRequest(@NonNull FillRequest request) {
174         cancelScheduledUnbind();
175         final PendingFillRequest pendingRequest = new PendingFillRequest(request, this);
176         mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, pendingRequest).sendToTarget();
177     }
178 
onSaveRequest(@onNull SaveRequest request)179     public void onSaveRequest(@NonNull SaveRequest request) {
180         cancelScheduledUnbind();
181         final PendingSaveRequest pendingRequest = new PendingSaveRequest(request, this);
182         mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, pendingRequest).sendToTarget();
183     }
184 
185     // Note: we are dumping without a lock held so this is a bit racy but
186     // adding a lock to a class that offloads to a handler thread would
187     // mean adding a lock adding overhead to normal runtime operation.
dump(@onNull String prefix, @NonNull PrintWriter pw)188     public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
189         String tab = "  ";
190         pw.append(prefix).append("service:").println();
191         pw.append(prefix).append(tab).append("userId=")
192                 .append(String.valueOf(mUserId)).println();
193         pw.append(prefix).append(tab).append("componentName=")
194                 .append(mComponentName.flattenToString()).println();
195         pw.append(prefix).append(tab).append("destroyed=")
196                 .append(String.valueOf(mDestroyed)).println();
197         pw.append(prefix).append(tab).append("bound=")
198                 .append(String.valueOf(isBound())).println();
199         pw.append(prefix).append(tab).append("hasPendingRequest=")
200                 .append(String.valueOf(mPendingRequest != null)).println();
201         pw.println();
202     }
203 
cancelScheduledUnbind()204     private void cancelScheduledUnbind() {
205         mHandler.removeMessages(MyHandler.MSG_UNBIND);
206     }
207 
scheduleUnbind()208     private void scheduleUnbind() {
209         cancelScheduledUnbind();
210         Message message = mHandler.obtainMessage(MyHandler.MSG_UNBIND);
211         mHandler.sendMessageDelayed(message, TIMEOUT_IDLE_BIND_MILLIS);
212     }
213 
handleUnbind()214     private void handleUnbind() {
215         ensureUnbound();
216     }
217 
handlePendingRequest(PendingRequest pendingRequest)218     private void handlePendingRequest(PendingRequest pendingRequest) {
219         if (mDestroyed || mCompleted) {
220             return;
221         }
222         if (!isBound()) {
223             if (mPendingRequest != null) {
224                 mPendingRequest.cancel();
225             }
226             mPendingRequest = pendingRequest;
227             ensureBound();
228         } else {
229             if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] handlePendingRequest()");
230             pendingRequest.run();
231             if (pendingRequest.isFinal()) {
232                 mCompleted = true;
233             }
234         }
235     }
236 
isBound()237     private boolean isBound() {
238         return mAutoFillService != null;
239     }
240 
ensureBound()241     private void ensureBound() {
242         if (isBound() || mBinding) {
243             return;
244         }
245         if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureBound()");
246         mBinding = true;
247 
248         boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection,
249                 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
250                 new UserHandle(mUserId));
251 
252         if (!willBind) {
253             if (sDebug) Slog.d(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent);
254             mBinding = false;
255 
256             if (!mServiceDied) {
257                 handleBinderDied();
258             }
259         }
260     }
261 
ensureUnbound()262     private void ensureUnbound() {
263         if (!isBound() && !mBinding) {
264             return;
265         }
266         if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()");
267         mBinding = false;
268         if (isBound()) {
269             try {
270                 mAutoFillService.onConnectedStateChanged(false);
271             } catch (Exception e) {
272                 Slog.w(LOG_TAG, "Exception calling onDisconnected(): " + e);
273             }
274             if (mAutoFillService != null) {
275                 mAutoFillService.asBinder().unlinkToDeath(this, 0);
276                 mAutoFillService = null;
277             }
278         }
279         mContext.unbindService(mServiceConnection);
280     }
281 
dispatchOnFillRequestSuccess(PendingRequest pendingRequest, int callingUid, int requestFlags, FillResponse response)282     private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest,
283             int callingUid, int requestFlags, FillResponse response) {
284         mHandler.getHandler().post(() -> {
285             if (handleResponseCallbackCommon(pendingRequest)) {
286                 mCallbacks.onFillRequestSuccess(requestFlags, response, callingUid,
287                         mComponentName.getPackageName());
288             }
289         });
290     }
291 
dispatchOnFillRequestFailure(PendingRequest pendingRequest, CharSequence message)292     private void dispatchOnFillRequestFailure(PendingRequest pendingRequest,
293             CharSequence message) {
294         mHandler.getHandler().post(() -> {
295             if (handleResponseCallbackCommon(pendingRequest)) {
296                 mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName());
297             }
298         });
299     }
300 
dispatchOnSaveRequestSuccess(PendingRequest pendingRequest)301     private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) {
302         mHandler.getHandler().post(() -> {
303             if (handleResponseCallbackCommon(pendingRequest)) {
304                 mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName());
305             }
306         });
307     }
308 
dispatchOnSaveRequestFailure(PendingRequest pendingRequest, CharSequence message)309     private void dispatchOnSaveRequestFailure(PendingRequest pendingRequest,
310             CharSequence message) {
311         mHandler.getHandler().post(() -> {
312             if (handleResponseCallbackCommon(pendingRequest)) {
313                 mCallbacks.onSaveRequestFailure(message, mComponentName.getPackageName());
314             }
315         });
316     }
317 
handleResponseCallbackCommon(PendingRequest pendingRequest)318     private boolean handleResponseCallbackCommon(PendingRequest pendingRequest) {
319         if (mDestroyed) {
320             return false;
321         }
322         if (mPendingRequest == pendingRequest) {
323             mPendingRequest = null;
324         }
325         if (mPendingRequest == null) {
326             scheduleUnbind();
327         }
328         return true;
329     }
330 
331     private class RemoteServiceConnection implements ServiceConnection {
332         @Override
onServiceConnected(ComponentName name, IBinder service)333         public void onServiceConnected(ComponentName name, IBinder service) {
334             if (mDestroyed || !mBinding) {
335                 mContext.unbindService(mServiceConnection);
336                 return;
337             }
338             mBinding = false;
339             mAutoFillService = IAutoFillService.Stub.asInterface(service);
340             try {
341                 service.linkToDeath(RemoteFillService.this, 0);
342             } catch (RemoteException re) {
343                 handleBinderDied();
344                 return;
345             }
346             try {
347                 mAutoFillService.onConnectedStateChanged(true);
348             } catch (RemoteException e) {
349                 Slog.w(LOG_TAG, "Exception calling onConnected(): " + e);
350             }
351 
352             if (mPendingRequest != null) {
353                 PendingRequest pendingRequest = mPendingRequest;
354                 mPendingRequest = null;
355                 handlePendingRequest(pendingRequest);
356             }
357 
358             mServiceDied = false;
359         }
360 
361         @Override
onServiceDisconnected(ComponentName name)362         public void onServiceDisconnected(ComponentName name) {
363             mBinding = true;
364             mAutoFillService = null;
365         }
366     }
367 
368     private final class MyHandler extends HandlerCaller {
369         public static final int MSG_DESTROY = 1;
370         public static final int MSG_BINDER_DIED = 2;
371         public static final int MSG_UNBIND = 3;
372         public static final int MSG_ON_PENDING_REQUEST = 4;
373 
MyHandler(Context context)374         public MyHandler(Context context) {
375             // Cannot use lambda - doesn't compile
376             super(context, FgThread.getHandler().getLooper(), new Callback() {
377                 @Override
378                 public void executeMessage(Message message) {
379                     if (mDestroyed) {
380                         Slog.w(LOG_TAG, "Not handling " + message + " as service for "
381                                 + mComponentName + " is already destroyed");
382                         return;
383                     }
384                     switch (message.what) {
385                         case MSG_DESTROY: {
386                             handleDestroy();
387                         } break;
388 
389                         case MSG_BINDER_DIED: {
390                             handleBinderDied();
391                         } break;
392 
393                         case MSG_UNBIND: {
394                             handleUnbind();
395                         } break;
396 
397                         case MSG_ON_PENDING_REQUEST: {
398                             handlePendingRequest((PendingRequest) message.obj);
399                         } break;
400                     }
401                 }
402             }, false);
403         }
404     }
405 
406     private static abstract class PendingRequest implements Runnable {
407         protected final Object mLock = new Object();
408         private final WeakReference<RemoteFillService> mWeakService;
409 
410         private final Runnable mTimeoutTrigger;
411         private final Handler mServiceHandler;
412 
413         @GuardedBy("mLock")
414         private boolean mCancelled;
415 
416         @GuardedBy("mLock")
417         private boolean mCompleted;
418 
PendingRequest(RemoteFillService service)419         PendingRequest(RemoteFillService service) {
420             mWeakService = new WeakReference<>(service);
421             mServiceHandler = service.mHandler.getHandler();
422             mTimeoutTrigger = () -> {
423                 synchronized (mLock) {
424                     if (mCancelled) {
425                         return;
426                     }
427                     mCompleted = true;
428                 }
429 
430                 Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out");
431                 final RemoteFillService remoteService = mWeakService.get();
432                 if (remoteService != null) {
433                     fail(remoteService);
434                 }
435             };
436             mServiceHandler.postAtTime(mTimeoutTrigger,
437                     SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
438         }
439 
getService()440         protected RemoteFillService getService() {
441             return mWeakService.get();
442         }
443 
444         /**
445          * Sub-classes must call this method when the remote service finishes, i.e., when it
446          * called {@code onFill...} or {@code onSave...}.
447          *
448          * @return {@code false} in the service is already finished, {@code true} otherwise.
449          */
finish()450         protected final boolean finish() {
451             synchronized (mLock) {
452                 if (mCompleted || mCancelled) {
453                     return false;
454                 }
455                 mCompleted = true;
456             }
457             mServiceHandler.removeCallbacks(mTimeoutTrigger);
458             return true;
459         }
460 
isCancelledLocked()461         protected boolean isCancelledLocked() {
462             return mCancelled;
463         }
464 
465         /**
466          * Cancels the service.
467          *
468          * @return {@code false} if service is already canceled, {@code true} otherwise.
469          */
cancel()470         boolean cancel() {
471             synchronized (mLock) {
472                 if (mCancelled || mCompleted) {
473                     return false;
474                 }
475                 mCancelled = true;
476             }
477 
478             mServiceHandler.removeCallbacks(mTimeoutTrigger);
479             return true;
480         }
481 
482         /**
483          * Called by the self-destructure timeout when the AutofilllService didn't reply to the
484          * request on time.
485          */
fail(RemoteFillService remoteService)486         abstract void fail(RemoteFillService remoteService);
487 
488         /**
489          * @return whether this request leads to a final state where no
490          * other requests can be made.
491          */
isFinal()492         boolean isFinal() {
493             return false;
494         }
495     }
496 
497     private static final class PendingFillRequest extends PendingRequest {
498         private final FillRequest mRequest;
499         private final IFillCallback mCallback;
500         private ICancellationSignal mCancellation;
501 
PendingFillRequest(FillRequest request, RemoteFillService service)502         public PendingFillRequest(FillRequest request, RemoteFillService service) {
503             super(service);
504             mRequest = request;
505 
506             mCallback = new IFillCallback.Stub() {
507                 @Override
508                 public void onCancellable(ICancellationSignal cancellation) {
509                     synchronized (mLock) {
510                         final boolean cancelled;
511                         synchronized (mLock) {
512                             mCancellation = cancellation;
513                             cancelled = isCancelledLocked();
514                         }
515                         if (cancelled) {
516                             try {
517                                 cancellation.cancel();
518                             } catch (RemoteException e) {
519                                 Slog.e(LOG_TAG, "Error requesting a cancellation", e);
520                             }
521                         }
522                     }
523                 }
524 
525                 @Override
526                 public void onSuccess(FillResponse response) {
527                     if (!finish()) return;
528 
529                     final RemoteFillService remoteService = getService();
530                     if (remoteService != null) {
531                         remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
532                                 getCallingUid(), request.getFlags(), response);
533                     }
534                 }
535 
536                 @Override
537                 public void onFailure(CharSequence message) {
538                     if (!finish()) return;
539 
540                     final RemoteFillService remoteService = getService();
541                     if (remoteService != null) {
542                         remoteService.dispatchOnFillRequestFailure(
543                                 PendingFillRequest.this, message);
544                     }
545                 }
546             };
547         }
548 
549         @Override
fail(RemoteFillService remoteService)550         void fail(RemoteFillService remoteService) {
551             remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
552         }
553 
554         @Override
run()555         public void run() {
556             final RemoteFillService remoteService = getService();
557             if (remoteService != null) {
558                 try {
559                     remoteService.mAutoFillService.onFillRequest(mRequest, mCallback);
560                 } catch (RemoteException e) {
561                     Slog.e(LOG_TAG, "Error calling on fill request", e);
562 
563                     remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
564                 }
565             }
566         }
567 
568         @Override
cancel()569         public boolean cancel() {
570             if (!super.cancel()) return false;
571 
572             final ICancellationSignal cancellation = mCancellation;
573             if (cancellation != null) {
574                 try {
575                     cancellation.cancel();
576                 } catch (RemoteException e) {
577                     Slog.e(LOG_TAG, "Error cancelling a fill request", e);
578                 }
579             }
580             return true;
581         }
582     }
583 
584     private static final class PendingSaveRequest extends PendingRequest {
585         private final SaveRequest mRequest;
586         private final ISaveCallback mCallback;
587 
PendingSaveRequest(@onNull SaveRequest request, @NonNull RemoteFillService service)588         public PendingSaveRequest(@NonNull SaveRequest request,
589                 @NonNull RemoteFillService service) {
590             super(service);
591             mRequest = request;
592 
593             mCallback = new ISaveCallback.Stub() {
594                 @Override
595                 public void onSuccess() {
596                     if (!finish()) return;
597 
598                     final RemoteFillService remoteService = getService();
599                     if (remoteService != null) {
600                         remoteService.dispatchOnSaveRequestSuccess(PendingSaveRequest.this);
601                     }
602                 }
603 
604                 @Override
605                 public void onFailure(CharSequence message) {
606                     if (!finish()) return;
607 
608                     final RemoteFillService remoteService = getService();
609                     if (remoteService != null) {
610                         remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this,
611                                 message);
612                     }
613                 }
614             };
615         }
616 
617         @Override
fail(RemoteFillService remoteService)618         void fail(RemoteFillService remoteService) {
619             remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
620         }
621 
622         @Override
run()623         public void run() {
624             final RemoteFillService remoteService = getService();
625             if (remoteService != null) {
626                 try {
627                     remoteService.mAutoFillService.onSaveRequest(mRequest, mCallback);
628                 } catch (RemoteException e) {
629                     Slog.e(LOG_TAG, "Error calling on save request", e);
630 
631                     remoteService.dispatchOnFillRequestFailure(PendingSaveRequest.this, null);
632                 }
633             }
634         }
635 
636         @Override
isFinal()637         public boolean isFinal() {
638             return true;
639         }
640     }
641 }
642