1 /* 2 * Copyright (C) 2021 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.scheduling; 18 19 import android.Manifest; 20 import android.annotation.CurrentTimeMillisLong; 21 import android.app.ActivityManager; 22 import android.app.ActivityManager.RunningServiceInfo; 23 import android.app.AlarmManager; 24 import android.content.BroadcastReceiver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.pm.PackageManager; 29 import android.net.TetheredClient; 30 import android.net.TetheringManager; 31 import android.net.TetheringManager.TetheringEventCallback; 32 import android.os.Binder; 33 import android.os.Handler; 34 import android.os.Looper; 35 import android.os.ParcelFileDescriptor; 36 import android.os.PowerManager; 37 import android.os.RemoteCallback; 38 import android.os.RemoteCallbackList; 39 import android.os.RemoteException; 40 import android.os.SystemClock; 41 import android.os.UserHandle; 42 import android.provider.DeviceConfig; 43 import android.scheduling.IRebootReadinessManager; 44 import android.scheduling.IRequestRebootReadinessStatusListener; 45 import android.scheduling.RebootReadinessManager; 46 import android.util.ArraySet; 47 import android.util.Log; 48 import android.util.SparseArray; 49 50 import com.android.internal.annotations.GuardedBy; 51 import com.android.internal.annotations.VisibleForTesting; 52 import com.android.modules.utils.HandlerExecutor; 53 import com.android.server.SystemService; 54 55 import java.io.FileDescriptor; 56 import java.io.PrintWriter; 57 import java.util.ArrayList; 58 import java.util.Collection; 59 import java.util.List; 60 import java.util.concurrent.CountDownLatch; 61 import java.util.concurrent.Executor; 62 import java.util.concurrent.TimeUnit; 63 64 /** 65 * Implementation of service that analyzes device state to detect if the device is in a suitable 66 * state to reboot. 67 * 68 * @hide 69 */ 70 public class RebootReadinessManagerService extends IRebootReadinessManager.Stub { 71 private static final String TAG = "RebootReadinessManager"; 72 73 private final RemoteCallbackList<IRequestRebootReadinessStatusListener> mCallbacks = 74 new RemoteCallbackList<IRequestRebootReadinessStatusListener>(); 75 private final Handler mHandler; 76 private final Executor mExecutor; 77 78 private final Object mLock = new Object(); 79 80 private final Context mContext; 81 82 private final ActivityManager mActivityManager; 83 84 private final AlarmManager mAlarmManager; 85 86 private final RebootReadinessLogger mRebootReadinessLogger; 87 88 // For testing purposes only. Listeners whose names start with this prefix will be able to 89 // inform the reboot signal, even if subsystem checks are disabled for testing. 90 private static final String TEST_CALLBACK_PREFIX = "TESTCOMPONENT"; 91 92 // DeviceConfig properties 93 private static final String PROPERTY_ACTIVE_POLLING_INTERVAL_MS = "active_polling_interval_ms"; 94 private static final String PROPERTY_INTERACTIVITY_THRESHOLD_MS = "interactivity_threshold_ms"; 95 private static final String PROPERTY_DISABLE_INTERACTIVITY_CHECK = 96 "disable_interactivity_check"; 97 private static final String PROPERTY_DISABLE_APP_ACTIVITY_CHECK = "disable_app_activity_check"; 98 private static final String PROPERTY_DISABLE_SUBSYSTEMS_CHECK = "disable_subsystems_check"; 99 private static final String PROPERTY_ALARM_CLOCK_THRESHOLD_MS = "alarm_clock_threshold_ms"; 100 private static final String PROPERTY_LOGGING_BLOCKING_ENTITY_THRESHOLD_MS = 101 "logging_blocking_entity_threshold_ms"; 102 103 104 private static final long DEFAULT_POLLING_INTERVAL_WHILE_ACTIVE_MS = 105 TimeUnit.MINUTES.toMillis(5); 106 private static final long DEFAULT_INTERACTIVITY_THRESHOLD_MS = TimeUnit.MINUTES.toMillis(30); 107 private static final long DEFAULT_ALARM_CLOCK_THRESHOLD_MS = TimeUnit.MINUTES.toMillis(10); 108 private static final long DEFAULT_LOGGING_BLOCKING_ENTITY_THRESHOLD_MS = 109 TimeUnit.HOURS.toMillis(1); 110 111 @GuardedBy("mLock") 112 private long mActivePollingIntervalMs = DEFAULT_POLLING_INTERVAL_WHILE_ACTIVE_MS; 113 114 @GuardedBy("mLock") 115 private long mInteractivityThresholdMs = DEFAULT_INTERACTIVITY_THRESHOLD_MS; 116 117 @GuardedBy("mLock") 118 private boolean mDisableInteractivityCheck = false; 119 120 @GuardedBy("mLock") 121 private boolean mReadyToReboot = false; 122 123 @GuardedBy("mLock") 124 private boolean mDisableAppActivityCheck = false; 125 126 @GuardedBy("mLock") 127 private boolean mDisableSubsystemsCheck = false; 128 129 @GuardedBy("mLock") 130 private long mAlarmClockThresholdMs = DEFAULT_ALARM_CLOCK_THRESHOLD_MS; 131 132 @GuardedBy("mLock") 133 private long mLoggingBlockingEntityThresholdMs = DEFAULT_LOGGING_BLOCKING_ENTITY_THRESHOLD_MS; 134 135 // A mapping of uid to package name for uids which have called markRebootPending. Reboot 136 // readiness state changed broadcasts will only be sent to the values in this map. 137 @GuardedBy("mLock") 138 private final SparseArray<ArraySet<String>> mCallingUidToPackageMap = new SparseArray<>(); 139 140 // When true, reboot readiness checks should not be performed. 141 @GuardedBy("mLock") 142 private boolean mCanceled = false; 143 144 // The last time the device stopped being in an interactive state, in relation to the time 145 // since the system booted. If the device is currently interactive, this will be MAX_VALUE. 146 @GuardedBy("mLock") 147 private long mLastTimeNotInteractiveMs = Long.MAX_VALUE; 148 149 150 // Metadata to be stored for use in metrics. 151 @GuardedBy("mLock") 152 @CurrentTimeMillisLong 153 private long mPollingStartTimeMs; 154 155 @GuardedBy("mLock") 156 private int mTimesBlockedByInteractivity; 157 158 @GuardedBy("mLock") 159 private int mTimesBlockedBySubsystems; 160 161 @GuardedBy("mLock") 162 private int mTimesBlockedByAppActivity; 163 164 @GuardedBy("mLock") 165 private boolean mBlockedByTethering = false; 166 167 private final TetheringEventCallback mTetheringEventCallback = new TetheringEventCallback() { 168 @Override 169 public void onClientsChanged(Collection<TetheredClient> clients) { 170 synchronized (mLock) { 171 mBlockedByTethering = clients.size() > 0; 172 } 173 } 174 }; 175 176 private final BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() { 177 @Override 178 public void onReceive(Context context, Intent intent) { 179 handleUserPresent(); 180 } 181 }; 182 183 private final AlarmManager.OnAlarmListener mPollStateListener = () -> { 184 synchronized (mLock) { 185 if (!mCanceled) { 186 pollRebootReadinessState(); 187 } else { 188 Log.w(TAG, "Received poll state callback while canceled."); 189 } 190 } 191 }; 192 RebootReadinessManagerService(Context context)193 RebootReadinessManagerService(Context context) { 194 this(context, new RebootReadinessLogger(context)); 195 } 196 197 @VisibleForTesting RebootReadinessManagerService(Context context, RebootReadinessLogger logger)198 RebootReadinessManagerService(Context context, RebootReadinessLogger logger) { 199 // TODO(b/161353402): Consolidate mHandler and mExecutor 200 mHandler = new Handler(Looper.getMainLooper()); 201 mExecutor = new HandlerExecutor(mHandler); 202 mRebootReadinessLogger = logger; 203 updateConfigs(); 204 DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_REBOOT_READINESS, 205 mExecutor, properties -> updateConfigs()); 206 BroadcastReceiver interactivityChangedReceiver = new BroadcastReceiver() { 207 @Override 208 public void onReceive(Context context, Intent intent) { 209 String action = intent.getAction(); 210 if (action.equals(Intent.ACTION_SCREEN_ON)) { 211 noteInteractivityStateChanged(true); 212 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 213 noteInteractivityStateChanged(false); 214 } 215 } 216 }; 217 IntentFilter interactivityFilter = new IntentFilter(); 218 interactivityFilter.addAction(Intent.ACTION_SCREEN_ON); 219 interactivityFilter.addAction(Intent.ACTION_SCREEN_OFF); 220 context.registerReceiver(interactivityChangedReceiver, interactivityFilter); 221 PowerManager powerManager = context.getSystemService(PowerManager.class); 222 if (powerManager != null) { 223 noteInteractivityStateChanged(powerManager.isInteractive()); 224 } 225 226 IntentFilter userPresentFilter = new IntentFilter(); 227 userPresentFilter.addAction(Intent.ACTION_USER_PRESENT); 228 context.registerReceiver(mUserPresentReceiver, userPresentFilter); 229 mActivityManager = context.getSystemService(ActivityManager.class); 230 mAlarmManager = context.getSystemService(AlarmManager.class); 231 TetheringManager mTetheringManager = context.getSystemService(TetheringManager.class); 232 if (mTetheringManager != null) { 233 mTetheringManager.registerTetheringEventCallback(mExecutor, mTetheringEventCallback); 234 } 235 mHandler.post(mRebootReadinessLogger::readMetricsPostReboot); 236 mContext = context; 237 } 238 239 @Override handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out, ParcelFileDescriptor err, String[] args)240 public int handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out, 241 ParcelFileDescriptor err, String[] args) { 242 return new RebootReadinessShellCommand(this, mContext).exec(this, in.getFileDescriptor(), 243 out.getFileDescriptor(), err.getFileDescriptor(), args); 244 } 245 246 /** 247 * Lifecycle class for RebootReadinessManagerService. 248 */ 249 public static class Lifecycle extends SystemService { 250 Lifecycle(Context context)251 public Lifecycle(Context context) { 252 super(context); 253 } 254 255 @Override onStart()256 public void onStart() { 257 RebootReadinessManagerService rebootReadinessManagerService = 258 new RebootReadinessManagerService(getContext()); 259 publishBinderService(Context.REBOOT_READINESS_SERVICE, rebootReadinessManagerService); 260 } 261 } 262 263 @Override markRebootPending(String callingPackage)264 public void markRebootPending(String callingPackage) { 265 mContext.enforceCallingPermission(Manifest.permission.REBOOT, 266 "Caller does not have REBOOT permission."); 267 synchronized (mLock) { 268 Log.i(TAG, "Starting reboot readiness checks for package: " + callingPackage); 269 // If there are existing clients waiting for a broadcast, reboot readiness checks 270 // are already ongoing. 271 if (mCallingUidToPackageMap.size() == 0) { 272 mCanceled = false; 273 resetMetrics(); 274 mHandler.removeCallbacksAndMessages(null); 275 mHandler.post(this::pollRebootReadinessState); 276 } else { 277 sendRebootReadyBroadcast(callingPackage, 278 Binder.getCallingUserHandle(), mReadyToReboot); 279 } 280 ArraySet<String> packagesForUid = 281 mCallingUidToPackageMap.get(Binder.getCallingUid(), new ArraySet<>()); 282 packagesForUid.add(callingPackage); 283 mCallingUidToPackageMap.put(Binder.getCallingUid(), packagesForUid); 284 } 285 } 286 287 @Override cancelPendingReboot(String callingPackage)288 public void cancelPendingReboot(String callingPackage) { 289 mContext.enforceCallingPermission(Manifest.permission.REBOOT, 290 "Caller does not have REBOOT permission"); 291 final int callingUid = Binder.getCallingUid(); 292 synchronized (mLock) { 293 ArraySet<String> packagesForUid = 294 mCallingUidToPackageMap.get(callingUid, new ArraySet<>()); 295 if (packagesForUid.contains(callingPackage)) { 296 Log.i(TAG, "Canceling reboot readiness checks for package: " + callingPackage); 297 packagesForUid.remove(callingPackage); 298 if (packagesForUid.size() == 0) { 299 // No remaining clients exist for this calling uid 300 mCallingUidToPackageMap.remove(callingUid); 301 } 302 303 // Only cancel readiness checks if there are no more uids with packages 304 // waiting for broadcasts 305 if (mCallingUidToPackageMap.size() == 0) { 306 mHandler.removeCallbacksAndMessages(null); 307 mAlarmManager.cancel(mPollStateListener); 308 mCanceled = true; 309 // Delete any logging information if the device is ready to reboot, since an 310 // unattended reboot should not take place if the checks are cancelled. 311 if (mReadyToReboot) { 312 mRebootReadinessLogger.deleteLoggingInformation(); 313 } 314 mReadyToReboot = false; 315 } 316 } else { 317 Log.w(TAG, "Package " + callingPackage + " tried to cancel reboot readiness" 318 + " checks but was not a client of this service."); 319 } 320 } 321 } 322 323 @Override isReadyToReboot()324 public boolean isReadyToReboot() { 325 mContext.enforceCallingPermission(Manifest.permission.REBOOT, 326 "Caller does not have REBOOT permission."); 327 synchronized (mLock) { 328 return mReadyToReboot; 329 } 330 } 331 332 @Override addRequestRebootReadinessStatusListener( IRequestRebootReadinessStatusListener callback)333 public void addRequestRebootReadinessStatusListener( 334 IRequestRebootReadinessStatusListener callback) { 335 mContext.enforceCallingPermission(Manifest.permission.SIGNAL_REBOOT_READINESS, 336 "Caller does not have SIGNAL_REBOOT_READINESS permission."); 337 mCallbacks.register(callback); 338 try { 339 callback.asBinder().linkToDeath( 340 () -> removeRequestRebootReadinessStatusListener(callback), 0); 341 } catch (RemoteException e) { 342 removeRequestRebootReadinessStatusListener(callback); 343 } 344 } 345 346 @Override removeRequestRebootReadinessStatusListener( IRequestRebootReadinessStatusListener callback)347 public void removeRequestRebootReadinessStatusListener( 348 IRequestRebootReadinessStatusListener callback) { 349 mContext.enforceCallingPermission(Manifest.permission.SIGNAL_REBOOT_READINESS, 350 "Caller does not have SIGNAL_REBOOT_READINESS permission."); 351 mCallbacks.unregister(callback); 352 } 353 pollRebootReadinessState()354 private void pollRebootReadinessState() { 355 synchronized (mLock) { 356 final boolean previousRebootReadiness = mReadyToReboot; 357 final boolean currentRebootReadiness = getRebootReadinessLocked(); 358 if (previousRebootReadiness != currentRebootReadiness) { 359 noteRebootReadinessStateChanged(currentRebootReadiness); 360 } 361 if (!mCanceled && !currentRebootReadiness) { 362 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, 363 System.currentTimeMillis() 364 + mActivePollingIntervalMs, 365 "poll_reboot_readiness", mPollStateListener, mHandler); 366 } 367 } 368 } 369 370 @GuardedBy("mLock") getRebootReadinessLocked()371 private boolean getRebootReadinessLocked() { 372 if (!(mDisableInteractivityCheck || checkDeviceInteractivity())) { 373 mTimesBlockedByInteractivity++; 374 Log.v(TAG, "Reboot blocked by device interactivity"); 375 return false; 376 } 377 378 if (!checkSystemComponentsState()) { 379 mTimesBlockedBySubsystems++; 380 return false; 381 } 382 383 if (!(mDisableAppActivityCheck || checkBackgroundAppActivity())) { 384 mTimesBlockedByAppActivity++; 385 return false; 386 } 387 388 return true; 389 } 390 391 @VisibleForTesting 392 @GuardedBy("mLock") checkSystemComponentsState()393 boolean checkSystemComponentsState() { 394 if (!mDisableSubsystemsCheck) { 395 if (mBlockedByTethering) { 396 return false; 397 } 398 399 AlarmManager.AlarmClockInfo alarmClockInfo = mAlarmManager.getNextAlarmClock(); 400 final long now = System.currentTimeMillis(); 401 if (alarmClockInfo != null 402 && (alarmClockInfo.getTriggerTime() - now) < mAlarmClockThresholdMs) { 403 return false; 404 } 405 } 406 407 final List<IRequestRebootReadinessStatusListener> blockingCallbacks = new ArrayList<>(); 408 final List<String> blockingCallbackNames = new ArrayList<>(); 409 int i = mCallbacks.beginBroadcast(); 410 CountDownLatch latch = new CountDownLatch(i); 411 while (i > 0) { 412 i--; 413 final IRequestRebootReadinessStatusListener callback = mCallbacks.getBroadcastItem(i); 414 try { 415 RemoteCallback remoteCallback = new RemoteCallback( 416 result -> { 417 boolean isReadyToReboot = result.getBoolean( 418 RebootReadinessManager.IS_REBOOT_READY_KEY); 419 String name = result.getString( 420 RebootReadinessManager.SUBSYSTEM_NAME_KEY); 421 if (!isReadyToReboot && (!mDisableSubsystemsCheck 422 || name.startsWith(TEST_CALLBACK_PREFIX))) { 423 blockingCallbacks.add(callback); 424 blockingCallbackNames.add(name); 425 } 426 latch.countDown(); 427 } 428 ); 429 callback.onRequestRebootReadinessStatus(remoteCallback); 430 } catch (RemoteException e) { 431 Log.e(TAG, "Could not resolve state of RebootReadinessCallback: " + e); 432 return false; 433 } 434 } 435 try { 436 latch.await(1, TimeUnit.MINUTES); 437 } catch (InterruptedException ignore) { 438 } 439 mCallbacks.finishBroadcast(); 440 mRebootReadinessLogger.maybeLogLongBlockingComponents(blockingCallbackNames, 441 mLoggingBlockingEntityThresholdMs); 442 if (blockingCallbacks.size() > 0) { 443 Log.v(TAG, "Reboot blocked by subsystems: " + String.join(",", blockingCallbackNames)); 444 return false; 445 } 446 return true; 447 } 448 449 @VisibleForTesting checkDeviceInteractivity()450 boolean checkDeviceInteractivity() { 451 final long now = SystemClock.elapsedRealtime(); 452 synchronized (mLock) { 453 return (now - mLastTimeNotInteractiveMs) > mInteractivityThresholdMs; 454 } 455 } 456 457 /** 458 * Check for important app activity in the background by querying the running services on the 459 * device. 460 */ 461 @VisibleForTesting checkBackgroundAppActivity()462 boolean checkBackgroundAppActivity() { 463 if (mActivityManager != null) { 464 final List<RunningServiceInfo> serviceInfos = 465 mActivityManager.getRunningServices(Integer.MAX_VALUE); 466 List<Integer> blockingUids = new ArrayList<>(); 467 for (int i = 0; i < serviceInfos.size(); i++) { 468 RunningServiceInfo info = serviceInfos.get(i); 469 if (info.foreground) { 470 blockingUids.add(info.uid); 471 } 472 } 473 mRebootReadinessLogger.maybeLogLongBlockingApps(blockingUids, 474 mLoggingBlockingEntityThresholdMs); 475 if (blockingUids.size() > 0) { 476 Log.v(TAG, "Reboot blocked by app uids: " + blockingUids.toString()); 477 return false; 478 } 479 return true; 480 } 481 return false; 482 } 483 noteRebootReadinessStateChanged(boolean isReadyToReboot)484 private void noteRebootReadinessStateChanged(boolean isReadyToReboot) { 485 synchronized (mLock) { 486 Log.i(TAG, "Reboot readiness state changed to " + isReadyToReboot); 487 mReadyToReboot = isReadyToReboot; 488 489 // Send state change broadcast to any packages which have a pending update 490 for (int i = 0; i < mCallingUidToPackageMap.size(); i++) { 491 UserHandle user = UserHandle.getUserHandleForUid(mCallingUidToPackageMap.keyAt(i)); 492 ArraySet<String> packageNames = mCallingUidToPackageMap.valueAt(i); 493 for (int j = 0; j < packageNames.size(); j++) { 494 sendRebootReadyBroadcast(packageNames.valueAt(j), user, isReadyToReboot); 495 } 496 } 497 if (mReadyToReboot) { 498 mRebootReadinessLogger.writeAfterRebootReadyBroadcast( 499 mPollingStartTimeMs, System.currentTimeMillis(), 500 mTimesBlockedByInteractivity, mTimesBlockedBySubsystems, 501 mTimesBlockedByAppActivity); 502 503 AlarmManager.AlarmClockInfo alarmClockInfo = mAlarmManager.getNextAlarmClock(); 504 if (alarmClockInfo != null) { 505 // Schedule a state check before the next alarm clock is triggered. This check 506 // is triggered within the alarm clock threshold window (plus a small tolerance) 507 // to ensure that this alarm clock will block the reboot at that time. 508 long stateCheckTriggerTime = alarmClockInfo.getTriggerTime() 509 - (mAlarmClockThresholdMs - TimeUnit.SECONDS.toMillis(1)); 510 if (stateCheckTriggerTime > System.currentTimeMillis()) { 511 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, 512 stateCheckTriggerTime, "poll_reboot_readiness", 513 mPollStateListener, mHandler); 514 } 515 } 516 } else { 517 mRebootReadinessLogger.writeAfterNotRebootReadyBroadcast(); 518 } 519 } 520 } 521 522 @GuardedBy("mLock") sendRebootReadyBroadcast(String packageName, UserHandle user, boolean isReadyToReboot)523 private void sendRebootReadyBroadcast(String packageName, UserHandle user, 524 boolean isReadyToReboot) { 525 Log.i(TAG, "Sending REBOOT_READY broadcast to package " + packageName 526 + " for user " + user.getIdentifier()); 527 Intent intent = new Intent(RebootReadinessManager.ACTION_REBOOT_READY); 528 intent.putExtra(RebootReadinessManager.EXTRA_IS_READY_TO_REBOOT, isReadyToReboot); 529 intent.setPackage(packageName); 530 mContext.sendBroadcastAsUser(intent, user, Manifest.permission.REBOOT); 531 } 532 updateConfigs()533 private void updateConfigs() { 534 synchronized (mLock) { 535 mActivePollingIntervalMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_REBOOT_READINESS, 536 PROPERTY_ACTIVE_POLLING_INTERVAL_MS, DEFAULT_POLLING_INTERVAL_WHILE_ACTIVE_MS); 537 mInteractivityThresholdMs = DeviceConfig.getLong( 538 DeviceConfig.NAMESPACE_REBOOT_READINESS, PROPERTY_INTERACTIVITY_THRESHOLD_MS, 539 DEFAULT_INTERACTIVITY_THRESHOLD_MS); 540 mDisableInteractivityCheck = DeviceConfig.getBoolean( 541 DeviceConfig.NAMESPACE_REBOOT_READINESS, 542 PROPERTY_DISABLE_INTERACTIVITY_CHECK, false); 543 mDisableAppActivityCheck = DeviceConfig.getBoolean( 544 DeviceConfig.NAMESPACE_REBOOT_READINESS, 545 PROPERTY_DISABLE_APP_ACTIVITY_CHECK, false); 546 mDisableSubsystemsCheck = DeviceConfig.getBoolean( 547 DeviceConfig.NAMESPACE_REBOOT_READINESS, 548 PROPERTY_DISABLE_SUBSYSTEMS_CHECK, false); 549 mAlarmClockThresholdMs = DeviceConfig.getLong( 550 DeviceConfig.NAMESPACE_REBOOT_READINESS, 551 PROPERTY_ALARM_CLOCK_THRESHOLD_MS, DEFAULT_ALARM_CLOCK_THRESHOLD_MS); 552 mLoggingBlockingEntityThresholdMs = DeviceConfig.getLong( 553 DeviceConfig.NAMESPACE_REBOOT_READINESS, 554 PROPERTY_LOGGING_BLOCKING_ENTITY_THRESHOLD_MS, 555 DEFAULT_LOGGING_BLOCKING_ENTITY_THRESHOLD_MS); 556 } 557 } 558 noteInteractivityStateChanged(boolean isInteractive)559 private void noteInteractivityStateChanged(boolean isInteractive) { 560 synchronized (mLock) { 561 if (isInteractive) { 562 mLastTimeNotInteractiveMs = Long.MAX_VALUE; 563 if (!mCanceled && mReadyToReboot) { 564 Log.i(TAG, "Device became interactive while reboot-ready"); 565 pollRebootReadinessState(); 566 } 567 } else { 568 mLastTimeNotInteractiveMs = SystemClock.elapsedRealtime(); 569 } 570 } 571 } 572 handleUserPresent()573 private void handleUserPresent() { 574 mContext.unregisterReceiver(mUserPresentReceiver); 575 mRebootReadinessLogger.writePostRebootMetrics(); 576 } 577 578 @GuardedBy("mLock") resetMetrics()579 private void resetMetrics() { 580 mPollingStartTimeMs = System.currentTimeMillis(); 581 mTimesBlockedByInteractivity = 0; 582 mTimesBlockedBySubsystems = 0; 583 mTimesBlockedByAppActivity = 0; 584 } 585 586 @VisibleForTesting getCallingPackages()587 SparseArray<ArraySet<String>> getCallingPackages() { 588 synchronized (mLock) { 589 return mCallingUidToPackageMap; 590 } 591 } 592 593 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)594 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 595 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 596 != PackageManager.PERMISSION_GRANTED) { 597 return; 598 } 599 600 synchronized (mLock) { 601 mRebootReadinessLogger.dump(pw); 602 if (mCallingUidToPackageMap.size() > 0) { 603 pw.print("Packages awaiting REBOOT_READY broadcast:"); 604 for (int i = 0; i < mCallingUidToPackageMap.size(); i++) { 605 ArraySet<String> packageNames = mCallingUidToPackageMap.valueAt(i); 606 for (int j = 0; j < packageNames.size(); j++) { 607 pw.print(" " + packageNames.valueAt(j)); 608 } 609 } 610 pw.println(); 611 pw.println("Current reboot readiness state: " + mReadyToReboot); 612 } 613 } 614 } 615 616 /** Writes information about any UIDs which are blocking the reboot. */ writeBlockingUids(PrintWriter pw)617 void writeBlockingUids(PrintWriter pw) { 618 mRebootReadinessLogger.writeBlockingUids(pw); 619 } 620 621 /** Writes information about any subsystems which are blocking the reboot. */ writeBlockingSubsystems(PrintWriter pw)622 void writeBlockingSubsystems(PrintWriter pw) { 623 mRebootReadinessLogger.writeBlockingSubsystems(pw); 624 } 625 } 626