Loading tests/RollbackTest/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -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 { Loading tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java +24 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } } Loading @@ -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; } Loading tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java +46 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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. Loading Loading @@ -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(); } } tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java +100 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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. */ Loading @@ -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"); } } Loading
tests/RollbackTest/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -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 { Loading
tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java +24 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } } Loading @@ -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; } Loading
tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java +46 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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. Loading Loading @@ -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(); } }
tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java +100 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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. */ Loading @@ -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"); } }