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