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