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