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 * This module tests for installations of packages that have only 32-bit native libraries. 62 */ 63 MODULE_EXCEPTIONS.add("CtsExtractNativeLibsAppTrue32"); 64 65 /** 66 * This module tests for installations of packages that have only 64-bit native libraries. 67 */ 68 MODULE_EXCEPTIONS.add("CtsExtractNativeLibsAppTrue64"); 69 } 70 71 private static final Set<String> BINARY_EXCEPTIONS = new HashSet<>(); 72 static { 73 /** 74 * This binary is a host side helper, so we do not need to check it. 75 */ 76 BINARY_EXCEPTIONS.add("sepolicy-analyze"); 77 } 78 79 /** 80 * Test that all apks have the same supported abis. 81 * Sometimes, if a module is missing LOCAL_MULTILIB := both, we will end up with only one of 82 * the two abis required and the second one will fail. 83 */ 84 @Test testApksAbis()85 public void testApksAbis() { 86 String ctsRoot = System.getProperty("CTS_ROOT"); 87 File testcases = new File(ctsRoot, "/android-cts/testcases/"); 88 if (!testcases.exists()) { 89 fail(String.format("%s does not exists", testcases)); 90 return; 91 } 92 File[] listApks = testcases.listFiles(new FilenameFilter() { 93 @Override 94 public boolean accept(File dir, String name) { 95 for (String module : MODULE_EXCEPTIONS) { 96 if (name.startsWith(module)) { 97 return false; 98 } 99 } 100 101 return name.endsWith(".apk"); 102 } 103 }); 104 assertTrue(listApks.length > 0); 105 int maxAbi = 0; 106 Map<String, Integer> apkToAbi = new HashMap<>(); 107 108 for (File testApk : listApks) { 109 AaptParser result = AaptParser.parse(testApk); 110 // Retry as we have seen flake with aapt sometimes. 111 if (result == null) { 112 for (int i = 0; i < 2; i++) { 113 result = AaptParser.parse(testApk); 114 if (result != null) { 115 break; 116 } 117 } 118 // If still couldn't parse the apk 119 if (result == null) { 120 fail(String.format("Fail to run 'aapt dump badging %s'", 121 testApk.getAbsolutePath())); 122 } 123 } 124 // We only check the apk that have native code 125 if (!result.getNativeCode().isEmpty()) { 126 List<String> supportedAbiApk = result.getNativeCode(); 127 Set<String> buildTarget = AbiUtils.getAbisForArch( 128 TestSuiteInfo.getInstance().getTargetArchs().get(0)); 129 // first check, all the abis are supported 130 for (String abi : supportedAbiApk) { 131 if (!buildTarget.contains(abi)) { 132 fail(String.format("apk %s %s does not support our abis [%s]", 133 testApk.getName(), supportedAbiApk, buildTarget)); 134 } 135 } 136 apkToAbi.put(testApk.getName(), supportedAbiApk.size()); 137 maxAbi = Math.max(maxAbi, supportedAbiApk.size()); 138 } 139 } 140 141 // We do a second pass to make sure nobody is short on abi 142 for (Entry<String, Integer> apk : apkToAbi.entrySet()) { 143 if (apk.getValue() < maxAbi) { 144 fail(String.format("apk %s only has %s abi when it should have %s", apk.getKey(), 145 apk.getValue(), maxAbi)); 146 } 147 } 148 } 149 150 /** 151 * Test that when CTS has multiple abis, we have binary for each ABI. In this case the abi will 152 * be the same with different bitness (only case supported by build system). 153 * <p/> 154 * If there is only one bitness, then we check that it's the right one. 155 */ 156 @Test testBinariesAbis()157 public void testBinariesAbis() { 158 String ctsRoot = System.getProperty("CTS_ROOT"); 159 File testcases = new File(ctsRoot, "/android-cts/testcases/"); 160 if (!testcases.exists()) { 161 fail(String.format("%s does not exist", testcases)); 162 return; 163 } 164 String[] listBinaries = testcases.list(new FilenameFilter() { 165 @Override 166 public boolean accept(File dir, String name) { 167 if (name.contains(".")) { 168 return false; 169 } 170 if (BINARY_EXCEPTIONS.contains(name)) { 171 return false; 172 } 173 File file = new File(dir, name); 174 if (file.isDirectory()) { 175 return false; 176 } 177 if (!file.canExecute()) { 178 return false; 179 } 180 return true; 181 } 182 }); 183 assertTrue(listBinaries.length > 0); 184 List<String> orderedList = Arrays.asList(listBinaries); 185 // we sort to have binary starting with same name, next to each other. The last two 186 // characters of their name with be the bitness (32 or 64). 187 Collections.sort(orderedList); 188 Set<String> buildTarget = AbiUtils.getAbisForArch( 189 TestSuiteInfo.getInstance().getTargetArchs().get(0)); 190 // We expect one binary per abi of CTS, they should be appended with 32 or 64 191 for (int i = 0; i < orderedList.size(); i=i + buildTarget.size()) { 192 List<String> subSet = orderedList.subList(i, i + buildTarget.size()); 193 if (subSet.size() > 1) { 194 String base = subSet.get(0).substring(0, subSet.get(0).length() - 2); 195 for (int j = 0; j < subSet.size(); j++) { 196 assertEquals(base, subSet.get(j).substring(0, subSet.get(j).length() - 2)); 197 } 198 } else { 199 String bitness = AbiUtils.getBitness(buildTarget.iterator().next()); 200 assertTrue(subSet.get(i).endsWith(bitness)); 201 } 202 } 203 } 204 } 205