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