Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a4b6865 authored by Harshit Mahajan's avatar Harshit Mahajan Committed by Android (Google) Code Review
Browse files

Merge changes from topics "cr-executor", "startExplicitHealthCheck" into main

* changes:
  Rename startObservingHealth API
  Allow observers to register custom executor
parents 2c22eca3 92ade0fb
Loading
Loading
Loading
Loading
+84 −42
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.android.server.crashrecovery.CrashRecoveryUtils.dumpCrashRecov

import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -91,6 +92,7 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

/**
@@ -336,20 +338,28 @@ public class PackageWatchdog {
    /**
     * Registers {@code observer} to listen for package failures. Add a new ObserverInternal for
     * this observer if it does not already exist.
     * For executing mitigations observers will receive callback on the given executor.
     *
     * <p>Observers are expected to call this on boot. It does not specify any packages but
     * it will resume observing any packages requested from a previous boot.
     *
     * @param observer instance of {@link PackageHealthObserver} for observing package failures
     *                 and boot loops.
     * @param executor Executor for the thread on which observers would receive callbacks
     * @hide
     */
    public void registerHealthObserver(PackageHealthObserver observer) {
    public void registerHealthObserver(@NonNull PackageHealthObserver observer,
            @NonNull @CallbackExecutor Executor executor) {
        synchronized (sLock) {
            ObserverInternal internalObserver = mAllObservers.get(observer.getUniqueIdentifier());
            if (internalObserver != null) {
                internalObserver.registeredObserver = observer;
                internalObserver.observerExecutor = executor;
            } else {
                internalObserver = new ObserverInternal(observer.getUniqueIdentifier(),
                        new ArrayList<>());
                internalObserver.registeredObserver = observer;
                internalObserver.observerExecutor = executor;
                mAllObservers.put(observer.getUniqueIdentifier(), internalObserver);
                syncState("added new observer");
            }
@@ -357,40 +367,54 @@ public class PackageWatchdog {
    }

    /**
     * Starts observing the health of the {@code packages} for {@code observer} and notifies
     * {@code observer} of any package failures within the monitoring duration.
     * Starts observing the health of the {@code packages} for {@code observer}.
     * Note: Observer needs to be registered with {@link #registerHealthObserver} before calling
     * this API.
     *
     * <p>If monitoring a package supporting explicit health check, at the end of the monitoring
     * duration if {@link #onHealthCheckPassed} was never called,
     * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} will be called as if the package failed.
     * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} will be called as if the
     * package failed.
     *
     * <p>If {@code observer} is already monitoring a package in {@code packageNames},
     * the monitoring window of that package will be reset to {@code durationMs} and the health
     * check state will be reset to a default depending on if the package is contained in
     * {@link mPackagesWithExplicitHealthCheckEnabled}.
     * check state will be reset to a default.
     *
     * <p>The {@code observer} must be registered with {@link #registerHealthObserver} before
     * calling this method.
     *
     * <p>If {@code packageNames} is empty, this will be a no-op.
     * @param packageNames The list of packages to check. If this is empty, the call will be a
     *                     no-op.
     *
     * <p>If {@code durationMs} is less than 1, a default monitoring duration
     * {@link #DEFAULT_OBSERVING_DURATION_MS} will be used.
     * @param timeoutMs The timeout after which Explicit Health Checks would not run. If this is
     *                  less than 1, a default monitoring duration 2 days will be used.
     *
     * @throws IllegalStateException if the observer was not previously registered
     * @hide
     */
    public void startObservingHealth(PackageHealthObserver observer, List<String> packageNames,
            long durationMs) {
    public void startExplicitHealthCheck(@NonNull PackageHealthObserver observer,
            @NonNull List<String> packageNames, long timeoutMs) {
        synchronized (sLock) {
            if (!mAllObservers.containsKey(observer.getUniqueIdentifier())) {
                Slog.wtf(TAG, "No observer found, need to register the observer: "
                        + observer.getUniqueIdentifier());
                throw new IllegalStateException("Observer not registered");
            }
        }
        if (packageNames.isEmpty()) {
            Slog.wtf(TAG, "No packages to observe, " + observer.getUniqueIdentifier());
            return;
        }
        if (durationMs < 1) {
            Slog.wtf(TAG, "Invalid duration " + durationMs + "ms for observer "
        if (timeoutMs < 1) {
            Slog.wtf(TAG, "Invalid duration " + timeoutMs + "ms for observer "
                    + observer.getUniqueIdentifier() + ". Not observing packages " + packageNames);
            durationMs = DEFAULT_OBSERVING_DURATION_MS;
            timeoutMs = DEFAULT_OBSERVING_DURATION_MS;
        }

        List<MonitoredPackage> packages = new ArrayList<>();
        for (int i = 0; i < packageNames.size(); i++) {
            // Health checks not available yet so health check state will start INACTIVE
            MonitoredPackage pkg = newMonitoredPackage(packageNames.get(i), durationMs, false);
            MonitoredPackage pkg = newMonitoredPackage(packageNames.get(i), timeoutMs, false);
            if (pkg != null) {
                packages.add(pkg);
            } else {
@@ -423,9 +447,6 @@ public class PackageWatchdog {
                }
            }

            // Register observer in case not already registered
            registerHealthObserver(observer);

            // Sync after we add the new packages to the observers. We may have received packges
            // requiring an earlier schedule than we are currently scheduled for.
            syncState("updated observers");
@@ -485,7 +506,7 @@ public class PackageWatchdog {
                    for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
                        VersionedPackage versionedPackage = packages.get(pIndex);
                        // Observer that will receive failure for versionedPackage
                        PackageHealthObserver currentObserverToNotify = null;
                        ObserverInternal currentObserverToNotify = null;
                        int currentObserverImpact = Integer.MAX_VALUE;
                        MonitoredPackage currentMonitoredPackage = null;

@@ -506,7 +527,7 @@ public class PackageWatchdog {
                                        versionedPackage, failureReason, mitigationCount);
                                if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0
                                        && impact < currentObserverImpact) {
                                    currentObserverToNotify = registeredObserver;
                                    currentObserverToNotify = observer;
                                    currentObserverImpact = impact;
                                    currentMonitoredPackage = p;
                                }
@@ -515,18 +536,23 @@ public class PackageWatchdog {

                        // Execute action with least user impact
                        if (currentObserverToNotify != null) {
                            int mitigationCount = 1;
                            int mitigationCount;
                            if (currentMonitoredPackage != null) {
                                currentMonitoredPackage.noteMitigationCallLocked();
                                mitigationCount =
                                        currentMonitoredPackage.getMitigationCountLocked();
                            } else {
                                mitigationCount = 1;
                            }
                            if (Flags.recoverabilityDetection()) {
                                maybeExecute(currentObserverToNotify, versionedPackage,
                                        failureReason, currentObserverImpact, mitigationCount);
                            } else {
                                currentObserverToNotify.onExecuteHealthCheckMitigation(
                                        versionedPackage, failureReason, mitigationCount);
                                PackageHealthObserver registeredObserver =
                                        currentObserverToNotify.registeredObserver;
                                currentObserverToNotify.observerExecutor.execute(() ->
                                        registeredObserver.onExecuteHealthCheckMitigation(
                                                versionedPackage, failureReason, mitigationCount));
                            }
                        }
                    }
@@ -539,10 +565,11 @@ public class PackageWatchdog {
     * For native crashes or explicit health check failures, call directly into each observer to
     * mitigate the error without going through failure threshold logic.
     */
    @GuardedBy("sLock")
    private void handleFailureImmediately(List<VersionedPackage> packages,
            @FailureReasons int failureReason) {
        VersionedPackage failingPackage = packages.size() > 0 ? packages.get(0) : null;
        PackageHealthObserver currentObserverToNotify = null;
        ObserverInternal currentObserverToNotify = null;
        int currentObserverImpact = Integer.MAX_VALUE;
        for (ObserverInternal observer: mAllObservers.values()) {
            PackageHealthObserver registeredObserver = observer.registeredObserver;
@@ -551,7 +578,7 @@ public class PackageWatchdog {
                        failingPackage, failureReason, 1);
                if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0
                        && impact < currentObserverImpact) {
                    currentObserverToNotify = registeredObserver;
                    currentObserverToNotify = observer;
                    currentObserverImpact = impact;
                }
            }
@@ -561,23 +588,30 @@ public class PackageWatchdog {
                maybeExecute(currentObserverToNotify, failingPackage, failureReason,
                        currentObserverImpact, /*mitigationCount=*/ 1);
            } else {
                currentObserverToNotify.onExecuteHealthCheckMitigation(failingPackage,
                        failureReason, 1);
                PackageHealthObserver registeredObserver =
                        currentObserverToNotify.registeredObserver;
                currentObserverToNotify.observerExecutor.execute(() ->
                        registeredObserver.onExecuteHealthCheckMitigation(failingPackage,
                                failureReason, 1));

            }
        }
    }

    private void maybeExecute(PackageHealthObserver currentObserverToNotify,
    private void maybeExecute(ObserverInternal currentObserverToNotify,
                              VersionedPackage versionedPackage,
                              @FailureReasons int failureReason,
                              int currentObserverImpact,
                              int mitigationCount) {
        if (allowMitigations(currentObserverImpact, versionedPackage)) {
            PackageHealthObserver registeredObserver;
            synchronized (sLock) {
                mLastMitigation = mSystemClock.uptimeMillis();
                registeredObserver = currentObserverToNotify.registeredObserver;
            }
            currentObserverToNotify.onExecuteHealthCheckMitigation(versionedPackage, failureReason,
                    mitigationCount);
            currentObserverToNotify.observerExecutor.execute(() ->
                    registeredObserver.onExecuteHealthCheckMitigation(versionedPackage,
                            failureReason, mitigationCount));
        }
    }

@@ -613,8 +647,7 @@ public class PackageWatchdog {
                    mBootThreshold.reset();
                }
                int mitigationCount = mBootThreshold.getMitigationCount() + 1;
                PackageHealthObserver currentObserverToNotify = null;
                ObserverInternal currentObserverInternal = null;
                ObserverInternal currentObserverToNotify = null;
                int currentObserverImpact = Integer.MAX_VALUE;
                for (int i = 0; i < mAllObservers.size(); i++) {
                    final ObserverInternal observer = mAllObservers.valueAt(i);
@@ -626,25 +659,31 @@ public class PackageWatchdog {
                                : registeredObserver.onBootLoop(mitigationCount);
                        if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0
                                && impact < currentObserverImpact) {
                            currentObserverToNotify = registeredObserver;
                            currentObserverInternal = observer;
                            currentObserverToNotify = observer;
                            currentObserverImpact = impact;
                        }
                    }
                }

                if (currentObserverToNotify != null) {
                    PackageHealthObserver registeredObserver =
                            currentObserverToNotify.registeredObserver;
                    if (Flags.recoverabilityDetection()) {
                        int currentObserverMitigationCount =
                                currentObserverInternal.getBootMitigationCount() + 1;
                        currentObserverInternal.setBootMitigationCount(
                                currentObserverToNotify.getBootMitigationCount() + 1;
                        currentObserverToNotify.setBootMitigationCount(
                                currentObserverMitigationCount);
                        saveAllObserversBootMitigationCountToMetadata(METADATA_FILE);
                        currentObserverToNotify.onExecuteBootLoopMitigation(
                                currentObserverMitigationCount);
                        currentObserverToNotify.observerExecutor
                                .execute(() -> registeredObserver.onExecuteBootLoopMitigation(
                                        currentObserverMitigationCount));
                    } else {
                        mBootThreshold.setMitigationCount(mitigationCount);
                        mBootThreshold.saveMitigationCountToMetadata();
                        currentObserverToNotify.onExecuteBootLoopMitigation(mitigationCount);
                        currentObserverToNotify.observerExecutor
                                .execute(() -> registeredObserver.onExecuteBootLoopMitigation(
                                        mitigationCount));

                    }
                }
            }
@@ -879,7 +918,7 @@ public class PackageWatchdog {
         * passed to observers in these API.
         *
         * <p> A persistent observer may choose to start observing certain failing packages, even if
         * it has not explicitly asked to watch the package with {@link #startObservingHealth}.
         * it has not explicitly asked to watch the package with {@link #startExplicitHealthCheck}.
         */
        default boolean mayObservePackage(@NonNull String packageName) {
            return false;
@@ -1136,8 +1175,10 @@ public class PackageWatchdog {
                        if (versionedPkg != null) {
                            Slog.i(TAG,
                                    "Explicit health check failed for package " + versionedPkg);
                            observer.observerExecutor.execute(() ->
                                    registeredObserver.onExecuteHealthCheckMitigation(versionedPkg,
                                    PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK, 1);
                                            PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK,
                                            1));
                        }
                    }
                }
@@ -1395,6 +1436,7 @@ public class PackageWatchdog {
        @Nullable
        @GuardedBy("sLock")
        public PackageHealthObserver registeredObserver;
        public Executor observerExecutor;
        private int mMitigationCount;

        ObserverInternal(String name, List<MonitoredPackage> packages) {
+2 −2
Original line number Diff line number Diff line
@@ -160,7 +160,7 @@ public class RescueParty {
    /** Register the Rescue Party observer as a Package Watchdog health observer */
    public static void registerHealthObserver(Context context) {
        PackageWatchdog.getInstance(context).registerHealthObserver(
                RescuePartyObserver.getInstance(context));
                RescuePartyObserver.getInstance(context), context.getMainExecutor());
    }

    private static boolean isDisabled() {
@@ -313,7 +313,7 @@ public class RescueParty {
            callingPackageList.addAll(callingPackages);
            Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: "
                    + updatedNamespace);
            PackageWatchdog.getInstance(context).startObservingHealth(
            PackageWatchdog.getInstance(context).startExplicitHealthCheck(
                    rescuePartyObserver,
                    callingPackageList,
                    DEFAULT_OBSERVING_DURATION_MS);
+3 −2
Original line number Diff line number Diff line
@@ -111,7 +111,8 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
        dataDir.mkdirs();
        mLastStagedRollbackIdsFile = new File(dataDir, "last-staged-rollback-ids");
        mTwoPhaseRollbackEnabledFile = new File(dataDir, "two-phase-rollback-enabled");
        PackageWatchdog.getInstance(mContext).registerHealthObserver(this);
        PackageWatchdog.getInstance(mContext).registerHealthObserver(this,
                context.getMainExecutor());

        if (SystemProperties.getBoolean("sys.boot_completed", false)) {
            // Load the value from the file if system server has crashed and restarted
@@ -280,7 +281,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
    @AnyThread
    @NonNull
    public void startObservingHealth(@NonNull List<String> packages, @NonNull long durationMs) {
        PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
        PackageWatchdog.getInstance(mContext).startExplicitHealthCheck(this, packages, durationMs);
    }

    @AnyThread
+5 −4
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

/**
@@ -362,7 +363,7 @@ public class PackageWatchdog {
     * it will resume observing any packages requested from a previous boot.
     * @hide
     */
    public void registerHealthObserver(PackageHealthObserver observer) {
    public void registerHealthObserver(PackageHealthObserver observer, Executor ignoredExecutor) {
        synchronized (mLock) {
            ObserverInternal internalObserver = mAllObservers.get(observer.getUniqueIdentifier());
            if (internalObserver != null) {
@@ -396,7 +397,7 @@ public class PackageWatchdog {
     * {@link #DEFAULT_OBSERVING_DURATION_MS} will be used.
     * @hide
     */
    public void startObservingHealth(PackageHealthObserver observer, List<String> packageNames,
    public void startExplicitHealthCheck(PackageHealthObserver observer, List<String> packageNames,
            long durationMs) {
        if (packageNames.isEmpty()) {
            Slog.wtf(TAG, "No packages to observe, " + observer.getUniqueIdentifier());
@@ -445,7 +446,7 @@ public class PackageWatchdog {
            }

            // Register observer in case not already registered
            registerHealthObserver(observer);
            registerHealthObserver(observer, null);

            // Sync after we add the new packages to the observers. We may have received packges
            // requiring an earlier schedule than we are currently scheduled for.
@@ -861,7 +862,7 @@ public class PackageWatchdog {
         * otherwise
         *
         * <p> A persistent observer may choose to start observing certain failing packages, even if
         * it has not explicitly asked to watch the package with {@link #startObservingHealth}.
         * it has not explicitly asked to watch the package with {@link #startExplicitHealthCheck}.
         */
        default boolean mayObservePackage(@NonNull String packageName) {
            return false;
+2 −2
Original line number Diff line number Diff line
@@ -166,7 +166,7 @@ public class RescueParty {
    /** Register the Rescue Party observer as a Package Watchdog health observer */
    public static void registerHealthObserver(Context context) {
        PackageWatchdog.getInstance(context).registerHealthObserver(
                RescuePartyObserver.getInstance(context));
                RescuePartyObserver.getInstance(context), null);
    }

    private static boolean isDisabled() {
@@ -387,7 +387,7 @@ public class RescueParty {
            callingPackageList.addAll(callingPackages);
            Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: "
                    + updatedNamespace);
            PackageWatchdog.getInstance(context).startObservingHealth(
            PackageWatchdog.getInstance(context).startExplicitHealthCheck(
                    rescuePartyObserver,
                    callingPackageList,
                    DEFAULT_OBSERVING_DURATION_MS);
Loading