1 /* 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 17 package com.android.server.attention; 18 19 import static android.content.Context.BIND_AUTO_CREATE; 20 import static android.content.Context.BIND_FOREGROUND_SERVICE; 21 import static android.content.Context.BIND_INCLUDE_CAPABILITIES; 22 import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE; 23 import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCELLED; 24 import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN; 25 26 import android.Manifest; 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.app.ActivityThread; 30 import android.attention.AttentionManagerInternal; 31 import android.attention.AttentionManagerInternal.AttentionCallbackInternal; 32 import android.content.BroadcastReceiver; 33 import android.content.ComponentName; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.content.ServiceConnection; 38 import android.content.pm.PackageManager; 39 import android.content.pm.ResolveInfo; 40 import android.content.pm.ServiceInfo; 41 import android.hardware.SensorPrivacyManager; 42 import android.os.Binder; 43 import android.os.Handler; 44 import android.os.IBinder; 45 import android.os.Looper; 46 import android.os.Message; 47 import android.os.PowerManager; 48 import android.os.RemoteException; 49 import android.os.ResultReceiver; 50 import android.os.ShellCallback; 51 import android.os.ShellCommand; 52 import android.os.SystemClock; 53 import android.os.UserHandle; 54 import android.provider.DeviceConfig; 55 import android.service.attention.AttentionService; 56 import android.service.attention.AttentionService.AttentionFailureCodes; 57 import android.service.attention.AttentionService.AttentionSuccessCodes; 58 import android.service.attention.IAttentionCallback; 59 import android.service.attention.IAttentionService; 60 import android.text.TextUtils; 61 import android.util.Slog; 62 63 import com.android.internal.annotations.GuardedBy; 64 import com.android.internal.annotations.VisibleForTesting; 65 import com.android.internal.util.DumpUtils; 66 import com.android.internal.util.FrameworkStatsLog; 67 import com.android.internal.util.IndentingPrintWriter; 68 import com.android.server.SystemService; 69 70 import java.io.FileDescriptor; 71 import java.io.PrintWriter; 72 import java.util.Objects; 73 import java.util.Set; 74 75 /** 76 * An attention service implementation that runs in System Server process. 77 * This service publishes a LocalService and reroutes calls to a {@link AttentionService} that it 78 * manages. 79 */ 80 public class AttentionManagerService extends SystemService { 81 private static final String LOG_TAG = "AttentionManagerService"; 82 private static final boolean DEBUG = false; 83 84 /** Service will unbind if connection is not used for that amount of time. */ 85 private static final long CONNECTION_TTL_MILLIS = 60_000; 86 87 /** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */ 88 @VisibleForTesting 89 static final String KEY_SERVICE_ENABLED = "service_enabled"; 90 91 /** Default value in absence of {@link DeviceConfig} override. */ 92 private static final boolean DEFAULT_SERVICE_ENABLED = true; 93 94 @VisibleForTesting 95 boolean mIsServiceEnabled; 96 97 /** 98 * DeviceConfig flag name, describes how much time we consider a result fresh; if the check 99 * attention called within that period - cached value will be returned. 100 */ 101 @VisibleForTesting 102 static final String KEY_STALE_AFTER_MILLIS = "stale_after_millis"; 103 104 /** Default value in absence of {@link DeviceConfig} override. */ 105 @VisibleForTesting 106 static final long DEFAULT_STALE_AFTER_MILLIS = 1_000; 107 108 @VisibleForTesting 109 long mStaleAfterMillis; 110 111 /** The size of the buffer that stores recent attention check results. */ 112 @VisibleForTesting 113 protected static final int ATTENTION_CACHE_BUFFER_SIZE = 5; 114 115 private final AttentionServiceConnection mConnection = new AttentionServiceConnection(); 116 private static String sTestAttentionServicePackage; 117 private final Context mContext; 118 private final PowerManager mPowerManager; 119 private final SensorPrivacyManager mPrivacyManager; 120 private final Object mLock; 121 @GuardedBy("mLock") 122 @VisibleForTesting 123 protected IAttentionService mService; 124 @GuardedBy("mLock") 125 private AttentionCheckCacheBuffer mAttentionCheckCacheBuffer; 126 @GuardedBy("mLock") 127 private boolean mBinding; 128 private AttentionHandler mAttentionHandler; 129 130 @VisibleForTesting 131 ComponentName mComponentName; 132 133 @VisibleForTesting 134 @GuardedBy("mLock") 135 AttentionCheck mCurrentAttentionCheck; 136 AttentionManagerService(Context context)137 public AttentionManagerService(Context context) { 138 this(context, (PowerManager) context.getSystemService(Context.POWER_SERVICE), 139 new Object(), null); 140 mAttentionHandler = new AttentionHandler(); 141 } 142 143 @VisibleForTesting AttentionManagerService(Context context, PowerManager powerManager, Object lock, AttentionHandler handler)144 AttentionManagerService(Context context, PowerManager powerManager, Object lock, 145 AttentionHandler handler) { 146 super(context); 147 mContext = Objects.requireNonNull(context); 148 mPowerManager = powerManager; 149 mLock = lock; 150 mAttentionHandler = handler; 151 mPrivacyManager = SensorPrivacyManager.getInstance(context); 152 } 153 154 @Override onBootPhase(int phase)155 public void onBootPhase(int phase) { 156 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 157 mContext.registerReceiver(new ScreenStateReceiver(), 158 new IntentFilter(Intent.ACTION_SCREEN_OFF)); 159 160 readValuesFromDeviceConfig(); 161 DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_ATTENTION_MANAGER_SERVICE, 162 ActivityThread.currentApplication().getMainExecutor(), 163 (properties) -> onDeviceConfigChange(properties.getKeyset())); 164 } 165 } 166 167 @Override onStart()168 public void onStart() { 169 publishBinderService(Context.ATTENTION_SERVICE, new BinderService()); 170 publishLocalService(AttentionManagerInternal.class, new LocalService()); 171 } 172 173 /** Returns {@code true} if attention service is configured on this device. */ isServiceConfigured(Context context)174 public static boolean isServiceConfigured(Context context) { 175 return !TextUtils.isEmpty(getServiceConfigPackage(context)); 176 } 177 178 /** Resolves and sets up the attention service if it had not been done yet. */ 179 @VisibleForTesting isServiceAvailable()180 protected boolean isServiceAvailable() { 181 if (mComponentName == null) { 182 mComponentName = resolveAttentionService(mContext); 183 } 184 return mComponentName != null; 185 } 186 getIsServiceEnabled()187 private boolean getIsServiceEnabled() { 188 return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_SERVICE_ENABLED, 189 DEFAULT_SERVICE_ENABLED); 190 } 191 192 /** 193 * How much time we consider a result fresh; if the check attention called within that period - 194 * cached value will be returned. 195 */ 196 @VisibleForTesting getStaleAfterMillis()197 protected long getStaleAfterMillis() { 198 final long millis = DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE, 199 KEY_STALE_AFTER_MILLIS, 200 DEFAULT_STALE_AFTER_MILLIS); 201 202 if (millis < 0 || millis > 10_000) { 203 Slog.w(LOG_TAG, "Bad flag value supplied for: " + KEY_STALE_AFTER_MILLIS); 204 return DEFAULT_STALE_AFTER_MILLIS; 205 } 206 207 return millis; 208 } 209 onDeviceConfigChange(@onNull Set<String> keys)210 private void onDeviceConfigChange(@NonNull Set<String> keys) { 211 for (String key : keys) { 212 switch (key) { 213 case KEY_SERVICE_ENABLED: 214 case KEY_STALE_AFTER_MILLIS: 215 readValuesFromDeviceConfig(); 216 return; 217 default: 218 Slog.i(LOG_TAG, "Ignoring change on " + key); 219 } 220 } 221 } 222 readValuesFromDeviceConfig()223 private void readValuesFromDeviceConfig() { 224 mIsServiceEnabled = getIsServiceEnabled(); 225 mStaleAfterMillis = getStaleAfterMillis(); 226 227 Slog.i(LOG_TAG, "readValuesFromDeviceConfig():" 228 + "\nmIsServiceEnabled=" + mIsServiceEnabled 229 + "\nmStaleAfterMillis=" + mStaleAfterMillis); 230 } 231 232 /** 233 * Checks whether user attention is at the screen and calls in the provided callback. 234 * 235 * Calling this multiple times quickly in a row will result in either a) returning a cached 236 * value, if present, or b) returning {@code false} because only one active request at a time is 237 * allowed. 238 * 239 * @return {@code true} if the framework was able to dispatch the request 240 */ 241 @VisibleForTesting checkAttention(long timeout, AttentionCallbackInternal callbackInternal)242 boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) { 243 Objects.requireNonNull(callbackInternal); 244 245 if (!mIsServiceEnabled) { 246 Slog.w(LOG_TAG, "Trying to call checkAttention() on an unsupported device."); 247 return false; 248 } 249 250 if (!isServiceAvailable()) { 251 Slog.w(LOG_TAG, "Service is not available at this moment."); 252 return false; 253 } 254 255 if (mPrivacyManager.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA)) { 256 Slog.w(LOG_TAG, "Camera is locked by a toggle."); 257 return false; 258 } 259 260 // don't allow attention check in screen off state or power save mode 261 if (!mPowerManager.isInteractive() || mPowerManager.isPowerSaveMode()) { 262 return false; 263 } 264 265 synchronized (mLock) { 266 final long now = SystemClock.uptimeMillis(); 267 // schedule shutting down the connection if no one resets this timer 268 freeIfInactiveLocked(); 269 270 // lazily start the service, which should be very lightweight to start 271 bindLocked(); 272 273 // throttle frequent requests 274 final AttentionCheckCache cache = mAttentionCheckCacheBuffer == null ? null 275 : mAttentionCheckCacheBuffer.getLast(); 276 if (cache != null && now < cache.mLastComputed + mStaleAfterMillis) { 277 callbackInternal.onSuccess(cache.mResult, cache.mTimestamp); 278 return true; 279 } 280 281 // prevent spamming with multiple requests, only one at a time is allowed 282 if (mCurrentAttentionCheck != null) { 283 if (!mCurrentAttentionCheck.mIsDispatched 284 || !mCurrentAttentionCheck.mIsFulfilled) { 285 return false; 286 } 287 } 288 289 mCurrentAttentionCheck = new AttentionCheck(callbackInternal, this); 290 291 if (mService != null) { 292 try { 293 // schedule request cancellation if not returned by that point yet 294 cancelAfterTimeoutLocked(timeout); 295 mService.checkAttention(mCurrentAttentionCheck.mIAttentionCallback); 296 mCurrentAttentionCheck.mIsDispatched = true; 297 } catch (RemoteException e) { 298 Slog.e(LOG_TAG, "Cannot call into the AttentionService"); 299 return false; 300 } 301 } 302 return true; 303 } 304 } 305 306 /** Cancels the specified attention check. */ 307 @VisibleForTesting cancelAttentionCheck(AttentionCallbackInternal callbackInternal)308 void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) { 309 synchronized (mLock) { 310 if (!mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) { 311 Slog.w(LOG_TAG, "Cannot cancel a non-current request"); 312 return; 313 } 314 cancel(); 315 } 316 } 317 318 @GuardedBy("mLock") 319 @VisibleForTesting freeIfInactiveLocked()320 protected void freeIfInactiveLocked() { 321 // If we are called here, it means someone used the API again - reset the timer then. 322 mAttentionHandler.removeMessages(AttentionHandler.CHECK_CONNECTION_EXPIRATION); 323 324 // Schedule resources cleanup if no one calls the API again. 325 mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CHECK_CONNECTION_EXPIRATION, 326 CONNECTION_TTL_MILLIS); 327 } 328 329 @GuardedBy("mLock") cancelAfterTimeoutLocked(long timeout)330 private void cancelAfterTimeoutLocked(long timeout) { 331 mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.ATTENTION_CHECK_TIMEOUT, 332 timeout); 333 } 334 getServiceConfigPackage(Context context)335 private static String getServiceConfigPackage(Context context) { 336 return context.getPackageManager().getAttentionServicePackageName(); 337 } 338 339 /** 340 * Provides attention service component name at runtime, making sure it's provided by the 341 * system. 342 */ resolveAttentionService(Context context)343 private static ComponentName resolveAttentionService(Context context) { 344 final String serviceConfigPackage = getServiceConfigPackage(context); 345 346 String resolvedPackage; 347 int flags = PackageManager.MATCH_SYSTEM_ONLY; 348 if (!TextUtils.isEmpty(sTestAttentionServicePackage)) { 349 resolvedPackage = sTestAttentionServicePackage; 350 flags = PackageManager.GET_META_DATA; 351 } else if (!TextUtils.isEmpty(serviceConfigPackage)) { 352 resolvedPackage = serviceConfigPackage; 353 } else { 354 return null; 355 } 356 357 final Intent intent = new Intent(AttentionService.SERVICE_INTERFACE).setPackage( 358 resolvedPackage); 359 360 final ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent, flags); 361 if (resolveInfo == null || resolveInfo.serviceInfo == null) { 362 Slog.wtf(LOG_TAG, String.format("Service %s not found in package %s", 363 AttentionService.SERVICE_INTERFACE, serviceConfigPackage 364 )); 365 return null; 366 } 367 368 final ServiceInfo serviceInfo = resolveInfo.serviceInfo; 369 final String permission = serviceInfo.permission; 370 if (Manifest.permission.BIND_ATTENTION_SERVICE.equals(permission)) { 371 return serviceInfo.getComponentName(); 372 } 373 Slog.e(LOG_TAG, String.format( 374 "Service %s should require %s permission. Found %s permission", 375 serviceInfo.getComponentName(), 376 Manifest.permission.BIND_ATTENTION_SERVICE, 377 serviceInfo.permission)); 378 return null; 379 } 380 dumpInternal(IndentingPrintWriter ipw)381 private void dumpInternal(IndentingPrintWriter ipw) { 382 ipw.println("Attention Manager Service (dumpsys attention) state:\n"); 383 ipw.println("isServiceEnabled=" + mIsServiceEnabled); 384 ipw.println("mStaleAfterMillis=" + mStaleAfterMillis); 385 ipw.println("AttentionServicePackageName=" + getServiceConfigPackage(mContext)); 386 ipw.println("Resolved component:"); 387 if (mComponentName != null) { 388 ipw.increaseIndent(); 389 ipw.println("Component=" + mComponentName.getPackageName()); 390 ipw.println("Class=" + mComponentName.getClassName()); 391 ipw.decreaseIndent(); 392 } 393 ipw.println("binding=" + mBinding); 394 ipw.println("current attention check:"); 395 synchronized (mLock) { 396 if (mCurrentAttentionCheck != null) { 397 mCurrentAttentionCheck.dump(ipw); 398 } 399 if (mAttentionCheckCacheBuffer != null) { 400 mAttentionCheckCacheBuffer.dump(ipw); 401 } 402 } 403 } 404 405 private final class LocalService extends AttentionManagerInternal { 406 @Override isAttentionServiceSupported()407 public boolean isAttentionServiceSupported() { 408 return AttentionManagerService.this.mIsServiceEnabled; 409 } 410 411 @Override checkAttention(long timeout, AttentionCallbackInternal callbackInternal)412 public boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) { 413 return AttentionManagerService.this.checkAttention(timeout, callbackInternal); 414 } 415 416 @Override cancelAttentionCheck(AttentionCallbackInternal callbackInternal)417 public void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) { 418 AttentionManagerService.this.cancelAttentionCheck(callbackInternal); 419 } 420 } 421 422 @VisibleForTesting 423 protected static final class AttentionCheckCacheBuffer { 424 private final AttentionCheckCache[] mQueue; 425 private int mStartIndex; 426 private int mSize; 427 AttentionCheckCacheBuffer()428 AttentionCheckCacheBuffer() { 429 mQueue = new AttentionCheckCache[ATTENTION_CACHE_BUFFER_SIZE]; 430 mStartIndex = 0; 431 mSize = 0; 432 } 433 getLast()434 public AttentionCheckCache getLast() { 435 int lastIdx = (mStartIndex + mSize - 1) % ATTENTION_CACHE_BUFFER_SIZE; 436 return mSize == 0 ? null : mQueue[lastIdx]; 437 } 438 add(@onNull AttentionCheckCache cache)439 public void add(@NonNull AttentionCheckCache cache) { 440 int nextIndex = (mStartIndex + mSize) % ATTENTION_CACHE_BUFFER_SIZE; 441 mQueue[nextIndex] = cache; 442 if (mSize == ATTENTION_CACHE_BUFFER_SIZE) { 443 mStartIndex++; 444 } else { 445 mSize++; 446 } 447 } 448 get(int offset)449 public AttentionCheckCache get(int offset) { 450 return offset >= mSize ? null 451 : mQueue[(mStartIndex + offset) % ATTENTION_CACHE_BUFFER_SIZE]; 452 } 453 dump(IndentingPrintWriter ipw)454 private void dump(IndentingPrintWriter ipw) { 455 ipw.println("attention check cache:"); 456 AttentionCheckCache cache; 457 for (int i = 0; i < mSize; i++) { 458 cache = get(i); 459 if (cache != null) { 460 ipw.increaseIndent(); 461 ipw.println("timestamp=" + cache.mTimestamp); 462 ipw.println("result=" + cache.mResult); 463 ipw.decreaseIndent(); 464 } 465 } 466 } 467 } 468 469 @VisibleForTesting 470 protected static final class AttentionCheckCache { 471 private final long mLastComputed; 472 private final int mResult; 473 private final long mTimestamp; 474 AttentionCheckCache(long lastComputed, @AttentionService.AttentionSuccessCodes int result, long timestamp)475 AttentionCheckCache(long lastComputed, @AttentionService.AttentionSuccessCodes int result, 476 long timestamp) { 477 mLastComputed = lastComputed; 478 mResult = result; 479 mTimestamp = timestamp; 480 } 481 } 482 483 @VisibleForTesting 484 static final class AttentionCheck { 485 private final AttentionCallbackInternal mCallbackInternal; 486 private final IAttentionCallback mIAttentionCallback; 487 488 private boolean mIsDispatched; 489 private boolean mIsFulfilled; 490 AttentionCheck(AttentionCallbackInternal callbackInternal, AttentionManagerService service)491 AttentionCheck(AttentionCallbackInternal callbackInternal, 492 AttentionManagerService service) { 493 mCallbackInternal = callbackInternal; 494 mIAttentionCallback = new IAttentionCallback.Stub() { 495 @Override 496 public void onSuccess(@AttentionSuccessCodes int result, long timestamp) { 497 if (mIsFulfilled) { 498 return; 499 } 500 mIsFulfilled = true; 501 callbackInternal.onSuccess(result, timestamp); 502 logStats(result); 503 service.appendResultToAttentionCacheBuffer( 504 new AttentionCheckCache(SystemClock.uptimeMillis(), result, 505 timestamp)); 506 } 507 508 @Override 509 public void onFailure(@AttentionFailureCodes int error) { 510 if (mIsFulfilled) { 511 return; 512 } 513 mIsFulfilled = true; 514 callbackInternal.onFailure(error); 515 logStats(error); 516 } 517 518 private void logStats(int result) { 519 FrameworkStatsLog.write( 520 FrameworkStatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, 521 result); 522 } 523 }; 524 } 525 cancelInternal()526 void cancelInternal() { 527 mIsFulfilled = true; 528 mCallbackInternal.onFailure(ATTENTION_FAILURE_CANCELLED); 529 } 530 dump(IndentingPrintWriter ipw)531 void dump(IndentingPrintWriter ipw) { 532 ipw.increaseIndent(); 533 ipw.println("is dispatched=" + mIsDispatched); 534 ipw.println("is fulfilled:=" + mIsFulfilled); 535 ipw.decreaseIndent(); 536 } 537 } 538 appendResultToAttentionCacheBuffer(AttentionCheckCache cache)539 private void appendResultToAttentionCacheBuffer(AttentionCheckCache cache) { 540 synchronized (mLock) { 541 if (mAttentionCheckCacheBuffer == null) { 542 mAttentionCheckCacheBuffer = new AttentionCheckCacheBuffer(); 543 } 544 mAttentionCheckCacheBuffer.add(cache); 545 } 546 } 547 548 private class AttentionServiceConnection implements ServiceConnection { 549 @Override onServiceConnected(ComponentName name, IBinder service)550 public void onServiceConnected(ComponentName name, IBinder service) { 551 init(IAttentionService.Stub.asInterface(service)); 552 } 553 554 @Override onServiceDisconnected(ComponentName name)555 public void onServiceDisconnected(ComponentName name) { 556 cleanupService(); 557 } 558 559 @Override onBindingDied(ComponentName name)560 public void onBindingDied(ComponentName name) { 561 cleanupService(); 562 } 563 564 @Override onNullBinding(ComponentName name)565 public void onNullBinding(ComponentName name) { 566 cleanupService(); 567 } 568 cleanupService()569 void cleanupService() { 570 init(null); 571 } 572 init(@ullable IAttentionService service)573 private void init(@Nullable IAttentionService service) { 574 synchronized (mLock) { 575 mService = service; 576 mBinding = false; 577 handlePendingCallbackLocked(); 578 } 579 } 580 } 581 582 @GuardedBy("mLock") handlePendingCallbackLocked()583 private void handlePendingCallbackLocked() { 584 if (mCurrentAttentionCheck != null && !mCurrentAttentionCheck.mIsDispatched) { 585 if (mService != null) { 586 try { 587 mService.checkAttention(mCurrentAttentionCheck.mIAttentionCallback); 588 mCurrentAttentionCheck.mIsDispatched = true; 589 } catch (RemoteException e) { 590 Slog.e(LOG_TAG, "Cannot call into the AttentionService"); 591 } 592 } else { 593 mCurrentAttentionCheck.mCallbackInternal.onFailure(ATTENTION_FAILURE_UNKNOWN); 594 } 595 } 596 } 597 598 @VisibleForTesting 599 protected class AttentionHandler extends Handler { 600 private static final int CHECK_CONNECTION_EXPIRATION = 1; 601 private static final int ATTENTION_CHECK_TIMEOUT = 2; 602 AttentionHandler()603 AttentionHandler() { 604 super(Looper.myLooper()); 605 } 606 607 @Override handleMessage(Message msg)608 public void handleMessage(Message msg) { 609 switch (msg.what) { 610 // Do not occupy resources when not in use - unbind proactively. 611 case CHECK_CONNECTION_EXPIRATION: { 612 cancelAndUnbindLocked(); 613 } 614 break; 615 616 // Callee is no longer interested in the attention check result - cancel. 617 case ATTENTION_CHECK_TIMEOUT: { 618 synchronized (mLock) { 619 cancel(); 620 } 621 } 622 break; 623 624 default: 625 break; 626 } 627 } 628 } 629 630 @VisibleForTesting 631 @GuardedBy("mLock") cancel()632 void cancel() { 633 if (mCurrentAttentionCheck.mIsFulfilled) { 634 if (DEBUG) { 635 Slog.d(LOG_TAG, "Trying to cancel the check that has been already fulfilled."); 636 } 637 return; 638 } 639 640 if (mService == null) { 641 mCurrentAttentionCheck.cancelInternal(); 642 return; 643 } 644 645 try { 646 mService.cancelAttentionCheck(mCurrentAttentionCheck.mIAttentionCallback); 647 } catch (RemoteException e) { 648 Slog.e(LOG_TAG, "Unable to cancel attention check"); 649 mCurrentAttentionCheck.cancelInternal(); 650 } 651 } 652 653 @GuardedBy("mLock") cancelAndUnbindLocked()654 private void cancelAndUnbindLocked() { 655 synchronized (mLock) { 656 if (mCurrentAttentionCheck == null) { 657 return; 658 } 659 cancel(); 660 if (mService == null) { 661 return; 662 } 663 mAttentionHandler.post(() -> mContext.unbindService(mConnection)); 664 // Note: this will set mBinding to false even though it could still be trying to bind 665 // (i.e. the runnable was posted in bindLocked but then cancelAndUnbindLocked was 666 // called before it's run yet). This is a safe state at the moment, 667 // since it will eventually, but feels like a source for confusion down the road and 668 // may cause some expensive and unnecessary work to be done. 669 mConnection.cleanupService(); 670 } 671 } 672 673 /** Binds to the system's AttentionService which provides an actual implementation. */ 674 @GuardedBy("mLock") bindLocked()675 private void bindLocked() { 676 // No need to bind if service is binding or has already been bound. 677 if (mBinding || mService != null) { 678 return; 679 } 680 681 mBinding = true; 682 // mContext.bindServiceAsUser() calls into ActivityManagerService which it may already 683 // hold the lock and had called into PowerManagerService, which holds a lock. 684 // That would create a deadlock. To solve that, putting it on a handler. 685 mAttentionHandler.post(() -> { 686 final Intent serviceIntent = new Intent( 687 AttentionService.SERVICE_INTERFACE).setComponent( 688 mComponentName); 689 // Note: no reason to clear the calling identity, we won't have one in a handler. 690 mContext.bindServiceAsUser(serviceIntent, mConnection, 691 BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_INCLUDE_CAPABILITIES, 692 UserHandle.CURRENT); 693 694 }); 695 } 696 697 /** 698 * Unbinds and stops the service when the screen off intent is received. 699 * Attention service only makes sense when screen is ON; disconnect and stop service otherwise. 700 */ 701 private final class ScreenStateReceiver extends BroadcastReceiver { 702 @Override onReceive(Context context, Intent intent)703 public void onReceive(Context context, Intent intent) { 704 if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { 705 cancelAndUnbindLocked(); 706 } 707 } 708 } 709 710 private final class AttentionManagerServiceShellCommand extends ShellCommand { 711 class TestableAttentionCallbackInternal extends AttentionCallbackInternal { 712 private int mLastCallbackCode = -1; 713 714 @Override onSuccess(int result, long timestamp)715 public void onSuccess(int result, long timestamp) { 716 mLastCallbackCode = result; 717 } 718 719 @Override onFailure(int error)720 public void onFailure(int error) { 721 mLastCallbackCode = error; 722 } 723 reset()724 public void reset() { 725 mLastCallbackCode = -1; 726 } 727 getLastCallbackCode()728 public int getLastCallbackCode() { 729 return mLastCallbackCode; 730 } 731 } 732 733 final TestableAttentionCallbackInternal mTestableAttentionCallback = 734 new TestableAttentionCallbackInternal(); 735 736 @Override onCommand(@ullable final String cmd)737 public int onCommand(@Nullable final String cmd) { 738 if (cmd == null) { 739 return handleDefaultCommands(cmd); 740 } 741 final PrintWriter err = getErrPrintWriter(); 742 try { 743 switch (cmd) { 744 case "getAttentionServiceComponent": 745 return cmdResolveAttentionServiceComponent(); 746 case "call": 747 switch (getNextArgRequired()) { 748 case "checkAttention": 749 return cmdCallCheckAttention(); 750 case "cancelCheckAttention": 751 return cmdCallCancelAttention(); 752 default: 753 throw new IllegalArgumentException("Invalid argument"); 754 } 755 case "setTestableAttentionService": 756 return cmdSetTestableAttentionService(getNextArgRequired()); 757 case "clearTestableAttentionService": 758 return cmdClearTestableAttentionService(); 759 case "getLastTestCallbackCode": 760 return cmdGetLastTestCallbackCode(); 761 default: 762 return handleDefaultCommands(cmd); 763 } 764 } catch (IllegalArgumentException e) { 765 err.println("Error: " + e.getMessage()); 766 } 767 return -1; 768 } 769 cmdSetTestableAttentionService(String testingServicePackage)770 private int cmdSetTestableAttentionService(String testingServicePackage) { 771 final PrintWriter out = getOutPrintWriter(); 772 if (TextUtils.isEmpty(testingServicePackage)) { 773 out.println("false"); 774 } else { 775 sTestAttentionServicePackage = testingServicePackage; 776 resetStates(); 777 out.println(mComponentName != null ? "true" : "false"); 778 } 779 return 0; 780 } 781 cmdClearTestableAttentionService()782 private int cmdClearTestableAttentionService() { 783 sTestAttentionServicePackage = ""; 784 mTestableAttentionCallback.reset(); 785 resetStates(); 786 return 0; 787 } 788 cmdCallCheckAttention()789 private int cmdCallCheckAttention() { 790 final PrintWriter out = getOutPrintWriter(); 791 boolean calledSuccessfully = checkAttention(2000, mTestableAttentionCallback); 792 out.println(calledSuccessfully ? "true" : "false"); 793 return 0; 794 } 795 cmdCallCancelAttention()796 private int cmdCallCancelAttention() { 797 final PrintWriter out = getOutPrintWriter(); 798 cancelAttentionCheck(mTestableAttentionCallback); 799 out.println("true"); 800 return 0; 801 } 802 cmdResolveAttentionServiceComponent()803 private int cmdResolveAttentionServiceComponent() { 804 final PrintWriter out = getOutPrintWriter(); 805 ComponentName resolvedComponent = resolveAttentionService(mContext); 806 out.println(resolvedComponent != null ? resolvedComponent.flattenToShortString() : ""); 807 return 0; 808 } 809 cmdGetLastTestCallbackCode()810 private int cmdGetLastTestCallbackCode() { 811 final PrintWriter out = getOutPrintWriter(); 812 out.println(mTestableAttentionCallback.getLastCallbackCode()); 813 return 0; 814 } 815 resetStates()816 private void resetStates() { 817 mComponentName = resolveAttentionService(mContext); 818 } 819 820 @Override onHelp()821 public void onHelp() { 822 final PrintWriter out = getOutPrintWriter(); 823 out.println("Attention commands: "); 824 out.println(" setTestableAttentionService <service_package>: Bind to a custom" 825 + " implementation of attention service"); 826 out.println(" ---<service_package>:"); 827 out.println( 828 " := Package containing the Attention Service implementation to bind to"); 829 out.println(" ---returns:"); 830 out.println(" := true, if was bound successfully"); 831 out.println(" := false, if was not bound successfully"); 832 out.println(" clearTestableAttentionService: Undo custom bindings. Revert to previous" 833 + " behavior"); 834 out.println(" getAttentionServiceComponent: Get the current service component string"); 835 out.println(" ---returns:"); 836 out.println(" := If valid, the component string (in shorten form) for the" 837 + " currently bound service."); 838 out.println(" := else, empty string"); 839 out.println(" call checkAttention: Calls check attention"); 840 out.println(" ---returns:"); 841 out.println( 842 " := true, if the call was successfully dispatched to the service " 843 + "implementation." 844 + " (to see the result, call getLastTestCallbackCode)"); 845 out.println(" := false, otherwise"); 846 out.println(" call cancelCheckAttention: Cancels check attention"); 847 out.println(" getLastTestCallbackCode"); 848 out.println(" ---returns:"); 849 out.println( 850 " := An integer, representing the last callback code received from the " 851 + "bounded implementation. If none, it will return -1"); 852 } 853 } 854 855 private final class BinderService extends Binder { 856 AttentionManagerServiceShellCommand mAttentionManagerServiceShellCommand = 857 new AttentionManagerServiceShellCommand(); 858 859 @Override onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)860 public void onShellCommand(FileDescriptor in, FileDescriptor out, 861 FileDescriptor err, 862 String[] args, ShellCallback callback, 863 ResultReceiver resultReceiver) { 864 mAttentionManagerServiceShellCommand.exec(this, in, out, err, args, callback, 865 resultReceiver); 866 } 867 868 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)869 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 870 if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) { 871 return; 872 } 873 874 dumpInternal(new IndentingPrintWriter(pw, " ")); 875 } 876 } 877 } 878