1 /* 2 * Copyright (C) 2018 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.internal.infra; 18 19 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.app.ActivityManager; 24 import android.app.ApplicationExitInfo; 25 import android.app.IActivityManager; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.ServiceConnection; 30 import android.content.pm.ParceledListSlice; 31 import android.os.Handler; 32 import android.os.IBinder; 33 import android.os.IBinder.DeathRecipient; 34 import android.os.IInterface; 35 import android.os.RemoteException; 36 import android.os.SystemClock; 37 import android.os.UserHandle; 38 import android.util.Slog; 39 import android.util.TimeUtils; 40 41 import com.android.internal.annotations.GuardedBy; 42 43 import java.io.PrintWriter; 44 import java.lang.ref.WeakReference; 45 import java.util.ArrayList; 46 import java.util.List; 47 48 /** 49 * Base class representing a remote service. 50 * 51 * <p>It abstracts away the binding and unbinding from the remote implementation, so clients can 52 * call its methods without worrying about when and how to bind/unbind/timeout. 53 * 54 * <p>All state of this class is modified on a handler thread. 55 * 56 * <p><b>NOTE: </b>this class should not be extended directly, you should extend either 57 * {@link AbstractSinglePendingRequestRemoteService} or 58 * {@link AbstractMultiplePendingRequestsRemoteService}. 59 * 60 * <p>See {@code com.android.server.autofill.RemoteFillService} for a concrete 61 * (no pun intended) example of how to use it. 62 * 63 * @param <S> the concrete remote service class 64 * @param <I> the interface of the binder service 65 * 66 * @deprecated Use {@link ServiceConnector} to manage remote service connections 67 * 68 * @hide 69 */ 70 //TODO(b/117779333): improve javadoc above instead of using Autofill as an example 71 @Deprecated 72 public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I>, 73 I extends IInterface> implements DeathRecipient { 74 private static final int SERVICE_NOT_EXIST = -1; 75 private static final int MSG_BIND = 1; 76 private static final int MSG_UNBIND = 2; 77 78 public static final long PERMANENT_BOUND_TIMEOUT_MS = 0; 79 80 protected static final int LAST_PRIVATE_MSG = MSG_UNBIND; 81 82 // TODO(b/117779333): convert all booleans into an integer / flags 83 public final boolean mVerbose; 84 85 protected final String mTag = getClass().getSimpleName(); 86 protected final Handler mHandler; 87 protected final ComponentName mComponentName; 88 89 private final Context mContext; 90 private final Intent mIntent; 91 private final VultureCallback<S> mVultureCallback; 92 private final int mUserId; 93 private final ServiceConnection mServiceConnection = new RemoteServiceConnection(); 94 private final int mBindingFlags; 95 protected I mService; 96 97 private boolean mBound; 98 private boolean mConnecting; 99 private boolean mDestroyed; 100 private boolean mServiceDied; 101 private boolean mCompleted; 102 103 // Used just for debugging purposes (on dump) 104 private long mNextUnbind; 105 private int mServiceExitReason; 106 private int mServiceExitSubReason; 107 108 /** Requests that have been scheduled, but that are not finished yet */ 109 private final ArrayList<BasePendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>(); 110 111 /** 112 * Callback called when the service dies. 113 * 114 * @param <T> service class 115 */ 116 public interface VultureCallback<T> { 117 /** 118 * Called when the service dies. 119 * 120 * @param service service that died! 121 */ onServiceDied(T service)122 void onServiceDied(T service); 123 } 124 125 // NOTE: must be package-protected so this class is not extended outside AbstractRemoteService(@onNull Context context, @NonNull String serviceInterface, @NonNull ComponentName componentName, int userId, @NonNull VultureCallback<S> callback, @NonNull Handler handler, int bindingFlags, boolean verbose)126 AbstractRemoteService(@NonNull Context context, @NonNull String serviceInterface, 127 @NonNull ComponentName componentName, int userId, @NonNull VultureCallback<S> callback, 128 @NonNull Handler handler, int bindingFlags, boolean verbose) { 129 mContext = context; 130 mVultureCallback = callback; 131 mVerbose = verbose; 132 mComponentName = componentName; 133 mIntent = new Intent(serviceInterface).setComponent(mComponentName); 134 mUserId = userId; 135 mHandler = new Handler(handler.getLooper()); 136 mBindingFlags = bindingFlags; 137 mServiceExitReason = SERVICE_NOT_EXIST; 138 mServiceExitSubReason = SERVICE_NOT_EXIST; 139 } 140 141 /** 142 * Destroys this service. 143 */ destroy()144 public final void destroy() { 145 mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleDestroy, this)); 146 } 147 148 /** 149 * Checks whether this service is destroyed. 150 */ isDestroyed()151 public final boolean isDestroyed() { 152 return mDestroyed; 153 } 154 155 /** 156 * Gets the name of the service. 157 */ 158 @NonNull getComponentName()159 public final ComponentName getComponentName() { 160 return mComponentName; 161 } 162 handleOnConnectedStateChangedInternal(boolean connected)163 private void handleOnConnectedStateChangedInternal(boolean connected) { 164 handleOnConnectedStateChanged(connected); 165 if (connected) { 166 handlePendingRequests(); 167 } 168 } 169 170 /** 171 * Handles the pending requests when the connection it bounds to the remote service. 172 */ handlePendingRequests()173 abstract void handlePendingRequests(); 174 175 /** 176 * Callback called when the system connected / disconnected to the service and the pending 177 * requests have been handled. 178 * 179 * @param state {@code true} when connected, {@code false} when disconnected. 180 */ handleOnConnectedStateChanged(boolean state)181 protected void handleOnConnectedStateChanged(boolean state) { 182 } 183 184 /** 185 * Gets the base Binder interface from the service. 186 */ 187 @NonNull getServiceInterface(@onNull IBinder service)188 protected abstract I getServiceInterface(@NonNull IBinder service); 189 190 /** 191 * Defines how long after the last interaction with the service we would unbind. 192 * 193 * @return time to unbind (in millis), or {@link #PERMANENT_BOUND_TIMEOUT_MS} to not unbind. 194 */ getTimeoutIdleBindMillis()195 protected abstract long getTimeoutIdleBindMillis(); 196 197 /** 198 * Defines how long after we make a remote request to a fill service we timeout. 199 * 200 * <p>Just need to be overridden by subclasses that uses sync {@link PendingRequest}s. 201 * 202 * @throws UnsupportedOperationException if called when not overridden. 203 * 204 */ getRemoteRequestMillis()205 protected long getRemoteRequestMillis() { 206 throw new UnsupportedOperationException("not implemented by " + getClass()); 207 } 208 209 /** 210 * Gets the currently registered service interface or {@code null} if the service is not 211 * connected. 212 */ 213 @Nullable getServiceInterface()214 public final I getServiceInterface() { 215 return mService; 216 } 217 handleDestroy()218 private void handleDestroy() { 219 if (checkIfDestroyed()) return; 220 handleOnDestroy(); 221 handleEnsureUnbound(); 222 mDestroyed = true; 223 } 224 225 /** 226 * Clears the state when this object is destroyed. 227 * 228 * <p>Typically used to cancel the pending requests. 229 */ handleOnDestroy()230 protected abstract void handleOnDestroy(); 231 232 @Override // from DeathRecipient binderDied()233 public void binderDied() { 234 mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleBinderDied, this)); 235 } 236 handleBinderDied()237 private void handleBinderDied() { 238 if (checkIfDestroyed()) return; 239 if (mService != null) { 240 mService.asBinder().unlinkToDeath(this, 0); 241 } 242 updateServicelicationExitInfo(mComponentName, mUserId); 243 mConnecting = true; 244 mService = null; 245 mServiceDied = true; 246 cancelScheduledUnbind(); 247 @SuppressWarnings("unchecked") // TODO(b/117779333): fix this warning 248 final S castService = (S) this; 249 mVultureCallback.onServiceDied(castService); 250 handleBindFailure(); 251 } 252 updateServicelicationExitInfo(ComponentName componentName, int userId)253 private void updateServicelicationExitInfo(ComponentName componentName, int userId) { 254 IActivityManager am = ActivityManager.getService(); 255 String packageName = componentName.getPackageName(); 256 ParceledListSlice<ApplicationExitInfo> plistSlice = null; 257 try { 258 plistSlice = am.getHistoricalProcessExitReasons(packageName, 0, 1, userId); 259 } catch (RemoteException e) { 260 // do nothing. The local binder so it can not throw it. 261 } 262 if (plistSlice == null) { 263 mServiceExitReason = ApplicationExitInfo.REASON_UNKNOWN; 264 mServiceExitSubReason = ApplicationExitInfo.SUBREASON_UNKNOWN; 265 return; 266 } 267 List<ApplicationExitInfo> list = plistSlice.getList(); 268 if (list.isEmpty()) { 269 mServiceExitReason = ApplicationExitInfo.REASON_UNKNOWN; 270 mServiceExitSubReason = ApplicationExitInfo.SUBREASON_UNKNOWN; 271 return; 272 } 273 ApplicationExitInfo info = list.get(0); 274 mServiceExitReason = info.getReason(); 275 mServiceExitSubReason = info.getSubReason(); 276 if (mVerbose) { 277 Slog.v(mTag, "updateServicelicationExitInfo: exitReason=" 278 + ApplicationExitInfo.reasonCodeToString(mServiceExitReason) 279 + " exitSubReason= " + ApplicationExitInfo.subreasonToString( 280 mServiceExitSubReason)); 281 } 282 } 283 284 // Note: we are dumping without a lock held so this is a bit racy but 285 // adding a lock to a class that offloads to a handler thread would 286 // mean adding a lock adding overhead to normal runtime operation. 287 /** 288 * Dump it! 289 */ dump(@onNull String prefix, @NonNull PrintWriter pw)290 public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { 291 String tab = " "; 292 pw.append(prefix).append("service:").println(); 293 pw.append(prefix).append(tab).append("userId=") 294 .append(String.valueOf(mUserId)).println(); 295 pw.append(prefix).append(tab).append("componentName=") 296 .append(mComponentName.flattenToString()).println(); 297 pw.append(prefix).append(tab).append("destroyed=") 298 .append(String.valueOf(mDestroyed)).println(); 299 pw.append(prefix).append(tab).append("numUnfinishedRequests=") 300 .append(String.valueOf(mUnfinishedRequests.size())).println(); 301 pw.append(prefix).append(tab).append("bound=") 302 .append(String.valueOf(mBound)); 303 final boolean bound = handleIsBound(); 304 pw.append(prefix).append(tab).append("connected=") 305 .append(String.valueOf(bound)); 306 final long idleTimeout = getTimeoutIdleBindMillis(); 307 if (bound) { 308 if (idleTimeout > 0) { 309 pw.append(" (unbind in : "); 310 TimeUtils.formatDuration(mNextUnbind - SystemClock.elapsedRealtime(), pw); 311 pw.append(")"); 312 } else { 313 pw.append(" (permanently bound)"); 314 } 315 } 316 pw.println(); 317 if (mServiceExitReason != SERVICE_NOT_EXIST) { 318 pw.append(prefix).append(tab).append("serviceExistReason=") 319 .append(ApplicationExitInfo.reasonCodeToString(mServiceExitReason)); 320 pw.println(); 321 } 322 if (mServiceExitSubReason != SERVICE_NOT_EXIST) { 323 pw.append(prefix).append(tab).append("serviceExistSubReason=") 324 .append(ApplicationExitInfo.subreasonToString(mServiceExitSubReason)); 325 pw.println(); 326 } 327 pw.append(prefix).append("mBindingFlags=").println(mBindingFlags); 328 pw.append(prefix).append("idleTimeout=") 329 .append(Long.toString(idleTimeout / 1000)).append("s\n"); 330 pw.append(prefix).append("requestTimeout="); 331 try { 332 pw.append(Long.toString(getRemoteRequestMillis() / 1000)).append("s\n"); 333 } catch (UnsupportedOperationException e) { 334 pw.append("not supported\n"); 335 } 336 pw.println(); 337 } 338 339 /** 340 * Schedules a "sync" request. 341 * 342 * <p>This request must be responded by the service somehow (typically using a callback), 343 * othewise it will trigger a {@link PendingRequest#onTimeout(AbstractRemoteService)} if the 344 * service doesn't respond. 345 */ scheduleRequest(@onNull BasePendingRequest<S, I> pendingRequest)346 protected void scheduleRequest(@NonNull BasePendingRequest<S, I> pendingRequest) { 347 mHandler.sendMessage(obtainMessage( 348 AbstractRemoteService::handlePendingRequest, this, pendingRequest)); 349 } 350 351 /** 352 * Marks a pendingRequest as finished. 353 * 354 * @param finshedRequest The request that is finished 355 */ finishRequest(@onNull BasePendingRequest<S, I> finshedRequest)356 void finishRequest(@NonNull BasePendingRequest<S, I> finshedRequest) { 357 mHandler.sendMessage( 358 obtainMessage(AbstractRemoteService::handleFinishRequest, this, finshedRequest)); 359 } 360 handleFinishRequest(@onNull BasePendingRequest<S, I> finshedRequest)361 private void handleFinishRequest(@NonNull BasePendingRequest<S, I> finshedRequest) { 362 mUnfinishedRequests.remove(finshedRequest); 363 364 if (mUnfinishedRequests.isEmpty()) { 365 scheduleUnbind(); 366 } 367 } 368 369 /** 370 * Schedules an async request. 371 * 372 * <p>This request is not expecting a callback from the service, hence it's represented by 373 * a simple {@link Runnable}. 374 */ scheduleAsyncRequest(@onNull AsyncRequest<I> request)375 protected void scheduleAsyncRequest(@NonNull AsyncRequest<I> request) { 376 // TODO(b/117779333): fix generics below 377 @SuppressWarnings({"unchecked", "rawtypes"}) 378 final MyAsyncPendingRequest<S, I> asyncRequest = new MyAsyncPendingRequest(this, request); 379 mHandler.sendMessage( 380 obtainMessage(AbstractRemoteService::handlePendingRequest, this, asyncRequest)); 381 } 382 383 /** 384 * Executes an async request immediately instead of sending it to Handler queue as what 385 * {@link scheduleAsyncRequest} does. 386 * 387 * <p>This request is not expecting a callback from the service, hence it's represented by 388 * a simple {@link Runnable}. 389 */ executeAsyncRequest(@onNull AsyncRequest<I> request)390 protected void executeAsyncRequest(@NonNull AsyncRequest<I> request) { 391 // TODO(b/117779333): fix generics below 392 @SuppressWarnings({"unchecked", "rawtypes"}) 393 final MyAsyncPendingRequest<S, I> asyncRequest = new MyAsyncPendingRequest(this, request); 394 handlePendingRequest(asyncRequest); 395 } 396 cancelScheduledUnbind()397 private void cancelScheduledUnbind() { 398 mHandler.removeMessages(MSG_UNBIND); 399 } 400 401 /** 402 * Schedules a request to bind to the remote service. 403 * 404 * <p>Typically used on constructor for implementations that need a permanent connection to 405 * the remote service. 406 */ scheduleBind()407 protected void scheduleBind() { 408 if (mHandler.hasMessages(MSG_BIND)) { 409 if (mVerbose) Slog.v(mTag, "scheduleBind(): already scheduled"); 410 return; 411 } 412 mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleEnsureBound, this) 413 .setWhat(MSG_BIND)); 414 } 415 416 /** 417 * Schedules a request to automatically unbind from the service after the 418 * {@link #getTimeoutIdleBindMillis() idle timeout} expires. 419 */ scheduleUnbind()420 protected void scheduleUnbind() { 421 scheduleUnbind(true); 422 } 423 scheduleUnbind(boolean delay)424 private void scheduleUnbind(boolean delay) { 425 long unbindDelay = getTimeoutIdleBindMillis(); 426 427 if (unbindDelay <= PERMANENT_BOUND_TIMEOUT_MS) { 428 if (mVerbose) Slog.v(mTag, "not scheduling unbind when value is " + unbindDelay); 429 return; 430 } 431 432 if (!delay) { 433 unbindDelay = 0; 434 } 435 436 cancelScheduledUnbind(); 437 // TODO(b/117779333): make sure it's unbound if the service settings changing (right now 438 // it's not) 439 440 mNextUnbind = SystemClock.elapsedRealtime() + unbindDelay; 441 if (mVerbose) Slog.v(mTag, "unbinding in " + unbindDelay + "ms: " + mNextUnbind); 442 mHandler.sendMessageDelayed(obtainMessage(AbstractRemoteService::handleUnbind, this) 443 .setWhat(MSG_UNBIND), unbindDelay); 444 } 445 handleUnbind()446 private void handleUnbind() { 447 if (checkIfDestroyed()) return; 448 449 handleEnsureUnbound(); 450 } 451 452 /** 453 * Handles a request, either processing it right now when bound, or saving it to be handled when 454 * bound. 455 */ handlePendingRequest(@onNull BasePendingRequest<S, I> pendingRequest)456 protected final void handlePendingRequest(@NonNull BasePendingRequest<S, I> pendingRequest) { 457 if (checkIfDestroyed() || mCompleted) return; 458 459 if (!handleIsBound()) { 460 if (mVerbose) Slog.v(mTag, "handlePendingRequest(): queuing " + pendingRequest); 461 handlePendingRequestWhileUnBound(pendingRequest); 462 handleEnsureBound(); 463 } else { 464 if (mVerbose) Slog.v(mTag, "handlePendingRequest(): " + pendingRequest); 465 466 mUnfinishedRequests.add(pendingRequest); 467 cancelScheduledUnbind(); 468 469 pendingRequest.run(); 470 if (pendingRequest.isFinal()) { 471 mCompleted = true; 472 } 473 } 474 } 475 476 /** 477 * Defines what to do with a request that arrives while not bound to the service. 478 */ handlePendingRequestWhileUnBound( @onNull BasePendingRequest<S, I> pendingRequest)479 abstract void handlePendingRequestWhileUnBound( 480 @NonNull BasePendingRequest<S, I> pendingRequest); 481 482 /** 483 * Called if {@link Context#bindServiceAsUser} returns {@code false}, or 484 * if {@link DeathRecipient#binderDied()} is called. 485 */ handleBindFailure()486 abstract void handleBindFailure(); 487 488 // This is actually checking isConnected. TODO: rename this and other related methods (or just 489 // stop using this class..) handleIsBound()490 private boolean handleIsBound() { 491 return mService != null; 492 } 493 handleEnsureBound()494 private void handleEnsureBound() { 495 if (handleIsBound() || mConnecting) return; 496 497 if (mVerbose) Slog.v(mTag, "ensureBound()"); 498 mConnecting = true; 499 500 final int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE 501 | Context.BIND_INCLUDE_CAPABILITIES | mBindingFlags; 502 503 final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags, 504 mHandler, new UserHandle(mUserId)); 505 mBound = true; 506 507 if (!willBind) { 508 Slog.w(mTag, "could not bind to " + mIntent + " using flags " + flags); 509 mConnecting = false; 510 511 if (!mServiceDied) { 512 handleBinderDied(); 513 } 514 } 515 } 516 handleEnsureUnbound()517 private void handleEnsureUnbound() { 518 if (!handleIsBound() && !mConnecting) return; 519 520 if (mVerbose) Slog.v(mTag, "ensureUnbound()"); 521 mConnecting = false; 522 if (handleIsBound()) { 523 handleOnConnectedStateChangedInternal(false); 524 if (mService != null) { 525 mService.asBinder().unlinkToDeath(this, 0); 526 mService = null; 527 } 528 } 529 mNextUnbind = 0; 530 if (mBound) { 531 mContext.unbindService(mServiceConnection); 532 mBound = false; 533 } 534 } 535 536 private class RemoteServiceConnection implements ServiceConnection { 537 @Override onServiceConnected(ComponentName name, IBinder service)538 public void onServiceConnected(ComponentName name, IBinder service) { 539 if (mVerbose) Slog.v(mTag, "onServiceConnected()"); 540 if (mDestroyed || !mConnecting) { 541 // This is abnormal. Unbinding the connection has been requested already. 542 Slog.wtf(mTag, "onServiceConnected() was dispatched after unbindService."); 543 return; 544 } 545 mConnecting = false; 546 try { 547 service.linkToDeath(AbstractRemoteService.this, 0); 548 } catch (RemoteException re) { 549 handleBinderDied(); 550 return; 551 } 552 mService = getServiceInterface(service); 553 mServiceExitReason = SERVICE_NOT_EXIST; 554 mServiceExitSubReason = SERVICE_NOT_EXIST; 555 handleOnConnectedStateChangedInternal(true); 556 mServiceDied = false; 557 } 558 559 @Override onServiceDisconnected(ComponentName name)560 public void onServiceDisconnected(ComponentName name) { 561 if (mVerbose) Slog.v(mTag, "onServiceDisconnected()"); 562 mConnecting = true; 563 mService = null; 564 } 565 566 @Override onBindingDied(ComponentName name)567 public void onBindingDied(ComponentName name) { 568 if (mVerbose) Slog.v(mTag, "onBindingDied()"); 569 scheduleUnbind(false); 570 } 571 } 572 checkIfDestroyed()573 private boolean checkIfDestroyed() { 574 if (mDestroyed) { 575 if (mVerbose) { 576 Slog.v(mTag, "Not handling operation as service for " + mComponentName 577 + " is already destroyed"); 578 } 579 } 580 return mDestroyed; 581 } 582 583 @Override toString()584 public String toString() { 585 return getClass().getSimpleName() + "[" + mComponentName 586 + " " + System.identityHashCode(this) 587 + (mService != null ? " (bound)" : " (unbound)") 588 + (mDestroyed ? " (destroyed)" : "") 589 + "]"; 590 } 591 592 /** 593 * Base class for the requests serviced by the remote service. 594 * 595 * <p><b>NOTE: </b> this class is not used directly, you should either override 596 * {@link com.android.internal.infra.AbstractRemoteService.PendingRequest} for sync requests, or 597 * use {@link AbstractRemoteService#scheduleAsyncRequest(AsyncRequest)} for async requests. 598 * 599 * @param <S> the remote service class 600 * @param <I> the interface of the binder service 601 */ 602 public abstract static class BasePendingRequest<S extends AbstractRemoteService<S, I>, 603 I extends IInterface> implements Runnable { 604 protected final String mTag = getClass().getSimpleName(); 605 protected final Object mLock = new Object(); 606 607 final WeakReference<S> mWeakService; 608 609 @GuardedBy("mLock") 610 boolean mCancelled; 611 612 @GuardedBy("mLock") 613 boolean mCompleted; 614 BasePendingRequest(@onNull S service)615 BasePendingRequest(@NonNull S service) { 616 mWeakService = new WeakReference<>(service); 617 } 618 619 /** 620 * Gets a reference to the remote service. 621 */ getService()622 protected final S getService() { 623 return mWeakService.get(); 624 } 625 626 /** 627 * Subclasses must call this method when the remote service finishes, i.e., when the service 628 * finishes processing a request. 629 * 630 * @return {@code false} in the service is already finished, {@code true} otherwise. 631 */ finish()632 protected final boolean finish() { 633 synchronized (mLock) { 634 if (mCompleted || mCancelled) { 635 return false; 636 } 637 mCompleted = true; 638 } 639 640 S service = mWeakService.get(); 641 if (service != null) { 642 service.finishRequest(this); 643 } 644 645 onFinished(); 646 647 return true; 648 } 649 onFinished()650 void onFinished() { } 651 652 /** 653 * Called when request fails due to reasons internal to {@link AbstractRemoteService}, 654 * e.g. failure to bind to service. 655 */ onFailed()656 protected void onFailed() { } 657 658 /** 659 * Checks whether this request was cancelled. 660 */ 661 @GuardedBy("mLock") isCancelledLocked()662 protected final boolean isCancelledLocked() { 663 return mCancelled; 664 } 665 666 /** 667 * Cancels the service. 668 * 669 * @return {@code false} if service is already canceled, {@code true} otherwise. 670 */ cancel()671 public boolean cancel() { 672 synchronized (mLock) { 673 if (mCancelled || mCompleted) { 674 return false; 675 } 676 mCancelled = true; 677 } 678 679 onCancel(); 680 return true; 681 } 682 onCancel()683 void onCancel() {} 684 685 /** 686 * Checks whether this request leads to a final state where no other requests can be made. 687 */ isFinal()688 protected boolean isFinal() { 689 return false; 690 } 691 isRequestCompleted()692 protected boolean isRequestCompleted() { 693 synchronized (mLock) { 694 return mCompleted; 695 } 696 } 697 } 698 699 /** 700 * Base class for the requests serviced by the remote service. 701 * 702 * <p><b>NOTE: </b> this class is typically used when the service needs to use a callback to 703 * communicate back with the system server. For cases where that's not needed, you should use 704 * {@link AbstractRemoteService#scheduleAsyncRequest(AsyncRequest)} instead. 705 * 706 * <p><b>NOTE: </b> you must override {@link AbstractRemoteService#getRemoteRequestMillis()}, 707 * otherwise the constructor will throw an {@link UnsupportedOperationException}. 708 * 709 * @param <S> the remote service class 710 * @param <I> the interface of the binder service 711 */ 712 public abstract static class PendingRequest<S extends AbstractRemoteService<S, I>, 713 I extends IInterface> extends BasePendingRequest<S, I> { 714 715 private final Runnable mTimeoutTrigger; 716 private final Handler mServiceHandler; 717 PendingRequest(S service)718 protected PendingRequest(S service) { 719 super(service); 720 mServiceHandler = service.mHandler; 721 722 mTimeoutTrigger = () -> { 723 synchronized (mLock) { 724 if (mCancelled) { 725 return; 726 } 727 mCompleted = true; 728 } 729 730 final S remoteService = mWeakService.get(); 731 if (remoteService != null) { 732 // TODO(b/117779333): we should probably ignore it if service is destroyed. 733 Slog.w(mTag, "timed out after " + service.getRemoteRequestMillis() + " ms"); 734 remoteService.finishRequest(this); 735 onTimeout(remoteService); 736 } else { 737 Slog.w(mTag, "timed out (no service)"); 738 } 739 }; 740 mServiceHandler.postAtTime(mTimeoutTrigger, 741 SystemClock.uptimeMillis() + service.getRemoteRequestMillis()); 742 } 743 744 @Override onFinished()745 final void onFinished() { 746 mServiceHandler.removeCallbacks(mTimeoutTrigger); 747 } 748 749 @Override onCancel()750 final void onCancel() { 751 mServiceHandler.removeCallbacks(mTimeoutTrigger); 752 } 753 754 /** 755 * Called by the self-destruct timeout when the remote service didn't reply to the 756 * request on time. 757 */ onTimeout(S remoteService)758 protected abstract void onTimeout(S remoteService); 759 } 760 761 /** 762 * Represents a request that does not expect a callback from the remote service. 763 * 764 * @param <I> the interface of the binder service 765 */ 766 public interface AsyncRequest<I extends IInterface> { 767 768 /** 769 * Run Forrest, run! 770 */ run(@onNull I binder)771 void run(@NonNull I binder) throws RemoteException; 772 } 773 774 private static final class MyAsyncPendingRequest<S extends AbstractRemoteService<S, I>, 775 I extends IInterface> extends BasePendingRequest<S, I> { 776 private static final String TAG = MyAsyncPendingRequest.class.getSimpleName(); 777 778 private final AsyncRequest<I> mRequest; 779 MyAsyncPendingRequest(@onNull S service, @NonNull AsyncRequest<I> request)780 protected MyAsyncPendingRequest(@NonNull S service, @NonNull AsyncRequest<I> request) { 781 super(service); 782 783 mRequest = request; 784 } 785 786 @Override run()787 public void run() { 788 final S remoteService = getService(); 789 if (remoteService == null) return; 790 try { 791 mRequest.run(remoteService.mService); 792 } catch (RemoteException e) { 793 Slog.w(TAG, "exception handling async request (" + this + "): " + e); 794 } finally { 795 finish(); 796 } 797 } 798 } 799 } 800