Home | History | Annotate | Download | only in presubmit
      1 /*
      2  * Copyright (C) 2017 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 package com.android.compatibility.common.tradefed.presubmit;
     17 
     18 import static org.junit.Assert.assertEquals;
     19 import static org.junit.Assert.assertTrue;
     20 import static org.junit.Assert.fail;
     21 
     22 import com.android.tradefed.testtype.suite.TestSuiteInfo;
     23 import com.android.tradefed.util.AaptParser;
     24 import com.android.tradefed.util.AbiUtils;
     25 
     26 import org.junit.Test;
     27 import org.junit.runner.RunWith;
     28 import org.junit.runners.JUnit4;
     29 
     30 import java.io.File;
     31 import java.io.FilenameFilter;
     32 import java.util.Arrays;
     33 import java.util.Collections;
     34 import java.util.HashMap;
     35 import java.util.HashSet;
     36 import java.util.List;
     37 import java.util.Map;
     38 import java.util.Map.Entry;
     39 import java.util.Set;
     40 
     41 /**
     42  * Tests to validate that the build is containing usable test artifact.
     43  */
     44 @RunWith(JUnit4.class)
     45 public class ValidateTestsAbi {
     46 
     47     private static final Set<String> MODULE_EXCEPTIONS = new HashSet<>();
     48     static {
     49         /**
     50          *  This particular module is shipping all it's dependencies in all abis with prebuilt stuff.
     51          *  Excluding it for now to have the test setup.
     52          */
     53         MODULE_EXCEPTIONS.add("CtsSplitApp");
     54 
     55         /**
     56          *  This module tests for security vulnerabilities when installing attacker-devised APKs.
     57          */
     58         MODULE_EXCEPTIONS.add("CtsCorruptApkTests");
     59     }
     60 
     61     private static final Set<String> BINARY_EXCEPTIONS = new HashSet<>();
     62     static {
     63         /**
     64          * This binary is a host side helper, so we do not need to check it.
     65          */
     66         BINARY_EXCEPTIONS.add("sepolicy-analyze");
     67     }
     68 
     69     /**
     70      * Test that all apks have the same supported abis.
     71      * Sometimes, if a module is missing LOCAL_MULTILIB := both, we will end up with only one of
     72      * the two abis required and the second one will fail.
     73      */
     74     @Test
     75     public void testApksAbis() {
     76         String ctsRoot = System.getProperty("CTS_ROOT");
     77         File testcases = new File(ctsRoot, "/android-cts/testcases/");
     78         if (!testcases.exists()) {
     79             fail(String.format("%s does not exists", testcases));
     80             return;
     81         }
     82         File[] listApks = testcases.listFiles(new FilenameFilter() {
     83             @Override
     84             public boolean accept(File dir, String name) {
     85                 for (String module : MODULE_EXCEPTIONS) {
     86                     if (name.startsWith(module)) {
     87                         return false;
     88                     }
     89                 }
     90 
     91                 return name.endsWith(".apk");
     92             }
     93         });
     94         assertTrue(listApks.length > 0);
     95         int maxAbi = 0;
     96         Map<String, Integer> apkToAbi = new HashMap<>();
     97 
     98         for (File testApk : listApks) {
     99             AaptParser result = AaptParser.parse(testApk);
    100             // Retry as we have seen flake with aapt sometimes.
    101             if (result == null) {
    102                 for (int i = 0; i < 2; i++) {
    103                     result = AaptParser.parse(testApk);
    104                     if (result != null) {
    105                         break;
    106                     }
    107                 }
    108                 // If still couldn't parse the apk
    109                 if (result == null) {
    110                     fail(String.format("Fail to run 'aapt dump badging %s'",
    111                             testApk.getAbsolutePath()));
    112                 }
    113             }
    114             // We only check the apk that have native code
    115             if (!result.getNativeCode().isEmpty()) {
    116                 List<String> supportedAbiApk = result.getNativeCode();
    117                 Set<String> buildTarget = AbiUtils.getAbisForArch(
    118                         TestSuiteInfo.getInstance().getTargetArch());
    119                 // first check, all the abis are supported
    120                 for (String abi : supportedAbiApk) {
    121                     if (!buildTarget.contains(abi)) {
    122                         fail(String.format("apk %s %s does not support our abis [%s]",
    123                                 testApk.getName(), supportedAbiApk, buildTarget));
    124                     }
    125                 }
    126                 apkToAbi.put(testApk.getName(), supportedAbiApk.size());
    127                 maxAbi = Math.max(maxAbi, supportedAbiApk.size());
    128             }
    129         }
    130 
    131         // We do a second pass to make sure nobody is short on abi
    132         for (Entry<String, Integer> apk : apkToAbi.entrySet()) {
    133             if (apk.getValue() < maxAbi) {
    134                 fail(String.format("apk %s only has %s abi when it should have %s", apk.getKey(),
    135                         apk.getValue(), maxAbi));
    136             }
    137         }
    138     }
    139 
    140     /**
    141      * Test that when CTS has multiple abis, we have binary for each ABI. In this case the abi will
    142      * be the same with different bitness (only case supported by build system).
    143      * <p/>
    144      * If there is only one bitness, then we check that it's the right one.
    145      */
    146     @Test
    147     public void testBinariesAbis() {
    148         String ctsRoot = System.getProperty("CTS_ROOT");
    149         File testcases = new File(ctsRoot, "/android-cts/testcases/");
    150         if (!testcases.exists()) {
    151             fail(String.format("%s does not exist", testcases));
    152             return;
    153         }
    154         String[] listBinaries = testcases.list(new FilenameFilter() {
    155             @Override
    156             public boolean accept(File dir, String name) {
    157                 if (name.contains(".")) {
    158                     return false;
    159                 }
    160                 if (BINARY_EXCEPTIONS.contains(name)) {
    161                     return false;
    162                 }
    163                 File file = new File(dir, name);
    164                 if (file.isDirectory()) {
    165                     return false;
    166                 }
    167                 if (!file.canExecute()) {
    168                     return false;
    169                 }
    170                 return true;
    171             }
    172         });
    173         assertTrue(listBinaries.length > 0);
    174         List<String> orderedList = Arrays.asList(listBinaries);
    175         // we sort to have binary starting with same name, next to each other. The last two
    176         // characters of their name with be the bitness (32 or 64).
    177         Collections.sort(orderedList);
    178         Set<String> buildTarget = AbiUtils.getAbisForArch(
    179                 TestSuiteInfo.getInstance().getTargetArch());
    180         // We expect one binary per abi of CTS, they should be appended with 32 or 64
    181         for (int i = 0; i < orderedList.size(); i=i + buildTarget.size()) {
    182             List<String> subSet = orderedList.subList(i, i + buildTarget.size());
    183             if (subSet.size() > 1) {
    184                 String base = subSet.get(0).substring(0, subSet.get(0).length() - 2);
    185                 for (int j = 0; j < subSet.size(); j++) {
    186                     assertEquals(base, subSet.get(j).substring(0, subSet.get(j).length() - 2));
    187                 }
    188             } else {
    189                 String bitness = AbiUtils.getBitness(buildTarget.iterator().next());
    190                 assertTrue(subSet.get(i).endsWith(bitness));
    191             }
    192         }
    193     }
    194 }
    195