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

Commit e77a3e1d authored by Zimuzo's avatar Zimuzo
Browse files

Add network health check watchdog triggered rollback tests

This cl improves code coverage for the PackageWatchdog explicit health
checks.

Updating the NetworkStack triggers an explicit health check with
a time deadline. At the deadline, if network is unavailable on the device,
the update is rolled back, if network is available, nothing happens.

Bug: 132640467
Test: atest StagedRollbackTest

Change-Id: I16a40244de9345930a1c981188aa33546fe872fc
parent 6cf5ea63
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -95,7 +95,7 @@ android_test {
        ":RollbackTestAppASplitV2",
    ],
    test_config: "RollbackTest.xml",
    sdk_version: "test_current",
    // TODO: sdk_version: "test_current" when Intent#resolveSystemservice is TestApi
}

java_test_host {
+24 −5
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
@@ -82,13 +83,31 @@ class RollbackTestUtils {
     * Returns -1 if the package is not currently installed.
     */
    static long getInstalledVersion(String packageName) {
        PackageInfo pi = getPackageInfo(packageName);
        if (pi == null) {
            return -1;
        } else {
            return pi.getLongVersionCode();
        }
    }

    private static boolean isSystemAppWithoutUpdate(String packageName) {
        PackageInfo pi = getPackageInfo(packageName);
        if (pi == null) {
            return false;
        } else {
            return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)
                    && ((pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0);
        }
    }

    private static PackageInfo getPackageInfo(String packageName) {
        Context context = InstrumentationRegistry.getContext();
        PackageManager pm = context.getPackageManager();
        try {
            PackageInfo info = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
            return info.getLongVersionCode();
            return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
        } catch (PackageManager.NameNotFoundException e) {
            return -1;
            return null;
        }
    }

@@ -109,8 +128,8 @@ class RollbackTestUtils {
     * @throws AssertionError if package can't be uninstalled.
     */
    static void uninstall(String packageName) throws InterruptedException, IOException {
        // No need to uninstall if the package isn't installed.
        if (getInstalledVersion(packageName) == -1) {
        // No need to uninstall if the package isn't installed or is installed on /system.
        if (getInstalledVersion(packageName) == -1 || isSystemAppWithoutUpdate(packageName)) {
            return;
        }

+46 −0
Original line number Diff line number Diff line
@@ -21,7 +21,9 @@ import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfo

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.VersionedPackage;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
@@ -30,6 +32,8 @@ import androidx.test.InstrumentationRegistry;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

@@ -54,6 +58,8 @@ public class StagedRollbackTest {
    private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
    private static final String TEST_APP_A_V1 = "RollbackTestAppAv1.apk";
    private static final String TEST_APP_A_CRASHING_V2 = "RollbackTestAppACrashingV2.apk";
    private static final String NETWORK_STACK_CONNECTOR_CLASS =
            "android.net.INetworkStackConnector";

    /**
     * Adopts common shell permissions needed for rollback tests.
@@ -157,4 +163,44 @@ public class StagedRollbackTest {
        assertTrue(rollback.isStaged());
        assertNotEquals(-1, rollback.getCommittedSessionId());
    }

    @Test
    public void resetNetworkStack() throws Exception {
        RollbackManager rm = RollbackTestUtils.getRollbackManager();
        String networkStack = getNetworkStackPackageName();

        rm.expireRollbackForPackage(networkStack);
        RollbackTestUtils.uninstall(networkStack);

        assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
                        networkStack));
    }

    @Test
    public void assertNetworkStackRollbackAvailable() throws Exception {
        RollbackManager rm = RollbackTestUtils.getRollbackManager();
        assertNotNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
                        getNetworkStackPackageName()));
    }

    @Test
    public void assertNetworkStackRollbackCommitted() throws Exception {
        RollbackManager rm = RollbackTestUtils.getRollbackManager();
        assertNotNull(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
                        getNetworkStackPackageName()));
    }

    @Test
    public void assertNoNetworkStackRollbackCommitted() throws Exception {
        RollbackManager rm = RollbackTestUtils.getRollbackManager();
        assertNull(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
                        getNetworkStackPackageName()));
    }

    private String getNetworkStackPackageName() {
        Intent intent = new Intent(NETWORK_STACK_CONNECTOR_CLASS);
        ComponentName comp = intent.resolveSystemService(
                InstrumentationRegistry.getContext().getPackageManager(), 0);
        return comp.getPackageName();
    }
}
+100 −0
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@@ -43,6 +45,20 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
                    phase));
    }

    @Before
    public void setUp() throws Exception {
        // Disconnect internet so we can test network health triggered rollbacks
        getDevice().executeShellCommand("svc wifi disable");
        getDevice().executeShellCommand("svc data disable");
    }

    @After
    public void tearDown() throws Exception {
        // Reconnect internet after testing network health triggered rollbacks
        getDevice().executeShellCommand("svc wifi enable");
        getDevice().executeShellCommand("svc data enable");
    }

    /**
     * Tests watchdog triggered staged rollbacks involving only apks.
     */
@@ -63,6 +79,90 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
        }

        getDevice().waitForDeviceAvailable();

        runPhase("testBadApkOnlyConfirmRollback");
    }

    /**
     * Tests failed network health check triggers watchdog staged rollbacks.
     */
    @Test
    public void testNetworkFailedRollback() throws Exception {
        // Remove available rollbacks and uninstall NetworkStack on /data/
        runPhase("resetNetworkStack");
        // Reduce health check deadline
        getDevice().executeShellCommand("device_config put rollback "
                + "watchdog_request_timeout_millis 300000");
        // Simulate re-installation of new NetworkStack with rollbacks enabled
        getDevice().executeShellCommand("pm install -r --staged --enable-rollback "
                + "/system/priv-app/NetworkStack/NetworkStack.apk");

        // Sleep to allow writes to disk before reboot
        Thread.sleep(5000);
        // Reboot device to activate staged package
        getDevice().reboot();
        getDevice().waitForDeviceAvailable();

        // Verify rollback was enabled
        runPhase("assertNetworkStackRollbackAvailable");

        // Sleep for < health check deadline
        Thread.sleep(5000);
        // Verify rollback was not executed before health check deadline
        runPhase("assertNoNetworkStackRollbackCommitted");
        try {
            // This is expected to fail due to the device being rebooted out
            // from underneath the test. If this fails for reasons other than
            // the device reboot, those failures should result in failure of
            // the assertNetworkStackExecutedRollback phase.
            CLog.logAndDisplay(LogLevel.INFO, "Sleep and expect to fail while sleeping");
            // Sleep for > health check deadline
            Thread.sleep(260000);
        } catch (AssertionError e) {
            // AssertionError is expected.
        }

        getDevice().waitForDeviceAvailable();
        // Verify rollback was executed after health check deadline
        runPhase("assertNetworkStackRollbackCommitted");
    }

    /**
     * Tests passed network health check does not trigger watchdog staged rollbacks.
     */
    @Test
    public void testNetworkPassedDoesNotRollback() throws Exception {
        // Remove available rollbacks and uninstall NetworkStack on /data/
        runPhase("resetNetworkStack");
        // Reduce health check deadline, here unlike the network failed case, we use
        // a longer deadline because joining a network can take a much longer time for
        // reasons external to the device than 'not joining'
        getDevice().executeShellCommand("device_config put rollback "
                + "watchdog_request_timeout_millis 300000");
        // Simulate re-installation of new NetworkStack with rollbacks enabled
        getDevice().executeShellCommand("pm install -r --staged --enable-rollback "
                + "/system/priv-app/NetworkStack/NetworkStack.apk");

        // Sleep to allow writes to disk before reboot
        Thread.sleep(5000);
        // Reboot device to activate staged package
        getDevice().reboot();
        getDevice().waitForDeviceAvailable();

        // Verify rollback was enabled
        runPhase("assertNetworkStackRollbackAvailable");

        // Connect to internet so network health check passes
        getDevice().executeShellCommand("svc wifi enable");
        getDevice().executeShellCommand("svc data enable");

        // Wait for device available because emulator device may restart after turning
        // on mobile data
        getDevice().waitForDeviceAvailable();

        // Sleep for > health check deadline
        Thread.sleep(310000);
        // Verify rollback was not executed after health check deadline
        runPhase("assertNoNetworkStackRollbackCommitted");
    }
}