• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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