1 /* 2 * Copyright (C) 2010 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 android.os.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 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.os.Build; 26 import android.os.SystemProperties; 27 import android.platform.test.annotations.AppModeSdkSandbox; 28 import android.platform.test.ravenwood.RavenwoodRule; 29 30 import com.android.compatibility.common.util.CddTest; 31 32 import org.junit.Before; 33 import org.junit.Test; 34 35 import java.io.IOException; 36 import java.util.Arrays; 37 import java.util.HashSet; 38 import java.util.List; 39 import java.util.Scanner; 40 import java.util.Set; 41 import java.util.regex.Pattern; 42 43 /** 44 * CTS for the {@link Build} class. 45 * 46 * This class contains tests that must pass without having a {@link RavenwoodRule}, 47 * so do not add one in this class. {@link #setUp()} has a check to ensure it. 48 * 49 * For tests that do require a {@link RavenwoodRule}, use {@link BuildExtTest} instead. 50 */ 51 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).") 52 public class BuildTest { 53 54 static final String RO_PRODUCT_CPU_ABILIST = "ro.product.cpu.abilist"; 55 static final String RO_PRODUCT_CPU_ABILIST32 = "ro.product.cpu.abilist32"; 56 static final String RO_PRODUCT_CPU_ABILIST64 = "ro.product.cpu.abilist64"; 57 static final String DEVICE = "ro.product.device"; 58 static final String MANUFACTURER = "ro.product.manufacturer"; 59 static final String MODEL = "ro.product.model"; 60 61 @Before setUp()62 public void setUp() { 63 // Ensure this class doesn't have a RavenwoodRule. 64 for (var field : this.getClass().getFields()) { 65 if (field.getType() == RavenwoodRule.class) { 66 fail("This clsas is not supposed to have a RavenwoodRule. See the class javadoc."); 67 } 68 } 69 } 70 71 /** 72 * Check if minimal properties are set (note that these might come from either 73 * /system/build.props or /oem/oem.props. 74 */ 75 @Test 76 @CddTest(requirements = {"3.2.2/C-0-1"}) testBuildProperties()77 public void testBuildProperties() throws Exception { 78 assertNotNull("Build.DEVICE should be defined", Build.DEVICE); 79 assertNotNull("Build.MANUFACTURER should be defined", Build.MANUFACTURER); 80 assertNotNull("Build.MODEL should be defined", Build.MODEL); 81 } 82 83 /** 84 * Verify that the CPU ABI fields on device match the permitted ABIs defined by CDD. 85 */ 86 @Test 87 @CddTest(requirements = {"3.3.1/C-0-6"}) testCpuAbi_valuesMatchPermitted()88 public void testCpuAbi_valuesMatchPermitted() throws Exception { 89 for (String abi : Build.SUPPORTED_ABIS) { 90 if (abi.endsWith("-hwasan")) { 91 // HWASan builds are not official builds and support *-hwasan ABIs. 92 return; 93 } 94 } 95 // The permitted ABIs are listed in https://developer.android.com/ndk/guides/abis. 96 Set<String> just32 = new HashSet<>(Arrays.asList("armeabi", "armeabi-v7a", "x86")); 97 Set<String> just64 = new HashSet<>(Arrays.asList("x86_64", "arm64-v8a", "riscv64")); 98 Set<String> all = new HashSet<>(); 99 all.addAll(just32); 100 all.addAll(just64); 101 Set<String> allAndEmpty = new HashSet<>(all); 102 allAndEmpty.add(""); 103 104 // The cpu abi fields on the device must match the permitted values. 105 assertValueIsAllowed(all, Build.CPU_ABI); 106 // CPU_ABI2 will be empty when the device does not support a secondary CPU architecture. 107 assertValueIsAllowed(allAndEmpty, Build.CPU_ABI2); 108 109 // The supported abi fields on the device must match the permitted values. 110 assertValuesAreAllowed(all, Build.SUPPORTED_ABIS); 111 assertValuesAreAllowed(just32, Build.SUPPORTED_32_BIT_ABIS); 112 assertValuesAreAllowed(just64, Build.SUPPORTED_64_BIT_ABIS); 113 } 114 runTestCpuAbiCommon()115 static void runTestCpuAbiCommon() throws Exception { 116 // The build property must match Build.SUPPORTED_ABIS exactly. 117 final String[] abiListProperty = getStringList(RO_PRODUCT_CPU_ABILIST); 118 assertEquals(Arrays.toString(abiListProperty), Arrays.toString(Build.SUPPORTED_ABIS)); 119 120 List<String> abiList = Arrays.asList(abiListProperty); 121 122 // Every supported 32 bit ABI must be present in Build.SUPPORTED_ABIS. 123 for (String abi : Build.SUPPORTED_32_BIT_ABIS) { 124 assertTrue(abiList.contains(abi)); 125 assertFalse(Build.is64BitAbi(abi)); 126 } 127 128 // Every supported 64 bit ABI must be present in Build.SUPPORTED_ABIS. 129 for (String abi : Build.SUPPORTED_64_BIT_ABIS) { 130 assertTrue(abiList.contains(abi)); 131 assertTrue(Build.is64BitAbi(abi)); 132 } 133 134 // Build.CPU_ABI and Build.CPU_ABI2 must be present in Build.SUPPORTED_ABIS. 135 assertTrue(abiList.contains(Build.CPU_ABI)); 136 if (!Build.CPU_ABI2.isEmpty()) { 137 assertTrue(abiList.contains(Build.CPU_ABI2)); 138 } 139 } 140 runTestCpuAbi32()141 static void runTestCpuAbi32() throws Exception { 142 List<String> abi32 = Arrays.asList(Build.SUPPORTED_32_BIT_ABIS); 143 assertTrue(abi32.contains(Build.CPU_ABI)); 144 145 if (!Build.CPU_ABI2.isEmpty()) { 146 assertTrue(abi32.contains(Build.CPU_ABI2)); 147 } 148 } 149 runTestCpuAbi64()150 static void runTestCpuAbi64() { 151 List<String> abi64 = Arrays.asList(Build.SUPPORTED_64_BIT_ABIS); 152 assertTrue(abi64.contains(Build.CPU_ABI)); 153 154 if (!Build.CPU_ABI2.isEmpty()) { 155 assertTrue(abi64.contains(Build.CPU_ABI2)); 156 } 157 } 158 getStringList(String property)159 static String[] getStringList(String property) throws IOException { 160 String value = getProperty(property); 161 if (value.isEmpty()) { 162 return new String[0]; 163 } else { 164 return value.split(","); 165 } 166 } 167 168 /** 169 * @param property name passed to getprop 170 */ getProperty(String property)171 static String getProperty(String property) 172 throws IOException { 173 Process process = new ProcessBuilder("getprop", property).start(); 174 Scanner scanner = null; 175 String line = ""; 176 try { 177 scanner = new Scanner(process.getInputStream()); 178 line = scanner.nextLine(); 179 } finally { 180 if (scanner != null) { 181 scanner.close(); 182 } 183 } 184 return line; 185 } 186 assertValueIsAllowed(Set<String> allowedValues, String actualValue)187 private static void assertValueIsAllowed(Set<String> allowedValues, String actualValue) { 188 assertTrue("Expected one of " + allowedValues + ", but was: '" + actualValue + "'", 189 allowedValues.contains(actualValue)); 190 } 191 assertValuesAreAllowed(Set<String> allowedValues, String[] actualValues)192 private static void assertValuesAreAllowed(Set<String> allowedValues, String[] actualValues) { 193 for (String actualValue : actualValues) { 194 assertValueIsAllowed(allowedValues, actualValue); 195 } 196 } 197 198 private static final Pattern BOARD_PATTERN = 199 Pattern.compile("^([0-9A-Za-z._-]+)$"); 200 private static final Pattern BRAND_PATTERN = 201 Pattern.compile("^([0-9A-Za-z._-]+)$"); 202 private static final Pattern DEVICE_PATTERN = 203 Pattern.compile("^([0-9A-Za-z._-]+)$"); 204 private static final Pattern ID_PATTERN = 205 Pattern.compile("^([0-9A-Za-z._-]+)$"); 206 private static final Pattern HARDWARE_PATTERN = 207 Pattern.compile("^([0-9A-Za-z.,_-]+)$"); 208 private static final Pattern PRODUCT_PATTERN = 209 Pattern.compile("^([0-9A-Za-z._-]+)$"); 210 private static final Pattern SOC_MANUFACTURER_PATTERN = 211 Pattern.compile("^([0-9A-Za-z ]+)$"); 212 private static final Pattern SOC_MODEL_PATTERN = 213 Pattern.compile("^([0-9A-Za-z ._/+-]+)$"); 214 private static final Pattern SERIAL_NUMBER_PATTERN = 215 Pattern.compile("^([0-9A-Za-z]{6,20})$"); 216 private static final Pattern SKU_PATTERN = 217 Pattern.compile("^([0-9A-Za-z.,_-]+)$"); 218 private static final Pattern TAGS_PATTERN = 219 Pattern.compile("^([0-9A-Za-z.,_-]+)$"); 220 private static final Pattern TYPE_PATTERN = 221 Pattern.compile("^([0-9A-Za-z._-]+)$"); 222 223 /** Tests that check for valid values of constants in Build. */ 224 @Test testBuildConstants()225 public void testBuildConstants() { 226 // Build.VERSION.* constants tested by BuildVersionTest 227 228 assertTrue(BOARD_PATTERN.matcher(Build.BOARD).matches()); 229 230 assertTrue(BRAND_PATTERN.matcher(Build.BRAND).matches()); 231 232 assertTrue(DEVICE_PATTERN.matcher(Build.DEVICE).matches()); 233 234 // Build.FINGERPRINT tested by BuildVersionTest 235 236 assertTrue(HARDWARE_PATTERN.matcher(Build.HARDWARE).matches()); 237 238 assertNotEmpty(Build.HOST); 239 240 assertTrue(ID_PATTERN.matcher(Build.ID).matches()); 241 242 assertNotEmpty(Build.MANUFACTURER); 243 244 assertNotEmpty(Build.MODEL); 245 246 assertEquals(Build.SOC_MANUFACTURER, Build.SOC_MANUFACTURER.trim()); 247 assertTrue(SOC_MANUFACTURER_PATTERN.matcher(Build.SOC_MANUFACTURER).matches()); 248 if (getVendorPartitionVersion() > Build.VERSION_CODES.R) { 249 assertFalse(Build.SOC_MANUFACTURER.equals(Build.UNKNOWN)); 250 } 251 252 assertEquals(Build.SOC_MODEL, Build.SOC_MODEL.trim()); 253 assertTrue(SOC_MODEL_PATTERN.matcher(Build.SOC_MODEL).matches()); 254 if (getVendorPartitionVersion() > Build.VERSION_CODES.R) { 255 assertFalse(Build.SOC_MODEL.equals(Build.UNKNOWN)); 256 } 257 258 assertTrue(PRODUCT_PATTERN.matcher(Build.PRODUCT).matches()); 259 260 assertTrue(SERIAL_NUMBER_PATTERN.matcher(Build.SERIAL).matches()); 261 262 assertTrue(SKU_PATTERN.matcher(Build.SKU).matches()); 263 264 assertTrue(SKU_PATTERN.matcher(Build.ODM_SKU).matches()); 265 266 assertTrue(TAGS_PATTERN.matcher(Build.TAGS).matches()); 267 268 // No format requirements stated in CDD for Build.TIME 269 270 assertTrue(TYPE_PATTERN.matcher(Build.TYPE).matches()); 271 272 assertNotEmpty(Build.USER); 273 } 274 275 /** 276 * Verify that SDK versions are bounded by both high and low expected 277 * values. 278 */ 279 @Test testSdkInt()280 public void testSdkInt() { 281 assertTrue( 282 "Current SDK version " + Build.VERSION.SDK_INT 283 + " is invalid; must be at least VERSION_CODES.BASE", 284 Build.VERSION.SDK_INT >= Build.VERSION_CODES.BASE); 285 assertTrue( 286 "First SDK version " + Build.VERSION.DEVICE_INITIAL_SDK_INT 287 + " is invalid; must be at least VERSION_CODES.BASE", 288 Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.BASE); 289 290 // During development of a new release SDK_INT is less than DEVICE_INITIAL_SDK_INT 291 if (Build.VERSION.CODENAME.equals("REL")) { 292 assertTrue( 293 "Current SDK version " + Build.VERSION.SDK_INT 294 + " must be at least first SDK version " 295 + Build.VERSION.DEVICE_INITIAL_SDK_INT, 296 Build.VERSION.SDK_INT >= Build.VERSION.DEVICE_INITIAL_SDK_INT); 297 } 298 } 299 300 /** 301 * Verify that MEDIA_PERFORMANCE_CLASS are bounded by both high and low expected values. 302 */ 303 @Test testMediaPerformanceClass()304 public void testMediaPerformanceClass() { 305 // media performance class value of 0 is valid 306 if (Build.VERSION.MEDIA_PERFORMANCE_CLASS == 0) { 307 return; 308 } 309 310 assertTrue( 311 "Media Performance Class " + Build.VERSION.MEDIA_PERFORMANCE_CLASS 312 + " is invalid; must be at least VERSION_CODES.R", 313 Build.VERSION.MEDIA_PERFORMANCE_CLASS >= Build.VERSION_CODES.R); 314 assertTrue( 315 "Media Performance Class " + Build.VERSION.MEDIA_PERFORMANCE_CLASS 316 + " is invalid; must be at most VERSION.SDK_INT", 317 // we use RESOURCES_SDK_INT to account for active development versions 318 Build.VERSION.MEDIA_PERFORMANCE_CLASS <= Build.VERSION.RESOURCES_SDK_INT); 319 } 320 assertNotEmpty(String value)321 private void assertNotEmpty(String value) { 322 assertNotNull(value); 323 assertFalse(value.isEmpty()); 324 } 325 getVendorPartitionVersion()326 private int getVendorPartitionVersion() { 327 String version = SystemProperties.get("ro.vndk.version"); 328 try { 329 return Integer.parseInt(version); 330 } catch (NumberFormatException ignore) { 331 return Build.VERSION_CODES.CUR_DEVELOPMENT; 332 } 333 } 334 } 335