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