• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.fastboot_getvar;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotEquals;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24 
25 import android.platform.test.annotations.RequiresDevice;
26 import com.android.tradefed.device.DeviceProperties;
27 import com.android.tradefed.device.ITestDevice;
28 import com.android.tradefed.invoker.TestInformation;
29 import com.android.tradefed.log.LogUtil.CLog;
30 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
31 import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
32 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
33 import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
34 import java.text.ParseException;
35 import java.text.SimpleDateFormat;
36 import java.util.Arrays;
37 import java.util.HashSet;
38 import java.util.concurrent.ConcurrentHashMap;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
41 import org.junit.Assert;
42 import org.junit.Assume;
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 
47 /* VTS test to verify userspace fastboot getvar information. */
48 @RequiresDevice
49 @RunWith(DeviceJUnit4ClassRunner.class)
50 public class FastbootGetvarUserspaceTest extends BaseHostJUnit4Test {
51     private static final int PLATFORM_API_LEVEL_R = 30;
52     private static final int ANDROID_RELEASE_VERSION_R = 11;
53 
54     private static String executeShellKernelARM64 =
55             "cat /proc/config.gz | gzip -d | grep CONFIG_ARM64=y";
56 
57     // IMPORTANT: Multiple instances of this class will be created while sharding
58     // the tests across multiple devices. So it needs to use ConcurrentHashMap to
59     // make these static variables thread-safe.
60     private static ConcurrentHashMap<ITestDevice, String> sDeviceCodeName =
61             new ConcurrentHashMap<>();
62     private static ConcurrentHashMap<ITestDevice, Boolean> sDeviceIsGKI10 =
63             new ConcurrentHashMap<>();
64 
65     @BeforeClassWithInfo
setUpClass(TestInformation testInfo)66     public static void setUpClass(TestInformation testInfo) throws Exception {
67         // Collects information while adb is available, prior to rebooting into fastbootd.
68         boolean isKernelARM64 = testInfo.getDevice()
69                                         .executeShellCommand(executeShellKernelARM64)
70                                         .contains("CONFIG_ARM64");
71         boolean isGKI10 = false;
72         if (isKernelARM64) {
73             String output = testInfo.getDevice().executeShellCommand("uname -r");
74             Pattern p = Pattern.compile("^(\\d+)\\.(\\d+)");
75             Matcher m1 = p.matcher(output);
76             assertTrue(m1.find());
77             isGKI10 = (Integer.parseInt(m1.group(1)) == 5 && Integer.parseInt(m1.group(2)) == 4);
78         }
79 
80         // Gets the code name via adb first. The following test cases might
81         // assert different values based on if the build is a final release build
82         // or not, where the value of the code name will be "REL" in this case.
83         String codeName = testInfo.getDevice().getProperty(DeviceProperties.BUILD_CODENAME);
84         assertNotNull(codeName);
85         codeName = codeName.trim();
86 
87         // Saves the local variables to static variables for later use, because adb
88         // is not available in the following tests.
89         sDeviceIsGKI10.put(testInfo.getDevice(), isGKI10);
90         sDeviceCodeName.put(testInfo.getDevice(), codeName);
91 
92         // Transfers from adb to fastbootd.
93         if (!isGKI10) {
94             testInfo.getDevice().rebootIntoFastbootd();
95         }
96     }
97 
98     @Before
setUp()99     public void setUp() throws Exception {
100         Assume.assumeFalse("Skipping test for fastbootd on GKI 1.0",
101                 sDeviceIsGKI10.get(getTestInformation().getDevice()));
102     }
103 
104     @AfterClassWithInfo
tearDownClass(TestInformation testInfo)105     public static void tearDownClass(TestInformation testInfo) throws Exception {
106         if (!sDeviceIsGKI10.get(testInfo.getDevice())) {
107             testInfo.getDevice().reboot(); // reboot from fastbootd to adb.
108         }
109         sDeviceIsGKI10.remove(testInfo.getDevice());
110         sDeviceCodeName.remove(testInfo.getDevice());
111     }
112 
113     /* Devices launching in R and after must export cpu-abi. */
114     @Test
testCpuAbiInfo()115     public void testCpuAbiInfo() throws Exception {
116         final HashSet<String> allCpuAbis = new HashSet<String>(
117                 Arrays.asList("armeabi-v7a", "arm64-v8a", "mips", "mips64", "x86", "x86_64"));
118         String cpuAbi = getTestInformation().getDevice().getFastbootVariable("cpu-abi");
119         CLog.d("cpuAbi: '%s'", cpuAbi);
120         assertTrue(allCpuAbis.contains(cpuAbi));
121     }
122 
123     /* Devices launching in R and after must export version-os. */
124     @Test
testOsVersion()125     public void testOsVersion() throws Exception {
126         String osVersion = getTestInformation().getDevice().getFastbootVariable("version-os");
127         CLog.d("os version: '%s'", osVersion);
128         // The value of osVersion is derived from "ro.build.version.release",
129         // which is a user-visible version string. The value does not have
130         // has any particular structure. See https://r.android.com/657597 for
131         // details.
132         assertNotNull(osVersion);
133     }
134 
135     /* Devices launching in R and after must export version-vndk. */
136     @Test
testVndkVersion()137     public void testVndkVersion() throws Exception {
138         String vndkVersion = getTestInformation().getDevice().getFastbootVariable("version-vndk");
139         String codeName = sDeviceCodeName.get(getTestInformation().getDevice());
140         CLog.d("vndk version: '%s', code name: '%s'", vndkVersion, codeName);
141         // The value of vndkVersion might be a letter or a string on pre-release builds,
142         // e.g., R or Tiramisu.
143         // And it is a number representing the API level on final release builds, e.g., 30.
144         if ("REL".equals(codeName)) {
145             try {
146                 int intVndkVersion = Integer.parseInt(vndkVersion);
147                 assertTrue(intVndkVersion >= PLATFORM_API_LEVEL_R);
148             } catch (NumberFormatException nfe) {
149                 fail("ro.vndk.version should be a number. But the current value is " + vndkVersion);
150             }
151         } else {
152             assertNotNull(vndkVersion);
153         }
154     }
155 
156     /* Devices launching in R and after must export dynamic-partition. */
157     @Test
testDynamicPartition()158     public void testDynamicPartition() throws Exception {
159         String dynamic_partition =
160                 getTestInformation().getDevice().getFastbootVariable("dynamic-partition");
161         CLog.d("dynamic_partition: '%s'", dynamic_partition);
162         assertTrue(dynamic_partition.equals("true"));
163     }
164 
165     /* Devices launching in R and after must export treble-enabled. */
166     @Test
testTrebleEnable()167     public void testTrebleEnable() throws Exception {
168         String treble_enabled =
169                 getTestInformation().getDevice().getFastbootVariable("treble-enabled");
170         CLog.d("treble_enabled: '%s'", treble_enabled);
171         assertTrue(treble_enabled.equals("true") || treble_enabled.equals("false"));
172     }
173 
174     /* Devices launching in R and after must export first-api-level. */
175     @Test
testFirstApiLevel()176     public void testFirstApiLevel() throws Exception {
177         String first_api_level =
178                 getTestInformation().getDevice().getFastbootVariable("first-api-level");
179         CLog.d("first_api_level: '%s'", first_api_level);
180         try {
181             int api_level = Integer.parseInt(first_api_level);
182             assertTrue(api_level >= PLATFORM_API_LEVEL_R);
183         } catch (NumberFormatException nfe) {
184             fail("Failed to parse first-api-level: " + first_api_level);
185         }
186     }
187 
188     /* Devices launching in R and after must export security-patch-level. */
189     @Test
testSecurityPatchLevel()190     public void testSecurityPatchLevel() throws Exception {
191         String SPL = getTestInformation().getDevice().getFastbootVariable("security-patch-level");
192         CLog.d("SPL: '%s'", SPL);
193         try {
194             SimpleDateFormat template = new SimpleDateFormat("yyyy-MM-dd");
195             template.parse(SPL);
196         } catch (ParseException e) {
197             fail("Failed to parse security-patch-level: " + SPL);
198         }
199     }
200 
201     /* Devices launching in R and after must export system-fingerprint. */
202     @Test
testSystemFingerprint()203     public void testSystemFingerprint() throws Exception {
204         String systemFingerprint =
205                 getTestInformation().getDevice().getFastbootVariable("system-fingerprint");
206         CLog.d("system fingerprint: '%s'", systemFingerprint);
207         verifyFingerprint(systemFingerprint);
208     }
209 
210     /* Devices launching in R and after must export vendor-fingerprint. */
211     @Test
testVendorFingerprint()212     public void testVendorFingerprint() throws Exception {
213         String vendorFingerprint =
214                 getTestInformation().getDevice().getFastbootVariable("vendor-fingerprint");
215         CLog.d("vendor fingerprint: '%s'", vendorFingerprint);
216         verifyFingerprint(vendorFingerprint);
217     }
218 
219     /*
220      *  Verifies the fingerprint defined in CDD.
221      *    https://source.android.com/compatibility/cdd
222      *
223      *  The fingerprint should be of format:
224      *    $(BRAND)/$(PRODUCT)/$(DEVICE):$(VERSION.RELEASE)/$(ID)/$(VERSION.INCREMENTAL):$(TYPE)/$(TAGS).
225      */
verifyFingerprint(String fingerprint)226     private void verifyFingerprint(String fingerprint) {
227         final HashSet<String> allBuildVariants =
228                 new HashSet<String>(Arrays.asList("user", "userdebug", "eng"));
229 
230         final HashSet<String> allTags =
231                 new HashSet<String>(Arrays.asList("release-keys", "dev-keys", "test-keys"));
232 
233         verifyFingerprintStructure(fingerprint);
234 
235         String[] fingerprintSegs = fingerprint.split("/");
236         assertTrue(fingerprintSegs[0].matches("^[a-zA-Z0-9_-]+$")); // BRAND
237         assertTrue(fingerprintSegs[1].matches("^[a-zA-Z0-9_-]+$")); // PRODUCT
238 
239         String[] devicePlatform = fingerprintSegs[2].split(":");
240         assertEquals(2, devicePlatform.length);
241         assertTrue(devicePlatform[0].matches("^[a-zA-Z0-9_-]+$")); // DEVICE
242 
243         assertTrue(fingerprintSegs[3].matches("^[a-zA-Z0-9._-]+$")); // ID
244 
245         String[] buildNumberVariant = fingerprintSegs[4].split(":");
246         assertTrue(buildNumberVariant[0].matches("^[^ :\\/~]+$")); // VERSION.INCREMENTAL
247         assertTrue(allBuildVariants.contains(buildNumberVariant[1])); // TYPE
248 
249         assertTrue(allTags.contains(fingerprintSegs[5])); // TAG
250     }
251 
verifyFingerprintStructure(String fingerprint)252     private void verifyFingerprintStructure(String fingerprint) {
253         assertEquals("Build fingerprint must not include whitespace", -1, fingerprint.indexOf(' '));
254 
255         String[] segments = fingerprint.split("/");
256         assertEquals("Build fingerprint does not match expected format", 6, segments.length);
257 
258         String[] devicePlatform = segments[2].split(":");
259         assertEquals(2, devicePlatform.length);
260 
261         assertTrue(segments[4].contains(":"));
262         String buildVariant = segments[4].split(":")[1];
263         assertTrue(buildVariant.length() > 0);
264     }
265 }
266