blob: 7f9e5a7c5c7c4e42b0eb9112ab7f01b9c1a9665f [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.compatibility.common.tradefed.presubmit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import com.android.compatibility.SuiteInfo;
import com.android.tradefed.util.AaptParser;
import com.android.tradefed.util.AbiUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Tests to validate that the build is containing usable test artifact.
*/
@RunWith(JUnit4.class)
public class ValidateTestsAbi {
private static final Set<String> MODULE_EXCEPTIONS = new HashSet<>();
static {
/**
* This particular module is shipping all it's dependencies in all abis with prebuilt stuff.
* Excluding it for now to have the test setup.
*/
MODULE_EXCEPTIONS.add("CtsSplitApp");
/**
* This module tests for security vulnerabilities when installing attacker-devised APKs.
*/
MODULE_EXCEPTIONS.add("CtsCorruptApkTests");
}
private static final Set<String> BINARY_EXCEPTIONS = new HashSet<>();
static {
/**
* This binary is a host side helper, so we do not need to check it.
*/
BINARY_EXCEPTIONS.add("sepolicy-analyze");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("testhevc32");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("testavc32");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("testmpeg232");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("testhevc_mem132");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("testavc_mem132");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("testmpeg2_mem132");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("testhevc_mem232");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("testavc_mem232");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("testmpeg2_mem232");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2018-934932");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2017-068432");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2017-1319032");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2016-390932");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2017-1324132");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2017-084032");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2017-1318932");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2017-083232");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2017-083332");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2017-1317932");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2020-000232");
/**
* This binary only exists in 32-bit.
*/
BINARY_EXCEPTIONS.add("CVE-2019-217632");
}
/**
* Test that all apks have the same supported abis.
* Sometimes, if a module is missing LOCAL_MULTILIB := both, we will end up with only one of
* the two abis required and the second one will fail.
*/
@Test
public void testApksAbis() {
String ctsRoot = System.getProperty("CTS_ROOT");
File testcases = new File(ctsRoot, "/android-cts/testcases/");
if (!testcases.exists()) {
fail(String.format("%s does not exists", testcases));
return;
}
File[] listApks = testcases.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
for (String module : MODULE_EXCEPTIONS) {
if (name.startsWith(module)) {
return false;
}
}
return name.endsWith(".apk");
}
});
assertTrue(listApks.length > 0);
int maxAbi = 0;
Map<String, Integer> apkToAbi = new HashMap<>();
for (File testApk : listApks) {
AaptParser result = AaptParser.parse(testApk);
// We only check the apk that have native code
if (!result.getNativeCode().isEmpty()) {
List<String> supportedAbiApk = result.getNativeCode();
Set<String> buildTarget = AbiUtils.getAbisForArch(SuiteInfo.TARGET_ARCH);
// first check, all the abis are supported
for (String abi : supportedAbiApk) {
if (!buildTarget.contains(abi)) {
fail(String.format("apk %s %s does not support our abis [%s]",
testApk.getName(), supportedAbiApk, buildTarget));
}
}
apkToAbi.put(testApk.getName(), supportedAbiApk.size());
maxAbi = Math.max(maxAbi, supportedAbiApk.size());
}
}
// We do a second pass to make sure nobody is short on abi
for (Entry<String, Integer> apk : apkToAbi.entrySet()) {
if (apk.getValue() < maxAbi) {
fail(String.format("apk %s only has %s abi when it should have %s", apk.getKey(),
apk.getValue(), maxAbi));
}
}
}
/**
* Test that when CTS has multiple abis, we have binary for each ABI. In this case the abi will
* be the same with different bitness (only case supported by build system).
* <p/>
* If there is only one bitness, then we check that it's the right one.
*/
@Test
public void testBinariesAbis() {
String ctsRoot = System.getProperty("CTS_ROOT");
File testcases = new File(ctsRoot, "/android-cts/testcases/");
if (!testcases.exists()) {
fail(String.format("%s does not exist", testcases));
return;
}
String[] listBinaries = testcases.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.contains(".")) {
return false;
}
if (BINARY_EXCEPTIONS.contains(name)) {
return false;
}
File file = new File(dir, name);
if (file.isDirectory()) {
return false;
}
if (!file.canExecute()) {
return false;
}
return true;
}
});
assertTrue(listBinaries.length > 0);
List<String> orderedList = Arrays.asList(listBinaries);
// we sort to have binary starting with same name, next to each other. The last two
// characters of their name with be the bitness (32 or 64).
Collections.sort(orderedList);
Set<String> buildTarget = AbiUtils.getAbisForArch(SuiteInfo.TARGET_ARCH);
// We expect one binary per abi of CTS, they should be appended with 32 or 64
for (int i = 0; i < orderedList.size(); i=i + buildTarget.size()) {
List<String> subSet = orderedList.subList(i, i + buildTarget.size());
if (subSet.size() > 1) {
String base = subSet.get(0).substring(0, subSet.get(0).length() - 2);
for (int j = 0; j < subSet.size(); j++) {
assertEquals(base, subSet.get(j).substring(0, subSet.get(j).length() - 2));
}
} else {
String bitness = AbiUtils.getBitness(buildTarget.iterator().next());
assertTrue(subSet.get(i).endsWith(bitness));
}
}
}
}