From 858845f72d4bda3f2dbfb84e91465226d41c13b1 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Wed, 14 Jul 2021 11:17:04 +0800 Subject: [PATCH] Support rollback for rebootless apex (2/n) The code is already there. We just need to remove the restriction to enable rollback support. * Note only the RETAIN policy is supported for rebootless APEX. * Note this CL breaks CtsInstallHostTestCases. We will fix it in the next CL. Bug: 195517333 Test: atest StagedRollbackTest Change-Id: Ib218186fe1448f1f316d2c3b895636efc657ee0c --- .../server/pm/PackageInstallerService.java | 5 ---- .../rollback/RollbackManagerServiceImpl.java | 5 ++++ tests/RollbackTest/Android.bp | 8 ++++-- .../tests/rollback/StagedRollbackTest.java | 27 +++++++++++++++++++ .../rollback/host/StagedRollbackTest.java | 18 ++++++++++--- 5 files changed, 52 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index b34a3a2b8dcbf..9b0cab5db8324 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -651,11 +651,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements if (params.isMultiPackage) { throw new IllegalArgumentException("A multi-session can't be set as APEX."); } - if (!params.isStaged - && (params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) { - throw new IllegalArgumentException( - "Non-staged APEX session doesn't support INSTALL_ENABLE_ROLLBACK"); - } if (isCalledBySystemOrShell(callingUid) || mBypassNextAllowedApexUpdateCheck) { params.installFlags |= PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK; } else { diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index e7b275643b662..d0a96b14495ae 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -843,6 +843,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba final String packageName = newPackage.getPackageName(); final int rollbackDataPolicy = computeRollbackDataPolicy( session.rollbackDataPolicy, newPackage.getRollbackDataPolicy()); + if (!session.isStaged() && (installFlags & PackageManager.INSTALL_APEX) != 0 + && rollbackDataPolicy != PackageManager.ROLLBACK_DATA_POLICY_RETAIN) { + Slog.e(TAG, "Only RETAIN is supported for rebootless APEX: " + packageName); + return false; + } Slog.i(TAG, "Enabling rollback for install of " + packageName + ", session:" + session.sessionId + ", rollbackDataPolicy=" + rollbackDataPolicy); diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp index 6e1cef496f405..9f6ce4e8425b4 100644 --- a/tests/RollbackTest/Android.bp +++ b/tests/RollbackTest/Android.bp @@ -31,7 +31,8 @@ android_test { test_config: "RollbackTest.xml", java_resources: [ ":com.android.apex.apkrollback.test_v2", - ":com.android.apex.apkrollback.test_v2Crashing" + ":com.android.apex.apkrollback.test_v2Crashing", + ":test.rebootless_apex_v2", ], } @@ -47,7 +48,10 @@ java_test_host { ], test_suites: ["general-tests"], test_config: "StagedRollbackTest.xml", - data: [":com.android.apex.apkrollback.test_v1"], + data: [ + ":com.android.apex.apkrollback.test_v1", + ":test.rebootless_apex_v1", + ], } java_test_host { diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java index 539090b2d7858..4512876a8b00c 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java @@ -240,6 +240,33 @@ public class StagedRollbackTest { assertThat(rollback.getCommittedSessionId()).isNotEqualTo(-1); } + @Test + public void testRollbackRebootlessApex() throws Exception { + final String packageName = "test.apex.rebootless"; + assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(1); + + // install + TestApp apex1 = new TestApp("TestRebootlessApexV1", packageName, 1, + /* isApex= */ true, "test.rebootless_apex_v1.apex"); + TestApp apex2 = new TestApp("TestRebootlessApexV2", packageName, 2, + /* isApex= */ true, "test.rebootless_apex_v2.apex"); + Install.single(apex2).setEnableRollback(PackageManager.ROLLBACK_DATA_POLICY_RETAIN) + .commit(); + + // verify rollback + assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(2); + RollbackManager rm = RollbackUtils.getRollbackManager(); + RollbackInfo rollback = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), packageName); + assertThat(rollback).isNotNull(); + assertThat(rollback).packagesContainsExactly(Rollback.from(apex2).to(apex1)); + assertThat(rollback).isNotStaged(); + + // rollback + RollbackUtils.rollback(rollback.getRollbackId()); + assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(1); + } + @Test public void hasMainlineModule() throws Exception { String pkgName = getModuleMetadataPackageName(); diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java index 293f1597684a6..3576a78048270 100644 --- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java +++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java @@ -96,7 +96,9 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex", "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex", apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "*", - apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "*"); + apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "*", + "/system/apex/test.rebootless_apex_v*.apex", + "/data/apex/active/test.apex.rebootless*.apex"); } /** @@ -160,7 +162,7 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { */ @Test public void testRollbackApexWithApkCrashing() throws Exception { - pushTestApex(); + pushTestApex(APK_IN_APEX_TESTAPEX_NAME + "_v1.apex"); // Install an apex with apk that crashes runPhase("testRollbackApexWithApkCrashing_Phase1_Install"); @@ -180,6 +182,15 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null); } + /** + * Tests rollback is supported correctly for rebootless apex + */ + @Test + public void testRollbackRebootlessApex() throws Exception { + pushTestApex("test.rebootless_apex_v1.apex"); + runPhase("testRollbackRebootlessApex"); + } + /** * Tests that packages are monitored across multiple reboots. */ @@ -204,9 +215,8 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { runPhase("testWatchdogMonitorsAcrossReboots_Phase3_VerifyRollback"); } - private void pushTestApex() throws Exception { + private void pushTestApex(String fileName) throws Exception { CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild()); - final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex"; final File apex = buildHelper.getTestFile(fileName); try { getDevice().enableAdbRoot();