Merge changes from topic "bug195517333"

* changes:
  Support rollback for rebootless apex (2/n)
  Handle downgrade install for rebootless apexes correctly (1/n)
This commit is contained in:
JW Wang
2021-10-18 09:09:21 +00:00
committed by Android (Google) Code Review
10 changed files with 73 additions and 42 deletions

View File

@@ -1035,17 +1035,6 @@ public abstract class ApexManager {
}
}
private void checkDowngrade(PackageInfo existingApexPkg, PackageInfo newApexPkg)
throws PackageManagerException {
final long currentVersionCode = existingApexPkg.applicationInfo.longVersionCode;
final long newVersionCode = newApexPkg.applicationInfo.longVersionCode;
if (currentVersionCode > newVersionCode) {
throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE,
"Downgrade of APEX package " + newApexPkg.packageName
+ " is not allowed");
}
}
@Override
void installPackage(File apexFile, PackageParser2 packageParser)
throws PackageManagerException {
@@ -1069,7 +1058,6 @@ public abstract class ApexManager {
"It is forbidden to install new APEX packages");
}
checkApexSignature(existingApexPkg, newApexPkg);
checkDowngrade(existingApexPkg, newApexPkg);
ApexInfo apexInfo = waitForApexService().installAndActivatePackage(
apexFile.getAbsolutePath());
final ParsedPackage parsedPackage2 = packageParser.parsePackage(

View File

@@ -688,11 +688,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 {

View File

@@ -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);

View File

@@ -347,24 +347,6 @@ public class ApexManagerTest {
assertThat(e).hasMessageThat().contains("It is forbidden to install new APEX packages");
}
@Test
public void testInstallPackageDowngrade() throws Exception {
File activeApex = extractResource("test.apex_rebootless_v2",
"test.rebootless_apex_v2.apex");
ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
/* isFactory= */ false, activeApex);
when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
File installedApex = extractResource("test.apex_rebootless_v1",
"test.rebootless_apex_v1.apex");
PackageManagerException e = expectThrows(PackageManagerException.class,
() -> mApexManager.installPackage(installedApex, mPackageParser2));
assertThat(e).hasMessageThat().contains(
"Downgrade of APEX package test.apex.rebootless is not allowed");
}
@Test
public void testInstallPackage_activeOnSystem() throws Exception {
ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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();

View File

@@ -59,6 +59,7 @@ java_test_host {
":StagedInstallTestApexV2_WrongSha",
":TestAppAv1",
":test.rebootless_apex_v1",
":test.rebootless_apex_v2",
],
test_suites: ["general-tests"],
test_config: "StagedInstallInternalTest.xml",

View File

@@ -476,6 +476,18 @@ public class StagedInstallInternalTest {
assertThat(captor.getValue().stagedApexModuleNames).hasLength(0);
}
@Test
public void testRebootlessDowngrade() throws Exception {
final String packageName = "test.apex.rebootless";
assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(2);
TestApp apex1 = new TestApp("TestRebootlessApexV1", packageName, 1,
/* isApex= */ true, "test.rebootless_apex_v1.apex");
InstallUtils.commitExpectingFailure(AssertionError.class,
"INSTALL_FAILED_VERSION_DOWNGRADE", Install.single(apex1));
Install.single(apex1).setRequestDowngrade().commit();
assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(1);
}
private IPackageManagerNative getPackageManagerNative() {
IBinder binder = ServiceManager.waitForService("package_native");
assertThat(binder).isNotNull();

View File

@@ -91,7 +91,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex",
"/system/apex/test.rebootless_apex_v1.apex",
"/system/apex/test.rebootless_apex_v*.apex",
"/data/apex/active/test.apex.rebootless*.apex",
TEST_VENDOR_APEX_ALLOW_LIST);
}
@@ -493,6 +493,13 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
runPhase("testStagedApexObserver");
}
@Test
public void testRebootlessDowngrade() throws Exception {
pushTestApex("test.rebootless_apex_v2.apex");
getDevice().reboot();
runPhase("testRebootlessDowngrade");
}
private List<String> getStagingDirectories() throws DeviceNotAvailableException {
String baseDir = "/data/app-staging";
try {