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