diff options
3 files changed, 255 insertions, 285 deletions
diff --git a/test/odsign/test-src/com/android/tests/odsign/DeviceState.java b/test/odsign/test-src/com/android/tests/odsign/DeviceState.java index 012908cc2b..8379cbadde 100644 --- a/test/odsign/test-src/com/android/tests/odsign/DeviceState.java +++ b/test/odsign/test-src/com/android/tests/odsign/DeviceState.java @@ -43,6 +43,8 @@ public class DeviceState { private static final String APEX_INFO_FILE = "/apex/apex-info-list.xml"; private static final String TEST_JAR_RESOURCE_NAME = "/art-gtest-jars-Main.jar"; private static final String PHENOTYPE_FLAG_NAMESPACE = "runtime_native_boot"; + private static final String ART_APEX_DALVIK_CACHE_BACKUP_DIRNAME = + OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME + ".bak"; private final TestInformation mTestInfo; private final OdsignTestUtils mTestUtils; @@ -51,6 +53,7 @@ public class DeviceState { private Set<String> mMountPoints = new HashSet<>(); private Map<String, String> mMutatedProperties = new HashMap<>(); private Set<String> mMutatedPhenotypeFlags = new HashSet<>(); + private boolean mHasArtifactsBackup = false; public DeviceState(TestInformation testInfo) throws Exception { mTestInfo = testInfo; @@ -81,6 +84,14 @@ public class DeviceState { mTestInfo.getDevice().executeShellV2Command( "device_config set_sync_disabled_for_tests none"); } + + if (mHasArtifactsBackup) { + mTestInfo.getDevice().executeShellV2Command( + String.format("rm -rf '%s'", OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME)); + mTestInfo.getDevice().executeShellV2Command( + String.format("mv '%s' '%s'", ART_APEX_DALVIK_CACHE_BACKUP_DIRNAME, + OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME)); + } } /** Simulates that the ART APEX has been upgraded. */ @@ -163,6 +174,15 @@ public class DeviceState { } } + public void backupArtifacts() throws Exception { + mTestInfo.getDevice().executeShellV2Command( + String.format("rm -rf '%s'", ART_APEX_DALVIK_CACHE_BACKUP_DIRNAME)); + mTestUtils.assertCommandSucceeds( + String.format("cp -r '%s' '%s'", OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME, + ART_APEX_DALVIK_CACHE_BACKUP_DIRNAME)); + mHasArtifactsBackup = true; + } + /** * Pushes the file to a temporary location and bind-mount it at the given path. This is useful * when the path is readonly. diff --git a/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java b/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java index ab0297b0a1..83424ced18 100644 --- a/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java +++ b/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java @@ -17,9 +17,7 @@ package com.android.tests.odsign; import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertWithMessage; import com.android.tradefed.invoker.TestInformation; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; @@ -32,7 +30,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -42,16 +39,6 @@ import java.util.Set; */ @RunWith(DeviceJUnit4ClassRunner.class) public class OdrefreshHostTest extends BaseHostJUnit4Test { - private static final String CACHE_INFO_FILE = - OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME + "/cache-info.xml"; - private static final String ODREFRESH_BIN = "odrefresh"; - private static final String ART_APEX_DALVIK_CACHE_BACKUP_DIRNAME = - OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME + ".bak"; - - private static final String TAG = "OdrefreshHostTest"; - private static final String ZYGOTE_ARTIFACTS_KEY = TAG + ":ZYGOTE_ARTIFACTS"; - private static final String SYSTEM_SERVER_ARTIFACTS_KEY = TAG + ":SYSTEM_SERVER_ARTIFACTS"; - private OdsignTestUtils mTestUtils; private DeviceState mDeviceState; @@ -60,30 +47,10 @@ public class OdrefreshHostTest extends BaseHostJUnit4Test { OdsignTestUtils testUtils = new OdsignTestUtils(testInfo); testUtils.installTestApex(); testUtils.reboot(); - - HashSet<String> zygoteArtifacts = new HashSet<>(); - for (String zygoteName : testUtils.ZYGOTE_NAMES) { - zygoteArtifacts.addAll( - testUtils.getZygoteLoadedArtifacts(zygoteName).orElse(new HashSet<>())); - } - Set<String> systemServerArtifacts = testUtils.getSystemServerLoadedArtifacts(); - - testInfo.properties().put(ZYGOTE_ARTIFACTS_KEY, String.join(":", zygoteArtifacts)); - testInfo.properties() - .put(SYSTEM_SERVER_ARTIFACTS_KEY, String.join(":", systemServerArtifacts)); - - // Backup the artifacts. - testInfo.getDevice().executeShellV2Command( - String.format("rm -rf '%s'", ART_APEX_DALVIK_CACHE_BACKUP_DIRNAME)); - testUtils.assertCommandSucceeds( - String.format("cp -r '%s' '%s'", OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME, - ART_APEX_DALVIK_CACHE_BACKUP_DIRNAME)); } @AfterClassWithInfo public static void afterClassWithDevice(TestInformation testInfo) throws Exception { - testInfo.getDevice().executeShellV2Command( - String.format("rm -rf '%s'", ART_APEX_DALVIK_CACHE_BACKUP_DIRNAME)); OdsignTestUtils testUtils = new OdsignTestUtils(testInfo); testUtils.uninstallTestApex(); testUtils.reboot(); @@ -93,13 +60,7 @@ public class OdrefreshHostTest extends BaseHostJUnit4Test { public void setUp() throws Exception { mTestUtils = new OdsignTestUtils(getTestInformation()); mDeviceState = new DeviceState(getTestInformation()); - - // Restore the artifacts to ensure a clean initial state. - getDevice().executeShellV2Command( - String.format("rm -rf '%s'", OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME)); - mTestUtils.assertCommandSucceeds( - String.format("cp -r '%s' '%s'", ART_APEX_DALVIK_CACHE_BACKUP_DIRNAME, - OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME)); + mDeviceState.backupArtifacts(); } @After @@ -111,56 +72,56 @@ public class OdrefreshHostTest extends BaseHostJUnit4Test { public void verifyArtSamegradeUpdateTriggersCompilation() throws Exception { mDeviceState.simulateArtApexUpgrade(); long timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); - assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); } @Test public void verifyOtherApexSamegradeUpdateTriggersCompilation() throws Exception { mDeviceState.simulateApexUpgrade(); long timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); - assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); } @Test public void verifyBootClasspathOtaTriggersCompilation() throws Exception { mDeviceState.simulateBootClasspathOta(); long timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); - assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); } @Test public void verifySystemServerOtaTriggersCompilation() throws Exception { mDeviceState.simulateSystemServerOta(); long timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); - assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); } @Test public void verifyMissingArtifactTriggersCompilation() throws Exception { Set<String> missingArtifacts = simulateMissingArtifacts(); Set<String> remainingArtifacts = new HashSet<>(); - remainingArtifacts.addAll(getZygoteArtifacts()); - remainingArtifacts.addAll(getSystemServerArtifacts()); + remainingArtifacts.addAll(mTestUtils.getZygotesExpectedArtifacts()); + remainingArtifacts.addAll(mTestUtils.getSystemServerExpectedArtifacts()); remainingArtifacts.removeAll(missingArtifacts); mTestUtils.removeCompilationLogToAvoidBackoff(); long timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); - assertArtifactsNotModifiedAfter(remainingArtifacts, timeMs); - assertArtifactsModifiedAfter(missingArtifacts, timeMs); + mTestUtils.assertNotModifiedAfter(remainingArtifacts, timeMs); + mTestUtils.assertModifiedAfter(missingArtifacts, timeMs); } @Test @@ -168,37 +129,37 @@ public class OdrefreshHostTest extends BaseHostJUnit4Test { mDeviceState.setPhenotypeFlag("enable_uffd_gc", "false"); long timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should be re-compiled. - assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); mDeviceState.setPhenotypeFlag("enable_uffd_gc", "true"); timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should be re-compiled. - assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); // Run odrefresh again with the flag unchanged. timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should not be re-compiled. - assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsNotModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); mDeviceState.setPhenotypeFlag("enable_uffd_gc", null); timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should be re-compiled. - assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); } @Test @@ -207,37 +168,37 @@ public class OdrefreshHostTest extends BaseHostJUnit4Test { mDeviceState.setPhenotypeFlag("systemservercompilerfilter_override", null); long timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should not be re-compiled. - assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsNotModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); mDeviceState.setPhenotypeFlag("systemservercompilerfilter_override", "speed"); timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should be re-compiled. - assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); // Run odrefresh again with the flag unchanged. timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should not be re-compiled. - assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsNotModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); mDeviceState.setPhenotypeFlag("systemservercompilerfilter_override", "verify"); timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should be re-compiled. - assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); } @Test @@ -245,77 +206,77 @@ public class OdrefreshHostTest extends BaseHostJUnit4Test { // Change a system property from empty to a value. mDeviceState.setProperty("dalvik.vm.foo", "1"); long timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should be re-compiled. - assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); // Run again with the same value. timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should not be re-compiled. - assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsNotModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); // Change the system property to another value. mDeviceState.setProperty("dalvik.vm.foo", "2"); timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should be re-compiled. - assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); // Run again with the same value. timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should not be re-compiled. - assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsNotModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); // Change the system property to empty. mDeviceState.setProperty("dalvik.vm.foo", ""); timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should be re-compiled. - assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); // Run again with the same value. timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // Artifacts should not be re-compiled. - assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsNotModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); } @Test public void verifyNoCompilationWhenCacheIsGood() throws Exception { mTestUtils.removeCompilationLogToAvoidBackoff(); long timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); - assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsNotModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); } @Test public void verifyUnexpectedFilesAreCleanedUp() throws Exception { String unexpected = OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME + "/unexpected"; getDevice().pushString("" /* contents */, unexpected); - runOdrefresh(); + mTestUtils.runOdrefresh(); - assertFalse(getDevice().doesFileExist(unexpected)); + assertThat(getDevice().doesFileExist(unexpected)).isFalse(); } @Test public void verifyCacheInfoOmitsIrrelevantApexes() throws Exception { - String cacheInfo = getDevice().pullFileContents(CACHE_INFO_FILE); + String cacheInfo = getDevice().pullFileContents(OdsignTestUtils.CACHE_INFO_FILE); // cacheInfo should list all APEXes that have compilable JARs and // none that do not. @@ -332,12 +293,12 @@ public class OdrefreshHostTest extends BaseHostJUnit4Test { mTestUtils.removeCompilationLogToAvoidBackoff(); mDeviceState.simulateApexUpgrade(); long timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh("--compilation-os-mode"); + mTestUtils.runOdrefresh("--compilation-os-mode"); - assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); - String cacheInfo = getDevice().pullFileContents(CACHE_INFO_FILE); + String cacheInfo = getDevice().pullFileContents(OdsignTestUtils.CACHE_INFO_FILE); assertThat(cacheInfo).contains("compilationOsMode=\"true\""); // Compilation OS does not write the compilation log to the host. @@ -345,116 +306,57 @@ public class OdrefreshHostTest extends BaseHostJUnit4Test { // Simulate the odrefresh invocation on the next boot. timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); // odrefresh should not re-compile anything. - assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs); - assertArtifactsNotModifiedAfter(getSystemServerArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); + mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); } @Test public void verifyMinimalCompilation() throws Exception { mTestUtils.removeCompilationLogToAvoidBackoff(); getDevice().executeShellV2Command( - "rm -rf " + OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME); - runOdrefresh("--minimal"); + "rm -rf " + OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME); + mTestUtils.runOdrefresh("--minimal"); mTestUtils.restartZygote(); // The minimal boot image should be loaded. - Set<String> minimalZygoteArtifacts = - mTestUtils.verifyZygotesLoadedArtifacts("boot_minimal"); + mTestUtils.verifyZygotesLoadedArtifacts("boot_minimal"); // Running the command again should not overwrite the minimal boot image. mTestUtils.removeCompilationLogToAvoidBackoff(); long timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh("--minimal"); + mTestUtils.runOdrefresh("--minimal"); - assertArtifactsNotModifiedAfter(minimalZygoteArtifacts, timeMs); + Set<String> minimalZygoteArtifacts = mTestUtils.getZygotesExpectedArtifacts("boot_minimal"); + mTestUtils.assertNotModifiedAfter(minimalZygoteArtifacts, timeMs); // A normal odrefresh invocation should replace the minimal boot image with a full one. mTestUtils.removeCompilationLogToAvoidBackoff(); timeMs = mTestUtils.getCurrentTimeMs(); - runOdrefresh(); + mTestUtils.runOdrefresh(); for (String artifact : minimalZygoteArtifacts) { - assertFalse( + assertWithMessage( String.format( - "Artifact %s should be cleaned up while it still exists", artifact), - getDevice().doesFileExist(artifact)); + "Artifact %s should be cleaned up while it still exists", artifact)) + .that(getDevice().doesFileExist(artifact)) + .isFalse(); } - assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs); + mTestUtils.assertModifiedAfter(mTestUtils.getZygotesExpectedArtifacts(), timeMs); } private Set<String> simulateMissingArtifacts() throws Exception { Set<String> missingArtifacts = new HashSet<>(); - String sample = getSystemServerArtifacts().iterator().next(); + String sample = mTestUtils.getSystemServerExpectedArtifacts().iterator().next(); for (String extension : OdsignTestUtils.APP_ARTIFACT_EXTENSIONS) { - String artifact = replaceExtension(sample, extension); + String artifact = OdsignTestUtils.replaceExtension(sample, extension); getDevice().deleteFile(artifact); missingArtifacts.add(artifact); } return missingArtifacts; } - - private void assertArtifactsModifiedAfter(Set<String> artifacts, long timeMs) throws Exception { - for (String artifact : artifacts) { - long modifiedTime = mTestUtils.getModifiedTimeMs(artifact); - assertTrue( - String.format( - "Artifact %s is not re-compiled. Modified time: %d, Reference time: %d", - artifact, - modifiedTime, - timeMs), - modifiedTime > timeMs); - } - } - - private void assertArtifactsNotModifiedAfter(Set<String> artifacts, long timeMs) - throws Exception { - for (String artifact : artifacts) { - long modifiedTime = mTestUtils.getModifiedTimeMs(artifact); - assertTrue( - String.format( - "Artifact %s is unexpectedly re-compiled. " + - "Modified time: %d, Reference time: %d", - artifact, - modifiedTime, - timeMs), - modifiedTime < timeMs); - } - } - - private String replaceExtension(String filename, String extension) throws Exception { - int index = filename.lastIndexOf("."); - assertTrue("Extension not found in filename: " + filename, index != -1); - return filename.substring(0, index) + extension; - } - - private Set<String> getColonSeparatedSet(String key) { - String value = getTestInformation().properties().get(key); - if (value == null || value.isEmpty()) { - return new HashSet<>(); - } - return new HashSet<>(Arrays.asList(value.split(":"))); - } - - private Set<String> getZygoteArtifacts() { - return getColonSeparatedSet(ZYGOTE_ARTIFACTS_KEY); - } - - private Set<String> getSystemServerArtifacts() { - return getColonSeparatedSet(SYSTEM_SERVER_ARTIFACTS_KEY); - } - - private void runOdrefresh() throws Exception { - runOdrefresh("" /* extraArgs */); - } - - private void runOdrefresh(String extraArgs) throws Exception { - getDevice().executeShellV2Command(ODREFRESH_BIN + " --check"); - getDevice().executeShellV2Command( - ODREFRESH_BIN + " --partial-compilation --no-refresh " + extraArgs + " --compile"); - } } diff --git a/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java b/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java index a11139e6f5..83cd881fbe 100644 --- a/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java +++ b/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java @@ -21,8 +21,6 @@ import static com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; @@ -30,7 +28,6 @@ import android.cts.install.lib.host.InstallUtilsHost; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.ITestDevice; -import com.android.tradefed.device.ITestDevice.ApexInfo; import com.android.tradefed.device.TestDeviceOptions; import com.android.tradefed.invoker.TestInformation; import com.android.tradefed.result.FileInputStreamSource; @@ -48,20 +45,24 @@ import java.time.Duration; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Optional; +import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; public class OdsignTestUtils { public static final String ART_APEX_DALVIK_CACHE_DIRNAME = "/data/misc/apexdata/com.android.art/dalvik-cache"; + public static final String CACHE_INFO_FILE = ART_APEX_DALVIK_CACHE_DIRNAME + "/cache-info.xml"; - public static final List<String> ZYGOTE_NAMES = List.of("zygote", "zygote64"); + private static final String ODREFRESH_BIN = "odrefresh"; + + public static final String ZYGOTE_32_NAME = "zygote"; + public static final String ZYGOTE_64_NAME = "zygote64"; public static final List<String> APP_ARTIFACT_EXTENSIONS = List.of(".art", ".odex", ".vdex"); public static final List<String> BCP_ARTIFACT_EXTENSIONS = List.of(".art", ".oat", ".vdex"); @@ -75,11 +76,17 @@ public class OdsignTestUtils { private static final String TAG = "OdsignTestUtils"; private static final String PACKAGE_NAME_KEY = TAG + ":PACKAGE_NAME"; + // Keep in sync with `ABI_TO_INSTRUCTION_SET_MAP` in + // libcore/libart/src/main/java/dalvik/system/VMRuntime.java. + private static final Map<String, String> ABI_TO_INSTRUCTION_SET_MAP = + Map.of("armeabi", "arm", "armeabi-v7a", "arm", "x86", "x86", "x86_64", "x86_64", + "arm64-v8a", "arm64", "arm64-v8a-hwasan", "arm64", "riscv64", "riscv64"); + private final InstallUtilsHost mInstallUtils; private final TestInformation mTestInfo; public OdsignTestUtils(TestInformation testInfo) throws Exception { - assertNotNull(testInfo.getDevice()); + assertThat(testInfo.getDevice()).isNotNull(); mInstallUtils = new InstallUtilsHost(testInfo); mTestInfo = testInfo; } @@ -93,17 +100,13 @@ public class OdsignTestUtils { String packagesOutput = mTestInfo.getDevice().executeShellCommand("pm list packages -f --apex-only"); Pattern p = Pattern.compile( - "^package:(.*)=(com(?:\\.google)?\\.android(?:\\.go)?\\.art)$", - Pattern.MULTILINE); + "^package:(.*)=(com(?:\\.google)?\\.android(?:\\.go)?\\.art)$", Pattern.MULTILINE); Matcher m = p.matcher(packagesOutput); assertTrue("ART module not found. Packages are:\n" + packagesOutput, m.find()); String artApexPath = m.group(1); String artApexName = m.group(2); - CommandResult result = mTestInfo.getDevice().executeShellV2Command( - "pm install --apex " + artApexPath); - assertWithMessage("Failed to install APEX. Reason: " + result.toString()) - .that(result.getExitCode()).isEqualTo(0); + assertCommandSucceeds("pm install --apex " + artApexPath); mTestInfo.properties().put(PACKAGE_NAME_KEY, artApexName); @@ -119,14 +122,14 @@ public class OdsignTestUtils { } public Set<String> getMappedArtifacts(String pid, String grepPattern) throws Exception { - final String grepCommand = String.format("grep \"%s\" /proc/%s/maps", grepPattern, pid); - CommandResult result = mTestInfo.getDevice().executeShellV2Command(grepCommand); - assertTrue(result.toString(), result.getExitCode() == 0); + String grepCommand = String.format("grep \"%s\" /proc/%s/maps", grepPattern, pid); Set<String> mappedFiles = new HashSet<>(); - for (String line : result.getStdout().split("\\R")) { + for (String line : assertCommandSucceeds(grepCommand).split("\\R")) { int start = line.indexOf(ART_APEX_DALVIK_CACHE_DIRNAME); - if (line.contains("[")) { - continue; // ignore anonymously mapped sections which are quoted in square braces. + if (line.contains("[") || line.contains("(deleted)")) { + // Ignore anonymously mapped sections, which are quoted in square braces, and + // deleted mapped files. + continue; } mappedFiles.add(line.substring(start)); } @@ -134,110 +137,88 @@ public class OdsignTestUtils { } /** - * Returns the mapped artifacts of the Zygote process, or {@code Optional.empty()} if the - * process does not exist. + * Returns the mapped artifacts of the Zygote process. */ - public Optional<Set<String>> getZygoteLoadedArtifacts(String zygoteName) throws Exception { - final CommandResult result = - mTestInfo.getDevice().executeShellV2Command("pidof " + zygoteName); - if (result.getExitCode() != 0) { - return Optional.empty(); - } + public Set<String> getZygoteLoadedArtifacts(String zygoteName) throws Exception { // There may be multiple Zygote processes when Zygote just forks and has not executed any // app binary. We can take any of the pids. // We can't use the "-s" flag when calling `pidof` because the Toybox's `pidof` // implementation is wrong and it outputs multiple pids regardless of the "-s" flag, so we // split the output and take the first pid ourselves. - final String zygotePid = result.getStdout().trim().split("\\s+")[0]; + String zygotePid = assertCommandSucceeds("pidof " + zygoteName).split("\\s+")[0]; assertTrue(!zygotePid.isEmpty()); - final String grepPattern = ART_APEX_DALVIK_CACHE_DIRNAME + ".*boot"; - return Optional.of(getMappedArtifacts(zygotePid, grepPattern)); + String grepPattern = ART_APEX_DALVIK_CACHE_DIRNAME + "/.*/boot"; + return getMappedArtifacts(zygotePid, grepPattern); } public Set<String> getSystemServerLoadedArtifacts() throws Exception { - final CommandResult result = - mTestInfo.getDevice().executeShellV2Command("pidof system_server"); - assertTrue(result.toString(), result.getExitCode() == 0); - final String systemServerPid = result.getStdout().trim(); + String systemServerPid = assertCommandSucceeds("pidof system_server"); assertTrue(!systemServerPid.isEmpty()); - assertTrue( - "There should be exactly one `system_server` process", + assertTrue("There should be exactly one `system_server` process", systemServerPid.matches("\\d+")); // system_server artifacts are in the APEX data dalvik cache and names all contain // the word "@classes". Look for mapped files that match this pattern in the proc map for // system_server. - final String grepPattern = ART_APEX_DALVIK_CACHE_DIRNAME + ".*@classes"; + String grepPattern = ART_APEX_DALVIK_CACHE_DIRNAME + "/.*@classes"; return getMappedArtifacts(systemServerPid, grepPattern); } - public void verifyZygoteLoadedArtifacts(String zygoteName, Set<String> mappedArtifacts, - String bootImageStem) throws Exception { - assertTrue("Expect 3 bootclasspath artifacts", mappedArtifacts.size() == 3); - - String allArtifacts = mappedArtifacts.stream().collect(Collectors.joining(",")); + public Set<String> getZygoteExpectedArtifacts(String bootImageStem, String isa) + throws Exception { + Set<String> artifacts = new HashSet<>(); for (String extension : BCP_ARTIFACT_EXTENSIONS) { - final String artifact = bootImageStem + extension; - final boolean found = mappedArtifacts.stream().anyMatch(a -> a.endsWith(artifact)); - assertTrue(zygoteName + " " + artifact + " not found: '" + allArtifacts + "'", found); + artifacts.add(String.format( + "%s/%s/%s%s", ART_APEX_DALVIK_CACHE_DIRNAME, isa, bootImageStem, extension)); } + return artifacts; } - // Verifies that boot image files with the given stem are loaded by Zygote for each instruction - // set. Returns the verified files. - public HashSet<String> verifyZygotesLoadedArtifacts(String bootImageStem) throws Exception { - // There are potentially two zygote processes "zygote" and "zygote64". These are - // instances 32-bit and 64-bit unspecialized app_process processes. - // (frameworks/base/cmds/app_process). - int zygoteCount = 0; - HashSet<String> verifiedArtifacts = new HashSet<>(); - for (String zygoteName : ZYGOTE_NAMES) { - final Optional<Set<String>> mappedArtifacts = getZygoteLoadedArtifacts(zygoteName); - if (!mappedArtifacts.isPresent()) { - continue; - } - verifyZygoteLoadedArtifacts(zygoteName, mappedArtifacts.get(), bootImageStem); - zygoteCount += 1; - verifiedArtifacts.addAll(mappedArtifacts.get()); + public Set<String> getZygotesExpectedArtifacts(String bootImageStem) throws Exception { + Set<String> artifacts = new HashSet<>(); + for (String isa : getZygoteNamesAndIsas().values()) { + artifacts.addAll(getZygoteExpectedArtifacts(bootImageStem, isa)); } - assertTrue("No zygote processes found", zygoteCount > 0); - return verifiedArtifacts; + return artifacts; } - public void verifySystemServerLoadedArtifacts() throws Exception { + public Set<String> getZygotesExpectedArtifacts() throws Exception { + return getZygotesExpectedArtifacts("boot"); + } + + public Set<String> getSystemServerExpectedArtifacts() throws Exception { String[] classpathElements = getListFromEnvironmentVariable("SYSTEMSERVERCLASSPATH"); assertTrue("SYSTEMSERVERCLASSPATH is empty", classpathElements.length > 0); String[] standaloneJars = getListFromEnvironmentVariable("STANDALONE_SYSTEMSERVER_JARS"); - String[] allSystemServerJars = Stream - .concat(Arrays.stream(classpathElements), Arrays.stream(standaloneJars)) - .toArray(String[]::new); - - final Set<String> mappedArtifacts = getSystemServerLoadedArtifacts(); - assertTrue( - "No mapped artifacts under " + ART_APEX_DALVIK_CACHE_DIRNAME, - mappedArtifacts.size() > 0); - final String isa = getSystemServerIsa(mappedArtifacts.iterator().next()); - final String isaCacheDirectory = String.format("%s/%s", ART_APEX_DALVIK_CACHE_DIRNAME, isa); - - // Check components in the system_server classpath have mapped artifacts. - for (String element : allSystemServerJars) { - String escapedPath = element.substring(1).replace('/', '@'); - for (String extension : APP_ARTIFACT_EXTENSIONS) { - final String fullArtifactPath = - String.format("%s/%s@classes%s", isaCacheDirectory, escapedPath, extension); - assertTrue("Missing " + fullArtifactPath, mappedArtifacts.contains(fullArtifactPath)); - } + String[] allSystemServerJars = + Stream.concat(Arrays.stream(classpathElements), Arrays.stream(standaloneJars)) + .toArray(String[] ::new); + String isa = getSystemServerIsa(); + + Set<String> artifacts = new HashSet<>(); + for (String jar : allSystemServerJars) { + artifacts.addAll(getApexDataDalvikCacheFilenames(jar, isa)); } - for (String mappedArtifact : mappedArtifacts) { - // Check the mapped artifact has a .art, .odex or .vdex extension. - final boolean knownArtifactKind = - APP_ARTIFACT_EXTENSIONS.stream().anyMatch(e -> mappedArtifact.endsWith(e)); - assertTrue("Unknown artifact kind: " + mappedArtifact, knownArtifactKind); + return artifacts; + } + + // Verifies that boot image files with the given stem are loaded by Zygote for each instruction + // set. + public void verifyZygotesLoadedArtifacts(String bootImageStem) throws Exception { + for (var entry : getZygoteNamesAndIsas().entrySet()) { + assertThat(getZygoteLoadedArtifacts(entry.getKey())) + .containsAtLeastElementsIn( + getZygoteExpectedArtifacts(bootImageStem, entry.getValue())); } } + public void verifySystemServerLoadedArtifacts() throws Exception { + assertThat(getSystemServerLoadedArtifacts()) + .containsAtLeastElementsIn(getSystemServerExpectedArtifacts()); + } + public boolean haveCompilationLog() throws Exception { CommandResult result = mTestInfo.getDevice().executeShellV2Command("stat " + ODREFRESH_COMPILATION_LOG); @@ -253,7 +234,7 @@ public class OdsignTestUtils { // store default value and increase time-out for reboot int rebootTimeout = options.getRebootTimeout(); long onlineTimeout = options.getOnlineTimeout(); - options.setRebootTimeout((int)BOOT_COMPLETE_TIMEOUT.toMillis()); + options.setRebootTimeout((int) BOOT_COMPLETE_TIMEOUT.toMillis()); options.setOnlineTimeout(BOOT_COMPLETE_TIMEOUT.toMillis()); mTestInfo.getDevice().setOptions(options); @@ -273,9 +254,10 @@ public class OdsignTestUtils { // `waitForBootComplete` relies on `dev.bootcomplete`. mTestInfo.getDevice().executeShellCommand("setprop dev.bootcomplete 0"); mTestInfo.getDevice().executeShellCommand("setprop ctl.restart zygote"); - boolean success = mTestInfo.getDevice() - .waitForBootComplete(RESTART_ZYGOTE_COMPLETE_TIMEOUT.toMillis()); - assertWithMessage("Zygote didn't start in %s", BOOT_COMPLETE_TIMEOUT).that(success) + boolean success = mTestInfo.getDevice().waitForBootComplete( + RESTART_ZYGOTE_COMPLETE_TIMEOUT.toMillis()); + assertWithMessage("Zygote didn't start in %s", BOOT_COMPLETE_TIMEOUT) + .that(success) .isTrue(); } @@ -303,16 +285,45 @@ public class OdsignTestUtils { return new String[0]; } - private String getSystemServerIsa(String mappedArtifact) { - // Artifact path for system server artifacts has the form: - // ART_APEX_DALVIK_CACHE_DIRNAME + "/<arch>/system@framework@some.jar@classes.odex" - String[] pathComponents = mappedArtifact.split("/"); - return pathComponents[pathComponents.length - 2]; + private static String getInstructionSet(String abi) { + String instructionSet = ABI_TO_INSTRUCTION_SET_MAP.get(abi); + assertThat(instructionSet).isNotNull(); + return instructionSet; + } + + public Map<String, String> getZygoteNamesAndIsas() throws Exception { + Map<String, String> namesAndIsas = new HashMap<>(); + String abiList64 = mTestInfo.getDevice().getProperty("ro.product.cpu.abilist64"); + if (abiList64 != null && !abiList64.isEmpty()) { + namesAndIsas.put(ZYGOTE_64_NAME, getInstructionSet(abiList64.split(",")[0])); + } + String abiList32 = mTestInfo.getDevice().getProperty("ro.product.cpu.abilist32"); + if (abiList32 != null && !abiList32.isEmpty()) { + namesAndIsas.put(ZYGOTE_32_NAME, getInstructionSet(abiList32.split(",")[0])); + } + return namesAndIsas; + } + + public String getSystemServerIsa() throws Exception { + return getInstructionSet( + mTestInfo.getDevice().getProperty("ro.product.cpu.abilist").split(",")[0]); + } + + // Keep in sync with `GetApexDataDalvikCacheFilename` in art/libartbase/base/file_utils.cc. + public static Set<String> getApexDataDalvikCacheFilenames(String dexLocation, String isa) + throws Exception { + Set<String> filenames = new HashSet<>(); + String escapedPath = dexLocation.substring(1).replace('/', '@'); + for (String extension : APP_ARTIFACT_EXTENSIONS) { + filenames.add(String.format("%s/%s/%s@classes%s", ART_APEX_DALVIK_CACHE_DIRNAME, isa, + escapedPath, extension)); + } + return filenames; } private long parseFormattedDateTime(String dateTimeStr) throws Exception { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern( - "yyyy-MM-dd HH:mm:ss.nnnnnnnnn Z"); + DateTimeFormatter formatter = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.nnnnnnnnn Z"); ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateTimeStr, formatter); return zonedDateTime.toInstant().toEpochMilli(); } @@ -380,4 +391,41 @@ public class OdsignTestUtils { } return file; } + + public void assertModifiedAfter(Set<String> artifacts, long timeMs) throws Exception { + for (String artifact : artifacts) { + long modifiedTime = getModifiedTimeMs(artifact); + assertTrue( + String.format( + "Artifact %s is not re-compiled. Modified time: %d, Reference time: %d", + artifact, modifiedTime, timeMs), + modifiedTime > timeMs); + } + } + + public void assertNotModifiedAfter(Set<String> artifacts, long timeMs) throws Exception { + for (String artifact : artifacts) { + long modifiedTime = getModifiedTimeMs(artifact); + assertTrue(String.format("Artifact %s is unexpectedly re-compiled. " + + "Modified time: %d, Reference time: %d", + artifact, modifiedTime, timeMs), + modifiedTime < timeMs); + } + } + + public static String replaceExtension(String filename, String extension) throws Exception { + int index = filename.lastIndexOf("."); + assertTrue("Extension not found in filename: " + filename, index != -1); + return filename.substring(0, index) + extension; + } + + public void runOdrefresh() throws Exception { + runOdrefresh("" /* extraArgs */); + } + + public void runOdrefresh(String extraArgs) throws Exception { + mTestInfo.getDevice().executeShellV2Command(ODREFRESH_BIN + " --check"); + mTestInfo.getDevice().executeShellV2Command( + ODREFRESH_BIN + " --partial-compilation --no-refresh " + extraArgs + " --compile"); + } } |