• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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