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