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

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

Merge changes from topic "cherrypick-all_rollbacks-f6fjt3va46" into udc-dev

* changes:
  Fix rollback reason in rollback all case
  Add a level to commit all available rollbacks
parents ee08e56c 836e3fb6
Loading
Loading
Loading
Loading
+17 −13
Original line number Diff line number Diff line
@@ -426,7 +426,7 @@ public class PackageWatchdog {
                                }
                                int impact = registeredObserver.onHealthCheckFailed(
                                        versionedPackage, failureReason, mitigationCount);
                                if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
                                if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0
                                        && impact < currentObserverImpact) {
                                    currentObserverToNotify = registeredObserver;
                                    currentObserverImpact = impact;
@@ -466,7 +466,7 @@ public class PackageWatchdog {
            if (registeredObserver != null) {
                int impact = registeredObserver.onHealthCheckFailed(
                        failingPackage, failureReason, 1);
                if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
                if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0
                        && impact < currentObserverImpact) {
                    currentObserverToNotify = registeredObserver;
                    currentObserverImpact = impact;
@@ -494,7 +494,7 @@ public class PackageWatchdog {
                    PackageHealthObserver registeredObserver = observer.registeredObserver;
                    if (registeredObserver != null) {
                        int impact = registeredObserver.onBootLoop(mitigationCount);
                        if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
                        if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0
                                && impact < currentObserverImpact) {
                            currentObserverToNotify = registeredObserver;
                            currentObserverImpact = impact;
@@ -576,19 +576,23 @@ public class PackageWatchdog {

    /** Possible severity values of the user impact of a {@link PackageHealthObserver#execute}. */
    @Retention(SOURCE)
    @IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_NONE,
                     PackageHealthObserverImpact.USER_IMPACT_LOW,
                     PackageHealthObserverImpact.USER_IMPACT_MEDIUM,
                     PackageHealthObserverImpact.USER_IMPACT_HIGH})
    @IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_10,
                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_50,
                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_70,
                     PackageHealthObserverImpact.USER_IMPACT_LEVEL_100})
    public @interface PackageHealthObserverImpact {
        /** No action to take. */
        int USER_IMPACT_NONE = 0;
        int USER_IMPACT_LEVEL_0 = 0;
        /* Action has low user impact, user of a device will barely notice. */
        int USER_IMPACT_LOW = 1;
        /* Action has medium user impact, user of a device will likely notice. */
        int USER_IMPACT_MEDIUM = 3;
        int USER_IMPACT_LEVEL_10 = 10;
        /* Actions having medium user impact, user of a device will likely notice. */
        int USER_IMPACT_LEVEL_30 = 30;
        int USER_IMPACT_LEVEL_50 = 50;
        int USER_IMPACT_LEVEL_70 = 70;
        /* Action has high user impact, a last resort, user of a device will be very frustrated. */
        int USER_IMPACT_HIGH = 5;
        int USER_IMPACT_LEVEL_100 = 100;
    }

    /** Register instances of this interface to receive notifications on package failure. */
@@ -633,7 +637,7 @@ public class PackageWatchdog {
         *                        boot loop (including this time).
         */
        default @PackageHealthObserverImpact int onBootLoop(int mitigationCount) {
            return PackageHealthObserverImpact.USER_IMPACT_NONE;
            return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
        }

        /**
+6 −5
Original line number Diff line number Diff line
@@ -489,13 +489,14 @@ public class RescueParty {
        switch(rescueLevel) {
            case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
            case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
                return PackageHealthObserverImpact.USER_IMPACT_LOW;
                return PackageHealthObserverImpact.USER_IMPACT_LEVEL_10;
            case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
            case LEVEL_WARM_REBOOT:
                return PackageHealthObserverImpact.USER_IMPACT_LEVEL_50;
            case LEVEL_FACTORY_RESET:
                return PackageHealthObserverImpact.USER_IMPACT_HIGH;
                return PackageHealthObserverImpact.USER_IMPACT_LEVEL_100;
            default:
                return PackageHealthObserverImpact.USER_IMPACT_NONE;
                return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
        }
    }

@@ -633,7 +634,7 @@ public class RescueParty {
                return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
                        mayPerformReboot(failedPackage)));
            } else {
                return PackageHealthObserverImpact.USER_IMPACT_NONE;
                return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
            }
        }

@@ -677,7 +678,7 @@ public class RescueParty {
        @Override
        public int onBootLoop(int mitigationCount) {
            if (isDisabled()) {
                return PackageHealthObserverImpact.USER_IMPACT_NONE;
                return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
            }
            return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true));
        }
+29 −19
Original line number Diff line number Diff line
@@ -105,36 +105,46 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
    @Override
    public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
            @FailureReasons int failureReason, int mitigationCount) {
        // For native crashes, we will roll back any available rollbacks
        boolean anyRollbackAvailable = !mContext.getSystemService(RollbackManager.class)
                .getAvailableRollbacks().isEmpty();
        int impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;

        if (failureReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH
                && !mContext.getSystemService(RollbackManager.class)
                .getAvailableRollbacks().isEmpty()) {
            return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
        }
        if (getAvailableRollback(failedPackage) == null) {
            // Don't handle the notification, no rollbacks available for the package
            return PackageHealthObserverImpact.USER_IMPACT_NONE;
        } else {
                && anyRollbackAvailable) {
            // For native crashes, we will directly roll back any available rollbacks
            // Note: For non-native crashes the rollback-all step has higher impact
            impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
        } else if (mitigationCount == 1 && getAvailableRollback(failedPackage) != null) {
            // Rollback is available, we may get a callback into #execute
            return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
            impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
        } else if (mitigationCount > 1 && anyRollbackAvailable) {
            // If any rollbacks are available, we will commit them
            impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70;
        }

        return impact;
    }

    @Override
    public boolean execute(@Nullable VersionedPackage failedPackage,
            @FailureReasons int rollbackReason, int mitigationCount) {
        if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
            mHandler.post(() -> rollbackAll());
            mHandler.post(() -> rollbackAll(rollbackReason));
            return true;
        }

        if (mitigationCount == 1) {
            RollbackInfo rollback = getAvailableRollback(failedPackage);
            if (rollback == null) {
                Slog.w(TAG, "Expected rollback but no valid rollback found for " + failedPackage);
                return false;
            }
            mHandler.post(() -> rollbackPackage(rollback, failedPackage, rollbackReason));
        // Assume rollback executed successfully
        } else if (mitigationCount > 1) {
            mHandler.post(() -> rollbackAll(rollbackReason));
        }

        // Assume rollbacks executed successfully
        return true;
    }

@@ -468,7 +478,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
    }

    @WorkerThread
    private void rollbackAll() {
    private void rollbackAll(@FailureReasons int rollbackReason) {
        assertInWorkerThread();
        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
        List<RollbackInfo> rollbacks = rollbackManager.getAvailableRollbacks();
@@ -487,7 +497,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {

        for (RollbackInfo rollback : rollbacks) {
            VersionedPackage sample = rollback.getPackages().get(0).getVersionRolledBackFrom();
            rollbackPackage(rollback, sample, PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
            rollbackPackage(rollback, sample, rollbackReason);
        }
    }
}
+11 −11
Original line number Diff line number Diff line
@@ -567,36 +567,36 @@ public class RescuePartyTest {

        // Ensure that no action is taken for cases where the failure reason is unknown
        assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_UNKNOWN, 1),
                PackageHealthObserverImpact.USER_IMPACT_NONE);
                PackageHealthObserverImpact.USER_IMPACT_LEVEL_0);

        // Ensure the correct user impact is returned for each mitigation count.
        assertEquals(observer.onHealthCheckFailed(null,
                PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1),
                PackageHealthObserverImpact.USER_IMPACT_LOW);
                PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);

        assertEquals(observer.onHealthCheckFailed(null,
                PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2),
                PackageHealthObserverImpact.USER_IMPACT_LOW);
                PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);

        assertEquals(observer.onHealthCheckFailed(null,
                PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3),
                PackageHealthObserverImpact.USER_IMPACT_HIGH);
                PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);

        assertEquals(observer.onHealthCheckFailed(null,
                PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4),
                PackageHealthObserverImpact.USER_IMPACT_HIGH);
                PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
    }

    @Test
    public void testBootLoopLevels() {
        RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);

        assertEquals(observer.onBootLoop(0), PackageHealthObserverImpact.USER_IMPACT_NONE);
        assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LOW);
        assertEquals(observer.onBootLoop(2), PackageHealthObserverImpact.USER_IMPACT_LOW);
        assertEquals(observer.onBootLoop(3), PackageHealthObserverImpact.USER_IMPACT_HIGH);
        assertEquals(observer.onBootLoop(4), PackageHealthObserverImpact.USER_IMPACT_HIGH);
        assertEquals(observer.onBootLoop(5), PackageHealthObserverImpact.USER_IMPACT_HIGH);
        assertEquals(observer.onBootLoop(0), PackageHealthObserverImpact.USER_IMPACT_LEVEL_0);
        assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
        assertEquals(observer.onBootLoop(2), PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
        assertEquals(observer.onBootLoop(3), PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
        assertEquals(observer.onBootLoop(4), PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
        assertEquals(observer.onBootLoop(5), PackageHealthObserverImpact.USER_IMPACT_LEVEL_100);
    }

    @Test
+97 −6
Original line number Diff line number Diff line
@@ -16,31 +16,65 @@

package com.android.server.rollback;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.util.Log;
import android.util.Xml;

import androidx.test.runner.AndroidJUnit4;

import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.PackageWatchdog;
import com.android.server.SystemConfig;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
import org.xmlpull.v1.XmlPullParser;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;


@RunWith(AndroidJUnit4.class)
public class RollbackPackageHealthObserverTest {
    @Mock
    private Context mMockContext;
    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private PackageWatchdog mMockPackageWatchdog;
    @Mock
    RollbackManager mRollbackManager;
    @Mock
    RollbackInfo mRollbackInfo;
    @Mock
    PackageRollbackInfo mPackageRollbackInfo;

    private MockitoSession mSession;
    private static final String APP_A = "com.package.a";
    private static final long VERSION_CODE = 1L;
    private static final String LOG_TAG = "RollbackPackageHealthObserverTest";

    private SystemConfig mSysConfig;
@@ -50,6 +84,22 @@ public class RollbackPackageHealthObserverTest {
    @Before
    public void setup() {
        mSysConfig = new SystemConfigTestClass();

        mSession = ExtendedMockito.mockitoSession()
                .initMocks(this)
                .strictness(Strictness.LENIENT)
                .spyStatic(PackageWatchdog.class)
                .startMocking();

        // Mock PackageWatchdog
        doAnswer((Answer<PackageWatchdog>) invocationOnMock -> mMockPackageWatchdog)
                .when(() -> PackageWatchdog.getInstance(mMockContext));

    }

    @After
    public void tearDown() throws Exception {
        mSession.finishMocking();
    }

    /**
@@ -61,6 +111,47 @@ public class RollbackPackageHealthObserverTest {
        }
    }

    @Test
    public void testHealthCheckLevels() {
        RollbackPackageHealthObserver observer =
                spy(new RollbackPackageHealthObserver(mMockContext));
        VersionedPackage testFailedPackage = new VersionedPackage(APP_A, VERSION_CODE);


        when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);

        // Crashes with no rollbacks available
        assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
                observer.onHealthCheckFailed(null,
                        PackageWatchdog.FAILURE_REASON_NATIVE_CRASH, 1));
        assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
                observer.onHealthCheckFailed(null,
                        PackageWatchdog.FAILURE_REASON_APP_CRASH, 1));

        // Make the rollbacks available
        when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(mRollbackInfo));
        when(mRollbackInfo.getPackages()).thenReturn(List.of(mPackageRollbackInfo));
        when(mPackageRollbackInfo.getVersionRolledBackFrom()).thenReturn(testFailedPackage);

        // native crash
        assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
                observer.onHealthCheckFailed(null,
                        PackageWatchdog.FAILURE_REASON_NATIVE_CRASH, 1));
        // non-native crash
        assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
                observer.onHealthCheckFailed(testFailedPackage,
                        PackageWatchdog.FAILURE_REASON_APP_CRASH, 1));
        // Second non-native crash again
        assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_70,
                observer.onHealthCheckFailed(testFailedPackage,
                        PackageWatchdog.FAILURE_REASON_APP_CRASH, 2));
        // Subsequent crashes when rollbacks have completed
        when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of());
        assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
                observer.onHealthCheckFailed(testFailedPackage,
                        PackageWatchdog.FAILURE_REASON_APP_CRASH, 3));
    }

    /**
     * Test that isAutomaticRollbackDenied works correctly when packages that are not
     * denied are sent.
Loading