blob: f4c904dc750ed79c20a698f7229606b8e126d174 [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;
Philip P. Moltmann29ee0a42018-12-19 11:56:05 -080031import android.os.Looper;
Felipe Leme31a1f802018-10-16 11:24:55 -070032import android.os.RemoteException;
33import android.os.SystemClock;
34import android.os.UserHandle;
35import android.util.Slog;
Felipe Leme50b33dc2018-12-20 16:01:39 -080036import android.util.TimeUtils;
Felipe Leme31a1f802018-10-16 11:24:55 -070037
38import com.android.internal.annotations.GuardedBy;
39
40import java.io.PrintWriter;
41import java.lang.ref.WeakReference;
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -080042import java.util.ArrayList;
Felipe Leme31a1f802018-10-16 11:24:55 -070043
44/**
45 * Base class representing a remote service.
46 *
47 * <p>It abstracts away the binding and unbinding from the remote implementation, so clients can
48 * call its methods without worrying about when and how to bind/unbind/timeout.
49 *
50 * <p>All state of this class is modified on a handler thread.
51 *
Felipe Leme39233ff2018-11-28 16:54:23 -080052 * <p><b>NOTE: </b>this class should not be extended directly, you should extend either
53 * {@link AbstractSinglePendingRequestRemoteService} or
54 * {@link AbstractMultiplePendingRequestsRemoteService}.
55 *
Felipe Leme31a1f802018-10-16 11:24:55 -070056 * <p>See {@code com.android.server.autofill.RemoteFillService} for a concrete
57 * (no pun intended) example of how to use it.
58 *
Felipe Leme39233ff2018-11-28 16:54:23 -080059 * @param <S> the concrete remote service class
Felipe Lemeafb55b62018-12-06 11:36:09 -080060 * @param <I> the interface of the binder service
Felipe Leme39233ff2018-11-28 16:54:23 -080061 *
Felipe Leme31a1f802018-10-16 11:24:55 -070062 * @hide
63 */
64//TODO(b/117779333): improve javadoc above instead of using Autofill as an example
Felipe Lemeafb55b62018-12-06 11:36:09 -080065public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I>,
66 I extends IInterface> implements DeathRecipient {
Felipe Lemebb98ed62018-12-21 09:29:27 -080067 private static final int MSG_BIND = 1;
68 private static final int MSG_UNBIND = 2;
Felipe Leme31a1f802018-10-16 11:24:55 -070069
Felipe Lemee764fa22019-02-21 16:45:35 -080070 public static final long PERMANENT_BOUND_TIMEOUT_MS = 0;
Felipe Leme50b33dc2018-12-20 16:01:39 -080071
Felipe Leme31a1f802018-10-16 11:24:55 -070072 protected static final int LAST_PRIVATE_MSG = MSG_UNBIND;
73
74 // TODO(b/117779333): convert all booleans into an integer / flags
75 public final boolean mVerbose;
76
77 protected final String mTag = getClass().getSimpleName();
78 protected final Handler mHandler;
79 protected final ComponentName mComponentName;
80
Felipe Leme31a1f802018-10-16 11:24:55 -070081 private final Context mContext;
82 private final Intent mIntent;
Felipe Lemeafb55b62018-12-06 11:36:09 -080083 private final VultureCallback<S> mVultureCallback;
Felipe Leme31a1f802018-10-16 11:24:55 -070084 private final int mUserId;
85 private final ServiceConnection mServiceConnection = new RemoteServiceConnection();
86 private final boolean mBindInstantServiceAllowed;
Felipe Lemeafb55b62018-12-06 11:36:09 -080087 protected I mService;
Felipe Leme31a1f802018-10-16 11:24:55 -070088
89 private boolean mBinding;
90 private boolean mDestroyed;
91 private boolean mServiceDied;
92 private boolean mCompleted;
93
Felipe Leme50b33dc2018-12-20 16:01:39 -080094 // Used just for debugging purposes (on dump)
95 private long mNextUnbind;
96
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -080097 /** Requests that have been scheduled, but that are not finished yet */
Felipe Leme81299d02019-02-21 15:48:50 -080098 private final ArrayList<BasePendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>();
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -080099
Felipe Leme31a1f802018-10-16 11:24:55 -0700100 /**
101 * Callback called when the service dies.
Felipe Lemeafb55b62018-12-06 11:36:09 -0800102 *
103 * @param <T> service class
Felipe Leme31a1f802018-10-16 11:24:55 -0700104 */
Felipe Lemeafb55b62018-12-06 11:36:09 -0800105 public interface VultureCallback<T> {
Felipe Leme31a1f802018-10-16 11:24:55 -0700106 /**
107 * Called when the service dies.
108 *
109 * @param service service that died!
110 */
Felipe Lemeafb55b62018-12-06 11:36:09 -0800111 void onServiceDied(T service);
Felipe Leme31a1f802018-10-16 11:24:55 -0700112 }
113
Felipe Lemebb98ed62018-12-21 09:29:27 -0800114 // NOTE: must be package-protected so this class is not extended outside
Felipe Leme39233ff2018-11-28 16:54:23 -0800115 AbstractRemoteService(@NonNull Context context, @NonNull String serviceInterface,
Felipe Lemeafb55b62018-12-06 11:36:09 -0800116 @NonNull ComponentName componentName, int userId, @NonNull VultureCallback<S> callback,
Felipe Leme31a1f802018-10-16 11:24:55 -0700117 boolean bindInstantServiceAllowed, boolean verbose) {
118 mContext = context;
119 mVultureCallback = callback;
120 mVerbose = verbose;
121 mComponentName = componentName;
122 mIntent = new Intent(serviceInterface).setComponent(mComponentName);
123 mUserId = userId;
Philip P. Moltmann29ee0a42018-12-19 11:56:05 -0800124 mHandler = new Handler(Looper.getMainLooper());
Felipe Leme31a1f802018-10-16 11:24:55 -0700125 mBindInstantServiceAllowed = bindInstantServiceAllowed;
126 }
127
128 /**
129 * Destroys this service.
130 */
131 public final void destroy() {
132 mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleDestroy, this));
133 }
134
135 /**
136 * Checks whether this service is destroyed.
137 */
138 public final boolean isDestroyed() {
139 return mDestroyed;
140 }
141
Felipe Leme930f3242019-01-15 16:47:09 -0800142 /**
143 * Gets the name of the service.
144 */
145 @NonNull
146 public final ComponentName getComponentName() {
147 return mComponentName;
148 }
149
Felipe Leme39233ff2018-11-28 16:54:23 -0800150 private void handleOnConnectedStateChangedInternal(boolean connected) {
Adam Hef0d74092019-02-19 14:48:19 -0800151 handleOnConnectedStateChanged(connected);
Felipe Leme39233ff2018-11-28 16:54:23 -0800152 if (connected) {
153 handlePendingRequests();
154 }
Felipe Leme39233ff2018-11-28 16:54:23 -0800155 }
156
Felipe Leme31a1f802018-10-16 11:24:55 -0700157 /**
Felipe Leme39233ff2018-11-28 16:54:23 -0800158 * Handles the pending requests when the connection it bounds to the remote service.
159 */
160 abstract void handlePendingRequests();
161
162 /**
163 * Callback called when the system connected / disconnected to the service and the pending
164 * requests have been handled.
Felipe Leme31a1f802018-10-16 11:24:55 -0700165 *
166 * @param state {@code true} when connected, {@code false} when disconnected.
167 */
Felipe Leme39233ff2018-11-28 16:54:23 -0800168 protected void handleOnConnectedStateChanged(boolean state) {
Felipe Leme31a1f802018-10-16 11:24:55 -0700169 }
170
171 /**
172 * Gets the base Binder interface from the service.
173 */
174 @NonNull
Felipe Lemeafb55b62018-12-06 11:36:09 -0800175 protected abstract I getServiceInterface(@NonNull IBinder service);
Felipe Leme31a1f802018-10-16 11:24:55 -0700176
177 /**
Felipe Leme50b33dc2018-12-20 16:01:39 -0800178 * Defines how long after the last interaction with the service we would unbind.
179 *
180 * @return time to unbind (in millis), or {@link #PERMANENT_BOUND_TIMEOUT_MS} to not unbind.
Felipe Leme31a1f802018-10-16 11:24:55 -0700181 */
182 protected abstract long getTimeoutIdleBindMillis();
183
184 /**
185 * Defines how long after we make a remote request to a fill service we timeout.
Felipe Leme81299d02019-02-21 15:48:50 -0800186 *
187 * <p>Just need to be overridden by subclasses that uses sync {@link PendingRequest}s.
188 *
189 * @throws UnsupportedOperationException if called when not overridden.
190 *
Felipe Leme31a1f802018-10-16 11:24:55 -0700191 */
Felipe Leme81299d02019-02-21 15:48:50 -0800192 protected long getRemoteRequestMillis() {
193 throw new UnsupportedOperationException("not implemented by " + getClass());
194 }
Felipe Leme31a1f802018-10-16 11:24:55 -0700195
Philip P. Moltmann22b84982018-12-17 20:45:40 -0800196 /**
197 * Gets the currently registered service interface or {@code null} if the service is not
198 * connected.
199 */
200 @Nullable
201 public final I getServiceInterface() {
202 return mService;
203 }
204
Felipe Leme31a1f802018-10-16 11:24:55 -0700205 private void handleDestroy() {
206 if (checkIfDestroyed()) return;
Felipe Leme39233ff2018-11-28 16:54:23 -0800207 handleOnDestroy();
208 handleEnsureUnbound();
Felipe Leme31a1f802018-10-16 11:24:55 -0700209 mDestroyed = true;
210 }
211
Felipe Leme39233ff2018-11-28 16:54:23 -0800212 /**
213 * Clears the state when this object is destroyed.
214 *
215 * <p>Typically used to cancel the pending requests.
216 */
217 protected abstract void handleOnDestroy();
218
Felipe Leme31a1f802018-10-16 11:24:55 -0700219 @Override // from DeathRecipient
220 public void binderDied() {
221 mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleBinderDied, this));
222 }
223
224 private void handleBinderDied() {
225 if (checkIfDestroyed()) return;
Felipe Lemeafb55b62018-12-06 11:36:09 -0800226 if (mService != null) {
227 mService.asBinder().unlinkToDeath(this, 0);
Felipe Leme31a1f802018-10-16 11:24:55 -0700228 }
Felipe Lemeafb55b62018-12-06 11:36:09 -0800229 mService = null;
Felipe Leme31a1f802018-10-16 11:24:55 -0700230 mServiceDied = true;
Philip P. Moltmann26f8b802019-01-12 17:02:56 -0800231 cancelScheduledUnbind();
Felipe Lemeafb55b62018-12-06 11:36:09 -0800232 @SuppressWarnings("unchecked") // TODO(b/117779333): fix this warning
233 final S castService = (S) this;
234 mVultureCallback.onServiceDied(castService);
Felipe Leme31a1f802018-10-16 11:24:55 -0700235 }
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 */
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();
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800252 pw.append(prefix).append(tab).append("numUnfinishedRequests=")
Felipe Leme81299d02019-02-21 15:48:50 -0800253 .append(String.valueOf(mUnfinishedRequests.size())).println();
Felipe Leme50b33dc2018-12-20 16:01:39 -0800254 final boolean bound = handleIsBound();
Felipe Leme31a1f802018-10-16 11:24:55 -0700255 pw.append(prefix).append(tab).append("bound=")
Felipe Leme50b33dc2018-12-20 16:01:39 -0800256 .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();
Felipe Leme31a1f802018-10-16 11:24:55 -0700268 pw.append(prefix).append("mBindInstantServiceAllowed=").println(mBindInstantServiceAllowed);
269 pw.append(prefix).append("idleTimeout=")
Felipe Leme81299d02019-02-21 15:48:50 -0800270 .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 }
Felipe Leme31a1f802018-10-16 11:24:55 -0700277 pw.println();
278 }
279
Felipe Lemeafb55b62018-12-06 11:36:09 -0800280 /**
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 */
Felipe Leme81299d02019-02-21 15:48:50 -0800287 protected void scheduleRequest(@NonNull BasePendingRequest<S, I> pendingRequest) {
Felipe Leme31a1f802018-10-16 11:24:55 -0700288 mHandler.sendMessage(obtainMessage(
289 AbstractRemoteService::handlePendingRequest, this, pendingRequest));
290 }
291
Felipe Lemeafb55b62018-12-06 11:36:09 -0800292 /**
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800293 * Marks a pendingRequest as finished.
294 *
295 * @param finshedRequest The request that is finished
296 */
Felipe Leme81299d02019-02-21 15:48:50 -0800297 void finishRequest(@NonNull BasePendingRequest<S, I> finshedRequest) {
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800298 mHandler.sendMessage(
299 obtainMessage(AbstractRemoteService::handleFinishRequest, this, finshedRequest));
300 }
301
Felipe Leme81299d02019-02-21 15:48:50 -0800302 private void handleFinishRequest(@NonNull BasePendingRequest<S, I> finshedRequest) {
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800303 mUnfinishedRequests.remove(finshedRequest);
304
305 if (mUnfinishedRequests.isEmpty()) {
306 scheduleUnbind();
307 }
308 }
309
310 /**
Felipe Lemeafb55b62018-12-06 11:36:09 -0800311 * 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 */
316 protected void scheduleAsyncRequest(@NonNull AsyncRequest<I> request) {
Felipe Lemeafb55b62018-12-06 11:36:09 -0800317 // 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
324 private void cancelScheduledUnbind() {
Felipe Leme31a1f802018-10-16 11:24:55 -0700325 mHandler.removeMessages(MSG_UNBIND);
326 }
327
Felipe Lemebb98ed62018-12-21 09:29:27 -0800328 /**
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 */
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 */
Felipe Leme31a1f802018-10-16 11:24:55 -0700347 protected void scheduleUnbind() {
Felipe Leme50b33dc2018-12-20 16:01:39 -0800348 final long unbindDelay = getTimeoutIdleBindMillis();
349
350 if (unbindDelay <= 0) {
351 if (mVerbose) Slog.v(mTag, "not scheduling unbind when value is " + unbindDelay);
352 return;
353 }
354
Felipe Leme31a1f802018-10-16 11:24:55 -0700355 cancelScheduledUnbind();
Felipe Leme284ad1c2018-11-15 18:16:12 -0800356 // TODO(b/117779333): make sure it's unbound if the service settings changing (right now
357 // it's not)
Felipe Leme50b33dc2018-12-20 16:01:39 -0800358
359 mNextUnbind = SystemClock.elapsedRealtime() + unbindDelay;
360 if (mVerbose) Slog.v(mTag, "unbinding in " + unbindDelay + "ms: " + mNextUnbind);
Felipe Leme31a1f802018-10-16 11:24:55 -0700361 mHandler.sendMessageDelayed(obtainMessage(AbstractRemoteService::handleUnbind, this)
Felipe Leme50b33dc2018-12-20 16:01:39 -0800362 .setWhat(MSG_UNBIND), unbindDelay);
Felipe Leme31a1f802018-10-16 11:24:55 -0700363 }
364
365 private void handleUnbind() {
366 if (checkIfDestroyed()) return;
367
Felipe Leme39233ff2018-11-28 16:54:23 -0800368 handleEnsureUnbound();
Felipe Leme31a1f802018-10-16 11:24:55 -0700369 }
370
Felipe Leme39233ff2018-11-28 16:54:23 -0800371 /**
372 * Handles a request, either processing it right now when bound, or saving it to be handled when
373 * bound.
374 */
Felipe Leme81299d02019-02-21 15:48:50 -0800375 protected final void handlePendingRequest(@NonNull BasePendingRequest<S, I> pendingRequest) {
Felipe Leme31a1f802018-10-16 11:24:55 -0700376 if (checkIfDestroyed() || mCompleted) return;
377
Felipe Leme39233ff2018-11-28 16:54:23 -0800378 if (!handleIsBound()) {
Felipe Leme749b8892018-12-03 16:30:30 -0800379 if (mVerbose) Slog.v(mTag, "handlePendingRequest(): queuing " + pendingRequest);
Felipe Leme39233ff2018-11-28 16:54:23 -0800380 handlePendingRequestWhileUnBound(pendingRequest);
381 handleEnsureBound();
Felipe Leme31a1f802018-10-16 11:24:55 -0700382 } else {
383 if (mVerbose) Slog.v(mTag, "handlePendingRequest(): " + pendingRequest);
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800384
385 mUnfinishedRequests.add(pendingRequest);
386 cancelScheduledUnbind();
387
Felipe Leme31a1f802018-10-16 11:24:55 -0700388 pendingRequest.run();
389 if (pendingRequest.isFinal()) {
390 mCompleted = true;
391 }
392 }
393 }
394
Felipe Leme39233ff2018-11-28 16:54:23 -0800395 /**
396 * Defines what to do with a request that arrives while not bound to the service.
397 */
Felipe Leme81299d02019-02-21 15:48:50 -0800398 abstract void handlePendingRequestWhileUnBound(
399 @NonNull BasePendingRequest<S, I> pendingRequest);
Felipe Leme39233ff2018-11-28 16:54:23 -0800400
401 private boolean handleIsBound() {
Felipe Lemeafb55b62018-12-06 11:36:09 -0800402 return mService != null;
Felipe Leme31a1f802018-10-16 11:24:55 -0700403 }
404
Felipe Leme39233ff2018-11-28 16:54:23 -0800405 private void handleEnsureBound() {
406 if (handleIsBound() || mBinding) return;
Felipe Leme31a1f802018-10-16 11:24:55 -0700407
408 if (mVerbose) Slog.v(mTag, "ensureBound()");
409 mBinding = true;
410
411 int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
412 if (mBindInstantServiceAllowed) {
413 flags |= Context.BIND_ALLOW_INSTANT;
414 }
415
416 final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags,
Ethon_Huc21af2f2018-11-27 21:39:22 +0800417 mHandler, new UserHandle(mUserId));
Felipe Leme31a1f802018-10-16 11:24:55 -0700418
419 if (!willBind) {
420 Slog.w(mTag, "could not bind to " + mIntent + " using flags " + flags);
421 mBinding = false;
422
423 if (!mServiceDied) {
424 handleBinderDied();
425 }
426 }
427 }
428
Felipe Leme39233ff2018-11-28 16:54:23 -0800429 private void handleEnsureUnbound() {
430 if (!handleIsBound() && !mBinding) return;
Felipe Leme31a1f802018-10-16 11:24:55 -0700431
432 if (mVerbose) Slog.v(mTag, "ensureUnbound()");
433 mBinding = false;
Felipe Leme39233ff2018-11-28 16:54:23 -0800434 if (handleIsBound()) {
435 handleOnConnectedStateChangedInternal(false);
Felipe Lemeafb55b62018-12-06 11:36:09 -0800436 if (mService != null) {
437 mService.asBinder().unlinkToDeath(this, 0);
438 mService = null;
Felipe Leme31a1f802018-10-16 11:24:55 -0700439 }
440 }
Felipe Leme50b33dc2018-12-20 16:01:39 -0800441 mNextUnbind = 0;
Felipe Leme31a1f802018-10-16 11:24:55 -0700442 mContext.unbindService(mServiceConnection);
443 }
444
445 private class RemoteServiceConnection implements ServiceConnection {
446 @Override
447 public void onServiceConnected(ComponentName name, IBinder service) {
Felipe Leme39233ff2018-11-28 16:54:23 -0800448 if (mVerbose) Slog.v(mTag, "onServiceConnected()");
Felipe Leme31a1f802018-10-16 11:24:55 -0700449 if (mDestroyed || !mBinding) {
450 // This is abnormal. Unbinding the connection has been requested already.
451 Slog.wtf(mTag, "onServiceConnected() was dispatched after unbindService.");
452 return;
453 }
454 mBinding = false;
Felipe Lemeafb55b62018-12-06 11:36:09 -0800455 mService = getServiceInterface(service);
Felipe Leme31a1f802018-10-16 11:24:55 -0700456 try {
457 service.linkToDeath(AbstractRemoteService.this, 0);
458 } catch (RemoteException re) {
459 handleBinderDied();
460 return;
461 }
Felipe Leme39233ff2018-11-28 16:54:23 -0800462 handleOnConnectedStateChangedInternal(true);
Felipe Leme31a1f802018-10-16 11:24:55 -0700463 mServiceDied = false;
464 }
465
466 @Override
467 public void onServiceDisconnected(ComponentName name) {
468 mBinding = true;
Felipe Lemeafb55b62018-12-06 11:36:09 -0800469 mService = null;
Felipe Leme31a1f802018-10-16 11:24:55 -0700470 }
471 }
472
473 private boolean checkIfDestroyed() {
474 if (mDestroyed) {
475 if (mVerbose) {
476 Slog.v(mTag, "Not handling operation as service for " + mComponentName
477 + " is already destroyed");
478 }
479 }
480 return mDestroyed;
481 }
482
Felipe Leme31a1f802018-10-16 11:24:55 -0700483 /**
484 * Base class for the requests serviced by the remote service.
485 *
Felipe Leme81299d02019-02-21 15:48:50 -0800486 * <p><b>NOTE: </b> this class is not used directly, you should either override
487 * {@link com.android.internal.infra.AbstractRemoteService.PendingRequest} for sync requests, or
488 * use {@link AbstractRemoteService#scheduleAsyncRequest(AsyncRequest)} for async requests.
Felipe Lemeafb55b62018-12-06 11:36:09 -0800489 *
Felipe Leme31a1f802018-10-16 11:24:55 -0700490 * @param <S> the remote service class
Felipe Lemeafb55b62018-12-06 11:36:09 -0800491 * @param <I> the interface of the binder service
Felipe Leme31a1f802018-10-16 11:24:55 -0700492 */
Felipe Leme81299d02019-02-21 15:48:50 -0800493 public abstract static class BasePendingRequest<S extends AbstractRemoteService<S, I>,
Felipe Lemeafb55b62018-12-06 11:36:09 -0800494 I extends IInterface> implements Runnable {
Felipe Leme31a1f802018-10-16 11:24:55 -0700495 protected final String mTag = getClass().getSimpleName();
496 protected final Object mLock = new Object();
497
Felipe Leme81299d02019-02-21 15:48:50 -0800498 final WeakReference<S> mWeakService;
Felipe Leme31a1f802018-10-16 11:24:55 -0700499
500 @GuardedBy("mLock")
Felipe Leme81299d02019-02-21 15:48:50 -0800501 boolean mCancelled;
Felipe Leme31a1f802018-10-16 11:24:55 -0700502
503 @GuardedBy("mLock")
Felipe Leme81299d02019-02-21 15:48:50 -0800504 boolean mCompleted;
Felipe Leme31a1f802018-10-16 11:24:55 -0700505
Felipe Leme81299d02019-02-21 15:48:50 -0800506 BasePendingRequest(@NonNull S service) {
Felipe Leme31a1f802018-10-16 11:24:55 -0700507 mWeakService = new WeakReference<>(service);
Felipe Leme31a1f802018-10-16 11:24:55 -0700508 }
509
510 /**
511 * Gets a reference to the remote service.
512 */
513 protected final S getService() {
514 return mWeakService.get();
515 }
516
517 /**
518 * Subclasses must call this method when the remote service finishes, i.e., when the service
519 * finishes processing a request.
520 *
521 * @return {@code false} in the service is already finished, {@code true} otherwise.
522 */
523 protected final boolean finish() {
524 synchronized (mLock) {
525 if (mCompleted || mCancelled) {
526 return false;
527 }
528 mCompleted = true;
529 }
Philip P. Moltmann883ff1a62019-01-07 14:34:47 -0800530
531 S service = mWeakService.get();
532 if (service != null) {
533 service.finishRequest(this);
534 }
535
Felipe Leme81299d02019-02-21 15:48:50 -0800536 onFinished();
537
Felipe Leme31a1f802018-10-16 11:24:55 -0700538 return true;
539 }
540
Felipe Leme81299d02019-02-21 15:48:50 -0800541 void onFinished() { }
542
Felipe Leme31a1f802018-10-16 11:24:55 -0700543 /**
544 * Checks whether this request was cancelled.
545 */
546 @GuardedBy("mLock")
547 protected final boolean isCancelledLocked() {
548 return mCancelled;
549 }
550
551 /**
552 * Cancels the service.
553 *
554 * @return {@code false} if service is already canceled, {@code true} otherwise.
555 */
556 public boolean cancel() {
557 synchronized (mLock) {
558 if (mCancelled || mCompleted) {
559 return false;
560 }
561 mCancelled = true;
562 }
563
Felipe Leme81299d02019-02-21 15:48:50 -0800564 onCancel();
Felipe Leme31a1f802018-10-16 11:24:55 -0700565 return true;
566 }
567
Felipe Leme81299d02019-02-21 15:48:50 -0800568 void onCancel() {}
Felipe Leme31a1f802018-10-16 11:24:55 -0700569
570 /**
571 * Checks whether this request leads to a final state where no other requests can be made.
572 */
573 protected boolean isFinal() {
574 return false;
575 }
576 }
Felipe Lemeafb55b62018-12-06 11:36:09 -0800577
578 /**
Felipe Leme81299d02019-02-21 15:48:50 -0800579 * Base class for the requests serviced by the remote service.
580 *
581 * <p><b>NOTE: </b> this class is typically used when the service needs to use a callback to
582 * communicate back with the system server. For cases where that's not needed, you should use
583 * {@link AbstractRemoteService#scheduleAsyncRequest(AsyncRequest)} instead.
584 *
585 * <p><b>NOTE: </b> you must override {@link AbstractRemoteService#getRemoteRequestMillis()},
586 * otherwise the constructor will throw an {@link UnsupportedOperationException}.
587 *
588 * @param <S> the remote service class
589 * @param <I> the interface of the binder service
590 */
591 public abstract static class PendingRequest<S extends AbstractRemoteService<S, I>,
592 I extends IInterface> extends BasePendingRequest<S, I> {
593
594 private final Runnable mTimeoutTrigger;
595 private final Handler mServiceHandler;
596
597 protected PendingRequest(S service) {
598 super(service);
599 mServiceHandler = service.mHandler;
600
601 mTimeoutTrigger = () -> {
602 synchronized (mLock) {
603 if (mCancelled) {
604 return;
605 }
606 mCompleted = true;
607 }
608
609 final S remoteService = mWeakService.get();
610 if (remoteService != null) {
611 // TODO(b/117779333): we should probably ignore it if service is destroyed.
612 Slog.w(mTag, "timed out after " + service.getRemoteRequestMillis() + " ms");
613 onTimeout(remoteService);
614 } else {
615 Slog.w(mTag, "timed out (no service)");
616 }
617 };
618 mServiceHandler.postAtTime(mTimeoutTrigger,
619 SystemClock.uptimeMillis() + service.getRemoteRequestMillis());
620 }
621
622 @Override
623 final void onFinished() {
624 mServiceHandler.removeCallbacks(mTimeoutTrigger);
625 }
626
627 @Override
628 final void onCancel() {
629 mServiceHandler.removeCallbacks(mTimeoutTrigger);
630 }
631
632 /**
633 * Called by the self-destruct timeout when the remote service didn't reply to the
634 * request on time.
635 */
636 protected abstract void onTimeout(S remoteService);
637 }
638
639 /**
Felipe Lemeafb55b62018-12-06 11:36:09 -0800640 * Represents a request that does not expect a callback from the remote service.
641 *
642 * @param <I> the interface of the binder service
643 */
644 public interface AsyncRequest<I extends IInterface> {
645
646 /**
647 * Run Forrest, run!
648 */
649 void run(@NonNull I binder) throws RemoteException;
650 }
651
652 private static final class MyAsyncPendingRequest<S extends AbstractRemoteService<S, I>,
Felipe Leme81299d02019-02-21 15:48:50 -0800653 I extends IInterface> extends BasePendingRequest<S, I> {
Felipe Lemeafb55b62018-12-06 11:36:09 -0800654 private static final String TAG = MyAsyncPendingRequest.class.getSimpleName();
655
656 private final AsyncRequest<I> mRequest;
657
658 protected MyAsyncPendingRequest(@NonNull S service, @NonNull AsyncRequest<I> request) {
659 super(service);
660
661 mRequest = request;
662 }
663
664 @Override
665 public void run() {
666 final S remoteService = getService();
667 if (remoteService == null) return;
668 try {
669 mRequest.run(remoteService.mService);
670 } catch (RemoteException e) {
671 Slog.w(TAG, "exception handling async request (" + this + "): " + e);
672 } finally {
673 finish();
674 }
675 }
Felipe Lemeafb55b62018-12-06 11:36:09 -0800676 }
Felipe Leme31a1f802018-10-16 11:24:55 -0700677}