1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server; 18 19 import static android.content.Intent.ACTION_REBOOT; 20 import static android.content.Intent.ACTION_SHUTDOWN; 21 import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig; 22 23 import static com.android.server.crashrecovery.CrashRecoveryUtils.dumpCrashRecoveryEvents; 24 25 import static java.lang.annotation.RetentionPolicy.SOURCE; 26 27 import android.annotation.IntDef; 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.content.BroadcastReceiver; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.IntentFilter; 34 import android.content.pm.PackageInfo; 35 import android.content.pm.PackageManager; 36 import android.content.pm.VersionedPackage; 37 import android.crashrecovery.flags.Flags; 38 import android.net.ConnectivityModuleConnector; 39 import android.os.Environment; 40 import android.os.Handler; 41 import android.os.Looper; 42 import android.os.Process; 43 import android.os.SystemProperties; 44 import android.provider.DeviceConfig; 45 import android.sysprop.CrashRecoveryProperties; 46 import android.text.TextUtils; 47 import android.util.ArrayMap; 48 import android.util.ArraySet; 49 import android.util.AtomicFile; 50 import android.util.EventLog; 51 import android.util.IndentingPrintWriter; 52 import android.util.LongArrayQueue; 53 import android.util.Slog; 54 import android.util.Xml; 55 56 import com.android.internal.annotations.GuardedBy; 57 import com.android.internal.annotations.VisibleForTesting; 58 import com.android.internal.os.BackgroundThread; 59 import com.android.internal.util.XmlUtils; 60 import com.android.modules.utils.TypedXmlPullParser; 61 import com.android.modules.utils.TypedXmlSerializer; 62 63 import libcore.io.IoUtils; 64 65 import org.xmlpull.v1.XmlPullParserException; 66 67 import java.io.BufferedReader; 68 import java.io.BufferedWriter; 69 import java.io.File; 70 import java.io.FileInputStream; 71 import java.io.FileNotFoundException; 72 import java.io.FileOutputStream; 73 import java.io.FileReader; 74 import java.io.FileWriter; 75 import java.io.IOException; 76 import java.io.InputStream; 77 import java.io.ObjectInputStream; 78 import java.io.ObjectOutputStream; 79 import java.io.PrintWriter; 80 import java.lang.annotation.Retention; 81 import java.lang.annotation.RetentionPolicy; 82 import java.util.ArrayList; 83 import java.util.Collections; 84 import java.util.HashMap; 85 import java.util.Iterator; 86 import java.util.List; 87 import java.util.Map; 88 import java.util.NoSuchElementException; 89 import java.util.Set; 90 import java.util.concurrent.Executor; 91 import java.util.concurrent.TimeUnit; 92 93 /** 94 * Monitors the health of packages on the system and notifies interested observers when packages 95 * fail. On failure, the registered observer with the least user impacting mitigation will 96 * be notified. 97 * @hide 98 */ 99 public class PackageWatchdog { 100 private static final String TAG = "PackageWatchdog"; 101 102 static final String PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS = 103 "watchdog_trigger_failure_duration_millis"; 104 static final String PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT = 105 "watchdog_trigger_failure_count"; 106 static final String PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED = 107 "watchdog_explicit_health_check_enabled"; 108 109 // TODO: make the following values configurable via DeviceConfig 110 private static final long NATIVE_CRASH_POLLING_INTERVAL_MILLIS = 111 TimeUnit.SECONDS.toMillis(30); 112 private static final long NUMBER_OF_NATIVE_CRASH_POLLS = 10; 113 114 115 /** Reason for package failure could not be determined. */ 116 public static final int FAILURE_REASON_UNKNOWN = 0; 117 118 /** The package had a native crash. */ 119 public static final int FAILURE_REASON_NATIVE_CRASH = 1; 120 121 /** The package failed an explicit health check. */ 122 public static final int FAILURE_REASON_EXPLICIT_HEALTH_CHECK = 2; 123 124 /** The app crashed. */ 125 public static final int FAILURE_REASON_APP_CRASH = 3; 126 127 /** The app was not responding. */ 128 public static final int FAILURE_REASON_APP_NOT_RESPONDING = 4; 129 130 /** The device was boot looping. */ 131 public static final int FAILURE_REASON_BOOT_LOOP = 5; 132 133 /** @hide */ 134 @IntDef(prefix = { "FAILURE_REASON_" }, value = { 135 FAILURE_REASON_UNKNOWN, 136 FAILURE_REASON_NATIVE_CRASH, 137 FAILURE_REASON_EXPLICIT_HEALTH_CHECK, 138 FAILURE_REASON_APP_CRASH, 139 FAILURE_REASON_APP_NOT_RESPONDING, 140 FAILURE_REASON_BOOT_LOOP 141 }) 142 @Retention(RetentionPolicy.SOURCE) 143 public @interface FailureReasons {} 144 145 // Duration to count package failures before it resets to 0 146 @VisibleForTesting 147 static final int DEFAULT_TRIGGER_FAILURE_DURATION_MS = 148 (int) TimeUnit.MINUTES.toMillis(1); 149 // Number of package failures within the duration above before we notify observers 150 @VisibleForTesting 151 static final int DEFAULT_TRIGGER_FAILURE_COUNT = 5; 152 @VisibleForTesting 153 static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2); 154 // Sliding window for tracking how many mitigation calls were made for a package. 155 @VisibleForTesting 156 static final long DEFAULT_DEESCALATION_WINDOW_MS = TimeUnit.HOURS.toMillis(1); 157 // Whether explicit health checks are enabled or not 158 private static final boolean DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED = true; 159 160 @VisibleForTesting 161 static final int DEFAULT_BOOT_LOOP_TRIGGER_COUNT = 5; 162 163 static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10); 164 165 // Time needed to apply mitigation 166 private static final String MITIGATION_WINDOW_MS = 167 "persist.device_config.configuration.mitigation_window_ms"; 168 @VisibleForTesting 169 static final long DEFAULT_MITIGATION_WINDOW_MS = TimeUnit.SECONDS.toMillis(5); 170 171 // Threshold level at which or above user might experience significant disruption. 172 private static final String MAJOR_USER_IMPACT_LEVEL_THRESHOLD = 173 "persist.device_config.configuration.major_user_impact_level_threshold"; 174 private static final int DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD = 175 PackageHealthObserverImpact.USER_IMPACT_LEVEL_71; 176 177 // Comma separated list of all packages exempt from user impact level threshold. If a package 178 // in the list is crash looping, all the mitigations including factory reset will be performed. 179 private static final String PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD = 180 "persist.device_config.configuration.packages_exempt_from_impact_level_threshold"; 181 182 // Comma separated list of default packages exempt from user impact level threshold. 183 private static final String DEFAULT_PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD = 184 "com.android.systemui"; 185 186 private long mNumberOfNativeCrashPollsRemaining; 187 188 private static final int DB_VERSION = 1; 189 private static final String TAG_PACKAGE_WATCHDOG = "package-watchdog"; 190 private static final String TAG_PACKAGE = "package"; 191 private static final String TAG_OBSERVER = "observer"; 192 private static final String ATTR_VERSION = "version"; 193 private static final String ATTR_NAME = "name"; 194 private static final String ATTR_DURATION = "duration"; 195 private static final String ATTR_EXPLICIT_HEALTH_CHECK_DURATION = "health-check-duration"; 196 private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check"; 197 private static final String ATTR_MITIGATION_CALLS = "mitigation-calls"; 198 private static final String ATTR_MITIGATION_COUNT = "mitigation-count"; 199 200 // A file containing information about the current mitigation count in the case of a boot loop. 201 // This allows boot loop information to persist in the case of an fs-checkpoint being 202 // aborted. 203 private static final String METADATA_FILE = "/metadata/watchdog/mitigation_count.txt"; 204 205 /** 206 * EventLog tags used when logging into the event log. Note the values must be sync with 207 * frameworks/base/services/core/java/com/android/server/EventLogTags.logtags to get correct 208 * name translation. 209 */ 210 private static final int LOG_TAG_RESCUE_NOTE = 2900; 211 212 private static final Object sPackageWatchdogLock = new Object(); 213 @GuardedBy("sPackageWatchdogLock") 214 private static PackageWatchdog sPackageWatchdog; 215 216 private final Object mLock = new Object(); 217 // System server context 218 private final Context mContext; 219 // Handler to run short running tasks 220 private final Handler mShortTaskHandler; 221 // Handler for processing IO and long running tasks 222 private final Handler mLongTaskHandler; 223 // Contains (observer-name -> observer-handle) that have ever been registered from 224 // previous boots. Observers with all packages expired are periodically pruned. 225 // It is saved to disk on system shutdown and repouplated on startup so it survives reboots. 226 @GuardedBy("mLock") 227 private final ArrayMap<String, ObserverInternal> mAllObservers = new ArrayMap<>(); 228 // File containing the XML data of monitored packages /data/system/package-watchdog.xml 229 private final AtomicFile mPolicyFile; 230 private final ExplicitHealthCheckController mHealthCheckController; 231 private final ConnectivityModuleConnector mConnectivityModuleConnector; 232 private final Runnable mSyncRequests = this::syncRequests; 233 private final Runnable mSyncStateWithScheduledReason = this::syncStateWithScheduledReason; 234 private final Runnable mSaveToFile = this::saveToFile; 235 private final SystemClock mSystemClock; 236 private final BootThreshold mBootThreshold; 237 private final DeviceConfig.OnPropertiesChangedListener 238 mOnPropertyChangedListener = this::onPropertyChanged; 239 240 private final Set<String> mPackagesExemptFromImpactLevelThreshold = new ArraySet<>(); 241 242 // The set of packages that have been synced with the ExplicitHealthCheckController 243 @GuardedBy("mLock") 244 private Set<String> mRequestedHealthCheckPackages = new ArraySet<>(); 245 @GuardedBy("mLock") 246 private boolean mIsPackagesReady; 247 // Flag to control whether explicit health checks are supported or not 248 @GuardedBy("mLock") 249 private boolean mIsHealthCheckEnabled = DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED; 250 @GuardedBy("mLock") 251 private int mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_DURATION_MS; 252 @GuardedBy("mLock") 253 private int mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT; 254 // SystemClock#uptimeMillis when we last executed #syncState 255 // 0 if no prune is scheduled. 256 @GuardedBy("mLock") 257 private long mUptimeAtLastStateSync; 258 // If true, sync explicit health check packages with the ExplicitHealthCheckController. 259 @GuardedBy("mLock") 260 private boolean mSyncRequired = false; 261 262 @GuardedBy("mLock") 263 private long mLastMitigation = -1000000; 264 265 @FunctionalInterface 266 @VisibleForTesting 267 interface SystemClock { uptimeMillis()268 long uptimeMillis(); 269 } 270 PackageWatchdog(Context context)271 private PackageWatchdog(Context context) { 272 // Needs to be constructed inline 273 this(context, new AtomicFile( 274 new File(new File(Environment.getDataDirectory(), "system"), 275 "package-watchdog.xml")), 276 new Handler(Looper.myLooper()), BackgroundThread.getHandler(), 277 new ExplicitHealthCheckController(context), 278 ConnectivityModuleConnector.getInstance(), 279 android.os.SystemClock::uptimeMillis); 280 } 281 282 /** 283 * Creates a PackageWatchdog that allows injecting dependencies. 284 */ 285 @VisibleForTesting PackageWatchdog(Context context, AtomicFile policyFile, Handler shortTaskHandler, Handler longTaskHandler, ExplicitHealthCheckController controller, ConnectivityModuleConnector connectivityModuleConnector, SystemClock clock)286 PackageWatchdog(Context context, AtomicFile policyFile, Handler shortTaskHandler, 287 Handler longTaskHandler, ExplicitHealthCheckController controller, 288 ConnectivityModuleConnector connectivityModuleConnector, SystemClock clock) { 289 mContext = context; 290 mPolicyFile = policyFile; 291 mShortTaskHandler = shortTaskHandler; 292 mLongTaskHandler = longTaskHandler; 293 mHealthCheckController = controller; 294 mConnectivityModuleConnector = connectivityModuleConnector; 295 mSystemClock = clock; 296 mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS; 297 mBootThreshold = new BootThreshold(DEFAULT_BOOT_LOOP_TRIGGER_COUNT, 298 DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS); 299 300 loadFromFile(); 301 sPackageWatchdog = this; 302 } 303 304 /** 305 * Creating this temp constructor to match module constructor. 306 * Note: To be only used in tests. 307 * Creates a PackageWatchdog that allows injecting dependencies, 308 * except for connectivity module connector. 309 */ 310 @VisibleForTesting PackageWatchdog(Context context, AtomicFile policyFile, Handler shortTaskHandler, Handler longTaskHandler, ExplicitHealthCheckController controller, SystemClock clock)311 PackageWatchdog(Context context, AtomicFile policyFile, Handler shortTaskHandler, 312 Handler longTaskHandler, ExplicitHealthCheckController controller, 313 SystemClock clock) { 314 mContext = context; 315 mPolicyFile = policyFile; 316 mShortTaskHandler = shortTaskHandler; 317 mLongTaskHandler = longTaskHandler; 318 mHealthCheckController = controller; 319 mConnectivityModuleConnector = ConnectivityModuleConnector.getInstance(); 320 mSystemClock = clock; 321 mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS; 322 mBootThreshold = new BootThreshold(DEFAULT_BOOT_LOOP_TRIGGER_COUNT, 323 DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS); 324 325 loadFromFile(); 326 sPackageWatchdog = this; 327 } 328 329 /** Creates or gets singleton instance of PackageWatchdog. */ getInstance(@onNull Context context)330 public static @NonNull PackageWatchdog getInstance(@NonNull Context context) { 331 synchronized (sPackageWatchdogLock) { 332 if (sPackageWatchdog == null) { 333 new PackageWatchdog(context); 334 } 335 return sPackageWatchdog; 336 } 337 } 338 339 /** 340 * Called during boot to notify when packages are ready on the device so we can start 341 * binding. 342 * @hide 343 */ onPackagesReady()344 public void onPackagesReady() { 345 synchronized (mLock) { 346 mIsPackagesReady = true; 347 mHealthCheckController.setCallbacks(packageName -> onHealthCheckPassed(packageName), 348 packages -> onSupportedPackages(packages), 349 this::onSyncRequestNotified); 350 setPropertyChangedListenerLocked(); 351 updateConfigs(); 352 if (!Flags.refactorCrashrecovery()) { 353 registerConnectivityModuleHealthListener(); 354 } 355 } 356 } 357 358 /** 359 * Registers {@code observer} to listen for package failures. Add a new ObserverInternal for 360 * this observer if it does not already exist. 361 * 362 * <p>Observers are expected to call this on boot. It does not specify any packages but 363 * it will resume observing any packages requested from a previous boot. 364 * @hide 365 */ registerHealthObserver(Executor ignoredExecutor, PackageHealthObserver observer)366 public void registerHealthObserver(Executor ignoredExecutor, PackageHealthObserver observer) { 367 synchronized (mLock) { 368 ObserverInternal internalObserver = mAllObservers.get(observer.getUniqueIdentifier()); 369 if (internalObserver != null) { 370 internalObserver.registeredObserver = observer; 371 } else { 372 internalObserver = new ObserverInternal(observer.getUniqueIdentifier(), 373 new ArrayList<>()); 374 internalObserver.registeredObserver = observer; 375 mAllObservers.put(observer.getUniqueIdentifier(), internalObserver); 376 syncState("added new observer"); 377 } 378 } 379 } 380 381 /** 382 * Starts observing the health of the {@code packages} for {@code observer} and notifies 383 * {@code observer} of any package failures within the monitoring duration. 384 * 385 * <p>If monitoring a package supporting explicit health check, at the end of the monitoring 386 * duration if {@link #onHealthCheckPassed} was never called, 387 * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} will be called as if the package failed. 388 * 389 * <p>If {@code observer} is already monitoring a package in {@code packageNames}, 390 * the monitoring window of that package will be reset to {@code durationMs} and the health 391 * check state will be reset to a default depending on if the package is contained in 392 * {@link mPackagesWithExplicitHealthCheckEnabled}. 393 * 394 * <p>If {@code packageNames} is empty, this will be a no-op. 395 * 396 * <p>If {@code durationMs} is less than 1, a default monitoring duration 397 * {@link #DEFAULT_OBSERVING_DURATION_MS} will be used. 398 * @hide 399 */ startExplicitHealthCheck(List<String> packageNames, long durationMs, PackageHealthObserver observer)400 public void startExplicitHealthCheck(List<String> packageNames, long durationMs, 401 PackageHealthObserver observer) { 402 if (packageNames.isEmpty()) { 403 Slog.wtf(TAG, "No packages to observe, " + observer.getUniqueIdentifier()); 404 return; 405 } 406 if (durationMs < 1) { 407 Slog.wtf(TAG, "Invalid duration " + durationMs + "ms for observer " 408 + observer.getUniqueIdentifier() + ". Not observing packages " + packageNames); 409 durationMs = DEFAULT_OBSERVING_DURATION_MS; 410 } 411 412 List<MonitoredPackage> packages = new ArrayList<>(); 413 for (int i = 0; i < packageNames.size(); i++) { 414 // Health checks not available yet so health check state will start INACTIVE 415 MonitoredPackage pkg = newMonitoredPackage(packageNames.get(i), durationMs, false); 416 if (pkg != null) { 417 packages.add(pkg); 418 } else { 419 Slog.w(TAG, "Failed to create MonitoredPackage for pkg=" + packageNames.get(i)); 420 } 421 } 422 423 if (packages.isEmpty()) { 424 return; 425 } 426 427 // Sync before we add the new packages to the observers. This will #pruneObservers, 428 // causing any elapsed time to be deducted from all existing packages before we add new 429 // packages. This maintains the invariant that the elapsed time for ALL (new and existing) 430 // packages is the same. 431 mLongTaskHandler.post(() -> { 432 syncState("observing new packages"); 433 434 synchronized (mLock) { 435 ObserverInternal oldObserver = mAllObservers.get(observer.getUniqueIdentifier()); 436 if (oldObserver == null) { 437 Slog.d(TAG, observer.getUniqueIdentifier() + " started monitoring health " 438 + "of packages " + packageNames); 439 mAllObservers.put(observer.getUniqueIdentifier(), 440 new ObserverInternal(observer.getUniqueIdentifier(), packages)); 441 } else { 442 Slog.d(TAG, observer.getUniqueIdentifier() + " added the following " 443 + "packages to monitor " + packageNames); 444 oldObserver.updatePackagesLocked(packages); 445 } 446 } 447 448 // Register observer in case not already registered 449 registerHealthObserver(null, observer); 450 451 // Sync after we add the new packages to the observers. We may have received packges 452 // requiring an earlier schedule than we are currently scheduled for. 453 syncState("updated observers"); 454 }); 455 456 } 457 458 /** 459 * Unregisters {@code observer} from listening to package failure. 460 * Additionally, this stops observing any packages that may have previously been observed 461 * even from a previous boot. 462 * @hide 463 */ unregisterHealthObserver(PackageHealthObserver observer)464 public void unregisterHealthObserver(PackageHealthObserver observer) { 465 mLongTaskHandler.post(() -> { 466 synchronized (mLock) { 467 mAllObservers.remove(observer.getUniqueIdentifier()); 468 } 469 syncState("unregistering observer: " + observer.getUniqueIdentifier()); 470 }); 471 } 472 473 /** 474 * Called when a process fails due to a crash, ANR or explicit health check. 475 * 476 * <p>For each package contained in the process, one registered observer with the least user 477 * impact will be notified for mitigation. 478 * 479 * <p>This method could be called frequently if there is a severe problem on the device. 480 */ notifyPackageFailure(@onNull List<VersionedPackage> packages, @FailureReasons int failureReason)481 public void notifyPackageFailure(@NonNull List<VersionedPackage> packages, 482 @FailureReasons int failureReason) { 483 if (packages == null) { 484 Slog.w(TAG, "Could not resolve a list of failing packages"); 485 return; 486 } 487 synchronized (mLock) { 488 final long now = mSystemClock.uptimeMillis(); 489 if (Flags.recoverabilityDetection()) { 490 if (now >= mLastMitigation 491 && (now - mLastMitigation) < getMitigationWindowMs()) { 492 Slog.i(TAG, "Skipping notifyPackageFailure mitigation"); 493 return; 494 } 495 } 496 } 497 mLongTaskHandler.post(() -> { 498 synchronized (mLock) { 499 if (mAllObservers.isEmpty()) { 500 return; 501 } 502 boolean requiresImmediateAction = (failureReason == FAILURE_REASON_NATIVE_CRASH 503 || failureReason == FAILURE_REASON_EXPLICIT_HEALTH_CHECK); 504 if (requiresImmediateAction) { 505 handleFailureImmediately(packages, failureReason); 506 } else { 507 for (int pIndex = 0; pIndex < packages.size(); pIndex++) { 508 VersionedPackage versionedPackage = packages.get(pIndex); 509 // Observer that will receive failure for versionedPackage 510 PackageHealthObserver currentObserverToNotify = null; 511 int currentObserverImpact = Integer.MAX_VALUE; 512 MonitoredPackage currentMonitoredPackage = null; 513 514 // Find observer with least user impact 515 for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) { 516 ObserverInternal observer = mAllObservers.valueAt(oIndex); 517 PackageHealthObserver registeredObserver = observer.registeredObserver; 518 if (registeredObserver != null 519 && observer.notifyPackageFailureLocked( 520 versionedPackage.getPackageName())) { 521 MonitoredPackage p = observer.getMonitoredPackage( 522 versionedPackage.getPackageName()); 523 int mitigationCount = 1; 524 if (p != null) { 525 mitigationCount = p.getMitigationCountLocked() + 1; 526 } 527 int impact = registeredObserver.onHealthCheckFailed( 528 versionedPackage, failureReason, mitigationCount); 529 if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0 530 && impact < currentObserverImpact) { 531 currentObserverToNotify = registeredObserver; 532 currentObserverImpact = impact; 533 currentMonitoredPackage = p; 534 } 535 } 536 } 537 538 // Execute action with least user impact 539 if (currentObserverToNotify != null) { 540 int mitigationCount = 1; 541 if (currentMonitoredPackage != null) { 542 currentMonitoredPackage.noteMitigationCallLocked(); 543 mitigationCount = 544 currentMonitoredPackage.getMitigationCountLocked(); 545 } 546 if (Flags.recoverabilityDetection()) { 547 maybeExecute(currentObserverToNotify, versionedPackage, 548 failureReason, currentObserverImpact, mitigationCount); 549 } else { 550 currentObserverToNotify.onExecuteHealthCheckMitigation( 551 versionedPackage, failureReason, mitigationCount); 552 } 553 } 554 } 555 } 556 } 557 }); 558 } 559 560 /** 561 * For native crashes or explicit health check failures, call directly into each observer to 562 * mitigate the error without going through failure threshold logic. 563 */ handleFailureImmediately(List<VersionedPackage> packages, @FailureReasons int failureReason)564 private void handleFailureImmediately(List<VersionedPackage> packages, 565 @FailureReasons int failureReason) { 566 VersionedPackage failingPackage = packages.size() > 0 ? packages.get(0) : null; 567 PackageHealthObserver currentObserverToNotify = null; 568 int currentObserverImpact = Integer.MAX_VALUE; 569 for (ObserverInternal observer: mAllObservers.values()) { 570 PackageHealthObserver registeredObserver = observer.registeredObserver; 571 if (registeredObserver != null) { 572 int impact = registeredObserver.onHealthCheckFailed( 573 failingPackage, failureReason, 1); 574 if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0 575 && impact < currentObserverImpact) { 576 currentObserverToNotify = registeredObserver; 577 currentObserverImpact = impact; 578 } 579 } 580 } 581 if (currentObserverToNotify != null) { 582 if (Flags.recoverabilityDetection()) { 583 maybeExecute(currentObserverToNotify, failingPackage, failureReason, 584 currentObserverImpact, /*mitigationCount=*/ 1); 585 } else { 586 currentObserverToNotify.onExecuteHealthCheckMitigation(failingPackage, 587 failureReason, 1); 588 } 589 } 590 } 591 maybeExecute(PackageHealthObserver currentObserverToNotify, VersionedPackage versionedPackage, @FailureReasons int failureReason, int currentObserverImpact, int mitigationCount)592 private void maybeExecute(PackageHealthObserver currentObserverToNotify, 593 VersionedPackage versionedPackage, 594 @FailureReasons int failureReason, 595 int currentObserverImpact, 596 int mitigationCount) { 597 if (allowMitigations(currentObserverImpact, versionedPackage)) { 598 synchronized (mLock) { 599 mLastMitigation = mSystemClock.uptimeMillis(); 600 } 601 currentObserverToNotify.onExecuteHealthCheckMitigation(versionedPackage, failureReason, 602 mitigationCount); 603 } 604 } 605 allowMitigations(int currentObserverImpact, VersionedPackage versionedPackage)606 private boolean allowMitigations(int currentObserverImpact, 607 VersionedPackage versionedPackage) { 608 return currentObserverImpact < getUserImpactLevelLimit() 609 || getPackagesExemptFromImpactLevelThreshold().contains( 610 versionedPackage.getPackageName()); 611 } 612 getMitigationWindowMs()613 private long getMitigationWindowMs() { 614 return SystemProperties.getLong(MITIGATION_WINDOW_MS, DEFAULT_MITIGATION_WINDOW_MS); 615 } 616 617 618 /** 619 * Called when the system server boots. If the system server is detected to be in a boot loop, 620 * query each observer and perform the mitigation action with the lowest user impact. 621 * 622 * Note: PackageWatchdog considers system_server restart loop as bootloop. Full reboots 623 * are not counted in bootloop. 624 * @hide 625 */ 626 @SuppressWarnings("GuardedBy") noteBoot()627 public void noteBoot() { 628 synchronized (mLock) { 629 // if boot count has reached threshold, start mitigation. 630 // We wait until threshold number of restarts only for the first time. Perform 631 // mitigations for every restart after that. 632 boolean mitigate = mBootThreshold.incrementAndTest(); 633 if (mitigate) { 634 if (!Flags.recoverabilityDetection()) { 635 mBootThreshold.reset(); 636 } 637 int mitigationCount = mBootThreshold.getMitigationCount() + 1; 638 PackageHealthObserver currentObserverToNotify = null; 639 ObserverInternal currentObserverInternal = null; 640 int currentObserverImpact = Integer.MAX_VALUE; 641 for (int i = 0; i < mAllObservers.size(); i++) { 642 final ObserverInternal observer = mAllObservers.valueAt(i); 643 PackageHealthObserver registeredObserver = observer.registeredObserver; 644 if (registeredObserver != null) { 645 int impact = Flags.recoverabilityDetection() 646 ? registeredObserver.onBootLoop( 647 observer.getBootMitigationCount() + 1) 648 : registeredObserver.onBootLoop(mitigationCount); 649 if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0 650 && impact < currentObserverImpact) { 651 currentObserverToNotify = registeredObserver; 652 currentObserverInternal = observer; 653 currentObserverImpact = impact; 654 } 655 } 656 } 657 if (currentObserverToNotify != null) { 658 if (Flags.recoverabilityDetection()) { 659 int currentObserverMitigationCount = 660 currentObserverInternal.getBootMitigationCount() + 1; 661 currentObserverInternal.setBootMitigationCount( 662 currentObserverMitigationCount); 663 saveAllObserversBootMitigationCountToMetadata(METADATA_FILE); 664 currentObserverToNotify.onExecuteBootLoopMitigation( 665 currentObserverMitigationCount); 666 } else { 667 mBootThreshold.setMitigationCount(mitigationCount); 668 mBootThreshold.saveMitigationCountToMetadata(); 669 currentObserverToNotify.onExecuteBootLoopMitigation(mitigationCount); 670 } 671 } 672 } 673 } 674 } 675 676 // TODO(b/120598832): Optimize write? Maybe only write a separate smaller file? Also 677 // avoid holding lock? 678 // This currently adds about 7ms extra to shutdown thread 679 /** @hide Writes the package information to file during shutdown. */ writeNow()680 public void writeNow() { 681 synchronized (mLock) { 682 // Must only run synchronous tasks as this runs on the ShutdownThread and no other 683 // thread is guaranteed to run during shutdown. 684 if (!mAllObservers.isEmpty()) { 685 mLongTaskHandler.removeCallbacks(mSaveToFile); 686 pruneObserversLocked(); 687 saveToFile(); 688 Slog.i(TAG, "Last write to update package durations"); 689 } 690 } 691 } 692 693 /** 694 * Enables or disables explicit health checks. 695 * <p> If explicit health checks are enabled, the health check service is started. 696 * <p> If explicit health checks are disabled, pending explicit health check requests are 697 * passed and the health check service is stopped. 698 */ setExplicitHealthCheckEnabled(boolean enabled)699 private void setExplicitHealthCheckEnabled(boolean enabled) { 700 synchronized (mLock) { 701 mIsHealthCheckEnabled = enabled; 702 mHealthCheckController.setEnabled(enabled); 703 mSyncRequired = true; 704 // Prune to update internal state whenever health check is enabled/disabled 705 syncState("health check state " + (enabled ? "enabled" : "disabled")); 706 } 707 } 708 709 /** 710 * This method should be only called on mShortTaskHandler, since it modifies 711 * {@link #mNumberOfNativeCrashPollsRemaining}. 712 */ checkAndMitigateNativeCrashes()713 private void checkAndMitigateNativeCrashes() { 714 mNumberOfNativeCrashPollsRemaining--; 715 // Check if native watchdog reported a crash 716 if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) { 717 // We rollback all available low impact rollbacks when crash is unattributable 718 notifyPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH); 719 // we stop polling after an attempt to execute rollback, regardless of whether the 720 // attempt succeeds or not 721 } else { 722 if (mNumberOfNativeCrashPollsRemaining > 0) { 723 mShortTaskHandler.postDelayed(() -> checkAndMitigateNativeCrashes(), 724 NATIVE_CRASH_POLLING_INTERVAL_MILLIS); 725 } 726 } 727 } 728 729 /** 730 * Since this method can eventually trigger a rollback, it should be called 731 * only once boot has completed {@code onBootCompleted} and not earlier, because the install 732 * session must be entirely completed before we try to rollback. 733 * @hide 734 */ scheduleCheckAndMitigateNativeCrashes()735 public void scheduleCheckAndMitigateNativeCrashes() { 736 Slog.i(TAG, "Scheduling " + mNumberOfNativeCrashPollsRemaining + " polls to check " 737 + "and mitigate native crashes"); 738 mShortTaskHandler.post(()->checkAndMitigateNativeCrashes()); 739 } 740 getUserImpactLevelLimit()741 private int getUserImpactLevelLimit() { 742 return SystemProperties.getInt(MAJOR_USER_IMPACT_LEVEL_THRESHOLD, 743 DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD); 744 } 745 getPackagesExemptFromImpactLevelThreshold()746 private Set<String> getPackagesExemptFromImpactLevelThreshold() { 747 if (mPackagesExemptFromImpactLevelThreshold.isEmpty()) { 748 String packageNames = SystemProperties.get(PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD, 749 DEFAULT_PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD); 750 return Set.of(packageNames.split("\\s*,\\s*")); 751 } 752 return mPackagesExemptFromImpactLevelThreshold; 753 } 754 755 /** 756 * Indicates that the result of a mitigation executed during 757 * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} or 758 * {@link PackageHealthObserver#onExecuteBootLoopMitigation} is unknown. 759 */ 760 public static final int MITIGATION_RESULT_UNKNOWN = 761 ObserverMitigationResult.MITIGATION_RESULT_UNKNOWN; 762 763 /** 764 * Indicates that a mitigation was successfully triggered or executed during 765 * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} or 766 * {@link PackageHealthObserver#onExecuteBootLoopMitigation}. 767 */ 768 public static final int MITIGATION_RESULT_SUCCESS = 769 ObserverMitigationResult.MITIGATION_RESULT_SUCCESS; 770 771 /** 772 * Indicates that a mitigation executed during 773 * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} or 774 * {@link PackageHealthObserver#onExecuteBootLoopMitigation} was skipped. 775 */ 776 public static final int MITIGATION_RESULT_SKIPPED = 777 ObserverMitigationResult.MITIGATION_RESULT_SKIPPED; 778 779 /** 780 * Indicates that a mitigation executed during 781 * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} or 782 * {@link PackageHealthObserver#onExecuteBootLoopMitigation} failed, 783 * but the failure is potentially retryable. 784 */ 785 public static final int MITIGATION_RESULT_FAILURE_RETRYABLE = 786 ObserverMitigationResult.MITIGATION_RESULT_FAILURE_RETRYABLE; 787 788 /** 789 * Indicates that a mitigation executed during 790 * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} or 791 * {@link PackageHealthObserver#onExecuteBootLoopMitigation} failed, 792 * and the failure is not retryable. 793 */ 794 public static final int MITIGATION_RESULT_FAILURE_NON_RETRYABLE = 795 ObserverMitigationResult.MITIGATION_RESULT_FAILURE_NON_RETRYABLE; 796 797 /** 798 * Possible return values of the for mitigations executed during 799 * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} and 800 * {@link PackageHealthObserver#onExecuteBootLoopMitigation}. 801 * @hide 802 */ 803 @Retention(SOURCE) 804 @IntDef(prefix = "MITIGATION_RESULT_", value = { 805 ObserverMitigationResult.MITIGATION_RESULT_UNKNOWN, 806 ObserverMitigationResult.MITIGATION_RESULT_SUCCESS, 807 ObserverMitigationResult.MITIGATION_RESULT_SKIPPED, 808 ObserverMitigationResult.MITIGATION_RESULT_FAILURE_RETRYABLE, 809 ObserverMitigationResult.MITIGATION_RESULT_FAILURE_NON_RETRYABLE, 810 }) 811 public @interface ObserverMitigationResult { 812 int MITIGATION_RESULT_UNKNOWN = 0; 813 int MITIGATION_RESULT_SUCCESS = 1; 814 int MITIGATION_RESULT_SKIPPED = 2; 815 int MITIGATION_RESULT_FAILURE_RETRYABLE = 3; 816 int MITIGATION_RESULT_FAILURE_NON_RETRYABLE = 4; 817 } 818 819 /** Possible severity values of the user impact of a 820 * {@link PackageHealthObserver#onExecuteHealthCheckMitigation}. 821 * @hide 822 */ 823 @Retention(SOURCE) 824 @IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_LEVEL_0, 825 PackageHealthObserverImpact.USER_IMPACT_LEVEL_10, 826 PackageHealthObserverImpact.USER_IMPACT_LEVEL_20, 827 PackageHealthObserverImpact.USER_IMPACT_LEVEL_30, 828 PackageHealthObserverImpact.USER_IMPACT_LEVEL_40, 829 PackageHealthObserverImpact.USER_IMPACT_LEVEL_50, 830 PackageHealthObserverImpact.USER_IMPACT_LEVEL_70, 831 PackageHealthObserverImpact.USER_IMPACT_LEVEL_71, 832 PackageHealthObserverImpact.USER_IMPACT_LEVEL_75, 833 PackageHealthObserverImpact.USER_IMPACT_LEVEL_80, 834 PackageHealthObserverImpact.USER_IMPACT_LEVEL_90, 835 PackageHealthObserverImpact.USER_IMPACT_LEVEL_100}) 836 public @interface PackageHealthObserverImpact { 837 /** No action to take. */ 838 int USER_IMPACT_LEVEL_0 = 0; 839 /* Action has low user impact, user of a device will barely notice. */ 840 int USER_IMPACT_LEVEL_10 = 10; 841 /* Actions having medium user impact, user of a device will likely notice. */ 842 int USER_IMPACT_LEVEL_20 = 20; 843 int USER_IMPACT_LEVEL_30 = 30; 844 int USER_IMPACT_LEVEL_40 = 40; 845 int USER_IMPACT_LEVEL_50 = 50; 846 int USER_IMPACT_LEVEL_70 = 70; 847 /* Action has high user impact, a last resort, user of a device will be very frustrated. */ 848 int USER_IMPACT_LEVEL_71 = 71; 849 int USER_IMPACT_LEVEL_75 = 75; 850 int USER_IMPACT_LEVEL_80 = 80; 851 int USER_IMPACT_LEVEL_90 = 90; 852 int USER_IMPACT_LEVEL_100 = 100; 853 } 854 855 /** Register instances of this interface to receive notifications on package failure. */ 856 public interface PackageHealthObserver { 857 /** 858 * Called when health check fails for the {@code versionedPackage}. 859 * 860 * @param versionedPackage the package that is failing. This may be null if a native 861 * service is crashing. 862 * @param failureReason the type of failure that is occurring. 863 * @param mitigationCount the number of times mitigation has been called for this package 864 * (including this time). 865 * 866 * 867 * @return any one of {@link PackageHealthObserverImpact} to express the impact 868 * to the user on {@link #onExecuteHealthCheckMitigation} 869 */ onHealthCheckFailed( @ullable VersionedPackage versionedPackage, @FailureReasons int failureReason, int mitigationCount)870 @PackageHealthObserverImpact int onHealthCheckFailed( 871 @Nullable VersionedPackage versionedPackage, 872 @FailureReasons int failureReason, 873 int mitigationCount); 874 875 /** 876 * This would be called after {@link #onHealthCheckFailed}. 877 * This is called only if current observer returned least impact mitigation for failed 878 * health check. 879 * 880 * @param versionedPackage the package that is failing. This may be null if a native 881 * service is crashing. 882 * @param failureReason the type of failure that is occurring. 883 * @param mitigationCount the number of times mitigation has been called for this package 884 * (including this time). 885 * @return {@link #MITIGATION_RESULT_SUCCESS} if the mitigation was successful, 886 * {@link #MITIGATION_RESULT_FAILURE_RETRYABLE} if the mitigation failed but can be 887 * retried, 888 * {@link #MITIGATION_RESULT_FAILURE_NON_RETRYABLE} if the mitigation failed and 889 * cannot be retried, 890 * {@link #MITIGATION_RESULT_UNKNOWN} if the result of the mitigation is unknown, 891 * or {@link #MITIGATION_RESULT_SKIPPED} if the mitigation was skipped. 892 */ onExecuteHealthCheckMitigation( @ullable VersionedPackage versionedPackage, @FailureReasons int failureReason, int mitigationCount)893 @ObserverMitigationResult int onExecuteHealthCheckMitigation( 894 @Nullable VersionedPackage versionedPackage, 895 @FailureReasons int failureReason, int mitigationCount); 896 897 898 /** 899 * Called when the system server has booted several times within a window of time, defined 900 * by {@link #mBootThreshold} 901 * 902 * @param mitigationCount the number of times mitigation has been attempted for this 903 * boot loop (including this time). 904 */ onBootLoop(int mitigationCount)905 default @PackageHealthObserverImpact int onBootLoop(int mitigationCount) { 906 return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; 907 } 908 909 /** 910 * This would be called after {@link #onBootLoop}. 911 * This is called only if current observer returned least impact mitigation for fixing 912 * boot loop. 913 * 914 * @param mitigationCount the number of times mitigation has been attempted for this 915 * boot loop (including this time). 916 * 917 * @return {@link #MITIGATION_RESULT_SUCCESS} if the mitigation was successful, 918 * {@link #MITIGATION_RESULT_FAILURE_RETRYABLE} if the mitigation failed but can be 919 * retried, 920 * {@link #MITIGATION_RESULT_FAILURE_NON_RETRYABLE} if the mitigation failed and 921 * cannot be retried, 922 * {@link #MITIGATION_RESULT_UNKNOWN} if the result of the mitigation is unknown, 923 * or {@link #MITIGATION_RESULT_SKIPPED} if the mitigation was skipped. 924 */ onExecuteBootLoopMitigation(int mitigationCount)925 default @ObserverMitigationResult int onExecuteBootLoopMitigation(int mitigationCount) { 926 return ObserverMitigationResult.MITIGATION_RESULT_SKIPPED; 927 } 928 929 // TODO(b/120598832): Ensure uniqueness? 930 /** 931 * Identifier for the observer, should not change across device updates otherwise the 932 * watchdog may drop observing packages with the old name. 933 */ getUniqueIdentifier()934 @NonNull String getUniqueIdentifier(); 935 936 /** 937 * An observer will not be pruned if this is set, even if the observer is not explicitly 938 * monitoring any packages. 939 */ isPersistent()940 default boolean isPersistent() { 941 return false; 942 } 943 944 /** 945 * Returns {@code true} if this observer wishes to observe the given package, {@code false} 946 * otherwise 947 * 948 * <p> A persistent observer may choose to start observing certain failing packages, even if 949 * it has not explicitly asked to watch the package with {@link #startExplicitHealthCheck}. 950 */ mayObservePackage(@onNull String packageName)951 default boolean mayObservePackage(@NonNull String packageName) { 952 return false; 953 } 954 } 955 956 @VisibleForTesting getTriggerFailureCount()957 long getTriggerFailureCount() { 958 synchronized (mLock) { 959 return mTriggerFailureCount; 960 } 961 } 962 963 @VisibleForTesting getTriggerFailureDurationMs()964 long getTriggerFailureDurationMs() { 965 synchronized (mLock) { 966 return mTriggerFailureDurationMs; 967 } 968 } 969 970 /** 971 * Serializes and syncs health check requests with the {@link ExplicitHealthCheckController}. 972 */ syncRequestsAsync()973 private void syncRequestsAsync() { 974 mShortTaskHandler.removeCallbacks(mSyncRequests); 975 mShortTaskHandler.post(mSyncRequests); 976 } 977 978 /** 979 * Syncs health check requests with the {@link ExplicitHealthCheckController}. 980 * Calls to this must be serialized. 981 * 982 * @see #syncRequestsAsync 983 */ syncRequests()984 private void syncRequests() { 985 boolean syncRequired = false; 986 synchronized (mLock) { 987 if (mIsPackagesReady) { 988 Set<String> packages = getPackagesPendingHealthChecksLocked(); 989 if (mSyncRequired || !packages.equals(mRequestedHealthCheckPackages) 990 || packages.isEmpty()) { 991 syncRequired = true; 992 mRequestedHealthCheckPackages = packages; 993 } 994 } // else, we will sync requests when packages become ready 995 } 996 997 // Call outside lock to avoid holding lock when calling into the controller. 998 if (syncRequired) { 999 Slog.i(TAG, "Syncing health check requests for packages: " 1000 + mRequestedHealthCheckPackages); 1001 mHealthCheckController.syncRequests(mRequestedHealthCheckPackages); 1002 mSyncRequired = false; 1003 } 1004 } 1005 1006 /** 1007 * Updates the observers monitoring {@code packageName} that explicit health check has passed. 1008 * 1009 * <p> This update is strictly for registered observers at the time of the call 1010 * Observers that register after this signal will have no knowledge of prior signals and will 1011 * effectively behave as if the explicit health check hasn't passed for {@code packageName}. 1012 * 1013 * <p> {@code packageName} can still be considered failed if reported by 1014 * {@link #notifyPackageFailureLocked} before the package expires. 1015 * 1016 * <p> Triggered by components outside the system server when they are fully functional after an 1017 * update. 1018 */ onHealthCheckPassed(String packageName)1019 private void onHealthCheckPassed(String packageName) { 1020 Slog.i(TAG, "Health check passed for package: " + packageName); 1021 boolean isStateChanged = false; 1022 1023 synchronized (mLock) { 1024 for (int observerIdx = 0; observerIdx < mAllObservers.size(); observerIdx++) { 1025 ObserverInternal observer = mAllObservers.valueAt(observerIdx); 1026 MonitoredPackage monitoredPackage = observer.getMonitoredPackage(packageName); 1027 1028 if (monitoredPackage != null) { 1029 int oldState = monitoredPackage.getHealthCheckStateLocked(); 1030 int newState = monitoredPackage.tryPassHealthCheckLocked(); 1031 isStateChanged |= oldState != newState; 1032 } 1033 } 1034 } 1035 1036 if (isStateChanged) { 1037 syncState("health check passed for " + packageName); 1038 } 1039 } 1040 onSupportedPackages(List<PackageConfig> supportedPackages)1041 private void onSupportedPackages(List<PackageConfig> supportedPackages) { 1042 boolean isStateChanged = false; 1043 1044 Map<String, Long> supportedPackageTimeouts = new ArrayMap<>(); 1045 Iterator<PackageConfig> it = supportedPackages.iterator(); 1046 while (it.hasNext()) { 1047 PackageConfig info = it.next(); 1048 supportedPackageTimeouts.put(info.getPackageName(), info.getHealthCheckTimeoutMillis()); 1049 } 1050 1051 synchronized (mLock) { 1052 Slog.d(TAG, "Received supported packages " + supportedPackages); 1053 Iterator<ObserverInternal> oit = mAllObservers.values().iterator(); 1054 while (oit.hasNext()) { 1055 Iterator<MonitoredPackage> pit = oit.next().getMonitoredPackages() 1056 .values().iterator(); 1057 while (pit.hasNext()) { 1058 MonitoredPackage monitoredPackage = pit.next(); 1059 String packageName = monitoredPackage.getName(); 1060 int oldState = monitoredPackage.getHealthCheckStateLocked(); 1061 int newState; 1062 1063 if (supportedPackageTimeouts.containsKey(packageName)) { 1064 // Supported packages become ACTIVE if currently INACTIVE 1065 newState = monitoredPackage.setHealthCheckActiveLocked( 1066 supportedPackageTimeouts.get(packageName)); 1067 } else { 1068 // Unsupported packages are marked as PASSED unless already FAILED 1069 newState = monitoredPackage.tryPassHealthCheckLocked(); 1070 } 1071 isStateChanged |= oldState != newState; 1072 } 1073 } 1074 } 1075 1076 if (isStateChanged) { 1077 syncState("updated health check supported packages " + supportedPackages); 1078 } 1079 } 1080 onSyncRequestNotified()1081 private void onSyncRequestNotified() { 1082 synchronized (mLock) { 1083 mSyncRequired = true; 1084 syncRequestsAsync(); 1085 } 1086 } 1087 1088 @GuardedBy("mLock") getPackagesPendingHealthChecksLocked()1089 private Set<String> getPackagesPendingHealthChecksLocked() { 1090 Set<String> packages = new ArraySet<>(); 1091 Iterator<ObserverInternal> oit = mAllObservers.values().iterator(); 1092 while (oit.hasNext()) { 1093 ObserverInternal observer = oit.next(); 1094 Iterator<MonitoredPackage> pit = 1095 observer.getMonitoredPackages().values().iterator(); 1096 while (pit.hasNext()) { 1097 MonitoredPackage monitoredPackage = pit.next(); 1098 String packageName = monitoredPackage.getName(); 1099 if (monitoredPackage.isPendingHealthChecksLocked()) { 1100 packages.add(packageName); 1101 } 1102 } 1103 } 1104 return packages; 1105 } 1106 1107 /** 1108 * Syncs the state of the observers. 1109 * 1110 * <p> Prunes all observers, saves new state to disk, syncs health check requests with the 1111 * health check service and schedules the next state sync. 1112 */ syncState(String reason)1113 private void syncState(String reason) { 1114 synchronized (mLock) { 1115 Slog.i(TAG, "Syncing state, reason: " + reason); 1116 pruneObserversLocked(); 1117 1118 saveToFileAsync(); 1119 syncRequestsAsync(); 1120 1121 // Done syncing state, schedule the next state sync 1122 scheduleNextSyncStateLocked(); 1123 } 1124 } 1125 syncStateWithScheduledReason()1126 private void syncStateWithScheduledReason() { 1127 syncState("scheduled"); 1128 } 1129 1130 @GuardedBy("mLock") scheduleNextSyncStateLocked()1131 private void scheduleNextSyncStateLocked() { 1132 long durationMs = getNextStateSyncMillisLocked(); 1133 mShortTaskHandler.removeCallbacks(mSyncStateWithScheduledReason); 1134 if (durationMs == Long.MAX_VALUE) { 1135 Slog.i(TAG, "Cancelling state sync, nothing to sync"); 1136 mUptimeAtLastStateSync = 0; 1137 } else { 1138 mUptimeAtLastStateSync = mSystemClock.uptimeMillis(); 1139 mShortTaskHandler.postDelayed(mSyncStateWithScheduledReason, durationMs); 1140 } 1141 } 1142 1143 /** 1144 * Returns the next duration in millis to sync the watchdog state. 1145 * 1146 * @returns Long#MAX_VALUE if there are no observed packages. 1147 */ 1148 @GuardedBy("mLock") getNextStateSyncMillisLocked()1149 private long getNextStateSyncMillisLocked() { 1150 long shortestDurationMs = Long.MAX_VALUE; 1151 for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) { 1152 ArrayMap<String, MonitoredPackage> packages = mAllObservers.valueAt(oIndex) 1153 .getMonitoredPackages(); 1154 for (int pIndex = 0; pIndex < packages.size(); pIndex++) { 1155 MonitoredPackage mp = packages.valueAt(pIndex); 1156 long duration = mp.getShortestScheduleDurationMsLocked(); 1157 if (duration < shortestDurationMs) { 1158 shortestDurationMs = duration; 1159 } 1160 } 1161 } 1162 return shortestDurationMs; 1163 } 1164 1165 /** 1166 * Removes {@code elapsedMs} milliseconds from all durations on monitored packages 1167 * and updates other internal state. 1168 */ 1169 @GuardedBy("mLock") pruneObserversLocked()1170 private void pruneObserversLocked() { 1171 long elapsedMs = mUptimeAtLastStateSync == 0 1172 ? 0 : mSystemClock.uptimeMillis() - mUptimeAtLastStateSync; 1173 if (elapsedMs <= 0) { 1174 Slog.i(TAG, "Not pruning observers, elapsed time: " + elapsedMs + "ms"); 1175 return; 1176 } 1177 1178 Iterator<ObserverInternal> it = mAllObservers.values().iterator(); 1179 while (it.hasNext()) { 1180 ObserverInternal observer = it.next(); 1181 Set<MonitoredPackage> failedPackages = 1182 observer.prunePackagesLocked(elapsedMs); 1183 if (!failedPackages.isEmpty()) { 1184 onHealthCheckFailed(observer, failedPackages); 1185 } 1186 if (observer.getMonitoredPackages().isEmpty() && (observer.registeredObserver == null 1187 || !observer.registeredObserver.isPersistent())) { 1188 Slog.i(TAG, "Discarding observer " + observer.name + ". All packages expired"); 1189 it.remove(); 1190 } 1191 } 1192 } 1193 onHealthCheckFailed(ObserverInternal observer, Set<MonitoredPackage> failedPackages)1194 private void onHealthCheckFailed(ObserverInternal observer, 1195 Set<MonitoredPackage> failedPackages) { 1196 mLongTaskHandler.post(() -> { 1197 synchronized (mLock) { 1198 PackageHealthObserver registeredObserver = observer.registeredObserver; 1199 if (registeredObserver != null) { 1200 Iterator<MonitoredPackage> it = failedPackages.iterator(); 1201 while (it.hasNext()) { 1202 VersionedPackage versionedPkg = getVersionedPackage(it.next().getName()); 1203 if (versionedPkg != null) { 1204 Slog.i(TAG, 1205 "Explicit health check failed for package " + versionedPkg); 1206 registeredObserver.onExecuteHealthCheckMitigation(versionedPkg, 1207 PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK, 1); 1208 } 1209 } 1210 } 1211 } 1212 }); 1213 } 1214 1215 /** 1216 * Gets PackageInfo for the given package. Matches any user and apex. 1217 * 1218 * @throws PackageManager.NameNotFoundException if no such package is installed. 1219 */ getPackageInfo(String packageName)1220 private PackageInfo getPackageInfo(String packageName) 1221 throws PackageManager.NameNotFoundException { 1222 PackageManager pm = mContext.getPackageManager(); 1223 try { 1224 // The MATCH_ANY_USER flag doesn't mix well with the MATCH_APEX 1225 // flag, so make two separate attempts to get the package info. 1226 // We don't need both flags at the same time because we assume 1227 // apex files are always installed for all users. 1228 return pm.getPackageInfo(packageName, PackageManager.MATCH_ANY_USER); 1229 } catch (PackageManager.NameNotFoundException e) { 1230 return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX); 1231 } 1232 } 1233 1234 @Nullable getVersionedPackage(String packageName)1235 private VersionedPackage getVersionedPackage(String packageName) { 1236 final PackageManager pm = mContext.getPackageManager(); 1237 if (pm == null || TextUtils.isEmpty(packageName)) { 1238 return null; 1239 } 1240 try { 1241 final long versionCode = getPackageInfo(packageName).getLongVersionCode(); 1242 return new VersionedPackage(packageName, versionCode); 1243 } catch (PackageManager.NameNotFoundException e) { 1244 return null; 1245 } 1246 } 1247 1248 /** 1249 * Loads mAllObservers from file. 1250 * 1251 * <p>Note that this is <b>not</b> thread safe and should only called be called 1252 * from the constructor. 1253 */ loadFromFile()1254 private void loadFromFile() { 1255 InputStream infile = null; 1256 mAllObservers.clear(); 1257 try { 1258 infile = mPolicyFile.openRead(); 1259 final TypedXmlPullParser parser = Xml.resolvePullParser(infile); 1260 XmlUtils.beginDocument(parser, TAG_PACKAGE_WATCHDOG); 1261 int outerDepth = parser.getDepth(); 1262 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 1263 ObserverInternal observer = ObserverInternal.read(parser, this); 1264 if (observer != null) { 1265 mAllObservers.put(observer.name, observer); 1266 } 1267 } 1268 } catch (FileNotFoundException e) { 1269 // Nothing to monitor 1270 } catch (IOException | NumberFormatException | XmlPullParserException e) { 1271 Slog.wtf(TAG, "Unable to read monitored packages, deleting file", e); 1272 mPolicyFile.delete(); 1273 } finally { 1274 IoUtils.closeQuietly(infile); 1275 } 1276 } 1277 onPropertyChanged(DeviceConfig.Properties properties)1278 private void onPropertyChanged(DeviceConfig.Properties properties) { 1279 try { 1280 updateConfigs(); 1281 } catch (Exception ignore) { 1282 Slog.w(TAG, "Failed to reload device config changes"); 1283 } 1284 } 1285 1286 /** Adds a {@link DeviceConfig#OnPropertiesChangedListener}. */ setPropertyChangedListenerLocked()1287 private void setPropertyChangedListenerLocked() { 1288 DeviceConfig.addOnPropertiesChangedListener( 1289 DeviceConfig.NAMESPACE_ROLLBACK, 1290 mContext.getMainExecutor(), 1291 mOnPropertyChangedListener); 1292 } 1293 1294 @VisibleForTesting removePropertyChangedListener()1295 void removePropertyChangedListener() { 1296 DeviceConfig.removeOnPropertiesChangedListener(mOnPropertyChangedListener); 1297 } 1298 1299 /** 1300 * Health check is enabled or disabled after reading the flags 1301 * from DeviceConfig. 1302 */ 1303 @VisibleForTesting updateConfigs()1304 void updateConfigs() { 1305 synchronized (mLock) { 1306 mTriggerFailureCount = DeviceConfig.getInt( 1307 DeviceConfig.NAMESPACE_ROLLBACK, 1308 PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT, 1309 DEFAULT_TRIGGER_FAILURE_COUNT); 1310 if (mTriggerFailureCount <= 0) { 1311 mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT; 1312 } 1313 1314 mTriggerFailureDurationMs = DeviceConfig.getInt( 1315 DeviceConfig.NAMESPACE_ROLLBACK, 1316 PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS, 1317 DEFAULT_TRIGGER_FAILURE_DURATION_MS); 1318 if (mTriggerFailureDurationMs <= 0) { 1319 mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_DURATION_MS; 1320 } 1321 1322 setExplicitHealthCheckEnabled(DeviceConfig.getBoolean( 1323 DeviceConfig.NAMESPACE_ROLLBACK, 1324 PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED, 1325 DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED)); 1326 } 1327 } 1328 registerConnectivityModuleHealthListener()1329 private void registerConnectivityModuleHealthListener() { 1330 // TODO: have an internal method to trigger a rollback by reporting high severity errors, 1331 // and rely on ActivityManager to inform the watchdog of severe network stack crashes 1332 // instead of having this listener in parallel. 1333 mConnectivityModuleConnector.registerHealthListener( 1334 packageName -> { 1335 final VersionedPackage pkg = getVersionedPackage(packageName); 1336 if (pkg == null) { 1337 Slog.wtf(TAG, "NetworkStack failed but could not find its package"); 1338 return; 1339 } 1340 final List<VersionedPackage> pkgList = Collections.singletonList(pkg); 1341 notifyPackageFailure(pkgList, FAILURE_REASON_EXPLICIT_HEALTH_CHECK); 1342 }); 1343 } 1344 1345 /** 1346 * Persists mAllObservers to file. Threshold information is ignored. 1347 */ saveToFile()1348 private boolean saveToFile() { 1349 Slog.i(TAG, "Saving observer state to file"); 1350 synchronized (mLock) { 1351 FileOutputStream stream; 1352 try { 1353 stream = mPolicyFile.startWrite(); 1354 } catch (IOException e) { 1355 Slog.w(TAG, "Cannot update monitored packages", e); 1356 return false; 1357 } 1358 1359 try { 1360 TypedXmlSerializer out = Xml.resolveSerializer(stream); 1361 out.startDocument(null, true); 1362 out.startTag(null, TAG_PACKAGE_WATCHDOG); 1363 out.attributeInt(null, ATTR_VERSION, DB_VERSION); 1364 for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) { 1365 mAllObservers.valueAt(oIndex).writeLocked(out); 1366 } 1367 out.endTag(null, TAG_PACKAGE_WATCHDOG); 1368 out.endDocument(); 1369 mPolicyFile.finishWrite(stream); 1370 return true; 1371 } catch (IOException e) { 1372 Slog.w(TAG, "Failed to save monitored packages, restoring backup", e); 1373 mPolicyFile.failWrite(stream); 1374 return false; 1375 } 1376 } 1377 } 1378 saveToFileAsync()1379 private void saveToFileAsync() { 1380 if (!mLongTaskHandler.hasCallbacks(mSaveToFile)) { 1381 mLongTaskHandler.post(mSaveToFile); 1382 } 1383 } 1384 1385 /** @hide Convert a {@code LongArrayQueue} to a String of comma-separated values. */ longArrayQueueToString(LongArrayQueue queue)1386 public static String longArrayQueueToString(LongArrayQueue queue) { 1387 if (queue.size() > 0) { 1388 StringBuilder sb = new StringBuilder(); 1389 sb.append(queue.get(0)); 1390 for (int i = 1; i < queue.size(); i++) { 1391 sb.append(","); 1392 sb.append(queue.get(i)); 1393 } 1394 return sb.toString(); 1395 } 1396 return ""; 1397 } 1398 1399 /** @hide Parse a comma-separated String of longs into a LongArrayQueue. */ parseLongArrayQueue(String commaSeparatedValues)1400 public static LongArrayQueue parseLongArrayQueue(String commaSeparatedValues) { 1401 LongArrayQueue result = new LongArrayQueue(); 1402 if (!TextUtils.isEmpty(commaSeparatedValues)) { 1403 String[] values = commaSeparatedValues.split(","); 1404 for (String value : values) { 1405 result.addLast(Long.parseLong(value)); 1406 } 1407 } 1408 return result; 1409 } 1410 1411 1412 /** Dump status of every observer in mAllObservers. */ dump(@onNull PrintWriter pw)1413 public void dump(@NonNull PrintWriter pw) { 1414 if (Flags.synchronousRebootInRescueParty() && RescueParty.isRecoveryTriggeredReboot()) { 1415 dumpInternal(pw); 1416 } else { 1417 synchronized (mLock) { 1418 dumpInternal(pw); 1419 } 1420 } 1421 } 1422 dumpInternal(@onNull PrintWriter pw)1423 private void dumpInternal(@NonNull PrintWriter pw) { 1424 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 1425 ipw.println("Package Watchdog status"); 1426 ipw.increaseIndent(); 1427 synchronized (mLock) { 1428 for (String observerName : mAllObservers.keySet()) { 1429 ipw.println("Observer name: " + observerName); 1430 ipw.increaseIndent(); 1431 ObserverInternal observerInternal = mAllObservers.get(observerName); 1432 observerInternal.dump(ipw); 1433 ipw.decreaseIndent(); 1434 } 1435 } 1436 ipw.decreaseIndent(); 1437 dumpCrashRecoveryEvents(ipw); 1438 } 1439 1440 @VisibleForTesting 1441 @GuardedBy("mLock") registerObserverInternal(ObserverInternal observerInternal)1442 void registerObserverInternal(ObserverInternal observerInternal) { 1443 mAllObservers.put(observerInternal.name, observerInternal); 1444 } 1445 1446 /** 1447 * Represents an observer monitoring a set of packages along with the failure thresholds for 1448 * each package. 1449 * 1450 * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing 1451 * instances of this class. 1452 */ 1453 static class ObserverInternal { 1454 public final String name; 1455 @GuardedBy("mLock") 1456 private final ArrayMap<String, MonitoredPackage> mPackages = new ArrayMap<>(); 1457 @Nullable 1458 @GuardedBy("mLock") 1459 public PackageHealthObserver registeredObserver; 1460 private int mMitigationCount; 1461 ObserverInternal(String name, List<MonitoredPackage> packages)1462 ObserverInternal(String name, List<MonitoredPackage> packages) { 1463 this(name, packages, /*mitigationCount=*/ 0); 1464 } 1465 ObserverInternal(String name, List<MonitoredPackage> packages, int mitigationCount)1466 ObserverInternal(String name, List<MonitoredPackage> packages, int mitigationCount) { 1467 this.name = name; 1468 updatePackagesLocked(packages); 1469 this.mMitigationCount = mitigationCount; 1470 } 1471 1472 /** 1473 * Writes important {@link MonitoredPackage} details for this observer to file. 1474 * Does not persist any package failure thresholds. 1475 */ 1476 @GuardedBy("mLock") writeLocked(TypedXmlSerializer out)1477 public boolean writeLocked(TypedXmlSerializer out) { 1478 try { 1479 out.startTag(null, TAG_OBSERVER); 1480 out.attribute(null, ATTR_NAME, name); 1481 if (Flags.recoverabilityDetection()) { 1482 out.attributeInt(null, ATTR_MITIGATION_COUNT, mMitigationCount); 1483 } 1484 for (int i = 0; i < mPackages.size(); i++) { 1485 MonitoredPackage p = mPackages.valueAt(i); 1486 p.writeLocked(out); 1487 } 1488 out.endTag(null, TAG_OBSERVER); 1489 return true; 1490 } catch (IOException e) { 1491 Slog.w(TAG, "Cannot save observer", e); 1492 return false; 1493 } 1494 } 1495 getBootMitigationCount()1496 public int getBootMitigationCount() { 1497 return mMitigationCount; 1498 } 1499 setBootMitigationCount(int mitigationCount)1500 public void setBootMitigationCount(int mitigationCount) { 1501 mMitigationCount = mitigationCount; 1502 } 1503 1504 @GuardedBy("mLock") updatePackagesLocked(List<MonitoredPackage> packages)1505 public void updatePackagesLocked(List<MonitoredPackage> packages) { 1506 for (int pIndex = 0; pIndex < packages.size(); pIndex++) { 1507 MonitoredPackage p = packages.get(pIndex); 1508 MonitoredPackage existingPackage = getMonitoredPackage(p.getName()); 1509 if (existingPackage != null) { 1510 existingPackage.updateHealthCheckDuration(p.mDurationMs); 1511 } else { 1512 putMonitoredPackage(p); 1513 } 1514 } 1515 } 1516 1517 /** 1518 * Reduces the monitoring durations of all packages observed by this observer by 1519 * {@code elapsedMs}. If any duration is less than 0, the package is removed from 1520 * observation. If any health check duration is less than 0, the health check result 1521 * is evaluated. 1522 * 1523 * @return a {@link Set} of packages that were removed from the observer without explicit 1524 * health check passing, or an empty list if no package expired for which an explicit health 1525 * check was still pending 1526 */ 1527 @GuardedBy("mLock") prunePackagesLocked(long elapsedMs)1528 private Set<MonitoredPackage> prunePackagesLocked(long elapsedMs) { 1529 Set<MonitoredPackage> failedPackages = new ArraySet<>(); 1530 Iterator<MonitoredPackage> it = mPackages.values().iterator(); 1531 while (it.hasNext()) { 1532 MonitoredPackage p = it.next(); 1533 int oldState = p.getHealthCheckStateLocked(); 1534 int newState = p.handleElapsedTimeLocked(elapsedMs); 1535 if (oldState != HealthCheckState.FAILED 1536 && newState == HealthCheckState.FAILED) { 1537 Slog.i(TAG, "Package " + p.getName() + " failed health check"); 1538 failedPackages.add(p); 1539 } 1540 if (p.isExpiredLocked()) { 1541 it.remove(); 1542 } 1543 } 1544 return failedPackages; 1545 } 1546 1547 /** 1548 * Increments failure counts of {@code packageName}. 1549 * @returns {@code true} if failure threshold is exceeded, {@code false} otherwise 1550 * @hide 1551 */ 1552 @GuardedBy("mLock") notifyPackageFailureLocked(String packageName)1553 public boolean notifyPackageFailureLocked(String packageName) { 1554 if (getMonitoredPackage(packageName) == null && registeredObserver.isPersistent() 1555 && registeredObserver.mayObservePackage(packageName)) { 1556 putMonitoredPackage(sPackageWatchdog.newMonitoredPackage( 1557 packageName, DEFAULT_OBSERVING_DURATION_MS, false)); 1558 } 1559 MonitoredPackage p = getMonitoredPackage(packageName); 1560 if (p != null) { 1561 return p.onFailureLocked(); 1562 } 1563 return false; 1564 } 1565 1566 /** 1567 * Returns the map of packages monitored by this observer. 1568 * 1569 * @return a mapping of package names to {@link MonitoredPackage} objects. 1570 */ 1571 @GuardedBy("mLock") getMonitoredPackages()1572 public ArrayMap<String, MonitoredPackage> getMonitoredPackages() { 1573 return mPackages; 1574 } 1575 1576 /** 1577 * Returns the {@link MonitoredPackage} associated with a given package name if the 1578 * package is being monitored by this observer. 1579 * 1580 * @param packageName: the name of the package. 1581 * @return the {@link MonitoredPackage} object associated with the package name if one 1582 * exists, {@code null} otherwise. 1583 */ 1584 @GuardedBy("mLock") 1585 @Nullable getMonitoredPackage(String packageName)1586 public MonitoredPackage getMonitoredPackage(String packageName) { 1587 return mPackages.get(packageName); 1588 } 1589 1590 /** 1591 * Associates a {@link MonitoredPackage} with the observer. 1592 * 1593 * @param p: the {@link MonitoredPackage} to store. 1594 */ 1595 @GuardedBy("mLock") putMonitoredPackage(MonitoredPackage p)1596 public void putMonitoredPackage(MonitoredPackage p) { 1597 mPackages.put(p.getName(), p); 1598 } 1599 1600 /** 1601 * Returns one ObserverInternal from the {@code parser} and advances its state. 1602 * 1603 * <p>Note that this method is <b>not</b> thread safe. It should only be called from 1604 * #loadFromFile which in turn is only called on construction of the 1605 * singleton PackageWatchdog. 1606 **/ read(TypedXmlPullParser parser, PackageWatchdog watchdog)1607 public static ObserverInternal read(TypedXmlPullParser parser, PackageWatchdog watchdog) { 1608 String observerName = null; 1609 int observerMitigationCount = 0; 1610 if (TAG_OBSERVER.equals(parser.getName())) { 1611 observerName = parser.getAttributeValue(null, ATTR_NAME); 1612 if (TextUtils.isEmpty(observerName)) { 1613 Slog.wtf(TAG, "Unable to read observer name"); 1614 return null; 1615 } 1616 } 1617 List<MonitoredPackage> packages = new ArrayList<>(); 1618 int innerDepth = parser.getDepth(); 1619 try { 1620 if (Flags.recoverabilityDetection()) { 1621 try { 1622 observerMitigationCount = 1623 parser.getAttributeInt(null, ATTR_MITIGATION_COUNT); 1624 } catch (XmlPullParserException e) { 1625 Slog.i( 1626 TAG, 1627 "ObserverInternal mitigation count was not present."); 1628 } 1629 } 1630 while (XmlUtils.nextElementWithin(parser, innerDepth)) { 1631 if (TAG_PACKAGE.equals(parser.getName())) { 1632 try { 1633 MonitoredPackage pkg = watchdog.parseMonitoredPackage(parser); 1634 if (pkg != null) { 1635 packages.add(pkg); 1636 } 1637 } catch (NumberFormatException e) { 1638 Slog.wtf(TAG, "Skipping package for observer " + observerName, e); 1639 continue; 1640 } 1641 } 1642 } 1643 } catch (XmlPullParserException | IOException e) { 1644 Slog.wtf(TAG, "Unable to read observer " + observerName, e); 1645 return null; 1646 } 1647 if (packages.isEmpty()) { 1648 return null; 1649 } 1650 return new ObserverInternal(observerName, packages, observerMitigationCount); 1651 } 1652 1653 /** Dumps information about this observer and the packages it watches. */ dump(IndentingPrintWriter pw)1654 public void dump(IndentingPrintWriter pw) { 1655 boolean isPersistent = registeredObserver != null && registeredObserver.isPersistent(); 1656 pw.println("Persistent: " + isPersistent); 1657 for (String packageName : mPackages.keySet()) { 1658 MonitoredPackage p = getMonitoredPackage(packageName); 1659 pw.println(packageName + ": "); 1660 pw.increaseIndent(); 1661 pw.println("# Failures: " + p.mFailureHistory.size()); 1662 pw.println("Monitoring duration remaining: " + p.mDurationMs + "ms"); 1663 pw.println("Explicit health check duration: " + p.mHealthCheckDurationMs + "ms"); 1664 pw.println("Health check state: " + p.toString(p.mHealthCheckState)); 1665 pw.decreaseIndent(); 1666 } 1667 } 1668 } 1669 1670 /** @hide */ 1671 @Retention(SOURCE) 1672 @IntDef(value = { 1673 HealthCheckState.ACTIVE, 1674 HealthCheckState.INACTIVE, 1675 HealthCheckState.PASSED, 1676 HealthCheckState.FAILED}) 1677 public @interface HealthCheckState { 1678 // The package has not passed health check but has requested a health check 1679 int ACTIVE = 0; 1680 // The package has not passed health check and has not requested a health check 1681 int INACTIVE = 1; 1682 // The package has passed health check 1683 int PASSED = 2; 1684 // The package has failed health check 1685 int FAILED = 3; 1686 } 1687 newMonitoredPackage( String name, long durationMs, boolean hasPassedHealthCheck)1688 MonitoredPackage newMonitoredPackage( 1689 String name, long durationMs, boolean hasPassedHealthCheck) { 1690 return newMonitoredPackage(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck, 1691 new LongArrayQueue()); 1692 } 1693 newMonitoredPackage(String name, long durationMs, long healthCheckDurationMs, boolean hasPassedHealthCheck, LongArrayQueue mitigationCalls)1694 MonitoredPackage newMonitoredPackage(String name, long durationMs, long healthCheckDurationMs, 1695 boolean hasPassedHealthCheck, LongArrayQueue mitigationCalls) { 1696 return new MonitoredPackage(name, durationMs, healthCheckDurationMs, 1697 hasPassedHealthCheck, mitigationCalls); 1698 } 1699 parseMonitoredPackage(TypedXmlPullParser parser)1700 MonitoredPackage parseMonitoredPackage(TypedXmlPullParser parser) 1701 throws XmlPullParserException { 1702 String packageName = parser.getAttributeValue(null, ATTR_NAME); 1703 long duration = parser.getAttributeLong(null, ATTR_DURATION); 1704 long healthCheckDuration = parser.getAttributeLong(null, 1705 ATTR_EXPLICIT_HEALTH_CHECK_DURATION); 1706 boolean hasPassedHealthCheck = parser.getAttributeBoolean(null, ATTR_PASSED_HEALTH_CHECK); 1707 LongArrayQueue mitigationCalls = parseLongArrayQueue( 1708 parser.getAttributeValue(null, ATTR_MITIGATION_CALLS)); 1709 return newMonitoredPackage(packageName, 1710 duration, healthCheckDuration, hasPassedHealthCheck, mitigationCalls); 1711 } 1712 1713 /** 1714 * Represents a package and its health check state along with the time 1715 * it should be monitored for. 1716 * 1717 * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing 1718 * instances of this class. 1719 */ 1720 class MonitoredPackage { 1721 private final String mPackageName; 1722 // Times when package failures happen sorted in ascending order 1723 @GuardedBy("mLock") 1724 private final LongArrayQueue mFailureHistory = new LongArrayQueue(); 1725 // Times when an observer was called to mitigate this package's failure. Sorted in 1726 // ascending order. 1727 @GuardedBy("mLock") 1728 private final LongArrayQueue mMitigationCalls; 1729 // One of STATE_[ACTIVE|INACTIVE|PASSED|FAILED]. Updated on construction and after 1730 // methods that could change the health check state: handleElapsedTimeLocked and 1731 // tryPassHealthCheckLocked 1732 private int mHealthCheckState = HealthCheckState.INACTIVE; 1733 // Whether an explicit health check has passed. 1734 // This value in addition with mHealthCheckDurationMs determines the health check state 1735 // of the package, see #getHealthCheckStateLocked 1736 @GuardedBy("mLock") 1737 private boolean mHasPassedHealthCheck; 1738 // System uptime duration to monitor package. 1739 @GuardedBy("mLock") 1740 private long mDurationMs; 1741 // System uptime duration to check the result of an explicit health check 1742 // Initially, MAX_VALUE until we get a value from the health check service 1743 // and request health checks. 1744 // This value in addition with mHasPassedHealthCheck determines the health check state 1745 // of the package, see #getHealthCheckStateLocked 1746 @GuardedBy("mLock") 1747 private long mHealthCheckDurationMs = Long.MAX_VALUE; 1748 MonitoredPackage(String packageName, long durationMs, long healthCheckDurationMs, boolean hasPassedHealthCheck, LongArrayQueue mitigationCalls)1749 MonitoredPackage(String packageName, long durationMs, 1750 long healthCheckDurationMs, boolean hasPassedHealthCheck, 1751 LongArrayQueue mitigationCalls) { 1752 mPackageName = packageName; 1753 mDurationMs = durationMs; 1754 mHealthCheckDurationMs = healthCheckDurationMs; 1755 mHasPassedHealthCheck = hasPassedHealthCheck; 1756 mMitigationCalls = mitigationCalls; 1757 updateHealthCheckStateLocked(); 1758 } 1759 1760 /** Writes the salient fields to disk using {@code out}. 1761 * @hide 1762 */ 1763 @GuardedBy("mLock") writeLocked(TypedXmlSerializer out)1764 public void writeLocked(TypedXmlSerializer out) throws IOException { 1765 out.startTag(null, TAG_PACKAGE); 1766 out.attribute(null, ATTR_NAME, getName()); 1767 out.attributeLong(null, ATTR_DURATION, mDurationMs); 1768 out.attributeLong(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION, mHealthCheckDurationMs); 1769 out.attributeBoolean(null, ATTR_PASSED_HEALTH_CHECK, mHasPassedHealthCheck); 1770 LongArrayQueue normalizedCalls = normalizeMitigationCalls(); 1771 out.attribute(null, ATTR_MITIGATION_CALLS, longArrayQueueToString(normalizedCalls)); 1772 out.endTag(null, TAG_PACKAGE); 1773 } 1774 1775 /** 1776 * Increment package failures or resets failure count depending on the last package failure. 1777 * 1778 * @return {@code true} if failure count exceeds a threshold, {@code false} otherwise 1779 */ 1780 @GuardedBy("mLock") onFailureLocked()1781 public boolean onFailureLocked() { 1782 // Sliding window algorithm: find out if there exists a window containing failures >= 1783 // mTriggerFailureCount. 1784 final long now = mSystemClock.uptimeMillis(); 1785 mFailureHistory.addLast(now); 1786 while (now - mFailureHistory.peekFirst() > mTriggerFailureDurationMs) { 1787 // Prune values falling out of the window 1788 mFailureHistory.removeFirst(); 1789 } 1790 boolean failed = mFailureHistory.size() >= mTriggerFailureCount; 1791 if (failed) { 1792 mFailureHistory.clear(); 1793 } 1794 return failed; 1795 } 1796 1797 /** 1798 * Notes the timestamp of a mitigation call into the observer. 1799 */ 1800 @GuardedBy("mLock") noteMitigationCallLocked()1801 public void noteMitigationCallLocked() { 1802 mMitigationCalls.addLast(mSystemClock.uptimeMillis()); 1803 } 1804 1805 /** 1806 * Prunes any mitigation calls outside of the de-escalation window, and returns the 1807 * number of calls that are in the window afterwards. 1808 * 1809 * @return the number of mitigation calls made in the de-escalation window. 1810 */ 1811 @GuardedBy("mLock") getMitigationCountLocked()1812 public int getMitigationCountLocked() { 1813 try { 1814 final long now = mSystemClock.uptimeMillis(); 1815 while (now - mMitigationCalls.peekFirst() > DEFAULT_DEESCALATION_WINDOW_MS) { 1816 mMitigationCalls.removeFirst(); 1817 } 1818 } catch (NoSuchElementException ignore) { 1819 } 1820 1821 return mMitigationCalls.size(); 1822 } 1823 1824 /** 1825 * Before writing to disk, make the mitigation call timestamps relative to the current 1826 * system uptime. This is because they need to be relative to the uptime which will reset 1827 * at the next boot. 1828 * 1829 * @return a LongArrayQueue of the mitigation calls relative to the current system uptime. 1830 */ 1831 @GuardedBy("mLock") normalizeMitigationCalls()1832 public LongArrayQueue normalizeMitigationCalls() { 1833 LongArrayQueue normalized = new LongArrayQueue(); 1834 final long now = mSystemClock.uptimeMillis(); 1835 for (int i = 0; i < mMitigationCalls.size(); i++) { 1836 normalized.addLast(mMitigationCalls.get(i) - now); 1837 } 1838 return normalized; 1839 } 1840 1841 /** 1842 * Sets the initial health check duration. 1843 * 1844 * @return the new health check state 1845 */ 1846 @GuardedBy("mLock") setHealthCheckActiveLocked(long initialHealthCheckDurationMs)1847 public int setHealthCheckActiveLocked(long initialHealthCheckDurationMs) { 1848 if (initialHealthCheckDurationMs <= 0) { 1849 Slog.wtf(TAG, "Cannot set non-positive health check duration " 1850 + initialHealthCheckDurationMs + "ms for package " + getName() 1851 + ". Using total duration " + mDurationMs + "ms instead"); 1852 initialHealthCheckDurationMs = mDurationMs; 1853 } 1854 if (mHealthCheckState == HealthCheckState.INACTIVE) { 1855 // Transitions to ACTIVE 1856 mHealthCheckDurationMs = initialHealthCheckDurationMs; 1857 } 1858 return updateHealthCheckStateLocked(); 1859 } 1860 1861 /** 1862 * Updates the monitoring durations of the package. 1863 * 1864 * @return the new health check state 1865 */ 1866 @GuardedBy("mLock") handleElapsedTimeLocked(long elapsedMs)1867 public int handleElapsedTimeLocked(long elapsedMs) { 1868 if (elapsedMs <= 0) { 1869 Slog.w(TAG, "Cannot handle non-positive elapsed time for package " + getName()); 1870 return mHealthCheckState; 1871 } 1872 // Transitions to FAILED if now <= 0 and health check not passed 1873 mDurationMs -= elapsedMs; 1874 if (mHealthCheckState == HealthCheckState.ACTIVE) { 1875 // We only update health check durations if we have #setHealthCheckActiveLocked 1876 // This ensures we don't leave the INACTIVE state for an unexpected elapsed time 1877 // Transitions to FAILED if now <= 0 and health check not passed 1878 mHealthCheckDurationMs -= elapsedMs; 1879 } 1880 return updateHealthCheckStateLocked(); 1881 } 1882 1883 /** Explicitly update the monitoring duration of the package. */ 1884 @GuardedBy("mLock") updateHealthCheckDuration(long newDurationMs)1885 public void updateHealthCheckDuration(long newDurationMs) { 1886 mDurationMs = newDurationMs; 1887 } 1888 1889 /** 1890 * Marks the health check as passed and transitions to {@link HealthCheckState.PASSED} 1891 * if not yet {@link HealthCheckState.FAILED}. 1892 * 1893 * @return the new {@link HealthCheckState health check state} 1894 */ 1895 @GuardedBy("mLock") 1896 @HealthCheckState tryPassHealthCheckLocked()1897 public int tryPassHealthCheckLocked() { 1898 if (mHealthCheckState != HealthCheckState.FAILED) { 1899 // FAILED is a final state so only pass if we haven't failed 1900 // Transition to PASSED 1901 mHasPassedHealthCheck = true; 1902 } 1903 return updateHealthCheckStateLocked(); 1904 } 1905 1906 /** Returns the monitored package name. */ getName()1907 private String getName() { 1908 return mPackageName; 1909 } 1910 1911 /** 1912 * Returns the current {@link HealthCheckState health check state}. 1913 */ 1914 @GuardedBy("mLock") 1915 @HealthCheckState getHealthCheckStateLocked()1916 public int getHealthCheckStateLocked() { 1917 return mHealthCheckState; 1918 } 1919 1920 /** 1921 * Returns the shortest duration before the package should be scheduled for a prune. 1922 * 1923 * @return the duration or {@link Long#MAX_VALUE} if the package should not be scheduled 1924 */ 1925 @GuardedBy("mLock") getShortestScheduleDurationMsLocked()1926 public long getShortestScheduleDurationMsLocked() { 1927 // Consider health check duration only if #isPendingHealthChecksLocked is true 1928 return Math.min(toPositive(mDurationMs), 1929 isPendingHealthChecksLocked() 1930 ? toPositive(mHealthCheckDurationMs) : Long.MAX_VALUE); 1931 } 1932 1933 /** 1934 * Returns {@code true} if the total duration left to monitor the package is less than or 1935 * equal to 0 {@code false} otherwise. 1936 */ 1937 @GuardedBy("mLock") isExpiredLocked()1938 public boolean isExpiredLocked() { 1939 return mDurationMs <= 0; 1940 } 1941 1942 /** 1943 * Returns {@code true} if the package, {@link #getName} is expecting health check results 1944 * {@code false} otherwise. 1945 */ 1946 @GuardedBy("mLock") isPendingHealthChecksLocked()1947 public boolean isPendingHealthChecksLocked() { 1948 return mHealthCheckState == HealthCheckState.ACTIVE 1949 || mHealthCheckState == HealthCheckState.INACTIVE; 1950 } 1951 1952 /** 1953 * Updates the health check state based on {@link #mHasPassedHealthCheck} 1954 * and {@link #mHealthCheckDurationMs}. 1955 * 1956 * @return the new {@link HealthCheckState health check state} 1957 */ 1958 @GuardedBy("mLock") 1959 @HealthCheckState updateHealthCheckStateLocked()1960 private int updateHealthCheckStateLocked() { 1961 int oldState = mHealthCheckState; 1962 if (mHasPassedHealthCheck) { 1963 // Set final state first to avoid ambiguity 1964 mHealthCheckState = HealthCheckState.PASSED; 1965 } else if (mHealthCheckDurationMs <= 0 || mDurationMs <= 0) { 1966 // Set final state first to avoid ambiguity 1967 mHealthCheckState = HealthCheckState.FAILED; 1968 } else if (mHealthCheckDurationMs == Long.MAX_VALUE) { 1969 mHealthCheckState = HealthCheckState.INACTIVE; 1970 } else { 1971 mHealthCheckState = HealthCheckState.ACTIVE; 1972 } 1973 1974 if (oldState != mHealthCheckState) { 1975 Slog.i(TAG, "Updated health check state for package " + getName() + ": " 1976 + toString(oldState) + " -> " + toString(mHealthCheckState)); 1977 } 1978 return mHealthCheckState; 1979 } 1980 1981 /** Returns a {@link String} representation of the current health check state. */ toString(@ealthCheckState int state)1982 private String toString(@HealthCheckState int state) { 1983 switch (state) { 1984 case HealthCheckState.ACTIVE: 1985 return "ACTIVE"; 1986 case HealthCheckState.INACTIVE: 1987 return "INACTIVE"; 1988 case HealthCheckState.PASSED: 1989 return "PASSED"; 1990 case HealthCheckState.FAILED: 1991 return "FAILED"; 1992 default: 1993 return "UNKNOWN"; 1994 } 1995 } 1996 1997 /** Returns {@code value} if it is greater than 0 or {@link Long#MAX_VALUE} otherwise. */ toPositive(long value)1998 private long toPositive(long value) { 1999 return value > 0 ? value : Long.MAX_VALUE; 2000 } 2001 2002 /** Compares the equality of this object with another {@link MonitoredPackage}. */ 2003 @VisibleForTesting isEqualTo(MonitoredPackage pkg)2004 boolean isEqualTo(MonitoredPackage pkg) { 2005 return (getName().equals(pkg.getName())) 2006 && mDurationMs == pkg.mDurationMs 2007 && mHasPassedHealthCheck == pkg.mHasPassedHealthCheck 2008 && mHealthCheckDurationMs == pkg.mHealthCheckDurationMs 2009 && (mMitigationCalls.toString()).equals(pkg.mMitigationCalls.toString()); 2010 } 2011 } 2012 2013 @GuardedBy("mLock") 2014 @SuppressWarnings("GuardedBy") saveAllObserversBootMitigationCountToMetadata(String filePath)2015 void saveAllObserversBootMitigationCountToMetadata(String filePath) { 2016 HashMap<String, Integer> bootMitigationCounts = new HashMap<>(); 2017 for (int i = 0; i < mAllObservers.size(); i++) { 2018 final ObserverInternal observer = mAllObservers.valueAt(i); 2019 bootMitigationCounts.put(observer.name, observer.getBootMitigationCount()); 2020 } 2021 2022 FileOutputStream fileStream = null; 2023 ObjectOutputStream objectStream = null; 2024 try { 2025 fileStream = new FileOutputStream(new File(filePath)); 2026 objectStream = new ObjectOutputStream(fileStream); 2027 objectStream.writeObject(bootMitigationCounts); 2028 objectStream.flush(); 2029 } catch (Exception e) { 2030 Slog.i(TAG, "Could not save observers metadata to file: " + e); 2031 return; 2032 } finally { 2033 IoUtils.closeQuietly(objectStream); 2034 IoUtils.closeQuietly(fileStream); 2035 } 2036 } 2037 2038 /** 2039 * Handles the thresholding logic for system server boots. 2040 */ 2041 class BootThreshold { 2042 2043 private final int mBootTriggerCount; 2044 private final long mTriggerWindow; 2045 BootThreshold(int bootTriggerCount, long triggerWindow)2046 BootThreshold(int bootTriggerCount, long triggerWindow) { 2047 this.mBootTriggerCount = bootTriggerCount; 2048 this.mTriggerWindow = triggerWindow; 2049 } 2050 reset()2051 public void reset() { 2052 setStart(0); 2053 setCount(0); 2054 } 2055 getCount()2056 protected int getCount() { 2057 return CrashRecoveryProperties.rescueBootCount().orElse(0); 2058 } 2059 setCount(int count)2060 protected void setCount(int count) { 2061 CrashRecoveryProperties.rescueBootCount(count); 2062 } 2063 getStart()2064 public long getStart() { 2065 return CrashRecoveryProperties.rescueBootStart().orElse(0L); 2066 } 2067 getMitigationCount()2068 public int getMitigationCount() { 2069 return CrashRecoveryProperties.bootMitigationCount().orElse(0); 2070 } 2071 setStart(long start)2072 public void setStart(long start) { 2073 CrashRecoveryProperties.rescueBootStart(getStartTime(start)); 2074 } 2075 setMitigationStart(long start)2076 public void setMitigationStart(long start) { 2077 CrashRecoveryProperties.bootMitigationStart(getStartTime(start)); 2078 } 2079 getMitigationStart()2080 public long getMitigationStart() { 2081 return CrashRecoveryProperties.bootMitigationStart().orElse(0L); 2082 } 2083 setMitigationCount(int count)2084 public void setMitigationCount(int count) { 2085 CrashRecoveryProperties.bootMitigationCount(count); 2086 } 2087 constrain(long amount, long low, long high)2088 private static long constrain(long amount, long low, long high) { 2089 return amount < low ? low : (amount > high ? high : amount); 2090 } 2091 getStartTime(long start)2092 public long getStartTime(long start) { 2093 final long now = mSystemClock.uptimeMillis(); 2094 return constrain(start, 0, now); 2095 } 2096 saveMitigationCountToMetadata()2097 public void saveMitigationCountToMetadata() { 2098 try (BufferedWriter writer = new BufferedWriter(new FileWriter(METADATA_FILE))) { 2099 writer.write(String.valueOf(getMitigationCount())); 2100 } catch (Exception e) { 2101 Slog.e(TAG, "Could not save metadata to file: " + e); 2102 } 2103 } 2104 readMitigationCountFromMetadataIfNecessary()2105 public void readMitigationCountFromMetadataIfNecessary() { 2106 File bootPropsFile = new File(METADATA_FILE); 2107 if (bootPropsFile.exists()) { 2108 try (BufferedReader reader = new BufferedReader(new FileReader(METADATA_FILE))) { 2109 String mitigationCount = reader.readLine(); 2110 setMitigationCount(Integer.parseInt(mitigationCount)); 2111 bootPropsFile.delete(); 2112 } catch (Exception e) { 2113 Slog.i(TAG, "Could not read metadata file: " + e); 2114 } 2115 } 2116 } 2117 2118 2119 /** Increments the boot counter, and returns whether the device is bootlooping. */ 2120 @GuardedBy("mLock") incrementAndTest()2121 public boolean incrementAndTest() { 2122 if (Flags.recoverabilityDetection()) { 2123 readAllObserversBootMitigationCountIfNecessary(METADATA_FILE); 2124 } else { 2125 readMitigationCountFromMetadataIfNecessary(); 2126 } 2127 2128 final long now = mSystemClock.uptimeMillis(); 2129 if (now - getStart() < 0) { 2130 Slog.e(TAG, "Window was less than zero. Resetting start to current time."); 2131 setStart(now); 2132 setMitigationStart(now); 2133 } 2134 if (now - getMitigationStart() > DEFAULT_DEESCALATION_WINDOW_MS) { 2135 setMitigationStart(now); 2136 if (Flags.recoverabilityDetection()) { 2137 resetAllObserversBootMitigationCount(); 2138 } else { 2139 setMitigationCount(0); 2140 } 2141 } 2142 final long window = now - getStart(); 2143 if (window >= mTriggerWindow) { 2144 setCount(1); 2145 setStart(now); 2146 return false; 2147 } else { 2148 int count = getCount() + 1; 2149 setCount(count); 2150 EventLog.writeEvent(LOG_TAG_RESCUE_NOTE, Process.ROOT_UID, count, window); 2151 if (Flags.recoverabilityDetection()) { 2152 // After a reboot (e.g. by WARM_REBOOT or mainline rollback) we apply 2153 // mitigations without waiting for DEFAULT_BOOT_LOOP_TRIGGER_COUNT. 2154 return (count >= mBootTriggerCount) 2155 || (performedMitigationsDuringWindow() && count > 1); 2156 } 2157 return count >= mBootTriggerCount; 2158 } 2159 } 2160 2161 @GuardedBy("mLock") performedMitigationsDuringWindow()2162 private boolean performedMitigationsDuringWindow() { 2163 for (ObserverInternal observerInternal: mAllObservers.values()) { 2164 if (observerInternal.getBootMitigationCount() > 0) { 2165 return true; 2166 } 2167 } 2168 return false; 2169 } 2170 2171 @GuardedBy("mLock") resetAllObserversBootMitigationCount()2172 private void resetAllObserversBootMitigationCount() { 2173 for (int i = 0; i < mAllObservers.size(); i++) { 2174 final ObserverInternal observer = mAllObservers.valueAt(i); 2175 observer.setBootMitigationCount(0); 2176 } 2177 saveAllObserversBootMitigationCountToMetadata(METADATA_FILE); 2178 } 2179 2180 @GuardedBy("mLock") 2181 @SuppressWarnings("GuardedBy") readAllObserversBootMitigationCountIfNecessary(String filePath)2182 void readAllObserversBootMitigationCountIfNecessary(String filePath) { 2183 File metadataFile = new File(filePath); 2184 if (metadataFile.exists()) { 2185 FileInputStream fileStream = null; 2186 ObjectInputStream objectStream = null; 2187 HashMap<String, Integer> bootMitigationCounts = null; 2188 try { 2189 fileStream = new FileInputStream(metadataFile); 2190 objectStream = new ObjectInputStream(fileStream); 2191 bootMitigationCounts = 2192 (HashMap<String, Integer>) objectStream.readObject(); 2193 } catch (Exception e) { 2194 Slog.i(TAG, "Could not read observer metadata file: " + e); 2195 return; 2196 } finally { 2197 IoUtils.closeQuietly(objectStream); 2198 IoUtils.closeQuietly(fileStream); 2199 } 2200 2201 if (bootMitigationCounts == null || bootMitigationCounts.isEmpty()) { 2202 Slog.i(TAG, "No observer in metadata file"); 2203 return; 2204 } 2205 for (int i = 0; i < mAllObservers.size(); i++) { 2206 final ObserverInternal observer = mAllObservers.valueAt(i); 2207 if (bootMitigationCounts.containsKey(observer.name)) { 2208 observer.setBootMitigationCount( 2209 bootMitigationCounts.get(observer.name)); 2210 } 2211 } 2212 } 2213 } 2214 } 2215 2216 /** 2217 * Register broadcast receiver for shutdown. 2218 * We would save the observer state to persist across boots. 2219 * 2220 * @hide 2221 */ registerShutdownBroadcastReceiver()2222 public void registerShutdownBroadcastReceiver() { 2223 BroadcastReceiver shutdownEventReceiver = new BroadcastReceiver() { 2224 @Override 2225 public void onReceive(Context context, Intent intent) { 2226 // Only write if intent is relevant to device reboot or shutdown. 2227 String intentAction = intent.getAction(); 2228 if (ACTION_REBOOT.equals(intentAction) 2229 || ACTION_SHUTDOWN.equals(intentAction)) { 2230 writeNow(); 2231 } 2232 } 2233 }; 2234 2235 // Setup receiver for device reboots or shutdowns. 2236 IntentFilter filter = new IntentFilter(ACTION_REBOOT); 2237 filter.addAction(ACTION_SHUTDOWN); 2238 mContext.registerReceiverForAllUsers(shutdownEventReceiver, filter, null, 2239 /* run on main thread */ null); 2240 } 2241 } 2242