Home | History | Annotate | Download | only in cts
      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 android.os.Build.VERSION.CODENAME;
     20 import static android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
     21 
     22 import android.os.Build;
     23 import android.platform.test.annotations.RestrictedBuildTest;
     24 
     25 import dalvik.system.VMRuntime;
     26 
     27 import junit.framework.TestCase;
     28 
     29 import java.io.IOException;
     30 import java.lang.reflect.Field;
     31 import java.lang.reflect.Modifier;
     32 import java.util.Arrays;
     33 import java.util.List;
     34 import java.util.Scanner;
     35 import java.util.regex.Pattern;
     36 
     37 public class BuildTest extends TestCase {
     38 
     39     private static final String RO_PRODUCT_CPU_ABILIST = "ro.product.cpu.abilist";
     40     private static final String RO_PRODUCT_CPU_ABILIST32 = "ro.product.cpu.abilist32";
     41     private static final String RO_PRODUCT_CPU_ABILIST64 = "ro.product.cpu.abilist64";
     42 
     43     /** Tests that check the values of {@link Build#CPU_ABI} and {@link Build#CPU_ABI2}. */
     44     public void testCpuAbi() throws Exception {
     45         runTestCpuAbiCommon();
     46         if (VMRuntime.getRuntime().is64Bit()) {
     47             runTestCpuAbi64();
     48         } else {
     49             runTestCpuAbi32();
     50         }
     51     }
     52 
     53     private void runTestCpuAbiCommon() throws Exception {
     54         // The build property must match Build.SUPPORTED_ABIS exactly.
     55         final String[] abiListProperty = getStringList(RO_PRODUCT_CPU_ABILIST);
     56         assertEquals(Arrays.toString(abiListProperty), Arrays.toString(Build.SUPPORTED_ABIS));
     57 
     58         List<String> abiList = Arrays.asList(abiListProperty);
     59 
     60         // Every device must support at least one 32 bit ABI.
     61         assertTrue(Build.SUPPORTED_32_BIT_ABIS.length > 0);
     62 
     63         // Every supported 32 bit ABI must be present in Build.SUPPORTED_ABIS.
     64         for (String abi : Build.SUPPORTED_32_BIT_ABIS) {
     65             assertTrue(abiList.contains(abi));
     66             assertFalse(VMRuntime.is64BitAbi(abi));
     67         }
     68 
     69         // Every supported 64 bit ABI must be present in Build.SUPPORTED_ABIS.
     70         for (String abi : Build.SUPPORTED_64_BIT_ABIS) {
     71             assertTrue(abiList.contains(abi));
     72             assertTrue(VMRuntime.is64BitAbi(abi));
     73         }
     74 
     75         // Build.CPU_ABI and Build.CPU_ABI2 must be present in Build.SUPPORTED_ABIS.
     76         assertTrue(abiList.contains(Build.CPU_ABI));
     77         if (!Build.CPU_ABI2.isEmpty()) {
     78             assertTrue(abiList.contains(Build.CPU_ABI2));
     79         }
     80     }
     81 
     82     private void runTestCpuAbi32() throws Exception {
     83         List<String> abi32 = Arrays.asList(Build.SUPPORTED_32_BIT_ABIS);
     84         assertTrue(abi32.contains(Build.CPU_ABI));
     85 
     86         if (!Build.CPU_ABI2.isEmpty()) {
     87             assertTrue(abi32.contains(Build.CPU_ABI2));
     88         }
     89     }
     90 
     91     private void runTestCpuAbi64() {
     92         List<String> abi64 = Arrays.asList(Build.SUPPORTED_64_BIT_ABIS);
     93         assertTrue(abi64.contains(Build.CPU_ABI));
     94 
     95         if (!Build.CPU_ABI2.isEmpty()) {
     96             assertTrue(abi64.contains(Build.CPU_ABI2));
     97         }
     98     }
     99 
    100     private String[] getStringList(String property) throws IOException {
    101         String value = getProperty(property);
    102         if (value.isEmpty()) {
    103             return new String[0];
    104         } else {
    105             return value.split(",");
    106         }
    107     }
    108 
    109     /**
    110      * @param property name passed to getprop
    111      */
    112     static String getProperty(String property)
    113             throws IOException {
    114         Process process = new ProcessBuilder("getprop", property).start();
    115         Scanner scanner = null;
    116         String line = "";
    117         try {
    118             scanner = new Scanner(process.getInputStream());
    119             line = scanner.nextLine();
    120         } finally {
    121             if (scanner != null) {
    122                 scanner.close();
    123             }
    124         }
    125         return line;
    126     }
    127     /**
    128      * @param message shown when the test fails
    129      * @param property name passed to getprop
    130      * @param expected value of the property
    131      */
    132     private void assertProperty(String message, String property, String expected)
    133             throws IOException {
    134         Process process = new ProcessBuilder("getprop", property).start();
    135         Scanner scanner = null;
    136         try {
    137             scanner = new Scanner(process.getInputStream());
    138             String line = scanner.nextLine();
    139             assertEquals(message + " Value found: " + line , expected, line);
    140             assertFalse(scanner.hasNext());
    141         } finally {
    142             if (scanner != null) {
    143                 scanner.close();
    144             }
    145         }
    146     }
    147 
    148     /**
    149      * Check that a property is not set by scanning through the list of properties returned by
    150      * getprop, since calling getprop on an property set to "" and on a non-existent property
    151      * yields the same output.
    152      *
    153      * @param message shown when the test fails
    154      * @param property name passed to getprop
    155      */
    156     private void assertNoPropertySet(String message, String property) throws IOException {
    157         Process process = new ProcessBuilder("getprop").start();
    158         Scanner scanner = null;
    159         try {
    160             scanner = new Scanner(process.getInputStream());
    161             while (scanner.hasNextLine()) {
    162                 String line = scanner.nextLine();
    163                 assertFalse(message + "Property found: " + line,
    164                         line.startsWith("[" + property + "]"));
    165             }
    166         } finally {
    167             if (scanner != null) {
    168                 scanner.close();
    169             }
    170         }
    171     }
    172 
    173     private static final Pattern BOARD_PATTERN =
    174         Pattern.compile("^([0-9A-Za-z._-]+)$");
    175     private static final Pattern BRAND_PATTERN =
    176         Pattern.compile("^([0-9A-Za-z._-]+)$");
    177     private static final Pattern DEVICE_PATTERN =
    178         Pattern.compile("^([0-9A-Za-z._-]+)$");
    179     private static final Pattern ID_PATTERN =
    180         Pattern.compile("^([0-9A-Za-z._-]+)$");
    181     private static final Pattern HARDWARE_PATTERN =
    182         Pattern.compile("^([0-9A-Za-z.,_-]+)$");
    183     private static final Pattern PRODUCT_PATTERN =
    184         Pattern.compile("^([0-9A-Za-z._-]+)$");
    185     private static final Pattern SERIAL_NUMBER_PATTERN =
    186         Pattern.compile("^([0-9A-Za-z]{6,20})$");
    187     private static final Pattern TAGS_PATTERN =
    188         Pattern.compile("^([0-9A-Za-z.,_-]+)$");
    189     private static final Pattern TYPE_PATTERN =
    190         Pattern.compile("^([0-9A-Za-z._-]+)$");
    191 
    192     /** Tests that check for valid values of constants in Build. */
    193     public void testBuildConstants() {
    194         // Build.VERSION.* constants tested by BuildVersionTest
    195 
    196         assertTrue(BOARD_PATTERN.matcher(Build.BOARD).matches());
    197 
    198         assertTrue(BRAND_PATTERN.matcher(Build.BRAND).matches());
    199 
    200         assertTrue(DEVICE_PATTERN.matcher(Build.DEVICE).matches());
    201 
    202         // Build.FINGERPRINT tested by BuildVersionTest
    203 
    204         assertTrue(HARDWARE_PATTERN.matcher(Build.HARDWARE).matches());
    205 
    206         assertNotEmpty(Build.HOST);
    207 
    208         assertTrue(ID_PATTERN.matcher(Build.ID).matches());
    209 
    210         assertNotEmpty(Build.MANUFACTURER);
    211 
    212         assertNotEmpty(Build.MODEL);
    213 
    214         assertTrue(PRODUCT_PATTERN.matcher(Build.PRODUCT).matches());
    215 
    216         assertTrue(SERIAL_NUMBER_PATTERN.matcher(Build.SERIAL).matches());
    217 
    218         assertTrue(TAGS_PATTERN.matcher(Build.TAGS).matches());
    219 
    220         // No format requirements stated in CDD for Build.TIME
    221 
    222         assertTrue(TYPE_PATTERN.matcher(Build.TYPE).matches());
    223 
    224         assertNotEmpty(Build.USER);
    225 
    226         // CUR_DEVELOPMENT must be larger than any released version.
    227         Field[] fields = Build.VERSION_CODES.class.getDeclaredFields();
    228         for (Field field : fields) {
    229             if (field.getType().equals(int.class) && Modifier.isStatic(field.getModifiers())) {
    230                 String fieldName = field.getName();
    231                 final int fieldValue;
    232                 try {
    233                     fieldValue = field.getInt(null);
    234                 } catch (IllegalAccessException e) {
    235                     throw new AssertionError(e.getMessage());
    236                 }
    237                 if (fieldName.equals("CUR_DEVELOPMENT")) {
    238                     // It should be okay to change the value of this constant in future, but it
    239                     // should at least be a conscious decision.
    240                     assertEquals(10000, fieldValue);
    241                 } else if (fieldName.equals(CODENAME) && !CODENAME.equals("REL")) {
    242                     // This is the current development version. Note that fieldName can
    243                     // become < CUR_DEVELOPMENT before CODENAME becomes "REL", so we
    244                     // can't assertEquals(CUR_DEVELOPMENT, fieldValue) here.
    245                     assertTrue("Expected " + fieldName + " value to be <= " + CUR_DEVELOPMENT
    246                             + ", got " + fieldValue, fieldValue <= CUR_DEVELOPMENT);
    247                 } else {
    248                     assertTrue("Expected " + fieldName + " value to be < " + CUR_DEVELOPMENT
    249                             + ", got " + fieldValue, fieldValue < CUR_DEVELOPMENT);
    250                 }
    251             }
    252         }
    253     }
    254 
    255     /**
    256      * Verify that SDK versions are bounded by both high and low expected
    257      * values.
    258      */
    259     public void testSdkInt() {
    260         assertTrue(
    261                 "Current SDK version " + Build.VERSION.SDK_INT
    262                         + " is invalid; must be at least VERSION_CODES.BASE",
    263                 Build.VERSION.SDK_INT >= Build.VERSION_CODES.BASE);
    264         assertTrue(
    265                 "First SDK version " + Build.VERSION.FIRST_SDK_INT
    266                         + " is invalid; must be at least VERSION_CODES.BASE",
    267                 Build.VERSION.FIRST_SDK_INT >= Build.VERSION_CODES.BASE);
    268         assertTrue(
    269                 "Current SDK version " + Build.VERSION.SDK_INT
    270                         + " must be at least first SDK version " + Build.VERSION.FIRST_SDK_INT,
    271                 Build.VERSION.SDK_INT >= Build.VERSION.FIRST_SDK_INT);
    272     }
    273 
    274     static final String RO_DEBUGGABLE = "ro.debuggable";
    275     private static final String RO_SECURE = "ro.secure";
    276 
    277     /**
    278      * Assert that the device is a secure, not debuggable user build.
    279      *
    280      * Debuggable devices allow adb root and have the su command, allowing
    281      * escalations to root and unauthorized access to application data.
    282      *
    283      * Note: This test will fail on userdebug / eng devices, but should pass
    284      * on production (user) builds.
    285      */
    286     @RestrictedBuildTest
    287     public void testIsSecureUserBuild() throws IOException {
    288         assertEquals("Must be a user build", "user", Build.TYPE);
    289         assertProperty("Must be a non-debuggable build", RO_DEBUGGABLE, "0");
    290         assertProperty("Must be a secure build", RO_SECURE, "1");
    291     }
    292 
    293     private void assertNotEmpty(String value) {
    294         assertNotNull(value);
    295         assertFalse(value.isEmpty());
    296     }
    297 }
    298