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

Commit e53ab028 authored by Shafik Nassar's avatar Shafik Nassar Committed by android-build-merger
Browse files

Merge "Make Native Watchdog trigger RollbackManager rollback" into qt-dev am: bcbf219f

am: c73886b0

Change-Id: I1d1a1282b93e0bc08c20160951cf67707c3548ca
parents ca22c05a c73886b0
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -649,8 +649,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
                // hasn't actually been updated.
                onPackageReplaced(apexPackageName);
            }

            mPackageHealthObserver.onBootCompleted();
            mPackageHealthObserver.onBootCompletedAsync();
        });
    }

+65 −13
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.PowerManager;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Slog;
import android.util.StatsLog;
@@ -49,9 +50,12 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * {@code PackageHealthObserver} for {@code RollbackManagerService}.
 * {@link PackageHealthObserver} for {@link RollbackManagerService}.
 * This class monitors crashes and triggers RollbackManager rollback accordingly.
 * It also monitors native crashes for some short while after boot.
 *
 * @hide
 */
@@ -59,12 +63,21 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
    private static final String TAG = "RollbackPackageHealthObserver";
    private static final String NAME = "rollback-observer";
    private static final int INVALID_ROLLBACK_ID = -1;
    // TODO: make the following values configurable via DeviceConfig
    private static final long NATIVE_CRASH_POLLING_INTERVAL_MILLIS =
            TimeUnit.SECONDS.toMillis(30);
    private static final long NUMBER_OF_NATIVE_CRASH_POLLS = 10;

    private final Context mContext;
    private final Handler mHandler;
    private final File mLastStagedRollbackIdFile;
    // this field is initialized in the c'tor and then only accessed from mHandler thread, so
    // no need to guard with a lock
    private long mNumberOfNativeCrashPollsRemaining;

    RollbackPackageHealthObserver(Context context) {
        mContext = context;
        mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS;
        HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
        handlerThread.start();
        mHandler = handlerThread.getThreadHandler();
@@ -76,8 +89,6 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve

    @Override
    public int onHealthCheckFailed(VersionedPackage failedPackage) {
        VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();

        if (getAvailableRollback(mContext.getSystemService(RollbackManager.class), failedPackage)
                == null) {
            // Don't handle the notification, no rollbacks available for the package
@@ -145,16 +156,29 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
        PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
    }

    /** Verifies the rollback state after a reboot. */
    public void onBootCompleted() {
    /** Verifies the rollback state after a reboot and schedules polling for sometime after reboot
     * to check for native crashes and mitigate them if needed.
     */
    public void onBootCompletedAsync() {
        mHandler.post(()->onBootCompleted());
    }

    private void onBootCompleted() {
        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
        PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
        String moduleMetadataPackageName = getModuleMetadataPackageName();
        VersionedPackage newModuleMetadataPackage = getModuleMetadataPackage();

        if (getAvailableRollback(rollbackManager, newModuleMetadataPackage) != null) {
            scheduleCheckAndMitigateNativeCrashes();
        }

        int rollbackId = popLastStagedRollbackId();
        if (rollbackId == INVALID_ROLLBACK_ID) {
            // No staged rollback before reboot
            return;
        }

        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
        PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
        RollbackInfo rollback = null;
        for (RollbackInfo info : rollbackManager.getRecentlyCommittedRollbacks()) {
            if (rollbackId == info.getRollbackId()) {
@@ -168,14 +192,12 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
            return;
        }

        String moduleMetadataPackageName = getModuleMetadataPackageName();

        // Use the version of the metadata package that was installed before
        // we rolled back for logging purposes.
        VersionedPackage moduleMetadataPackage = null;
        VersionedPackage oldModuleMetadataPackage = null;
        for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
            if (packageRollback.getPackageName().equals(moduleMetadataPackageName)) {
                moduleMetadataPackage = packageRollback.getVersionRolledBackFrom();
                oldModuleMetadataPackage = packageRollback.getVersionRolledBackFrom();
                break;
            }
        }
@@ -187,12 +209,12 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
            return;
        }
        if (sessionInfo.isStagedSessionApplied()) {
            logEvent(moduleMetadataPackage,
            logEvent(oldModuleMetadataPackage,
                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS);
        } else if (sessionInfo.isStagedSessionReady()) {
            // TODO: What do for staged session ready but not applied
        } else {
            logEvent(moduleMetadataPackage,
            logEvent(oldModuleMetadataPackage,
                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE);
        }
    }
@@ -320,4 +342,34 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
                    moduleMetadataPackage.getPackageName(), moduleMetadataPackage.getVersionCode());
        }
    }

    /**
     * This method should be only called on mHandler thread, since it modifies
     * {@link #mNumberOfNativeCrashPollsRemaining} and we want to keep this class lock free.
     */
    private void checkAndMitigateNativeCrashes() {
        mNumberOfNativeCrashPollsRemaining--;
        // Check if native watchdog reported a crash
        if ("1".equals(SystemProperties.get("ro.init.updatable_crashing"))) {
            execute(getModuleMetadataPackage());
            // we stop polling after an attempt to execute rollback, regardless of whether the
            // attempt succeeds or not
        } else {
            if (mNumberOfNativeCrashPollsRemaining > 0) {
                mHandler.postDelayed(() -> checkAndMitigateNativeCrashes(),
                        NATIVE_CRASH_POLLING_INTERVAL_MILLIS);
            }
        }
    }

    /**
     * Since this method can eventually trigger a RollbackManager rollback, it should be called
     * only once boot has completed {@code onBootCompleted} and not earlier, because the install
     * session must be entirely completed before we try to rollback.
     */
    private void scheduleCheckAndMitigateNativeCrashes() {
        Slog.i(TAG, "Scheduling " + mNumberOfNativeCrashPollsRemaining + " polls to check "
                + "and mitigate native crashes");
        mHandler.post(()->checkAndMitigateNativeCrashes());
    }
}