blob: 2e709de5ad53b91a070a9569c4386d528ff56620 [file] [log] [blame]
Felipe Leme31a1f802018-10-16 11:24:55 -07001/*
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
Philip P. Moltmann29ee0a42018-12-19 11:56:05 -080017package com.android.internal.infra;
Felipe Leme31a1f802018-10-16 11:24:55 -070018
19import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
20
21import android.annotation.NonNull;
Philip P. Moltmann22b84982018-12-17 20:45:40 -080022import android.annotation.Nullable;
Felipe Leme31a1f802018-10-16 11:24:55 -070023import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
26import android.content.ServiceConnection;
27import android.os.Handler;
28import android.os.IBinder;
29import android.os.IBinder.DeathRecipient;
30import android.os.IInterface;
31import android.os.RemoteException;
32import android.os.SystemClock;
33import android.os.UserHandle;
34import android.util.Slog;
Felipe Leme50b33dc2018-12-20 16:01:39 -080035import android.util.TimeUtils;
Felipe Leme31a1f802018-10-16 11:24:55 -070036
37import com.android.internal.annotations.GuardedBy;
38
39import java.io.PrintWriter;
40import java.lang.ref.WeakReference;
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -080041import java.util.ArrayList;
Felipe Leme31a1f802018-10-16 11:24:55 -070042
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 *
Felipe Leme39233ff2018-11-28 16:54:23 -080051 * <p><b>NOTE: </b>this class should not be extended directly, you should extend either
52 * {@link AbstractSinglePendingRequestRemoteService} or
53 * {@link AbstractMultiplePendingRequestsRemoteService}.
54 *
Felipe Leme31a1f802018-10-16 11:24:55 -070055 * <p>See {@code com.android.server.autofill.RemoteFillService} for a concrete
56 * (no pun intended) example of how to use it.
57 *
Felipe Leme39233ff2018-11-28 16:54:23 -080058 * @param <S> the concrete remote service class
Felipe Lemeafb55b62018-12-06 11:36:09 -080059 * @param <I> the interface of the binder service
Felipe Leme39233ff2018-11-28 16:54:23 -080060 *
Felipe Leme31a1f802018-10-16 11:24:55 -070061 * @hide
62 */
63//TODO(b/117779333): improve javadoc above instead of using Autofill as an example
Felipe Lemeafb55b62018-12-06 11:36:09 -080064public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I>,
65 I extends IInterface> implements DeathRecipient {
Felipe Lemebb98ed62018-12-21 09:29:27 -080066 private static final int MSG_BIND = 1;
67 private static final int MSG_UNBIND = 2;
Felipe Leme31a1f802018-10-16 11:24:55 -070068
Felipe Lemee764fa22019-02-21 16:45:35 -080069 public static final long PERMANENT_BOUND_TIMEOUT_MS = 0;
Felipe Leme50b33dc2018-12-20 16:01:39 -080070
Felipe Leme31a1f802018-10-16 11:24:55 -070071 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
Felipe Leme31a1f802018-10-16 11:24:55 -070080 private final Context mContext;
81 private final Intent mIntent;
Felipe Lemeafb55b62018-12-06 11:36:09 -080082 private final VultureCallback<S> mVultureCallback;
Felipe Leme31a1f802018-10-16 11:24:55 -070083 private final int mUserId;
84 private final ServiceConnection mServiceConnection = new RemoteServiceConnection();
85 private final boolean mBindInstantServiceAllowed;
Felipe Lemeafb55b62018-12-06 11:36:09 -080086 protected I mService;
Felipe Leme31a1f802018-10-16 11:24:55 -070087
88 private boolean mBinding;
89 private boolean mDestroyed;
90 private boolean mServiceDied;
91 private boolean mCompleted;
92
Felipe Leme50b33dc2018-12-20 16:01:39 -080093 // Used just for debugging purposes (on dump)
94 private long mNextUnbind;
95
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -080096 /** Requests that have been scheduled, but that are not finished yet */
Felipe Leme81299d02019-02-21 15:48:50 -080097 private final ArrayList<BasePendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>();
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -080098
Felipe Leme31a1f802018-10-16 11:24:55 -070099 /**
100 * Callback called when the service dies.
Felipe Lemeafb55b62018-12-06 11:36:09 -0800101 *
102 * @param <T> service class
Felipe Leme31a1f802018-10-16 11:24:55 -0700103 */
Felipe Lemeafb55b62018-12-06 11:36:09 -0800104 public interface VultureCallback<T> {
Felipe Leme31a1f802018-10-16 11:24:55 -0700105 /**
106 * Called when the service dies.
107 *
108 * @param service service that died!
109 */
Felipe Lemeafb55b62018-12-06 11:36:09 -0800110 void onServiceDied(T service);
Felipe Leme31a1f802018-10-16 11:24:55 -0700111 }
112
Felipe Lemebb98ed62018-12-21 09:29:27 -0800113 // NOTE: must be package-protected so this class is not extended outside
Felipe Leme39233ff2018-11-28 16:54:23 -0800114 AbstractRemoteService(@NonNull Context context, @NonNull String serviceInterface,
Felipe Lemeafb55b62018-12-06 11:36:09 -0800115 @NonNull ComponentName componentName, int userId, @NonNull VultureCallback<S> callback,
Hai Zhanga4959e52019-03-06 12:21:07 -0800116 @NonNull Handler handler, boolean bindInstantServiceAllowed, boolean verbose) {
Felipe Leme31a1f802018-10-16 11:24:55 -0700117 mContext = context;
118 mVultureCallback = callback;
119 mVerbose = verbose;
120 mComponentName = componentName;
121 mIntent = new Intent(serviceInterface).setComponent(mComponentName);
122 mUserId = userId;
Hai Zhanga4959e52019-03-06 12:21:07 -0800123 mHandler = new Handler(handler.getLooper());
Felipe Leme31a1f802018-10-16 11:24:55 -0700124 mBindInstantServiceAllowed = bindInstantServiceAllowed;
125 }
126
127 /**
128 * Destroys this service.
129 */
130 public final void destroy() {
131 mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleDestroy, this));
132 }
133
134 /**
135 * Checks whether this service is destroyed.
136 */
137 public final boolean isDestroyed() {
138 return mDestroyed;
139 }
140
Felipe Leme930f3242019-01-15 16:47:09 -0800141 /**
142 * Gets the name of the service.
143 */
144 @NonNull
145 public final ComponentName getComponentName() {
146 return mComponentName;
147 }
148
Felipe Leme39233ff2018-11-28 16:54:23 -0800149 private void handleOnConnectedStateChangedInternal(boolean connected) {
Adam Hef0d74092019-02-19 14:48:19 -0800150 handleOnConnectedStateChanged(connected);
Felipe Leme39233ff2018-11-28 16:54:23 -0800151 if (connected) {
152 handlePendingRequests();
153 }
Felipe Leme39233ff2018-11-28 16:54:23 -0800154 }
155
Felipe Leme31a1f802018-10-16 11:24:55 -0700156 /**
Felipe Leme39233ff2018-11-28 16:54:23 -0800157 * Handles the pending requests when the connection it bounds to the remote service.
158 */
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.
Felipe Leme31a1f802018-10-16 11:24:55 -0700164 *
165 * @param state {@code true} when connected, {@code false} when disconnected.
166 */
Felipe Leme39233ff2018-11-28 16:54:23 -0800167 protected void handleOnConnectedStateChanged(boolean state) {
Felipe Leme31a1f802018-10-16 11:24:55 -0700168 }
169
170 /**
171 * Gets the base Binder interface from the service.
172 */
173 @NonNull
Felipe Lemeafb55b62018-12-06 11:36:09 -0800174 protected abstract I getServiceInterface(@NonNull IBinder service);
Felipe Leme31a1f802018-10-16 11:24:55 -0700175
176 /**
Felipe Leme50b33dc2018-12-20 16:01:39 -0800177 * 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.
Felipe Leme31a1f802018-10-16 11:24:55 -0700180 */
181 protected abstract long getTimeoutIdleBindMillis();
182
183 /**
184 * Defines how long after we make a remote request to a fill service we timeout.
Felipe Leme81299d02019-02-21 15:48:50 -0800185 *
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 *
Felipe Leme31a1f802018-10-16 11:24:55 -0700190 */
Felipe Leme81299d02019-02-21 15:48:50 -0800191 protected long getRemoteRequestMillis() {
192 throw new UnsupportedOperationException("not implemented by " + getClass());
193 }
Felipe Leme31a1f802018-10-16 11:24:55 -0700194
Philip P. Moltmann22b84982018-12-17 20:45:40 -0800195 /**
196 * Gets the currently registered service interface or {@code null} if the service is not
197 * connected.
198 */
199 @Nullable
200 public final I getServiceInterface() {
201 return mService;
202 }
203
Felipe Leme31a1f802018-10-16 11:24:55 -0700204 private void handleDestroy() {
205 if (checkIfDestroyed()) return;
Felipe Leme39233ff2018-11-28 16:54:23 -0800206 handleOnDestroy();
207 handleEnsureUnbound();
Felipe Leme31a1f802018-10-16 11:24:55 -0700208 mDestroyed = true;
209 }
210
Felipe Leme39233ff2018-11-28 16:54:23 -0800211 /**
212 * Clears the state when this object is destroyed.
213 *
214 * <p>Typically used to cancel the pending requests.
215 */
216 protected abstract void handleOnDestroy();
217
Felipe Leme31a1f802018-10-16 11:24:55 -0700218 @Override // from DeathRecipient
219 public void binderDied() {
220 mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleBinderDied, this));
221 }
222
223 private void handleBinderDied() {
224 if (checkIfDestroyed()) return;
Felipe Lemeafb55b62018-12-06 11:36:09 -0800225 if (mService != null) {
226 mService.asBinder().unlinkToDeath(this, 0);
Felipe Leme31a1f802018-10-16 11:24:55 -0700227 }
Felipe Lemeafb55b62018-12-06 11:36:09 -0800228 mService = null;
Felipe Leme31a1f802018-10-16 11:24:55 -0700229 mServiceDied = true;
Philip P. Moltmann26f8b802019-01-12 17:02:56 -0800230 cancelScheduledUnbind();
Felipe Lemeafb55b62018-12-06 11:36:09 -0800231 @SuppressWarnings("unchecked") // TODO(b/117779333): fix this warning
232 final S castService = (S) this;
233 mVultureCallback.onServiceDied(castService);
Felipe Leme31a1f802018-10-16 11:24:55 -0700234 }
235
236 // Note: we are dumping without a lock held so this is a bit racy but
237 // adding a lock to a class that offloads to a handler thread would
238 // mean adding a lock adding overhead to normal runtime operation.
239 /**
240 * Dump it!
241 */
242 public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
243 String tab = " ";
244 pw.append(prefix).append("service:").println();
245 pw.append(prefix).append(tab).append("userId=")
246 .append(String.valueOf(mUserId)).println();
247 pw.append(prefix).append(tab).append("componentName=")
248 .append(mComponentName.flattenToString()).println();
249 pw.append(prefix).append(tab).append("destroyed=")
250 .append(String.valueOf(mDestroyed)).println();
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800251 pw.append(prefix).append(tab).append("numUnfinishedRequests=")
Felipe Leme81299d02019-02-21 15:48:50 -0800252 .append(String.valueOf(mUnfinishedRequests.size())).println();
Felipe Leme50b33dc2018-12-20 16:01:39 -0800253 final boolean bound = handleIsBound();
Felipe Leme31a1f802018-10-16 11:24:55 -0700254 pw.append(prefix).append(tab).append("bound=")
Felipe Leme50b33dc2018-12-20 16:01:39 -0800255 .append(String.valueOf(bound));
256 final long idleTimeout = getTimeoutIdleBindMillis();
257 if (bound) {
258 if (idleTimeout > 0) {
259 pw.append(" (unbind in : ");
260 TimeUtils.formatDuration(mNextUnbind - SystemClock.elapsedRealtime(), pw);
261 pw.append(")");
262 } else {
263 pw.append(" (permanently bound)");
264 }
265 }
266 pw.println();
Felipe Leme31a1f802018-10-16 11:24:55 -0700267 pw.append(prefix).append("mBindInstantServiceAllowed=").println(mBindInstantServiceAllowed);
268 pw.append(prefix).append("idleTimeout=")
Felipe Leme81299d02019-02-21 15:48:50 -0800269 .append(Long.toString(idleTimeout / 1000)).append("s\n");
270 pw.append(prefix).append("requestTimeout=");
271 try {
272 pw.append(Long.toString(getRemoteRequestMillis() / 1000)).append("s\n");
273 } catch (UnsupportedOperationException e) {
274 pw.append("not supported\n");
275 }
Felipe Leme31a1f802018-10-16 11:24:55 -0700276 pw.println();
277 }
278
Felipe Lemeafb55b62018-12-06 11:36:09 -0800279 /**
280 * Schedules a "sync" request.
281 *
282 * <p>This request must be responded by the service somehow (typically using a callback),
283 * othewise it will trigger a {@link PendingRequest#onTimeout(AbstractRemoteService)} if the
284 * service doesn't respond.
285 */
Felipe Leme81299d02019-02-21 15:48:50 -0800286 protected void scheduleRequest(@NonNull BasePendingRequest<S, I> pendingRequest) {
Felipe Leme31a1f802018-10-16 11:24:55 -0700287 mHandler.sendMessage(obtainMessage(
288 AbstractRemoteService::handlePendingRequest, this, pendingRequest));
289 }
290
Felipe Lemeafb55b62018-12-06 11:36:09 -0800291 /**
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800292 * Marks a pendingRequest as finished.
293 *
294 * @param finshedRequest The request that is finished
295 */
Felipe Leme81299d02019-02-21 15:48:50 -0800296 void finishRequest(@NonNull BasePendingRequest<S, I> finshedRequest) {
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800297 mHandler.sendMessage(
298 obtainMessage(AbstractRemoteService::handleFinishRequest, this, finshedRequest));
299 }
300
Felipe Leme81299d02019-02-21 15:48:50 -0800301 private void handleFinishRequest(@NonNull BasePendingRequest<S, I> finshedRequest) {
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800302 mUnfinishedRequests.remove(finshedRequest);
303
304 if (mUnfinishedRequests.isEmpty()) {
305 scheduleUnbind();
306 }
307 }
308
309 /**
Felipe Lemeafb55b62018-12-06 11:36:09 -0800310 * Schedules an async request.
311 *
312 * <p>This request is not expecting a callback from the service, hence it's represented by
313 * a simple {@link Runnable}.
314 */
315 protected void scheduleAsyncRequest(@NonNull AsyncRequest<I> request) {
Felipe Lemeafb55b62018-12-06 11:36:09 -0800316 // TODO(b/117779333): fix generics below
317 @SuppressWarnings({"unchecked", "rawtypes"})
318 final MyAsyncPendingRequest<S, I> asyncRequest = new MyAsyncPendingRequest(this, request);
319 mHandler.sendMessage(
320 obtainMessage(AbstractRemoteService::handlePendingRequest, this, asyncRequest));
321 }
322
323 private void cancelScheduledUnbind() {
Felipe Leme31a1f802018-10-16 11:24:55 -0700324 mHandler.removeMessages(MSG_UNBIND);
325 }
326
Felipe Lemebb98ed62018-12-21 09:29:27 -0800327 /**
328 * Schedules a request to bind to the remote service.
329 *
330 * <p>Typically used on constructor for implementations that need a permanent connection to
331 * the remote service.
332 */
333 protected void scheduleBind() {
334 if (mHandler.hasMessages(MSG_BIND)) {
335 if (mVerbose) Slog.v(mTag, "scheduleBind(): already scheduled");
336 return;
337 }
338 mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleEnsureBound, this)
339 .setWhat(MSG_BIND));
340 }
341
342 /**
343 * Schedules a request to automatically unbind from the service after the
344 * {@link #getTimeoutIdleBindMillis() idle timeout} expires.
345 */
Felipe Leme31a1f802018-10-16 11:24:55 -0700346 protected void scheduleUnbind() {
Felipe Leme50b33dc2018-12-20 16:01:39 -0800347 final long unbindDelay = getTimeoutIdleBindMillis();
348
349 if (unbindDelay <= 0) {
350 if (mVerbose) Slog.v(mTag, "not scheduling unbind when value is " + unbindDelay);
351 return;
352 }
353
Felipe Leme31a1f802018-10-16 11:24:55 -0700354 cancelScheduledUnbind();
Felipe Leme284ad1c2018-11-15 18:16:12 -0800355 // TODO(b/117779333): make sure it's unbound if the service settings changing (right now
356 // it's not)
Felipe Leme50b33dc2018-12-20 16:01:39 -0800357
358 mNextUnbind = SystemClock.elapsedRealtime() + unbindDelay;
359 if (mVerbose) Slog.v(mTag, "unbinding in " + unbindDelay + "ms: " + mNextUnbind);
Felipe Leme31a1f802018-10-16 11:24:55 -0700360 mHandler.sendMessageDelayed(obtainMessage(AbstractRemoteService::handleUnbind, this)
Felipe Leme50b33dc2018-12-20 16:01:39 -0800361 .setWhat(MSG_UNBIND), unbindDelay);
Felipe Leme31a1f802018-10-16 11:24:55 -0700362 }
363
364 private void handleUnbind() {
365 if (checkIfDestroyed()) return;
366
Felipe Leme39233ff2018-11-28 16:54:23 -0800367 handleEnsureUnbound();
Felipe Leme31a1f802018-10-16 11:24:55 -0700368 }
369
Felipe Leme39233ff2018-11-28 16:54:23 -0800370 /**
371 * Handles a request, either processing it right now when bound, or saving it to be handled when
372 * bound.
373 */
Felipe Leme81299d02019-02-21 15:48:50 -0800374 protected final void handlePendingRequest(@NonNull BasePendingRequest<S, I> pendingRequest) {
Felipe Leme31a1f802018-10-16 11:24:55 -0700375 if (checkIfDestroyed() || mCompleted) return;
376
Felipe Leme39233ff2018-11-28 16:54:23 -0800377 if (!handleIsBound()) {
Felipe Leme749b8892018-12-03 16:30:30 -0800378 if (mVerbose) Slog.v(mTag, "handlePendingRequest(): queuing " + pendingRequest);
Felipe Leme39233ff2018-11-28 16:54:23 -0800379 handlePendingRequestWhileUnBound(pendingRequest);
380 handleEnsureBound();
Felipe Leme31a1f802018-10-16 11:24:55 -0700381 } else {
382 if (mVerbose) Slog.v(mTag, "handlePendingRequest(): " + pendingRequest);
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800383
384 mUnfinishedRequests.add(pendingRequest);
385 cancelScheduledUnbind();
386
Felipe Leme31a1f802018-10-16 11:24:55 -0700387 pendingRequest.run();
388 if (pendingRequest.isFinal()) {
389 mCompleted = true;
390 }
391 }
392 }
393
Felipe Leme39233ff2018-11-28 16:54:23 -0800394 /**
395 * Defines what to do with a request that arrives while not bound to the service.
396 */
Felipe Leme81299d02019-02-21 15:48:50 -0800397 abstract void handlePendingRequestWhileUnBound(
398 @NonNull BasePendingRequest<S, I> pendingRequest);
Felipe Leme39233ff2018-11-28 16:54:23 -0800399
400 private boolean handleIsBound() {
Felipe Lemeafb55b62018-12-06 11:36:09 -0800401 return mService != null;
Felipe Leme31a1f802018-10-16 11:24:55 -0700402 }
403
Felipe Leme39233ff2018-11-28 16:54:23 -0800404 private void handleEnsureBound() {
405 if (handleIsBound() || mBinding) return;
Felipe Leme31a1f802018-10-16 11:24:55 -0700406
407 if (mVerbose) Slog.v(mTag, "ensureBound()");
408 mBinding = true;
409
410 int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
411 if (mBindInstantServiceAllowed) {
412 flags |= Context.BIND_ALLOW_INSTANT;
413 }
414
415 final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags,
Ethon_Huc21af2f2018-11-27 21:39:22 +0800416 mHandler, new UserHandle(mUserId));
Felipe Leme31a1f802018-10-16 11:24:55 -0700417
418 if (!willBind) {
419 Slog.w(mTag, "could not bind to " + mIntent + " using flags " + flags);
420 mBinding = false;
421
422 if (!mServiceDied) {
423 handleBinderDied();
424 }
425 }
426 }
427
Felipe Leme39233ff2018-11-28 16:54:23 -0800428 private void handleEnsureUnbound() {
429 if (!handleIsBound() && !mBinding) return;
Felipe Leme31a1f802018-10-16 11:24:55 -0700430
431 if (mVerbose) Slog.v(mTag, "ensureUnbound()");
432 mBinding = false;
Felipe Leme39233ff2018-11-28 16:54:23 -0800433 if (handleIsBound()) {
434 handleOnConnectedStateChangedInternal(false);
Felipe Lemeafb55b62018-12-06 11:36:09 -0800435 if (mService != null) {
436 mService.asBinder().unlinkToDeath(this, 0);
437 mService = null;
Felipe Leme31a1f802018-10-16 11:24:55 -0700438 }
439 }
Felipe Leme50b33dc2018-12-20 16:01:39 -0800440 mNextUnbind = 0;
Felipe Leme31a1f802018-10-16 11:24:55 -0700441 mContext.unbindService(mServiceConnection);
442 }
443
444 private class RemoteServiceConnection implements ServiceConnection {
445 @Override
446 public void onServiceConnected(ComponentName name, IBinder service) {
Felipe Leme39233ff2018-11-28 16:54:23 -0800447 if (mVerbose) Slog.v(mTag, "onServiceConnected()");
Felipe Leme31a1f802018-10-16 11:24:55 -0700448 if (mDestroyed || !mBinding) {
449 // This is abnormal. Unbinding the connection has been requested already.
450 Slog.wtf(mTag, "onServiceConnected() was dispatched after unbindService.");
451 return;
452 }
453 mBinding = false;
Felipe Lemeafb55b62018-12-06 11:36:09 -0800454 mService = getServiceInterface(service);
Felipe Leme31a1f802018-10-16 11:24:55 -0700455 try {
456 service.linkToDeath(AbstractRemoteService.this, 0);
457 } catch (RemoteException re) {
458 handleBinderDied();
459 return;
460 }
Felipe Leme39233ff2018-11-28 16:54:23 -0800461 handleOnConnectedStateChangedInternal(true);
Felipe Leme31a1f802018-10-16 11:24:55 -0700462 mServiceDied = false;
463 }
464
465 @Override
466 public void onServiceDisconnected(ComponentName name) {
467 mBinding = true;
Felipe Lemeafb55b62018-12-06 11:36:09 -0800468 mService = null;
Felipe Leme31a1f802018-10-16 11:24:55 -0700469 }
470 }
471
472 private boolean checkIfDestroyed() {
473 if (mDestroyed) {
474 if (mVerbose) {
475 Slog.v(mTag, "Not handling operation as service for " + mComponentName
476 + " is already destroyed");
477 }
478 }
479 return mDestroyed;
480 }
481
Felipe Leme817b5e12019-03-07 14:32:56 -0800482 @Override
483 public String toString() {
484 return getClass().getSimpleName() + "[" + mComponentName + "]";
485 }
486
Felipe Leme31a1f802018-10-16 11:24:55 -0700487 /**
488 * Base class for the requests serviced by the remote service.
489 *
Felipe Leme81299d02019-02-21 15:48:50 -0800490 * <p><b>NOTE: </b> this class is not used directly, you should either override
491 * {@link com.android.internal.infra.AbstractRemoteService.PendingRequest} for sync requests, or
492 * use {@link AbstractRemoteService#scheduleAsyncRequest(AsyncRequest)} for async requests.
Felipe Lemeafb55b62018-12-06 11:36:09 -0800493 *
Felipe Leme31a1f802018-10-16 11:24:55 -0700494 * @param <S> the remote service class
Felipe Lemeafb55b62018-12-06 11:36:09 -0800495 * @param <I> the interface of the binder service
Felipe Leme31a1f802018-10-16 11:24:55 -0700496 */
Felipe Leme81299d02019-02-21 15:48:50 -0800497 public abstract static class BasePendingRequest<S extends AbstractRemoteService<S, I>,
Felipe Lemeafb55b62018-12-06 11:36:09 -0800498 I extends IInterface> implements Runnable {
Felipe Leme31a1f802018-10-16 11:24:55 -0700499 protected final String mTag = getClass().getSimpleName();
500 protected final Object mLock = new Object();
501
Felipe Leme81299d02019-02-21 15:48:50 -0800502 final WeakReference<S> mWeakService;
Felipe Leme31a1f802018-10-16 11:24:55 -0700503
504 @GuardedBy("mLock")
Felipe Leme81299d02019-02-21 15:48:50 -0800505 boolean mCancelled;
Felipe Leme31a1f802018-10-16 11:24:55 -0700506
507 @GuardedBy("mLock")
Felipe Leme81299d02019-02-21 15:48:50 -0800508 boolean mCompleted;
Felipe Leme31a1f802018-10-16 11:24:55 -0700509
Felipe Leme81299d02019-02-21 15:48:50 -0800510 BasePendingRequest(@NonNull S service) {
Felipe Leme31a1f802018-10-16 11:24:55 -0700511 mWeakService = new WeakReference<>(service);
Felipe Leme31a1f802018-10-16 11:24:55 -0700512 }
513
514 /**
515 * Gets a reference to the remote service.
516 */
517 protected final S getService() {
518 return mWeakService.get();
519 }
520
521 /**
522 * Subclasses must call this method when the remote service finishes, i.e., when the service
523 * finishes processing a request.
524 *
525 * @return {@code false} in the service is already finished, {@code true} otherwise.
526 */
527 protected final boolean finish() {
528 synchronized (mLock) {
529 if (mCompleted || mCancelled) {
530 return false;
531 }
532 mCompleted = true;
533 }
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800534
535 S service = mWeakService.get();
536 if (service != null) {
537 service.finishRequest(this);
538 }
539
Felipe Leme81299d02019-02-21 15:48:50 -0800540 onFinished();
541
Felipe Leme31a1f802018-10-16 11:24:55 -0700542 return true;
543 }
544
Felipe Leme81299d02019-02-21 15:48:50 -0800545 void onFinished() { }
546
Felipe Leme31a1f802018-10-16 11:24:55 -0700547 /**
548 * Checks whether this request was cancelled.
549 */
550 @GuardedBy("mLock")
551 protected final boolean isCancelledLocked() {
552 return mCancelled;
553 }
554
555 /**
556 * Cancels the service.
557 *
558 * @return {@code false} if service is already canceled, {@code true} otherwise.
559 */
560 public boolean cancel() {
561 synchronized (mLock) {
562 if (mCancelled || mCompleted) {
563 return false;
564 }
565 mCancelled = true;
566 }
567
Felipe Leme81299d02019-02-21 15:48:50 -0800568 onCancel();
Felipe Leme31a1f802018-10-16 11:24:55 -0700569 return true;
570 }
571
Felipe Leme81299d02019-02-21 15:48:50 -0800572 void onCancel() {}
Felipe Leme31a1f802018-10-16 11:24:55 -0700573
574 /**
575 * Checks whether this request leads to a final state where no other requests can be made.
576 */
577 protected boolean isFinal() {
578 return false;
579 }
580 }
Felipe Lemeafb55b62018-12-06 11:36:09 -0800581
582 /**
Felipe Leme81299d02019-02-21 15:48:50 -0800583 * Base class for the requests serviced by the remote service.
584 *
585 * <p><b>NOTE: </b> this class is typically used when the service needs to use a callback to
586 * communicate back with the system server. For cases where that's not needed, you should use
587 * {@link AbstractRemoteService#scheduleAsyncRequest(AsyncRequest)} instead.
588 *
589 * <p><b>NOTE: </b> you must override {@link AbstractRemoteService#getRemoteRequestMillis()},
590 * otherwise the constructor will throw an {@link UnsupportedOperationException}.
591 *
592 * @param <S> the remote service class
593 * @param <I> the interface of the binder service
594 */
595 public abstract static class PendingRequest<S extends AbstractRemoteService<S, I>,
596 I extends IInterface> extends BasePendingRequest<S, I> {
597
598 private final Runnable mTimeoutTrigger;
599 private final Handler mServiceHandler;
600
601 protected PendingRequest(S service) {
602 super(service);
603 mServiceHandler = service.mHandler;
604
605 mTimeoutTrigger = () -> {
606 synchronized (mLock) {
607 if (mCancelled) {
608 return;
609 }
610 mCompleted = true;
611 }
612
613 final S remoteService = mWeakService.get();
614 if (remoteService != null) {
615 // TODO(b/117779333): we should probably ignore it if service is destroyed.
616 Slog.w(mTag, "timed out after " + service.getRemoteRequestMillis() + " ms");
617 onTimeout(remoteService);
618 } else {
619 Slog.w(mTag, "timed out (no service)");
620 }
621 };
622 mServiceHandler.postAtTime(mTimeoutTrigger,
623 SystemClock.uptimeMillis() + service.getRemoteRequestMillis());
624 }
625
626 @Override
627 final void onFinished() {
628 mServiceHandler.removeCallbacks(mTimeoutTrigger);
629 }
630
631 @Override
632 final void onCancel() {
633 mServiceHandler.removeCallbacks(mTimeoutTrigger);
634 }
635
636 /**
637 * Called by the self-destruct timeout when the remote service didn't reply to the
638 * request on time.
639 */
640 protected abstract void onTimeout(S remoteService);
641 }
642
643 /**
Felipe Lemeafb55b62018-12-06 11:36:09 -0800644 * Represents a request that does not expect a callback from the remote service.
645 *
646 * @param <I> the interface of the binder service
647 */
648 public interface AsyncRequest<I extends IInterface> {
649
650 /**
651 * Run Forrest, run!
652 */
653 void run(@NonNull I binder) throws RemoteException;
654 }
655
656 private static final class MyAsyncPendingRequest<S extends AbstractRemoteService<S, I>,
Felipe Leme81299d02019-02-21 15:48:50 -0800657 I extends IInterface> extends BasePendingRequest<S, I> {
Felipe Lemeafb55b62018-12-06 11:36:09 -0800658 private static final String TAG = MyAsyncPendingRequest.class.getSimpleName();
659
660 private final AsyncRequest<I> mRequest;
661
662 protected MyAsyncPendingRequest(@NonNull S service, @NonNull AsyncRequest<I> request) {
663 super(service);
664
665 mRequest = request;
666 }
667
668 @Override
669 public void run() {
670 final S remoteService = getService();
671 if (remoteService == null) return;
672 try {
673 mRequest.run(remoteService.mService);
674 } catch (RemoteException e) {
675 Slog.w(TAG, "exception handling async request (" + this + "): " + e);
676 } finally {
677 finish();
678 }
679 }
Felipe Lemeafb55b62018-12-06 11:36:09 -0800680 }
Felipe Leme31a1f802018-10-16 11:24:55 -0700681}