RemoteFillService.java revision 5b2ca0e0ad4be4d8070c51c8924fee05af9c813a
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 17package com.android.server.autofill; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.app.assist.AssistStructure; 22import android.content.ComponentName; 23import android.content.Context; 24import android.content.Intent; 25import android.content.ServiceConnection; 26import android.os.Bundle; 27import android.os.IBinder; 28import android.os.IBinder.DeathRecipient; 29import android.os.ICancellationSignal; 30import android.os.Message; 31import android.os.RemoteException; 32import android.os.UserHandle; 33import android.service.autofill.AutoFillService; 34import android.service.autofill.FillResponse; 35import android.service.autofill.IAutoFillService; 36import android.service.autofill.IFillCallback; 37import android.service.autofill.ISaveCallback; 38import android.text.format.DateUtils; 39import android.util.Slog; 40import com.android.internal.os.HandlerCaller; 41import com.android.server.FgThread; 42 43import java.io.PrintWriter; 44import java.lang.ref.WeakReference; 45 46/** 47 * This class represents a remote fill service. It abstracts away the binding 48 * and unbinding from the remote implementation. 49 * 50 * <p>Clients can call methods of this class without worrying about when and 51 * how to bind/unbind/timeout. All state of this class is modified on a handler 52 * thread. 53 */ 54final class RemoteFillService implements DeathRecipient { 55 private static final String LOG_TAG = "RemoteFillService"; 56 57 private static final boolean DEBUG = Helper.DEBUG; 58 59 // How long after the last interaction with the service we would unbind 60 private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.MINUTE_IN_MILLIS; 61 62 private final Context mContext; 63 64 private final ComponentName mComponentName; 65 66 private final Intent mIntent; 67 68 private final FillServiceCallbacks mCallbacks; 69 70 private final int mUserId; 71 72 private final ServiceConnection mServiceConnection = new RemoteServiceConnection(); 73 74 private final HandlerCaller mHandler; 75 76 private IAutoFillService mAutoFillService; 77 78 private boolean mBinding; 79 80 private boolean mDestroyed; 81 82 private boolean mServiceDied; 83 84 private boolean mCompleted; 85 86 private PendingRequest mPendingRequest; 87 88 public interface FillServiceCallbacks { 89 void onFillRequestSuccess(FillResponse response); 90 void onFillRequestFailure(CharSequence message); 91 void onSaveRequestSuccess(); 92 void onSaveRequestFailure(CharSequence message); 93 void onServiceDied(RemoteFillService service); 94 } 95 96 public RemoteFillService(Context context, ComponentName componentName, 97 int userId, FillServiceCallbacks callbacks) { 98 mContext = context; 99 mCallbacks = callbacks; 100 mComponentName = componentName; 101 mIntent = new Intent(AutoFillService.SERVICE_INTERFACE) 102 .setComponent(mComponentName); 103 mUserId = userId; 104 mHandler = new MyHandler(context); 105 } 106 107 public void destroy() { 108 mHandler.obtainMessage(MyHandler.MSG_DESTROY).sendToTarget(); 109 } 110 111 private void handleDestroy() { 112 if (mPendingRequest != null) { 113 mPendingRequest.cancel(); 114 mPendingRequest = null; 115 } 116 ensureUnbound(); 117 mDestroyed = true; 118 } 119 120 @Override 121 public void binderDied() { 122 mHandler.obtainMessage(MyHandler.MSG_BINDER_DIED).sendToTarget(); 123 } 124 125 private void handleBinderDied() { 126 if (mAutoFillService != null) { 127 mAutoFillService.asBinder().unlinkToDeath(this, 0); 128 } 129 mAutoFillService = null; 130 mServiceDied = true; 131 mCallbacks.onServiceDied(this); 132 } 133 134 public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) { 135 cancelScheduledUnbind(); 136 PendingFillRequest request = new PendingFillRequest(structure, extras, this); 137 mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget(); 138 } 139 140 public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) { 141 cancelScheduledUnbind(); 142 PendingSaveRequest request = new PendingSaveRequest(structure, extras, this); 143 mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget(); 144 } 145 146 // Note: we are dumping without a lock held so this is a bit racy but 147 // adding a lock to a class that offloads to a handler thread would 148 // mean adding a lock adding overhead to normal runtime operation. 149 public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { 150 String tab = " "; 151 pw.append(prefix).append("service:").println(); 152 pw.append(prefix).append(tab).append("userId=") 153 .append(String.valueOf(mUserId)).println(); 154 pw.append(prefix).append(tab).append("componentName=") 155 .append(mComponentName.flattenToString()).println(); 156 pw.append(prefix).append(tab).append("destroyed=") 157 .append(String.valueOf(mDestroyed)).println(); 158 pw.append(prefix).append(tab).append("bound=") 159 .append(String.valueOf(isBound())).println(); 160 pw.append(prefix).append(tab).append("hasPendingRequest=") 161 .append(String.valueOf(mPendingRequest != null)).println(); 162 pw.println(); 163 } 164 165 private void cancelScheduledUnbind() { 166 mHandler.removeMessages(MyHandler.MSG_UNBIND); 167 } 168 169 private void scheduleUnbind() { 170 cancelScheduledUnbind(); 171 Message message = mHandler.obtainMessage(MyHandler.MSG_UNBIND); 172 mHandler.sendMessageDelayed(message, TIMEOUT_IDLE_BIND_MILLIS); 173 } 174 175 private void handleUnbind() { 176 ensureUnbound(); 177 } 178 179 private void handlePendingRequest(PendingRequest pendingRequest) { 180 if (mDestroyed || mCompleted) { 181 return; 182 } 183 if (pendingRequest.isFinal()) { 184 mCompleted = true; 185 } 186 if (!isBound()) { 187 if (mPendingRequest != null) { 188 mPendingRequest.cancel(); 189 } 190 mPendingRequest = pendingRequest; 191 ensureBound(); 192 } else { 193 if (DEBUG) { 194 Slog.d(LOG_TAG, "[user: " + mUserId + "] handlePendingRequest()"); 195 } 196 pendingRequest.run(); 197 } 198 } 199 200 private boolean isBound() { 201 return mAutoFillService != null; 202 } 203 204 private void ensureBound() { 205 if (isBound() || mBinding) { 206 return; 207 } 208 if (DEBUG) { 209 Slog.d(LOG_TAG, "[user: " + mUserId + "] ensureBound()"); 210 } 211 mBinding = true; 212 213 boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, 214 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, 215 new UserHandle(mUserId)); 216 217 if (!willBind) { 218 if (DEBUG) { 219 Slog.d(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent); 220 } 221 mBinding = false; 222 223 if (!mServiceDied) { 224 handleBinderDied(); 225 } 226 } 227 } 228 229 private void ensureUnbound() { 230 if (!isBound() && !mBinding) { 231 return; 232 } 233 if (DEBUG) { 234 Slog.d(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()"); 235 } 236 mBinding = false; 237 if (isBound()) { 238 mAutoFillService.asBinder().unlinkToDeath(this, 0); 239 mAutoFillService = null; 240 } 241 mContext.unbindService(mServiceConnection); 242 } 243 244 private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest, 245 FillResponse response) { 246 mHandler.getHandler().post(() -> { 247 if (handleResponseCallbackCommon(pendingRequest)) { 248 mCallbacks.onFillRequestSuccess(response); 249 } 250 }); 251 } 252 253 private void dispatchOnFillRequestFailure(PendingRequest pendingRequest, 254 CharSequence message) { 255 mHandler.getHandler().post(() -> { 256 if (handleResponseCallbackCommon(pendingRequest)) { 257 mCallbacks.onFillRequestFailure(message); 258 } 259 }); 260 } 261 262 private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) { 263 mHandler.getHandler().post(() -> { 264 if (handleResponseCallbackCommon(pendingRequest)) { 265 mCallbacks.onSaveRequestSuccess(); 266 } 267 }); 268 } 269 270 private void dispatchOnSaveRequestFailure(PendingRequest pendingRequest, 271 CharSequence message) { 272 mHandler.getHandler().post(() -> { 273 if (handleResponseCallbackCommon(pendingRequest)) { 274 mCallbacks.onSaveRequestFailure(message); 275 } 276 }); 277 } 278 279 private boolean handleResponseCallbackCommon(PendingRequest pendingRequest) { 280 if (mDestroyed) { 281 return false; 282 } 283 if (mPendingRequest == pendingRequest) { 284 mPendingRequest = null; 285 } 286 if (mPendingRequest == null) { 287 scheduleUnbind(); 288 } 289 return true; 290 } 291 292 private class RemoteServiceConnection implements ServiceConnection { 293 @Override 294 public void onServiceConnected(ComponentName name, IBinder service) { 295 if (mDestroyed || !mBinding) { 296 mContext.unbindService(mServiceConnection); 297 return; 298 } 299 mBinding = false; 300 mAutoFillService = IAutoFillService.Stub.asInterface(service); 301 try { 302 service.linkToDeath(RemoteFillService.this, 0); 303 } catch (RemoteException re) { 304 handleBinderDied(); 305 return; 306 } 307 308 if (mPendingRequest != null) { 309 handlePendingRequest(mPendingRequest); 310 } 311 312 mServiceDied = false; 313 } 314 315 @Override 316 public void onServiceDisconnected(ComponentName name) { 317 mBinding = true; 318 mAutoFillService = null; 319 } 320 } 321 322 private final class MyHandler extends HandlerCaller { 323 public static final int MSG_DESTROY = 1; 324 public static final int MSG_BINDER_DIED = 2; 325 public static final int MSG_UNBIND = 3; 326 public static final int MSG_ON_PENDING_REQUEST = 4; 327 328 public MyHandler(Context context) { 329 // Cannot use lambda - doesn't compile 330 super(context, FgThread.getHandler().getLooper(), new Callback() { 331 @Override 332 public void executeMessage(Message message) { 333 if (mDestroyed) { 334 Slog.w(LOG_TAG, "Not handling " + message + " as service for " 335 + mComponentName + " is already destroyed"); 336 return; 337 } 338 switch (message.what) { 339 case MSG_DESTROY: { 340 handleDestroy(); 341 } break; 342 343 case MSG_BINDER_DIED: { 344 handleBinderDied(); 345 } break; 346 347 case MSG_UNBIND: { 348 handleUnbind(); 349 } break; 350 351 case MSG_ON_PENDING_REQUEST: { 352 handlePendingRequest((PendingRequest) message.obj); 353 } break; 354 } 355 } 356 }, false); 357 } 358 } 359 360 private static abstract class PendingRequest implements Runnable { 361 void cancel() { 362 363 } 364 365 /** 366 * @return whether this request leads to a final state where no 367 * other requests can be made. 368 */ 369 boolean isFinal() { 370 return false; 371 } 372 } 373 374 private static final class PendingFillRequest extends PendingRequest { 375 private final Object mLock = new Object(); 376 private final WeakReference<RemoteFillService> mWeakService; 377 private AssistStructure mStructure; 378 private Bundle mExtras; 379 private final IFillCallback mCallback; 380 private ICancellationSignal mCancellation; 381 private boolean mCancelled; 382 383 public PendingFillRequest(AssistStructure structure, 384 Bundle extras, RemoteFillService service) { 385 mStructure = structure; 386 mExtras = extras; 387 mWeakService = new WeakReference<>(service); 388 mCallback = new IFillCallback.Stub() { 389 @Override 390 public void onCancellable(ICancellationSignal cancellation) { 391 synchronized (mLock) { 392 final boolean cancelled; 393 synchronized (mLock) { 394 mCancellation = cancellation; 395 cancelled = mCancelled; 396 } 397 if (cancelled) { 398 try { 399 cancellation.cancel(); 400 } catch (RemoteException e) { 401 Slog.e(LOG_TAG, "Error requesting a cancellation", e); 402 } 403 } 404 } 405 } 406 407 @Override 408 public void onSuccess(FillResponse response) { 409 RemoteFillService remoteService = mWeakService.get(); 410 if (remoteService != null) { 411 remoteService.dispatchOnFillRequestSuccess( 412 PendingFillRequest.this, response); 413 } 414 } 415 416 @Override 417 public void onFailure(CharSequence message) { 418 RemoteFillService remoteService = mWeakService.get(); 419 if (remoteService != null) { 420 remoteService.dispatchOnFillRequestFailure( 421 PendingFillRequest.this, message); 422 } 423 } 424 }; 425 } 426 427 @Override 428 public void run() { 429 RemoteFillService remoteService = mWeakService.get(); 430 if (remoteService != null) { 431 try { 432 remoteService.mAutoFillService.onFillRequest(mStructure, 433 mExtras, mCallback); 434 synchronized (mLock) { 435 mStructure = null; 436 mExtras = null; 437 } 438 } catch (RemoteException e) { 439 Slog.e(LOG_TAG, "Error calling on fill request", e); 440 cancel(); 441 } 442 } 443 } 444 445 @Override 446 public void cancel() { 447 final ICancellationSignal cancellation; 448 synchronized (mLock) { 449 if (mCancelled) { 450 return; 451 } 452 mCancelled = true; 453 cancellation = mCancellation; 454 } 455 if (cancellation == null) { 456 return; 457 } 458 try { 459 cancellation.cancel(); 460 } catch (RemoteException e) { 461 Slog.e(LOG_TAG, "Error cancelling a fill request", e); 462 } 463 } 464 } 465 466 private static final class PendingSaveRequest extends PendingRequest { 467 private final Object mLock = new Object(); 468 private final WeakReference<RemoteFillService> mWeakService; 469 private AssistStructure mStructure; 470 private Bundle mExtras; 471 private final ISaveCallback mCallback; 472 473 public PendingSaveRequest(@NonNull AssistStructure structure, 474 @Nullable Bundle extras, @NonNull RemoteFillService service) { 475 mStructure = structure; 476 mExtras = extras; 477 mWeakService = new WeakReference<>(service); 478 mCallback = new ISaveCallback.Stub() { 479 @Override 480 public void onSuccess() { 481 RemoteFillService service = mWeakService.get(); 482 if (service != null) { 483 service.dispatchOnSaveRequestSuccess( 484 PendingSaveRequest.this); 485 } 486 } 487 488 @Override 489 public void onFailure(CharSequence message) { 490 RemoteFillService service = mWeakService.get(); 491 if (service != null) { 492 service.dispatchOnSaveRequestFailure( 493 PendingSaveRequest.this, message); 494 } 495 } 496 }; 497 } 498 499 @Override 500 public void run() { 501 RemoteFillService service = mWeakService.get(); 502 if (service != null) { 503 try { 504 service.mAutoFillService.onSaveRequest(mStructure, 505 mExtras, mCallback); 506 synchronized (mLock) { 507 mStructure = null; 508 mExtras = null; 509 } 510 } catch (RemoteException e) { 511 Slog.e(LOG_TAG, "Error calling on save request", e); 512 } 513 } 514 } 515 516 @Override 517 public boolean isFinal() { 518 return true; 519 } 520 } 521} 522