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