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

Commit 7a87d16f authored by JW Wang's avatar JW Wang Committed by Android (Google) Code Review
Browse files

Merge changes I1889b063,I64a5d494

* changes:
  Remove unused locks (2/n)
  Fix up the threading model (1/n)
parents d6b47ab2 71c84cc2
Loading
Loading
Loading
Loading
+48 −24
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@ package com.android.server.rollback;

import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN;

import android.annotation.AnyThread;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -40,8 +42,8 @@ import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.PackageWatchdog;
import com.android.server.PackageWatchdog.FailureReasons;
@@ -59,6 +61,7 @@ import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;

/**
 * {@link PackageHealthObserver} for {@link RollbackManagerService}.
@@ -76,7 +79,6 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
    private final ApexManager mApexManager;
    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<>();

    RollbackPackageHealthObserver(Context context) {
@@ -113,7 +115,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
    public boolean execute(@Nullable VersionedPackage failedPackage,
            @FailureReasons int rollbackReason) {
        if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
            rollbackAll();
            mHandler.post(() -> rollbackAll());
            return true;
        }

@@ -122,7 +124,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
            Slog.w(TAG, "Expected rollback but no valid rollback found for " + failedPackage);
            return false;
        }
        rollbackPackage(rollback, failedPackage, rollbackReason);
        mHandler.post(() -> rollbackPackage(rollback, failedPackage, rollbackReason));
        // Assume rollback executed successfully
        return true;
    }
@@ -132,10 +134,15 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
        return NAME;
    }

    private void assertInWorkerThread() {
        Preconditions.checkState(mHandler.getLooper().isCurrentThread());
    }

    /**
     * Start observing health of {@code packages} for {@code durationMs}.
     * This may cause {@code packages} to be rolled back if they crash too freqeuntly.
     */
    @AnyThread
    void startObservingHealth(List<String> packages, long durationMs) {
        PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
    }
@@ -143,11 +150,14 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
    /** Verifies the rollback state after a reboot and schedules polling for sometime after reboot
     * to check for native crashes and mitigate them if needed.
     */
    @AnyThread
    void onBootCompletedAsync() {
        mHandler.post(()->onBootCompleted());
    }

    @WorkerThread
    private void onBootCompleted() {
        assertInWorkerThread();
        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
        if (!rollbackManager.getAvailableRollbacks().isEmpty()) {
            // TODO(gavincorkery): Call into Package Watchdog from outside the observer
@@ -162,6 +172,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
        }
    }

    @AnyThread
    private RollbackInfo getAvailableRollback(VersionedPackage failedPackage) {
        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
        for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
@@ -191,8 +202,10 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
        return null;
    }

    @WorkerThread
    private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager,
            int rollbackId, @Nullable VersionedPackage logPackage) {
        assertInWorkerThread();
        BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
@@ -202,12 +215,14 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
        };
        IntentFilter sessionUpdatedFilter =
                new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
        mContext.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
        mContext.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter, null, mHandler);
        return sessionUpdatedReceiver;
    }

    @WorkerThread
    private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId,
            BroadcastReceiver listener, @Nullable VersionedPackage logPackage) {
        assertInWorkerThread();
        PackageInstaller packageInstaller =
                mContext.getPackageManager().getPackageInstaller();
        List<RollbackInfo> recentRollbacks =
@@ -249,23 +264,25 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
     * Returns {@code true} if staged session associated with {@code rollbackId} was marked
     * as handled, {@code false} if already handled.
     */
    @WorkerThread
    private boolean markStagedSessionHandled(int rollbackId) {
        synchronized (mPendingStagedRollbackIds) {
        assertInWorkerThread();
        return mPendingStagedRollbackIds.remove(rollbackId);
    }
    }

    /**
     * Returns {@code true} if all pending staged rollback sessions were marked as handled,
     * {@code false} if there is any left.
     */
    @WorkerThread
    private boolean isPendingStagedSessionsEmpty() {
        synchronized (mPendingStagedRollbackIds) {
        assertInWorkerThread();
        return mPendingStagedRollbackIds.isEmpty();
    }
    }

    @WorkerThread
    private void saveStagedRollbackId(int stagedRollbackId, @Nullable VersionedPackage logPackage) {
        assertInWorkerThread();
        writeStagedRollbackId(mLastStagedRollbackIdsFile, stagedRollbackId, logPackage);
    }

@@ -286,7 +303,9 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
        }
    }

    @WorkerThread
    private SparseArray<String> popLastStagedRollbackIds() {
        assertInWorkerThread();
        try {
            return readStagedRollbackIds(mLastStagedRollbackIdsFile);
        } finally {
@@ -319,6 +338,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
    /**
     * Returns true if the package name is the name of a module.
     */
    @AnyThread
    private boolean isModule(String packageName) {
        // Check if the package is an APK inside an APEX. If it is, use the parent APEX package when
        // querying PackageManager.
@@ -346,8 +366,10 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
     * @param rollback {@code rollbackInfo} of the {@code failedPackage}
     * @param failedPackage the package that needs to be rolled back
     */
    @WorkerThread
    private void rollbackPackage(RollbackInfo rollback, VersionedPackage failedPackage,
            @FailureReasons int rollbackReason) {
        assertInWorkerThread();
        final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
        int reasonToLog = WatchdogRollbackLogger.mapFailureReasonToMetric(rollbackReason);
        final String failedPackageToLog;
@@ -366,15 +388,15 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
        WatchdogRollbackLogger.logEvent(logPackage,
                FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
                reasonToLog, failedPackageToLog);
        final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {

        Consumer<Intent> onResult = result -> {
            assertInWorkerThread();
            int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
                    RollbackManager.STATUS_FAILURE);
            if (status == RollbackManager.STATUS_SUCCESS) {
                if (rollback.isStaged()) {
                    int rollbackId = rollback.getRollbackId();
                    synchronized (mPendingStagedRollbackIds) {
                    mPendingStagedRollbackIds.add(rollbackId);
                    }
                    BroadcastReceiver listener =
                            listenForStagedSessionReady(rollbackManager, rollbackId,
                                    logPackage);
@@ -395,28 +417,30 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
                                .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
                        reasonToLog, failedPackageToLog);
            }
        };

        final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver(result -> {
            mHandler.post(() -> onResult.accept(result));
        });

        mHandler.post(() ->
        rollbackManager.commitRollback(rollback.getRollbackId(),
                        Collections.singletonList(failedPackage),
                        rollbackReceiver.getIntentSender()));
                Collections.singletonList(failedPackage), rollbackReceiver.getIntentSender());
    }

    @WorkerThread
    private void rollbackAll() {
        assertInWorkerThread();
        Slog.i(TAG, "Rolling back all available rollbacks");
        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
        List<RollbackInfo> rollbacks = rollbackManager.getAvailableRollbacks();

        // Add all rollback ids to mPendingStagedRollbackIds, so that we do not reboot before all
        // pending staged rollbacks are handled.
        synchronized (mPendingStagedRollbackIds) {
        for (RollbackInfo rollback : rollbacks) {
            if (rollback.isStaged()) {
                mPendingStagedRollbackIds.add(rollback.getRollbackId());
            }
        }
        }

        for (RollbackInfo rollback : rollbacks) {
            VersionedPackage sample = rollback.getPackages().get(0).getVersionRolledBackFrom();