1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tests.odsign; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 22 import com.android.tradefed.invoker.TestInformation; 23 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 24 import com.android.tradefed.testtype.junit4.AfterClassWithInfo; 25 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 26 import com.android.tradefed.testtype.junit4.BeforeClassWithInfo; 27 28 import org.junit.After; 29 import org.junit.Before; 30 import org.junit.Test; 31 import org.junit.runner.RunWith; 32 33 import java.util.HashSet; 34 import java.util.Set; 35 36 /** 37 * Test to check end-to-end odrefresh invocations, but without odsign amd fs-verity involved. 38 */ 39 @RunWith(DeviceJUnit4ClassRunner.class) 40 public class OdrefreshHostTest extends BaseHostJUnit4Test { 41 private OdsignTestUtils mTestUtils; 42 private DeviceState mDeviceState; 43 44 @BeforeClassWithInfo beforeClassWithDevice(TestInformation testInfo)45 public static void beforeClassWithDevice(TestInformation testInfo) throws Exception { 46 OdsignTestUtils testUtils = new OdsignTestUtils(testInfo); 47 testUtils.installTestApex(); 48 testUtils.reboot(); 49 } 50 51 @AfterClassWithInfo afterClassWithDevice(TestInformation testInfo)52 public static void afterClassWithDevice(TestInformation testInfo) throws Exception { 53 OdsignTestUtils testUtils = new OdsignTestUtils(testInfo); 54 testUtils.uninstallTestApex(); 55 testUtils.reboot(); 56 } 57 58 @Before setUp()59 public void setUp() throws Exception { 60 mTestUtils = new OdsignTestUtils(getTestInformation()); 61 mDeviceState = new DeviceState(getTestInformation()); 62 mDeviceState.backupArtifacts(); 63 } 64 65 @After tearDown()66 public void tearDown() throws Exception { 67 mDeviceState.restore(); 68 } 69 70 @Test verifyArtSamegradeUpdateTriggersCompilation()71 public void verifyArtSamegradeUpdateTriggersCompilation() throws Exception { 72 mDeviceState.simulateArtApexUpgrade(); 73 long timeMs = mTestUtils.getCurrentTimeMs(); 74 mTestUtils.runOdrefresh(); 75 76 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 77 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 78 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 79 } 80 81 @Test verifyOtherApexSamegradeUpdateTriggersCompilation()82 public void verifyOtherApexSamegradeUpdateTriggersCompilation() throws Exception { 83 mDeviceState.simulateApexUpgrade(); 84 long timeMs = mTestUtils.getCurrentTimeMs(); 85 mTestUtils.runOdrefresh(); 86 87 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 88 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 89 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 90 } 91 92 @Test verifyBootClasspathOtaTriggersCompilation()93 public void verifyBootClasspathOtaTriggersCompilation() throws Exception { 94 mDeviceState.simulateBootClasspathOta(); 95 long timeMs = mTestUtils.getCurrentTimeMs(); 96 mTestUtils.runOdrefresh(); 97 98 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 99 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 100 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 101 } 102 103 @Test verifySystemServerOtaTriggersCompilation()104 public void verifySystemServerOtaTriggersCompilation() throws Exception { 105 mDeviceState.simulateSystemServerOta(); 106 long timeMs = mTestUtils.getCurrentTimeMs(); 107 mTestUtils.runOdrefresh(); 108 109 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 110 mTestUtils.assertNotModifiedAfter( 111 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 112 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 113 } 114 115 @Test verifyMissingArtifactTriggersCompilation()116 public void verifyMissingArtifactTriggersCompilation() throws Exception { 117 Set<String> missingArtifacts = simulateMissingArtifacts(); 118 Set<String> remainingArtifacts = new HashSet<>(); 119 remainingArtifacts.addAll(mTestUtils.getExpectedPrimaryBootImage()); 120 remainingArtifacts.addAll(mTestUtils.getExpectedBootImageMainlineExtension()); 121 remainingArtifacts.addAll(mTestUtils.getSystemServerExpectedArtifacts()); 122 remainingArtifacts.removeAll(missingArtifacts); 123 124 mTestUtils.removeCompilationLogToAvoidBackoff(); 125 long timeMs = mTestUtils.getCurrentTimeMs(); 126 mTestUtils.runOdrefresh(); 127 128 mTestUtils.assertNotModifiedAfter(remainingArtifacts, timeMs); 129 mTestUtils.assertModifiedAfter(missingArtifacts, timeMs); 130 } 131 132 @Test verifyEnableUffdGcChangeTriggersCompilation()133 public void verifyEnableUffdGcChangeTriggersCompilation() throws Exception { 134 mDeviceState.setPhenotypeFlag("enable_uffd_gc", "false"); 135 136 long timeMs = mTestUtils.getCurrentTimeMs(); 137 mTestUtils.runOdrefresh(); 138 139 // Artifacts should be re-compiled. 140 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 141 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 142 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 143 144 mDeviceState.setPhenotypeFlag("enable_uffd_gc", "true"); 145 146 timeMs = mTestUtils.getCurrentTimeMs(); 147 mTestUtils.runOdrefresh(); 148 149 // Artifacts should be re-compiled. 150 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 151 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 152 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 153 154 // Run odrefresh again with the flag unchanged. 155 timeMs = mTestUtils.getCurrentTimeMs(); 156 mTestUtils.runOdrefresh(); 157 158 // Artifacts should not be re-compiled. 159 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 160 mTestUtils.assertNotModifiedAfter( 161 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 162 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 163 164 mDeviceState.setPhenotypeFlag("enable_uffd_gc", null); 165 166 timeMs = mTestUtils.getCurrentTimeMs(); 167 mTestUtils.runOdrefresh(); 168 169 // Artifacts should be re-compiled. 170 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 171 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 172 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 173 } 174 175 @Test verifySystemServerCompilerFilterOverrideChangeTriggersCompilation()176 public void verifySystemServerCompilerFilterOverrideChangeTriggersCompilation() 177 throws Exception { 178 mDeviceState.setPhenotypeFlag("systemservercompilerfilter_override", null); 179 180 long timeMs = mTestUtils.getCurrentTimeMs(); 181 mTestUtils.runOdrefresh(); 182 183 // Artifacts should not be re-compiled. 184 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 185 mTestUtils.assertNotModifiedAfter( 186 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 187 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 188 189 mDeviceState.setPhenotypeFlag("systemservercompilerfilter_override", "speed"); 190 191 timeMs = mTestUtils.getCurrentTimeMs(); 192 mTestUtils.runOdrefresh(); 193 194 // Artifacts should be re-compiled. 195 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 196 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 197 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 198 199 // Run odrefresh again with the flag unchanged. 200 timeMs = mTestUtils.getCurrentTimeMs(); 201 mTestUtils.runOdrefresh(); 202 203 // Artifacts should not be re-compiled. 204 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 205 mTestUtils.assertNotModifiedAfter( 206 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 207 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 208 209 mDeviceState.setPhenotypeFlag("systemservercompilerfilter_override", "verify"); 210 211 timeMs = mTestUtils.getCurrentTimeMs(); 212 mTestUtils.runOdrefresh(); 213 214 // Artifacts should be re-compiled. 215 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 216 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 217 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 218 } 219 220 @Test verifySystemPropertyMismatchTriggersCompilation()221 public void verifySystemPropertyMismatchTriggersCompilation() throws Exception { 222 // Change a system property from empty to a value. 223 mDeviceState.setProperty("dalvik.vm.foo", "1"); 224 long timeMs = mTestUtils.getCurrentTimeMs(); 225 mTestUtils.runOdrefresh(); 226 227 // Artifacts should be re-compiled. 228 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 229 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 230 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 231 232 // Run again with the same value. 233 timeMs = mTestUtils.getCurrentTimeMs(); 234 mTestUtils.runOdrefresh(); 235 236 // Artifacts should not be re-compiled. 237 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 238 mTestUtils.assertNotModifiedAfter( 239 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 240 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 241 242 // Change the system property to another value. 243 mDeviceState.setProperty("dalvik.vm.foo", "2"); 244 timeMs = mTestUtils.getCurrentTimeMs(); 245 mTestUtils.runOdrefresh(); 246 247 // Artifacts should be re-compiled. 248 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 249 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 250 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 251 252 // Run again with the same value. 253 timeMs = mTestUtils.getCurrentTimeMs(); 254 mTestUtils.runOdrefresh(); 255 256 // Artifacts should not be re-compiled. 257 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 258 mTestUtils.assertNotModifiedAfter( 259 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 260 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 261 262 // Change the system property to empty. 263 mDeviceState.setProperty("dalvik.vm.foo", ""); 264 timeMs = mTestUtils.getCurrentTimeMs(); 265 mTestUtils.runOdrefresh(); 266 267 // Artifacts should be re-compiled. 268 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 269 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 270 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 271 272 // Run again with the same value. 273 timeMs = mTestUtils.getCurrentTimeMs(); 274 mTestUtils.runOdrefresh(); 275 276 // Artifacts should not be re-compiled. 277 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 278 mTestUtils.assertNotModifiedAfter( 279 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 280 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 281 } 282 283 @Test verifyNoCompilationWhenCacheIsGood()284 public void verifyNoCompilationWhenCacheIsGood() throws Exception { 285 mTestUtils.removeCompilationLogToAvoidBackoff(); 286 long timeMs = mTestUtils.getCurrentTimeMs(); 287 mTestUtils.runOdrefresh(); 288 289 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 290 mTestUtils.assertNotModifiedAfter( 291 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 292 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 293 } 294 295 @Test verifyUnexpectedFilesAreCleanedUp()296 public void verifyUnexpectedFilesAreCleanedUp() throws Exception { 297 String unexpected = OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME + "/unexpected"; 298 getDevice().pushString("" /* contents */, unexpected); 299 mTestUtils.runOdrefresh(); 300 301 assertThat(getDevice().doesFileExist(unexpected)).isFalse(); 302 } 303 304 @Test verifyCacheInfoOmitsIrrelevantApexes()305 public void verifyCacheInfoOmitsIrrelevantApexes() throws Exception { 306 String cacheInfo = getDevice().pullFileContents(OdsignTestUtils.CACHE_INFO_FILE); 307 308 // cacheInfo should list all APEXes that have compilable JARs and 309 // none that do not. 310 311 // This should always contain classpath JARs, that's the reason it exists. 312 assertThat(cacheInfo).contains("name=\"com.android.sdkext\""); 313 314 // This should never contain classpath JARs, it's the native runtime. 315 assertThat(cacheInfo).doesNotContain("name=\"com.android.runtime\""); 316 } 317 318 @Test verifyCompilationOsMode()319 public void verifyCompilationOsMode() throws Exception { 320 mTestUtils.removeCompilationLogToAvoidBackoff(); 321 mDeviceState.simulateApexUpgrade(); 322 long timeMs = mTestUtils.getCurrentTimeMs(); 323 mTestUtils.runOdrefresh("--compilation-os-mode"); 324 325 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 326 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 327 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 328 329 String cacheInfo = getDevice().pullFileContents(OdsignTestUtils.CACHE_INFO_FILE); 330 assertThat(cacheInfo).contains("compilationOsMode=\"true\""); 331 332 // Compilation OS does not write the compilation log to the host. 333 mTestUtils.removeCompilationLogToAvoidBackoff(); 334 335 // Simulate the odrefresh invocation on the next boot. 336 timeMs = mTestUtils.getCurrentTimeMs(); 337 mTestUtils.runOdrefresh(); 338 339 // odrefresh should not re-compile anything. 340 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 341 mTestUtils.assertNotModifiedAfter( 342 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 343 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 344 } 345 346 @Test verifyMinimalCompilation()347 public void verifyMinimalCompilation() throws Exception { 348 mTestUtils.removeCompilationLogToAvoidBackoff(); 349 getDevice().executeShellV2Command( 350 "rm -rf " + OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME); 351 mTestUtils.runOdrefresh("--minimal"); 352 353 mTestUtils.restartZygote(); 354 355 // The minimal boot image should be loaded. 356 mTestUtils.verifyZygotesLoadedMinimalBootImage(); 357 358 // Running the command again should not overwrite the minimal boot image. 359 mTestUtils.removeCompilationLogToAvoidBackoff(); 360 long timeMs = mTestUtils.getCurrentTimeMs(); 361 mTestUtils.runOdrefresh("--minimal"); 362 363 Set<String> minimalZygoteArtifacts = mTestUtils.getExpectedMinimalBootImage(); 364 mTestUtils.assertNotModifiedAfter(minimalZygoteArtifacts, timeMs); 365 366 // A normal odrefresh invocation should replace the minimal boot image with a full one. 367 mTestUtils.removeCompilationLogToAvoidBackoff(); 368 timeMs = mTestUtils.getCurrentTimeMs(); 369 mTestUtils.runOdrefresh(); 370 371 for (String artifact : minimalZygoteArtifacts) { 372 assertWithMessage( 373 String.format( 374 "Artifact %s should be cleaned up while it still exists", artifact)) 375 .that(getDevice().doesFileExist(artifact)) 376 .isFalse(); 377 } 378 379 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 380 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 381 } 382 383 @Test verifyCompilationFailureBackoff()384 public void verifyCompilationFailureBackoff() throws Exception { 385 mDeviceState.makeDex2oatFail(); 386 mDeviceState.simulateArtApexUpgrade(); 387 388 // Run odrefresh. It should encounter dex2oat failures. 389 long timeMs = mTestUtils.getCurrentTimeMs(); 390 mTestUtils.runOdrefresh(); 391 392 // Artifacts don't exist because the compilation failed. 393 mTestUtils.assertModifiedAfter(Set.of(OdsignTestUtils.CACHE_INFO_FILE), timeMs); 394 mTestUtils.assertFilesNotExist(mTestUtils.getExpectedPrimaryBootImage()); 395 mTestUtils.assertFilesNotExist(mTestUtils.getExpectedBootImageMainlineExtension()); 396 mTestUtils.assertFilesNotExist(mTestUtils.getSystemServerExpectedArtifacts()); 397 398 // Run odrefresh again. 399 timeMs = mTestUtils.getCurrentTimeMs(); 400 mTestUtils.runOdrefresh(); 401 402 // It should not retry. 403 mTestUtils.assertNotModifiedAfter(Set.of(OdsignTestUtils.CACHE_INFO_FILE), timeMs); 404 405 // Simulate that the backoff time has passed. 406 mTestUtils.removeCompilationLogToAvoidBackoff(); 407 408 // Run odrefresh again. 409 timeMs = mTestUtils.getCurrentTimeMs(); 410 mTestUtils.runOdrefresh(); 411 412 // Now it should retry. 413 mTestUtils.assertModifiedAfter(Set.of(OdsignTestUtils.CACHE_INFO_FILE), timeMs); 414 } 415 simulateMissingArtifacts()416 private Set<String> simulateMissingArtifacts() throws Exception { 417 Set<String> missingArtifacts = new HashSet<>(); 418 String sample = mTestUtils.getSystemServerExpectedArtifacts().iterator().next(); 419 for (String extension : OdsignTestUtils.APP_ARTIFACT_EXTENSIONS) { 420 String artifact = OdsignTestUtils.replaceExtension(sample, extension); 421 getDevice().deleteFile(artifact); 422 missingArtifacts.add(artifact); 423 } 424 return missingArtifacts; 425 } 426 } 427