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

Commit 232a4d40 authored by Mohammad Samiul Islam's avatar Mohammad Samiul Islam
Browse files

Allow RPHO save and restore more than one rollback id for logging

We now want to log success/failure of more than one rollback.

While here, also increased the amount of information we log in logEvent.

Bug: 148002608
Test: builds successfully
Change-Id: Ic05f8117661120360d4592747bb596c76992c3a6
parent aa85de17
Loading
Loading
Loading
Loading
+61 −33
Original line number Diff line number Diff line
@@ -52,13 +52,15 @@ import com.android.server.PackageWatchdog.FailureReasons;
import com.android.server.PackageWatchdog.PackageHealthObserver;
import com.android.server.PackageWatchdog.PackageHealthObserverImpact;

import libcore.io.IoUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

@@ -72,11 +74,10 @@ import java.util.Set;
public final class RollbackPackageHealthObserver implements PackageHealthObserver {
    private static final String TAG = "RollbackPackageHealthObserver";
    private static final String NAME = "rollback-observer";
    private static final int INVALID_ROLLBACK_ID = -1;

    private final Context mContext;
    private final Handler mHandler;
    private final File mLastStagedRollbackIdFile;
    private final File mLastStagedRollbackIdsFile;
    // Staged rollback ids that have been committed but their session is not yet ready
    @GuardedBy("mPendingStagedRollbackIds")
    private final Set<Integer> mPendingStagedRollbackIds = new ArraySet<>();
@@ -88,7 +89,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
        mHandler = handlerThread.getThreadHandler();
        File dataDir = new File(Environment.getDataDirectory(), "rollback-observer");
        dataDir.mkdirs();
        mLastStagedRollbackIdFile = new File(dataDir, "last-staged-rollback-id");
        mLastStagedRollbackIdsFile = new File(dataDir, "last-staged-rollback-ids");
        PackageWatchdog.getInstance(mContext).registerHealthObserver(this);
    }

@@ -150,22 +151,27 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve

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

        if (!rollbackManager.getAvailableRollbacks().isEmpty()) {
            // TODO(gavincorkery): Call into Package Watchdog from outside the observer
            PackageWatchdog.getInstance(mContext).scheduleCheckAndMitigateNativeCrashes();
        }

        int rollbackId = popLastStagedRollbackId();
        if (rollbackId == INVALID_ROLLBACK_ID) {
            // No staged rollback before reboot
            return;
        List<Integer> rollbackIds = popLastStagedRollbackIds();
        Iterator<Integer> rollbackIterator = rollbackIds.iterator();
        while (rollbackIterator.hasNext()) {
            int rollbackId = rollbackIterator.next();
            logRollbackStatusOnBoot(rollbackId, rollbackManager.getRecentlyCommittedRollbacks());
        }

    }

    private void logRollbackStatusOnBoot(int rollbackId,
            List<RollbackInfo> recentlyCommittedRollbacks) {
        PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
        String moduleMetadataPackageName = getModuleMetadataPackageName();

        RollbackInfo rollback = null;
        for (RollbackInfo info : rollbackManager.getRecentlyCommittedRollbacks()) {
        for (RollbackInfo info : recentlyCommittedRollbacks) {
            if (rollbackId == info.getRollbackId()) {
                rollback = info;
                break;
@@ -294,7 +300,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
                    if (logPackage != null) {
                        // We save the rollback id so that after reboot, we can log if rollback was
                        // successful or not. If logPackage is null, then there is nothing to log.
                        saveLastStagedRollbackId(rollbackId);
                        saveStagedRollbackId(rollbackId);
                    }
                    logEvent(logPackage,
                            StatsLog
@@ -338,34 +344,38 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
        }
    }

    private void saveLastStagedRollbackId(int stagedRollbackId) {
    private void saveStagedRollbackId(int stagedRollbackId) {
        try {
            FileOutputStream fos = new FileOutputStream(mLastStagedRollbackIdFile);
            FileOutputStream fos = new FileOutputStream(mLastStagedRollbackIdsFile);
            PrintWriter pw = new PrintWriter(fos);
            pw.println(stagedRollbackId);
            pw.append(",").append(String.valueOf(stagedRollbackId));
            pw.flush();
            FileUtils.sync(fos);
            pw.close();
        } catch (IOException e) {
            Slog.e(TAG, "Failed to save last staged rollback id", e);
            mLastStagedRollbackIdFile.delete();
            mLastStagedRollbackIdsFile.delete();
        }
    }

    private int popLastStagedRollbackId() {
        int rollbackId = INVALID_ROLLBACK_ID;
        if (!mLastStagedRollbackIdFile.exists()) {
            return rollbackId;
    private List<Integer> popLastStagedRollbackIds() {
        try (BufferedReader reader =
                     new BufferedReader(new FileReader(mLastStagedRollbackIdsFile))) {
            String line = reader.readLine();
            // line is of format : ",id1,id2,id3....,idn"
            String[] sessionIdsStr = line.split(",");
            ArrayList<Integer> result = new ArrayList<>();
            for (String sessionIdStr: sessionIdsStr) {
                if (!TextUtils.isEmpty(sessionIdStr.trim())) {
                    result.add(Integer.parseInt(sessionIdStr));
                }

        try {
            rollbackId = Integer.parseInt(
                    IoUtils.readFileAsString(mLastStagedRollbackIdFile.getAbsolutePath()).trim());
        } catch (IOException | NumberFormatException e) {
            Slog.e(TAG, "Failed to retrieve last staged rollback id", e);
            }
        mLastStagedRollbackIdFile.delete();
        return rollbackId;
            return result;
        } catch (Exception ignore) {
            return Collections.emptyList();
        } finally {
            mLastStagedRollbackIdsFile.delete();
        }
    }

    private static String rollbackTypeToString(int type) {
@@ -383,12 +393,30 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
        }
    }

    private static String rollbackReasonToString(int reason) {
        switch (reason) {
            case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH:
                return "REASON_NATIVE_CRASH";
            case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK:
                return "REASON_EXPLICIT_HEALTH_CHECK";
            case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH:
                return "REASON_APP_CRASH";
            case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING:
                return "REASON_APP_NOT_RESPONDING";
            default:
                return "UNKNOWN";
        }
    }

    private static void logEvent(@Nullable VersionedPackage logPackage, int type,
            int rollbackReason, @NonNull String failingPackageName) {
        Slog.i(TAG, "Watchdog event occurred of type: " + rollbackTypeToString(type));
        Slog.i(TAG, "Watchdog event occurred with type: " + rollbackTypeToString(type)
                + " logPackage: " + logPackage
                + " rollbackReason: " + rollbackReasonToString(rollbackReason)
                + " failedPackageName: " + failingPackageName);
        if (logPackage != null) {
            StatsLog.logWatchdogRollbackOccurred(type, logPackage.getPackageName(),
                    logPackage.getVersionCode(), rollbackReason, failingPackageName);
                    logPackage.getLongVersionCode(), rollbackReason, failingPackageName);
        }
    }