blob: 1b45eb4f00bb4d8830b073a216816e160efda52b [file] [log] [blame]
Alex Salob81472f2018-12-12 14:44:28 -08001/*
2 * Copyright (C) 2019 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
17package com.android.server.attention;
18
Matt Papeaea28312019-03-07 13:51:38 -080019import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
Alex Saloeeba0232019-03-14 18:56:54 -070020import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCELLED;
Alex Salo10800342019-04-02 18:45:20 -070021import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN;
Alex Salo440fe3d2019-01-25 11:50:38 -080022
Alex Salob81472f2018-12-12 14:44:28 -080023import android.Manifest;
24import android.annotation.Nullable;
25import android.annotation.UserIdInt;
26import android.app.ActivityManager;
27import android.attention.AttentionManagerInternal;
28import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
29import android.content.BroadcastReceiver;
30import android.content.ComponentName;
31import android.content.Context;
32import android.content.Intent;
33import android.content.IntentFilter;
34import android.content.ServiceConnection;
35import android.content.pm.PackageManager;
36import android.content.pm.ResolveInfo;
37import android.content.pm.ServiceInfo;
38import android.os.Binder;
39import android.os.Handler;
40import android.os.IBinder;
41import android.os.Looper;
42import android.os.Message;
43import android.os.PowerManager;
44import android.os.RemoteException;
Aaron Li7565f8b2019-04-22 18:24:39 -070045import android.os.ResultReceiver;
46import android.os.ShellCallback;
47import android.os.ShellCommand;
Alex Salob81472f2018-12-12 14:44:28 -080048import android.os.SystemClock;
49import android.os.UserHandle;
Alex Salo440fe3d2019-01-25 11:50:38 -080050import android.provider.DeviceConfig;
Alex Salob81472f2018-12-12 14:44:28 -080051import android.service.attention.AttentionService;
52import android.service.attention.AttentionService.AttentionFailureCodes;
Alex Salo63829302019-04-06 14:57:30 -070053import android.service.attention.AttentionService.AttentionSuccessCodes;
Alex Salob81472f2018-12-12 14:44:28 -080054import android.service.attention.IAttentionCallback;
55import android.service.attention.IAttentionService;
56import android.text.TextUtils;
57import android.util.Slog;
58import android.util.SparseArray;
Alex Saloa060aee2019-01-21 14:36:41 -080059import android.util.StatsLog;
Alex Salob81472f2018-12-12 14:44:28 -080060
Alex Salob81472f2018-12-12 14:44:28 -080061import com.android.internal.annotations.GuardedBy;
Yi Jiangf9c9c162019-04-10 13:36:27 -070062import com.android.internal.annotations.VisibleForTesting;
Alex Salob81472f2018-12-12 14:44:28 -080063import com.android.internal.util.DumpUtils;
64import com.android.internal.util.IndentingPrintWriter;
65import com.android.internal.util.Preconditions;
66import com.android.server.SystemService;
67
Alex Salo5f5b5f42019-02-27 10:49:00 -080068import java.io.FileDescriptor;
Alex Salob81472f2018-12-12 14:44:28 -080069import java.io.PrintWriter;
70
71/**
72 * An attention service implementation that runs in System Server process.
73 * This service publishes a LocalService and reroutes calls to a {@link AttentionService} that it
74 * manages.
75 */
76public class AttentionManagerService extends SystemService {
77 private static final String LOG_TAG = "AttentionManagerService";
Alex Salo63829302019-04-06 14:57:30 -070078 private static final boolean DEBUG = false;
Alex Salob81472f2018-12-12 14:44:28 -080079
Alex Salo440fe3d2019-01-25 11:50:38 -080080 /** Default value in absence of {@link DeviceConfig} override. */
81 private static final boolean DEFAULT_SERVICE_ENABLED = true;
82
Alex Salob81472f2018-12-12 14:44:28 -080083 /** Service will unbind if connection is not used for that amount of time. */
84 private static final long CONNECTION_TTL_MILLIS = 60_000;
85
86 /** If the check attention called within that period - cached value will be returned. */
87 private static final long STALE_AFTER_MILLIS = 5_000;
88
Matt Papeaea28312019-03-07 13:51:38 -080089 /** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */
90 private static final String SERVICE_ENABLED = "service_enabled";
Aaron Li7565f8b2019-04-22 18:24:39 -070091 private static String sTestAttentionServicePackage;
Alex Salob81472f2018-12-12 14:44:28 -080092 private final Context mContext;
93 private final PowerManager mPowerManager;
Alex Salob81472f2018-12-12 14:44:28 -080094 private final Object mLock;
95 @GuardedBy("mLock")
96 private final SparseArray<UserState> mUserStates = new SparseArray<>();
Yi Jiangf9c9c162019-04-10 13:36:27 -070097 private AttentionHandler mAttentionHandler;
Alex Salob81472f2018-12-12 14:44:28 -080098
Yi Jiangf9c9c162019-04-10 13:36:27 -070099 @VisibleForTesting
100 ComponentName mComponentName;
Alex Salob81472f2018-12-12 14:44:28 -0800101
102 public AttentionManagerService(Context context) {
Yi Jiangf9c9c162019-04-10 13:36:27 -0700103 this(context, (PowerManager) context.getSystemService(Context.POWER_SERVICE),
104 new Object(), null);
105 mAttentionHandler = new AttentionHandler();
106 }
107
108 @VisibleForTesting
109 AttentionManagerService(Context context, PowerManager powerManager, Object lock,
110 AttentionHandler handler) {
Alex Salob81472f2018-12-12 14:44:28 -0800111 super(context);
112 mContext = Preconditions.checkNotNull(context);
Yi Jiangf9c9c162019-04-10 13:36:27 -0700113 mPowerManager = powerManager;
114 mLock = lock;
115 mAttentionHandler = handler;
Alex Salob81472f2018-12-12 14:44:28 -0800116 }
117
118 @Override
Alex Salo207e92d2019-05-20 15:59:48 -0700119 public void onBootPhase(int phase) {
120 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
121 mContext.registerReceiver(new ScreenStateReceiver(),
122 new IntentFilter(Intent.ACTION_SCREEN_OFF));
123 }
124 }
125
126 @Override
Alex Salob81472f2018-12-12 14:44:28 -0800127 public void onStart() {
Alex Salo5f5b5f42019-02-27 10:49:00 -0800128 publishBinderService(Context.ATTENTION_SERVICE, new BinderService());
Alex Salob81472f2018-12-12 14:44:28 -0800129 publishLocalService(AttentionManagerInternal.class, new LocalService());
130 }
131
132 @Override
Alex Salocde84302019-01-21 15:31:07 -0800133 public void onSwitchUser(int userId) {
Alex Salo1e32c072019-02-13 16:58:01 -0800134 cancelAndUnbindLocked(peekUserStateLocked(userId));
Alex Salob81472f2018-12-12 14:44:28 -0800135 }
136
Alex Salo7a6e3a62019-02-27 15:08:15 -0800137 /** Returns {@code true} if attention service is configured on this device. */
138 public static boolean isServiceConfigured(Context context) {
Aaron Li7565f8b2019-04-22 18:24:39 -0700139 return !TextUtils.isEmpty(getServiceConfigPackage(context));
Alex Salo7a6e3a62019-02-27 15:08:15 -0800140 }
141
Alex Salo50b701e2019-02-01 13:34:24 -0800142 /** Resolves and sets up the attention service if it had not been done yet. */
143 private boolean isServiceAvailable() {
144 if (mComponentName == null) {
Alex Salob81472f2018-12-12 14:44:28 -0800145 mComponentName = resolveAttentionService(mContext);
Alex Salob81472f2018-12-12 14:44:28 -0800146 }
Alex Salo50b701e2019-02-01 13:34:24 -0800147 return mComponentName != null;
Alex Salob81472f2018-12-12 14:44:28 -0800148 }
149
150 /**
151 * Returns {@code true} if attention service is supported on this device.
152 */
Yi Jiang99a84792019-03-13 15:32:48 -0700153 private boolean isAttentionServiceSupported() {
Alex Salo50b701e2019-02-01 13:34:24 -0800154 return isServiceEnabled() && isServiceAvailable();
Alex Salo440fe3d2019-01-25 11:50:38 -0800155 }
156
Yi Jiangf9c9c162019-04-10 13:36:27 -0700157 @VisibleForTesting
158 protected boolean isServiceEnabled() {
Matt Papeaea28312019-03-07 13:51:38 -0800159 return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, SERVICE_ENABLED,
160 DEFAULT_SERVICE_ENABLED);
Alex Salob81472f2018-12-12 14:44:28 -0800161 }
162
163 /**
164 * Checks whether user attention is at the screen and calls in the provided callback.
165 *
Alex Salo63829302019-04-06 14:57:30 -0700166 * Calling this multiple times quickly in a row will result in either a) returning a cached
167 * value, if present, or b) returning {@code false} because only one active request at a time is
168 * allowed.
169 *
170 * @return {@code true} if the framework was able to dispatch the request
Alex Salob81472f2018-12-12 14:44:28 -0800171 */
Yi Jiangf9c9c162019-04-10 13:36:27 -0700172 @VisibleForTesting
173 boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) {
Alex Saloeeba0232019-03-14 18:56:54 -0700174 Preconditions.checkNotNull(callbackInternal);
Alex Salob81472f2018-12-12 14:44:28 -0800175
176 if (!isAttentionServiceSupported()) {
177 Slog.w(LOG_TAG, "Trying to call checkAttention() on an unsupported device.");
178 return false;
179 }
180
181 // don't allow attention check in screen off state
182 if (!mPowerManager.isInteractive()) {
183 return false;
184 }
185
186 synchronized (mLock) {
Alex Salo1e32c072019-02-13 16:58:01 -0800187 final long now = SystemClock.uptimeMillis();
Alex Saloeeba0232019-03-14 18:56:54 -0700188 // schedule shutting down the connection if no one resets this timer
Alex Salo1e32c072019-02-13 16:58:01 -0800189 freeIfInactiveLocked();
Alex Salob81472f2018-12-12 14:44:28 -0800190
191 final UserState userState = getOrCreateCurrentUserStateLocked();
192 // lazily start the service, which should be very lightweight to start
Alex Salo042e43a2019-05-30 15:24:54 -0700193 userState.bindLocked();
Alex Salob81472f2018-12-12 14:44:28 -0800194
Alex Salo63829302019-04-06 14:57:30 -0700195 // throttle frequent requests
196 final AttentionCheckCache cache = userState.mAttentionCheckCache;
197 if (cache != null && now < cache.mLastComputed + STALE_AFTER_MILLIS) {
198 callbackInternal.onSuccess(cache.mResult, cache.mTimestamp);
199 return true;
200 }
Alex Salob81472f2018-12-12 14:44:28 -0800201
Alex Salo63829302019-04-06 14:57:30 -0700202 // prevent spamming with multiple requests, only one at a time is allowed
203 if (userState.mCurrentAttentionCheck != null) {
204 if (!userState.mCurrentAttentionCheck.mIsDispatched
205 || !userState.mCurrentAttentionCheck.mIsFulfilled) {
206 return false;
207 }
208 }
209
210 userState.mCurrentAttentionCheck = createAttentionCheck(callbackInternal, userState);
211
212 if (userState.mService != null) {
213 try {
Alex Saloeeba0232019-03-14 18:56:54 -0700214 // schedule request cancellation if not returned by that point yet
Alex Salob81472f2018-12-12 14:44:28 -0800215 cancelAfterTimeoutLocked(timeout);
Alex Saloeeba0232019-03-14 18:56:54 -0700216 userState.mService.checkAttention(
217 userState.mCurrentAttentionCheck.mIAttentionCallback);
Alex Salo63829302019-04-06 14:57:30 -0700218 userState.mCurrentAttentionCheck.mIsDispatched = true;
Alex Salob81472f2018-12-12 14:44:28 -0800219 } catch (RemoteException e) {
220 Slog.e(LOG_TAG, "Cannot call into the AttentionService");
221 return false;
222 }
223 }
224 return true;
225 }
226 }
227
Alex Salo63829302019-04-06 14:57:30 -0700228 private AttentionCheck createAttentionCheck(AttentionCallbackInternal callbackInternal,
229 UserState userState) {
230 final IAttentionCallback iAttentionCallback = new IAttentionCallback.Stub() {
231 @Override
232 public void onSuccess(@AttentionSuccessCodes int result, long timestamp) {
233 // the callback might have been cancelled already
234 if (!userState.mCurrentAttentionCheck.mIsFulfilled) {
235 callbackInternal.onSuccess(result, timestamp);
236 userState.mCurrentAttentionCheck.mIsFulfilled = true;
237 }
238
239 synchronized (mLock) {
240 userState.mAttentionCheckCache = new AttentionCheckCache(
241 SystemClock.uptimeMillis(), result,
242 timestamp);
243 }
244 StatsLog.write(
245 StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
246 result);
247 }
248
249 @Override
250 public void onFailure(@AttentionFailureCodes int error) {
251 // the callback might have been cancelled already
252 if (!userState.mCurrentAttentionCheck.mIsFulfilled) {
253 callbackInternal.onFailure(error);
254 userState.mCurrentAttentionCheck.mIsFulfilled = true;
255 }
256
257 StatsLog.write(
258 StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
259 error);
260 }
261 };
262
263 return new AttentionCheck(callbackInternal, iAttentionCallback);
264 }
265
Alex Salob81472f2018-12-12 14:44:28 -0800266 /** Cancels the specified attention check. */
Yi Jiangf9c9c162019-04-10 13:36:27 -0700267 @VisibleForTesting
268 void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) {
Alex Salocde84302019-01-21 15:31:07 -0800269 synchronized (mLock) {
Alex Salo1e32c072019-02-13 16:58:01 -0800270 final UserState userState = peekCurrentUserStateLocked();
271 if (userState == null) {
272 return;
273 }
Alex Salo63829302019-04-06 14:57:30 -0700274 if (!userState.mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) {
Alex Salocbe610a2019-05-01 14:18:46 -0700275 Slog.w(LOG_TAG, "Cannot cancel a non-current request");
Alex Salocde84302019-01-21 15:31:07 -0800276 return;
277 }
Alex Salo63829302019-04-06 14:57:30 -0700278 cancel(userState);
Alex Salob81472f2018-12-12 14:44:28 -0800279 }
280 }
281
282 @GuardedBy("mLock")
Yi Jiangf9c9c162019-04-10 13:36:27 -0700283 @VisibleForTesting
284 protected void freeIfInactiveLocked() {
Alex Salo1e32c072019-02-13 16:58:01 -0800285 // If we are called here, it means someone used the API again - reset the timer then.
286 mAttentionHandler.removeMessages(AttentionHandler.CHECK_CONNECTION_EXPIRATION);
287
288 // Schedule resources cleanup if no one calls the API again.
289 mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CHECK_CONNECTION_EXPIRATION,
Alex Salob81472f2018-12-12 14:44:28 -0800290 CONNECTION_TTL_MILLIS);
291 }
292
293 @GuardedBy("mLock")
294 private void cancelAfterTimeoutLocked(long timeout) {
295 mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.ATTENTION_CHECK_TIMEOUT,
296 timeout);
297 }
298
299
300 @GuardedBy("mLock")
Yi Jiangf9c9c162019-04-10 13:36:27 -0700301 @VisibleForTesting
302 protected UserState getOrCreateCurrentUserStateLocked() {
Alex Salocde84302019-01-21 15:31:07 -0800303 return getOrCreateUserStateLocked(ActivityManager.getCurrentUser());
Alex Salob81472f2018-12-12 14:44:28 -0800304 }
305
306 @GuardedBy("mLock")
Yi Jiangfa323e72019-04-16 17:23:11 -0700307 @VisibleForTesting
308 protected UserState getOrCreateUserStateLocked(int userId) {
Alex Salob81472f2018-12-12 14:44:28 -0800309 UserState result = mUserStates.get(userId);
310 if (result == null) {
Alex Salo042e43a2019-05-30 15:24:54 -0700311 result = new UserState(userId, mContext, mLock, mAttentionHandler, mComponentName);
Alex Salob81472f2018-12-12 14:44:28 -0800312 mUserStates.put(userId, result);
313 }
314 return result;
315 }
316
317 @GuardedBy("mLock")
Alex Salo1e32c072019-02-13 16:58:01 -0800318 @Nullable
Yi Jiangf9c9c162019-04-10 13:36:27 -0700319 @VisibleForTesting
320 protected UserState peekCurrentUserStateLocked() {
Alex Salocde84302019-01-21 15:31:07 -0800321 return peekUserStateLocked(ActivityManager.getCurrentUser());
Alex Salob81472f2018-12-12 14:44:28 -0800322 }
323
324 @GuardedBy("mLock")
Alex Salo1e32c072019-02-13 16:58:01 -0800325 @Nullable
326 private UserState peekUserStateLocked(int userId) {
Alex Salob81472f2018-12-12 14:44:28 -0800327 return mUserStates.get(userId);
328 }
329
Aaron Li7565f8b2019-04-22 18:24:39 -0700330 private static String getServiceConfigPackage(Context context) {
331 return context.getPackageManager().getAttentionServicePackageName();
Alex Salo7a6e3a62019-02-27 15:08:15 -0800332 }
333
Alex Salob81472f2018-12-12 14:44:28 -0800334 /**
335 * Provides attention service component name at runtime, making sure it's provided by the
336 * system.
337 */
338 private static ComponentName resolveAttentionService(Context context) {
Aaron Li7565f8b2019-04-22 18:24:39 -0700339 final String serviceConfigPackage = getServiceConfigPackage(context);
Alex Salo440fe3d2019-01-25 11:50:38 -0800340
Aaron Li7565f8b2019-04-22 18:24:39 -0700341 String resolvedPackage;
342 int flags = PackageManager.MATCH_SYSTEM_ONLY;
343 if (!TextUtils.isEmpty(sTestAttentionServicePackage)) {
344 resolvedPackage = sTestAttentionServicePackage;
345 flags = PackageManager.GET_META_DATA;
346 } else if (!TextUtils.isEmpty(serviceConfigPackage)) {
347 resolvedPackage = serviceConfigPackage;
348 } else {
Alex Salob81472f2018-12-12 14:44:28 -0800349 return null;
350 }
351
352 final Intent intent = new Intent(AttentionService.SERVICE_INTERFACE).setPackage(
Aaron Li7565f8b2019-04-22 18:24:39 -0700353 resolvedPackage);
Alex Salob81472f2018-12-12 14:44:28 -0800354
Aaron Li7565f8b2019-04-22 18:24:39 -0700355 final ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent, flags);
Alex Salob81472f2018-12-12 14:44:28 -0800356 if (resolveInfo == null || resolveInfo.serviceInfo == null) {
357 Slog.wtf(LOG_TAG, String.format("Service %s not found in package %s",
Aaron Li7565f8b2019-04-22 18:24:39 -0700358 AttentionService.SERVICE_INTERFACE, serviceConfigPackage
Alex Salob81472f2018-12-12 14:44:28 -0800359 ));
360 return null;
361 }
362
363 final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
364 final String permission = serviceInfo.permission;
365 if (Manifest.permission.BIND_ATTENTION_SERVICE.equals(permission)) {
366 return serviceInfo.getComponentName();
367 }
368 Slog.e(LOG_TAG, String.format(
369 "Service %s should require %s permission. Found %s permission",
370 serviceInfo.getComponentName(),
371 Manifest.permission.BIND_ATTENTION_SERVICE,
372 serviceInfo.permission));
373 return null;
374 }
375
Alex Salo5f5b5f42019-02-27 10:49:00 -0800376 private void dumpInternal(IndentingPrintWriter ipw) {
377 ipw.println("Attention Manager Service (dumpsys attention) state:\n");
Alex Salob81472f2018-12-12 14:44:28 -0800378
Alex Salo75b0a992019-04-30 15:00:30 -0700379 ipw.println("AttentionServicePackageName=" + getServiceConfigPackage(mContext));
380 ipw.println("Resolved component:");
381 if (mComponentName != null) {
382 ipw.increaseIndent();
383 ipw.println("Component=" + mComponentName.getPackageName());
384 ipw.println("Class=" + mComponentName.getClassName());
385 ipw.decreaseIndent();
386 }
387
Alex Salob81472f2018-12-12 14:44:28 -0800388 synchronized (mLock) {
389 int size = mUserStates.size();
390 ipw.print("Number user states: ");
Alex Salo5f5b5f42019-02-27 10:49:00 -0800391 ipw.println(size);
Alex Salob81472f2018-12-12 14:44:28 -0800392 if (size > 0) {
393 ipw.increaseIndent();
394 for (int i = 0; i < size; i++) {
395 UserState userState = mUserStates.valueAt(i);
396 ipw.print(i);
397 ipw.print(":");
398 userState.dump(ipw);
399 ipw.println();
400 }
401 ipw.decreaseIndent();
402 }
403 }
404 }
405
406 private final class LocalService extends AttentionManagerInternal {
407 @Override
408 public boolean isAttentionServiceSupported() {
409 return AttentionManagerService.this.isAttentionServiceSupported();
410 }
411
412 @Override
Alex Saloeeba0232019-03-14 18:56:54 -0700413 public boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) {
414 return AttentionManagerService.this.checkAttention(timeout, callbackInternal);
Alex Salob81472f2018-12-12 14:44:28 -0800415 }
416
417 @Override
Alex Saloeeba0232019-03-14 18:56:54 -0700418 public void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) {
419 AttentionManagerService.this.cancelAttentionCheck(callbackInternal);
Alex Salob81472f2018-12-12 14:44:28 -0800420 }
421 }
422
423 private static final class AttentionCheckCache {
424 private final long mLastComputed;
425 private final int mResult;
426 private final long mTimestamp;
427
428 AttentionCheckCache(long lastComputed, @AttentionService.AttentionSuccessCodes int result,
429 long timestamp) {
430 mLastComputed = lastComputed;
431 mResult = result;
432 mTimestamp = timestamp;
433 }
434 }
435
Yi Jiangf9c9c162019-04-10 13:36:27 -0700436 @VisibleForTesting
437 static final class AttentionCheck {
Alex Saloeeba0232019-03-14 18:56:54 -0700438 private final AttentionCallbackInternal mCallbackInternal;
439 private final IAttentionCallback mIAttentionCallback;
Alex Salo63829302019-04-06 14:57:30 -0700440 private boolean mIsDispatched;
441 private boolean mIsFulfilled;
Alex Saloeeba0232019-03-14 18:56:54 -0700442
443 AttentionCheck(AttentionCallbackInternal callbackInternal,
444 IAttentionCallback iAttentionCallback) {
445 mCallbackInternal = callbackInternal;
446 mIAttentionCallback = iAttentionCallback;
447 }
Alex Salo63829302019-04-06 14:57:30 -0700448
449 void cancelInternal() {
Aaron Li7565f8b2019-04-22 18:24:39 -0700450 mIsFulfilled = true;
Alex Salo63829302019-04-06 14:57:30 -0700451 mCallbackInternal.onFailure(ATTENTION_FAILURE_CANCELLED);
452 }
Alex Saloeeba0232019-03-14 18:56:54 -0700453 }
454
Yi Jiangf9c9c162019-04-10 13:36:27 -0700455 @VisibleForTesting
456 protected static class UserState {
Alex Salo042e43a2019-05-30 15:24:54 -0700457 private final ComponentName mComponentName;
458 private final AttentionServiceConnection mConnection = new AttentionServiceConnection();
Alex Salob81472f2018-12-12 14:44:28 -0800459
460 @GuardedBy("mLock")
461 IAttentionService mService;
462 @GuardedBy("mLock")
Alex Saloeeba0232019-03-14 18:56:54 -0700463 AttentionCheck mCurrentAttentionCheck;
Alex Salob81472f2018-12-12 14:44:28 -0800464 @GuardedBy("mLock")
Alex Salob81472f2018-12-12 14:44:28 -0800465 AttentionCheckCache mAttentionCheckCache;
Alex Salo042e43a2019-05-30 15:24:54 -0700466 @GuardedBy("mLock")
467 private boolean mBinding;
Alex Salob81472f2018-12-12 14:44:28 -0800468
469 @UserIdInt
Alex Salo042e43a2019-05-30 15:24:54 -0700470 private final int mUserId;
471 private final Context mContext;
472 private final Object mLock;
473 private final Handler mAttentionHandler;
Alex Salob81472f2018-12-12 14:44:28 -0800474
Alex Salo042e43a2019-05-30 15:24:54 -0700475 UserState(int userId, Context context, Object lock, Handler handler,
476 ComponentName componentName) {
Alex Salob81472f2018-12-12 14:44:28 -0800477 mUserId = userId;
478 mContext = Preconditions.checkNotNull(context);
479 mLock = Preconditions.checkNotNull(lock);
Alex Salo50b701e2019-02-01 13:34:24 -0800480 mComponentName = Preconditions.checkNotNull(componentName);
Alex Salo042e43a2019-05-30 15:24:54 -0700481 mAttentionHandler = handler;
Alex Salob81472f2018-12-12 14:44:28 -0800482 }
483
Alex Salob81472f2018-12-12 14:44:28 -0800484 @GuardedBy("mLock")
485 private void handlePendingCallbackLocked() {
Alex Salo63829302019-04-06 14:57:30 -0700486 if (!mCurrentAttentionCheck.mIsDispatched) {
487 if (mService != null) {
488 try {
489 mService.checkAttention(mCurrentAttentionCheck.mIAttentionCallback);
490 mCurrentAttentionCheck.mIsDispatched = true;
491 } catch (RemoteException e) {
492 Slog.e(LOG_TAG, "Cannot call into the AttentionService");
493 }
494 } else {
495 mCurrentAttentionCheck.mCallbackInternal.onFailure(ATTENTION_FAILURE_UNKNOWN);
496 }
Alex Salob81472f2018-12-12 14:44:28 -0800497 }
498 }
499
500 /** Binds to the system's AttentionService which provides an actual implementation. */
501 @GuardedBy("mLock")
Alex Salo042e43a2019-05-30 15:24:54 -0700502 private void bindLocked() {
Alex Salob81472f2018-12-12 14:44:28 -0800503 // No need to bind if service is binding or has already been bound.
504 if (mBinding || mService != null) {
Alex Salo042e43a2019-05-30 15:24:54 -0700505 return;
Alex Salob81472f2018-12-12 14:44:28 -0800506 }
507
Alex Salo042e43a2019-05-30 15:24:54 -0700508 mBinding = true;
509 // mContext.bindServiceAsUser() calls into ActivityManagerService which it may already
510 // hold the lock and had called into PowerManagerService, which holds a lock.
511 // That would create a deadlock. To solve that, putting it on a handler.
512 mAttentionHandler.post(() -> {
513 final Intent serviceIntent = new Intent(
Alex Salob81472f2018-12-12 14:44:28 -0800514 AttentionService.SERVICE_INTERFACE).setComponent(
Alex Salo50b701e2019-02-01 13:34:24 -0800515 mComponentName);
Alex Salo042e43a2019-05-30 15:24:54 -0700516 // Note: no reason to clear the calling identity, we won't have one in a handler.
517 mContext.bindServiceAsUser(serviceIntent, mConnection,
Alex Salob81472f2018-12-12 14:44:28 -0800518 Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
Alex Salo042e43a2019-05-30 15:24:54 -0700519
520 });
Alex Salob81472f2018-12-12 14:44:28 -0800521 }
522
523 private void dump(IndentingPrintWriter pw) {
Alex Salo75b0a992019-04-30 15:00:30 -0700524 pw.println("userId=" + mUserId);
Alex Salob81472f2018-12-12 14:44:28 -0800525 synchronized (mLock) {
Alex Salo75b0a992019-04-30 15:00:30 -0700526 pw.println("binding=" + mBinding);
527 pw.println("current attention check:");
528 if (mCurrentAttentionCheck != null) {
529 pw.increaseIndent();
530 pw.println("is dispatched=" + mCurrentAttentionCheck.mIsDispatched);
531 pw.println("is fulfilled:=" + mCurrentAttentionCheck.mIsFulfilled);
532 pw.decreaseIndent();
533 }
534 pw.println("attention check cache:");
535 if (mAttentionCheckCache != null) {
536 pw.increaseIndent();
537 pw.println("last computed=" + mAttentionCheckCache.mLastComputed);
538 pw.println("timestamp=" + mAttentionCheckCache.mTimestamp);
539 pw.println("result=" + mAttentionCheckCache.mResult);
540 pw.decreaseIndent();
541 }
Alex Salob81472f2018-12-12 14:44:28 -0800542 }
543 }
544
Yi Jiangf9c9c162019-04-10 13:36:27 -0700545 private class AttentionServiceConnection implements ServiceConnection {
Alex Salob81472f2018-12-12 14:44:28 -0800546 @Override
547 public void onServiceConnected(ComponentName name, IBinder service) {
548 init(IAttentionService.Stub.asInterface(service));
549 }
550
551 @Override
552 public void onServiceDisconnected(ComponentName name) {
553 cleanupService();
554 }
555
556 @Override
557 public void onBindingDied(ComponentName name) {
558 cleanupService();
559 }
560
561 @Override
562 public void onNullBinding(ComponentName name) {
563 cleanupService();
564 }
565
566 void cleanupService() {
567 init(null);
568 }
569
570 private void init(@Nullable IAttentionService service) {
571 synchronized (mLock) {
572 mService = service;
573 mBinding = false;
574 handlePendingCallbackLocked();
575 }
576 }
577 }
578 }
579
Yi Jiangf9c9c162019-04-10 13:36:27 -0700580 @VisibleForTesting
581 protected class AttentionHandler extends Handler {
Alex Salo1e32c072019-02-13 16:58:01 -0800582 private static final int CHECK_CONNECTION_EXPIRATION = 1;
Alex Salob81472f2018-12-12 14:44:28 -0800583 private static final int ATTENTION_CHECK_TIMEOUT = 2;
584
585 AttentionHandler() {
586 super(Looper.myLooper());
587 }
588
Alex Salo042e43a2019-05-30 15:24:54 -0700589 @Override
Alex Salob81472f2018-12-12 14:44:28 -0800590 public void handleMessage(Message msg) {
591 switch (msg.what) {
592 // Do not occupy resources when not in use - unbind proactively.
Alex Salo1e32c072019-02-13 16:58:01 -0800593 case CHECK_CONNECTION_EXPIRATION: {
Alex Salob81472f2018-12-12 14:44:28 -0800594 for (int i = 0; i < mUserStates.size(); i++) {
Alex Salo1e32c072019-02-13 16:58:01 -0800595 cancelAndUnbindLocked(mUserStates.valueAt(i));
Alex Salob81472f2018-12-12 14:44:28 -0800596 }
Alex Salob81472f2018-12-12 14:44:28 -0800597 }
598 break;
599
600 // Callee is no longer interested in the attention check result - cancel.
601 case ATTENTION_CHECK_TIMEOUT: {
Alex Salo1e32c072019-02-13 16:58:01 -0800602 synchronized (mLock) {
Alex Salo63829302019-04-06 14:57:30 -0700603 cancel(peekCurrentUserStateLocked());
Alex Salo1e32c072019-02-13 16:58:01 -0800604 }
Alex Salob81472f2018-12-12 14:44:28 -0800605 }
606 break;
607
608 default:
609 break;
610 }
611 }
612 }
613
Yi Jiangf9c9c162019-04-10 13:36:27 -0700614 @VisibleForTesting
615 void cancel(UserState userState) {
Alex Salo63829302019-04-06 14:57:30 -0700616 if (userState == null || userState.mCurrentAttentionCheck == null) {
617 return;
618 }
Alex Salo1e32c072019-02-13 16:58:01 -0800619
Alex Salo63829302019-04-06 14:57:30 -0700620 if (userState.mCurrentAttentionCheck.mIsFulfilled) {
621 if (DEBUG) {
622 Slog.d(LOG_TAG, "Trying to cancel the check that has been already fulfilled.");
Alex Salo1e32c072019-02-13 16:58:01 -0800623 }
Alex Salo63829302019-04-06 14:57:30 -0700624 return;
625 }
Alex Salo63829302019-04-06 14:57:30 -0700626
627 if (userState.mService == null) {
628 userState.mCurrentAttentionCheck.cancelInternal();
629 return;
630 }
631
632 try {
633 userState.mService.cancelAttentionCheck(
634 userState.mCurrentAttentionCheck.mIAttentionCallback);
635 } catch (RemoteException e) {
636 Slog.e(LOG_TAG, "Unable to cancel attention check");
637 userState.mCurrentAttentionCheck.cancelInternal();
Alex Salo1e32c072019-02-13 16:58:01 -0800638 }
639 }
640
641 @GuardedBy("mLock")
642 private void cancelAndUnbindLocked(UserState userState) {
643 synchronized (mLock) {
Yi Jiang4dfc3682019-03-20 16:50:40 -0700644 if (userState == null) {
645 return;
646 }
Alex Salo63829302019-04-06 14:57:30 -0700647
648 cancel(userState);
649
650 if (userState.mService == null) {
651 return;
652 }
Alex Salo1e32c072019-02-13 16:58:01 -0800653
Alex Salo042e43a2019-05-30 15:24:54 -0700654 mAttentionHandler.post(() -> mContext.unbindService(userState.mConnection));
655 // Note: this will set mBinding to false even though it could still be trying to bind
656 // (i.e. the runnable was posted in bindLocked but then cancelAndUnbindLocked was
657 // called before it's run yet). This is a safe state at the moment,
658 // since it will eventually, but feels like a source for confusion down the road and
659 // may cause some expensive and unnecessary work to be done.
Alex Salo1e32c072019-02-13 16:58:01 -0800660 userState.mConnection.cleanupService();
661 mUserStates.remove(userState.mUserId);
Alex Salob81472f2018-12-12 14:44:28 -0800662 }
663 }
664
665 /**
666 * Unbinds and stops the service when the screen off intent is received.
667 * Attention service only makes sense when screen is ON; disconnect and stop service otherwise.
668 */
669 private final class ScreenStateReceiver extends BroadcastReceiver {
670 @Override
671 public void onReceive(Context context, Intent intent) {
672 if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
Alex Salo1e32c072019-02-13 16:58:01 -0800673 cancelAndUnbindLocked(peekCurrentUserStateLocked());
Alex Salob81472f2018-12-12 14:44:28 -0800674 }
675 }
676 }
Alex Salo5f5b5f42019-02-27 10:49:00 -0800677
Aaron Li7565f8b2019-04-22 18:24:39 -0700678 private final class AttentionManagerServiceShellCommand extends ShellCommand {
679 class TestableAttentionCallbackInternal extends AttentionCallbackInternal {
680 private int mLastCallbackCode = -1;
681
682 @Override
683 public void onSuccess(int result, long timestamp) {
684 mLastCallbackCode = result;
685 }
686
687 @Override
688 public void onFailure(int error) {
689 mLastCallbackCode = error;
690 }
691
692 public void reset() {
693 mLastCallbackCode = -1;
694 }
695
696 public int getLastCallbackCode() {
697 return mLastCallbackCode;
698 }
699 }
700
701 final TestableAttentionCallbackInternal mTestableAttentionCallback =
702 new TestableAttentionCallbackInternal();
703
704 @Override
705 public int onCommand(@Nullable final String cmd) {
706 if (cmd == null) {
707 return handleDefaultCommands(cmd);
708 }
709 final PrintWriter err = getErrPrintWriter();
710 try {
711 switch (cmd) {
712 case "getAttentionServiceComponent":
713 return cmdResolveAttentionServiceComponent();
714 case "call":
715 switch (getNextArgRequired()) {
716 case "checkAttention":
717 return cmdCallCheckAttention();
718 case "cancelCheckAttention":
719 return cmdCallCancelAttention();
720 default:
721 throw new IllegalArgumentException("Invalid argument");
722 }
723 case "setTestableAttentionService":
724 return cmdSetTestableAttentionService(getNextArgRequired());
725 case "clearTestableAttentionService":
726 return cmdClearTestableAttentionService();
727 case "getLastTestCallbackCode":
728 return cmdGetLastTestCallbackCode();
729 default:
730 return handleDefaultCommands(cmd);
731 }
732 } catch (IllegalArgumentException e) {
733 err.println("Error: " + e.getMessage());
734 }
735 return -1;
736 }
737
738 private int cmdSetTestableAttentionService(String testingServicePackage) {
739 final PrintWriter out = getOutPrintWriter();
740 if (TextUtils.isEmpty(testingServicePackage)) {
741 out.println("false");
742 } else {
743 sTestAttentionServicePackage = testingServicePackage;
744 resetStates();
745 out.println(mComponentName != null ? "true" : "false");
746 }
747 return 0;
748 }
749
750 private int cmdClearTestableAttentionService() {
751 sTestAttentionServicePackage = "";
752 mTestableAttentionCallback.reset();
753 resetStates();
754 return 0;
755 }
756
757 private int cmdCallCheckAttention() {
758 final PrintWriter out = getOutPrintWriter();
759 boolean calledSuccessfully = checkAttention(2000, mTestableAttentionCallback);
760 out.println(calledSuccessfully ? "true" : "false");
761 return 0;
762 }
763
764 private int cmdCallCancelAttention() {
765 final PrintWriter out = getOutPrintWriter();
766 cancelAttentionCheck(mTestableAttentionCallback);
767 out.println("true");
768 return 0;
769 }
770
771 private int cmdResolveAttentionServiceComponent() {
772 final PrintWriter out = getOutPrintWriter();
773 ComponentName resolvedComponent = resolveAttentionService(mContext);
774 out.println(resolvedComponent != null ? resolvedComponent.flattenToShortString() : "");
775 return 0;
776 }
777
778 private int cmdGetLastTestCallbackCode() {
779 final PrintWriter out = getOutPrintWriter();
780 out.println(mTestableAttentionCallback.getLastCallbackCode());
781 return 0;
782 }
783
784 private void resetStates() {
785 mComponentName = resolveAttentionService(mContext);
786 mUserStates.clear();
787 }
788
789 @Override
790 public void onHelp() {
791 final PrintWriter out = getOutPrintWriter();
792 out.println("Attention commands: ");
793 out.println(" setTestableAttentionService <service_package>: Bind to a custom"
794 + " implementation of attention service");
795 out.println(" ---<service_package>:");
796 out.println(
797 " := Package containing the Attention Service implementation to bind to");
798 out.println(" ---returns:");
799 out.println(" := true, if was bound successfully");
800 out.println(" := false, if was not bound successfully");
801 out.println(" clearTestableAttentionService: Undo custom bindings. Revert to previous"
802 + " behavior");
803 out.println(" getAttentionServiceComponent: Get the current service component string");
804 out.println(" ---returns:");
805 out.println(" := If valid, the component string (in shorten form) for the"
806 + " currently bound service.");
807 out.println(" := else, empty string");
808 out.println(" call checkAttention: Calls check attention");
809 out.println(" ---returns:");
810 out.println(
811 " := true, if the call was successfully dispatched to the service "
812 + "implementation."
813 + " (to see the result, call getLastTestCallbackCode)");
814 out.println(" := false, otherwise");
815 out.println(" call cancelCheckAttention: Cancels check attention");
816 out.println(" getLastTestCallbackCode");
817 out.println(" ---returns:");
818 out.println(
819 " := An integer, representing the last callback code received from the "
820 + "bounded implementation. If none, it will return -1");
821 }
822 }
823
Alex Salo5f5b5f42019-02-27 10:49:00 -0800824 private final class BinderService extends Binder {
Aaron Li7565f8b2019-04-22 18:24:39 -0700825 AttentionManagerServiceShellCommand mAttentionManagerServiceShellCommand =
826 new AttentionManagerServiceShellCommand();
827
828 @Override
829 public void onShellCommand(FileDescriptor in, FileDescriptor out,
830 FileDescriptor err,
831 String[] args, ShellCallback callback,
832 ResultReceiver resultReceiver) {
833 mAttentionManagerServiceShellCommand.exec(this, in, out, err, args, callback,
834 resultReceiver);
835 }
836
Alex Salo5f5b5f42019-02-27 10:49:00 -0800837 @Override
838 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
839 if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) {
840 return;
841 }
842
843 dumpInternal(new IndentingPrintWriter(pw, " "));
844 }
845 }
Alex Salob81472f2018-12-12 14:44:28 -0800846}