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 import com.android.tradefed.util.CommandResult; 28 29 import org.junit.After; 30 import org.junit.Before; 31 import org.junit.Test; 32 import org.junit.runner.RunWith; 33 34 import java.util.HashSet; 35 import java.util.Set; 36 37 /** 38 * Test to check end-to-end odrefresh invocations, but without odsign and fs-verity involved. 39 */ 40 @RunWith(DeviceJUnit4ClassRunner.class) 41 public class OdrefreshHostTest extends BaseHostJUnit4Test { 42 private OdsignTestUtils mTestUtils; 43 private DeviceState mDeviceState; 44 45 @BeforeClassWithInfo beforeClassWithDevice(TestInformation testInfo)46 public static void beforeClassWithDevice(TestInformation testInfo) throws Exception { 47 OdsignTestUtils testUtils = new OdsignTestUtils(testInfo); 48 testUtils.installTestApex(); 49 testUtils.reboot(); 50 } 51 52 @AfterClassWithInfo afterClassWithDevice(TestInformation testInfo)53 public static void afterClassWithDevice(TestInformation testInfo) throws Exception { 54 OdsignTestUtils testUtils = new OdsignTestUtils(testInfo); 55 testUtils.uninstallTestApex(); 56 testUtils.reboot(); 57 } 58 59 @Before setUp()60 public void setUp() throws Exception { 61 mTestUtils = new OdsignTestUtils(getTestInformation()); 62 mDeviceState = new DeviceState(getTestInformation()); 63 mDeviceState.backupArtifacts(); 64 } 65 66 @After tearDown()67 public void tearDown() throws Exception { 68 mDeviceState.restore(); 69 } 70 71 @Test verifyArtSamegradeUpdateTriggersCompilation()72 public void verifyArtSamegradeUpdateTriggersCompilation() throws Exception { 73 mDeviceState.simulateArtApexUpgrade(); 74 long timeMs = mTestUtils.getCurrentTimeMs(); 75 mTestUtils.runOdrefresh(); 76 77 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 78 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 79 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 80 } 81 82 @Test verifyOtherApexSamegradeUpdateTriggersCompilation()83 public void verifyOtherApexSamegradeUpdateTriggersCompilation() throws Exception { 84 mDeviceState.simulateApexUpgrade(); 85 long timeMs = mTestUtils.getCurrentTimeMs(); 86 mTestUtils.runOdrefresh(); 87 88 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 89 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 90 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 91 } 92 93 @Test verifyBootClasspathOtaTriggersCompilation()94 public void verifyBootClasspathOtaTriggersCompilation() throws Exception { 95 mDeviceState.simulateBootClasspathOta(); 96 long timeMs = mTestUtils.getCurrentTimeMs(); 97 mTestUtils.runOdrefresh(); 98 99 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 100 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 101 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 102 } 103 104 @Test verifySystemServerOtaTriggersCompilation()105 public void verifySystemServerOtaTriggersCompilation() throws Exception { 106 mDeviceState.simulateSystemServerOta(); 107 long timeMs = mTestUtils.getCurrentTimeMs(); 108 mTestUtils.runOdrefresh(); 109 110 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 111 mTestUtils.assertNotModifiedAfter( 112 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 113 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 114 } 115 116 @Test verifyMissingArtifactTriggersCompilation()117 public void verifyMissingArtifactTriggersCompilation() throws Exception { 118 Set<String> missingArtifacts = simulateMissingArtifacts(); 119 Set<String> remainingArtifacts = new HashSet<>(); 120 remainingArtifacts.addAll(mTestUtils.getExpectedPrimaryBootImage()); 121 remainingArtifacts.addAll(mTestUtils.getExpectedBootImageMainlineExtension()); 122 remainingArtifacts.addAll(mTestUtils.getSystemServerExpectedArtifacts()); 123 remainingArtifacts.removeAll(missingArtifacts); 124 125 mTestUtils.removeCompilationLogToAvoidBackoff(); 126 long timeMs = mTestUtils.getCurrentTimeMs(); 127 mTestUtils.runOdrefresh(); 128 129 mTestUtils.assertNotModifiedAfter(remainingArtifacts, timeMs); 130 mTestUtils.assertModifiedAfter(missingArtifacts, timeMs); 131 } 132 133 @Test verifyPhenotypeFlagChangeTriggersCompilation()134 public void verifyPhenotypeFlagChangeTriggersCompilation() throws Exception { 135 // Simulate that the flag value is initially empty. 136 mDeviceState.setPhenotypeFlag("odrefresh_test_toggle", null); 137 138 long timeMs = mTestUtils.getCurrentTimeMs(); 139 mTestUtils.runOdrefresh(); 140 141 mDeviceState.setPhenotypeFlag("odrefresh_test_toggle", "false"); 142 143 timeMs = mTestUtils.getCurrentTimeMs(); 144 mTestUtils.runOdrefresh(); 145 146 // Artifacts should not be re-compiled. 147 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 148 mTestUtils.assertNotModifiedAfter( 149 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 150 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 151 152 mDeviceState.setPhenotypeFlag("odrefresh_test_toggle", "true"); 153 154 timeMs = mTestUtils.getCurrentTimeMs(); 155 mTestUtils.runOdrefresh(); 156 157 // Artifacts should be re-compiled. 158 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 159 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 160 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 161 162 // Run odrefresh again with the flag unchanged. 163 timeMs = mTestUtils.getCurrentTimeMs(); 164 mTestUtils.runOdrefresh(); 165 166 // Artifacts should not be re-compiled. 167 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 168 mTestUtils.assertNotModifiedAfter( 169 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 170 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 171 172 mDeviceState.setPhenotypeFlag("odrefresh_test_toggle", null); 173 174 timeMs = mTestUtils.getCurrentTimeMs(); 175 mTestUtils.runOdrefresh(); 176 177 // Artifacts should be re-compiled. 178 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 179 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 180 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 181 } 182 183 @Test verifySystemServerCompilerFilterOverrideChangeTriggersCompilation()184 public void verifySystemServerCompilerFilterOverrideChangeTriggersCompilation() 185 throws Exception { 186 mDeviceState.setPhenotypeFlag("systemservercompilerfilter_override", null); 187 188 long timeMs = mTestUtils.getCurrentTimeMs(); 189 mTestUtils.runOdrefresh(); 190 191 // Artifacts should not be re-compiled. 192 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 193 mTestUtils.assertNotModifiedAfter( 194 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 195 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 196 197 mDeviceState.setPhenotypeFlag("systemservercompilerfilter_override", "speed"); 198 199 timeMs = mTestUtils.getCurrentTimeMs(); 200 mTestUtils.runOdrefresh(); 201 202 // Artifacts should be re-compiled. 203 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 204 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 205 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 206 207 // Run odrefresh again with the flag unchanged. 208 timeMs = mTestUtils.getCurrentTimeMs(); 209 mTestUtils.runOdrefresh(); 210 211 // Artifacts should not be re-compiled. 212 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 213 mTestUtils.assertNotModifiedAfter( 214 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 215 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 216 217 mDeviceState.setPhenotypeFlag("systemservercompilerfilter_override", "verify"); 218 219 timeMs = mTestUtils.getCurrentTimeMs(); 220 mTestUtils.runOdrefresh(); 221 222 // Artifacts should be re-compiled. 223 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 224 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 225 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 226 } 227 228 @Test verifySystemPropertyMismatchTriggersCompilation()229 public void verifySystemPropertyMismatchTriggersCompilation() throws Exception { 230 // Change a system property from empty to a value. 231 mDeviceState.setProperty("dalvik.vm.foo", "1"); 232 long timeMs = mTestUtils.getCurrentTimeMs(); 233 mTestUtils.runOdrefresh(); 234 235 // Artifacts should be re-compiled. 236 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 237 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 238 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 239 240 // Run again with the same value. 241 timeMs = mTestUtils.getCurrentTimeMs(); 242 mTestUtils.runOdrefresh(); 243 244 // Artifacts should not be re-compiled. 245 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 246 mTestUtils.assertNotModifiedAfter( 247 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 248 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 249 250 // Change the system property to another value. 251 mDeviceState.setProperty("dalvik.vm.foo", "2"); 252 timeMs = mTestUtils.getCurrentTimeMs(); 253 mTestUtils.runOdrefresh(); 254 255 // Artifacts should be re-compiled. 256 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 257 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 258 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 259 260 // Run again with the same value. 261 timeMs = mTestUtils.getCurrentTimeMs(); 262 mTestUtils.runOdrefresh(); 263 264 // Artifacts should not be re-compiled. 265 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 266 mTestUtils.assertNotModifiedAfter( 267 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 268 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 269 270 // Change the system property to empty. 271 mDeviceState.setProperty("dalvik.vm.foo", ""); 272 timeMs = mTestUtils.getCurrentTimeMs(); 273 mTestUtils.runOdrefresh(); 274 275 // Artifacts should be re-compiled. 276 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 277 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 278 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 279 280 // Run again with the same value. 281 timeMs = mTestUtils.getCurrentTimeMs(); 282 mTestUtils.runOdrefresh(); 283 284 // Artifacts should not be re-compiled. 285 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 286 mTestUtils.assertNotModifiedAfter( 287 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 288 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 289 } 290 291 @Test verifyNoCompilationWhenCacheIsGood()292 public void verifyNoCompilationWhenCacheIsGood() throws Exception { 293 mTestUtils.removeCompilationLogToAvoidBackoff(); 294 long timeMs = mTestUtils.getCurrentTimeMs(); 295 mTestUtils.runOdrefresh(); 296 297 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 298 mTestUtils.assertNotModifiedAfter( 299 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 300 mTestUtils.assertNotModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 301 } 302 303 @Test verifyUnexpectedFilesAreCleanedUp()304 public void verifyUnexpectedFilesAreCleanedUp() throws Exception { 305 String unexpected = OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME + "/unexpected"; 306 getDevice().pushString("" /* contents */, unexpected); 307 mTestUtils.runOdrefresh(); 308 309 assertThat(getDevice().doesFileExist(unexpected)).isFalse(); 310 } 311 312 @Test verifyCacheInfoOmitsIrrelevantApexes()313 public void verifyCacheInfoOmitsIrrelevantApexes() throws Exception { 314 String cacheInfo = getDevice().pullFileContents(OdsignTestUtils.CACHE_INFO_FILE); 315 316 // cacheInfo should list all APEXes that have compilable JARs and 317 // none that do not. 318 319 // This should always contain classpath JARs, that's the reason it exists. 320 assertThat(cacheInfo).contains("name=\"com.android.sdkext\""); 321 322 // This should never contain classpath JARs, it's the native runtime. 323 assertThat(cacheInfo).doesNotContain("name=\"com.android.runtime\""); 324 } 325 326 @Test verifyCompilationOsMode()327 public void verifyCompilationOsMode() throws Exception { 328 try { 329 // In CompOS, dex2oat directly writes to the output dir. This is allowed on Microdroid 330 // but not allowed on Android, so we need to bypass the SELinux restriction. 331 mTestUtils.assertCommandSucceeds("setenforce 0"); 332 333 mTestUtils.removeCompilationLogToAvoidBackoff(); 334 mDeviceState.simulateApexUpgrade(); 335 long timeMs = mTestUtils.getCurrentTimeMs(); 336 mTestUtils.runOdrefresh("--compilation-os-mode"); 337 338 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 339 mTestUtils.assertModifiedAfter( 340 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 341 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 342 343 String cacheInfo = getDevice().pullFileContents(OdsignTestUtils.CACHE_INFO_FILE); 344 assertThat(cacheInfo).contains("compilationOsMode=\"true\""); 345 346 // Compilation OS does not write the compilation log to the host. 347 mTestUtils.removeCompilationLogToAvoidBackoff(); 348 349 // Simulate the odrefresh invocation on the next boot. 350 timeMs = mTestUtils.getCurrentTimeMs(); 351 mTestUtils.runOdrefresh(); 352 353 // odrefresh should not re-compile anything. 354 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 355 mTestUtils.assertNotModifiedAfter( 356 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 357 mTestUtils.assertNotModifiedAfter( 358 mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 359 } finally { 360 mTestUtils.assertCommandSucceeds("setenforce 1"); 361 } 362 } 363 364 @Test verifyMinimalCompilation()365 public void verifyMinimalCompilation() throws Exception { 366 mTestUtils.removeCompilationLogToAvoidBackoff(); 367 getDevice().executeShellV2Command( 368 "rm -rf " + OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME); 369 mTestUtils.runOdrefresh("--minimal"); 370 371 mTestUtils.restartZygote(); 372 373 // The minimal boot image should be loaded. 374 mTestUtils.verifyZygotesLoadedMinimalBootImage(); 375 376 // Running the command again should not overwrite the minimal boot image. 377 mTestUtils.removeCompilationLogToAvoidBackoff(); 378 long timeMs = mTestUtils.getCurrentTimeMs(); 379 mTestUtils.runOdrefresh("--minimal"); 380 381 Set<String> minimalZygoteArtifacts = mTestUtils.getExpectedMinimalBootImage(); 382 mTestUtils.assertNotModifiedAfter(minimalZygoteArtifacts, timeMs); 383 384 // A normal odrefresh invocation should replace the minimal boot image with a full one. 385 mTestUtils.removeCompilationLogToAvoidBackoff(); 386 timeMs = mTestUtils.getCurrentTimeMs(); 387 mTestUtils.runOdrefresh(); 388 389 for (String artifact : minimalZygoteArtifacts) { 390 assertWithMessage( 391 String.format( 392 "Artifact %s should be cleaned up while it still exists", artifact)) 393 .that(getDevice().doesFileExist(artifact)) 394 .isFalse(); 395 } 396 397 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 398 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 399 } 400 401 @Test verifyCompilationFailureBackoff()402 public void verifyCompilationFailureBackoff() throws Exception { 403 mDeviceState.makeDex2oatFail(); 404 mDeviceState.simulateArtApexUpgrade(); 405 406 // Run odrefresh. It should encounter dex2oat failures. 407 long timeMs = mTestUtils.getCurrentTimeMs(); 408 mTestUtils.runOdrefresh(); 409 410 // Artifacts don't exist because the compilation failed. 411 mTestUtils.assertModifiedAfter(Set.of(OdsignTestUtils.CACHE_INFO_FILE), timeMs); 412 mTestUtils.assertFilesNotExist(mTestUtils.getExpectedPrimaryBootImage()); 413 mTestUtils.assertFilesNotExist(mTestUtils.getExpectedBootImageMainlineExtension()); 414 mTestUtils.assertFilesNotExist(mTestUtils.getSystemServerExpectedArtifacts()); 415 416 // Run odrefresh again. 417 timeMs = mTestUtils.getCurrentTimeMs(); 418 mTestUtils.runOdrefresh(); 419 420 // It should not retry. 421 mTestUtils.assertNotModifiedAfter(Set.of(OdsignTestUtils.CACHE_INFO_FILE), timeMs); 422 423 // Simulate that the backoff time has passed. 424 mTestUtils.removeCompilationLogToAvoidBackoff(); 425 426 // Run odrefresh again. 427 timeMs = mTestUtils.getCurrentTimeMs(); 428 mTestUtils.runOdrefresh(); 429 430 // Now it should retry. 431 mTestUtils.assertModifiedAfter(Set.of(OdsignTestUtils.CACHE_INFO_FILE), timeMs); 432 } 433 434 /** 435 * Regression test of CVE-2021-39689 (b/206090748): if the device doesn't have the odsign 436 * security fix, there's a risk that the existing artifacts may be manipulated, and odsign will 437 * mistakenly sign them. Therefore, odrefresh should clear all artifacts and regenerate them. 438 * I.e., no matter the compilation succeeds or not, no existing artifacts should be left. 439 * 440 * On contrary, if the device has the odsign security fix, odrefresh should keep existing 441 * artifacts (see {@link #verifyMissingArtifactTriggersCompilation}). 442 */ 443 @Test verifyArtifactsClearedWhenNoPartialCompilation()444 public void verifyArtifactsClearedWhenNoPartialCompilation() throws Exception { 445 // Remove arbitrary system server artifacts to trigger compilation. 446 simulateMissingArtifacts(); 447 448 // The successful case. 449 mTestUtils.removeCompilationLogToAvoidBackoff(); 450 long timeMs = mTestUtils.getCurrentTimeMs(); 451 mTestUtils.runOdrefreshNoPartialCompilation(); 452 453 // Existing artifacts should be replaced with new ones. 454 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 455 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 456 mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs); 457 458 // Remove arbitrary system server artifacts to trigger compilation again. 459 simulateMissingArtifacts(); 460 461 // The failed case. 462 mDeviceState.makeDex2oatFail(); 463 mTestUtils.removeCompilationLogToAvoidBackoff(); 464 timeMs = mTestUtils.getCurrentTimeMs(); 465 mTestUtils.runOdrefreshNoPartialCompilation(); 466 467 // Existing artifacts should be gone. 468 mTestUtils.assertFilesNotExist(mTestUtils.getExpectedPrimaryBootImage()); 469 mTestUtils.assertFilesNotExist(mTestUtils.getExpectedBootImageMainlineExtension()); 470 mTestUtils.assertFilesNotExist(mTestUtils.getSystemServerExpectedArtifacts()); 471 } 472 473 /** 474 * If the compilation is skipped because a previous attempt partially failed, odrefresh should 475 * not clear existing artifacts. 476 */ 477 @Test verifyArtifactsKeptWhenCompilationSkippedNoPartialCompilation()478 public void verifyArtifactsKeptWhenCompilationSkippedNoPartialCompilation() throws Exception { 479 // Simulate that the compilation is partially failed. 480 mDeviceState.simulateBadSystemServerJar(); 481 long timeMs = mTestUtils.getCurrentTimeMs(); 482 mTestUtils.runOdrefreshNoPartialCompilation(); 483 484 // Verify the test setup: boot images are still generated. 485 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 486 mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 487 488 // Rerun odrefresh. The compilation is skipped this time. 489 timeMs = mTestUtils.getCurrentTimeMs(); 490 CommandResult result = mTestUtils.runOdrefreshNoPartialCompilation(); 491 492 // Existing artifacts should be kept. 493 mTestUtils.assertNotModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs); 494 mTestUtils.assertNotModifiedAfter( 495 mTestUtils.getExpectedBootImageMainlineExtension(), timeMs); 496 497 // Note that the existing artifacts may be manipulated (CVE-2021-39689). Make sure odrefresh 498 // returns `kOkay` rather than `kCompilationSuccess` or `kCompilationFailed`, so that odsign 499 // only verifies the artifacts but not sign them. 500 assertThat(result.getExitCode()).isEqualTo(0); 501 } 502 simulateMissingArtifacts()503 private Set<String> simulateMissingArtifacts() throws Exception { 504 Set<String> missingArtifacts = new HashSet<>(); 505 String sample = mTestUtils.getSystemServerExpectedArtifacts().iterator().next(); 506 for (String extension : OdsignTestUtils.APP_ARTIFACT_EXTENSIONS) { 507 String artifact = OdsignTestUtils.replaceExtension(sample, extension); 508 getDevice().deleteFile(artifact); 509 missingArtifacts.add(artifact); 510 } 511 return missingArtifacts; 512 } 513 } 514