1 /*
2  * Copyright (C) 2016 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.tradefed.util;
17 
18 import java.util.HashSet;
19 import java.util.LinkedHashMap;
20 import java.util.LinkedHashSet;
21 import java.util.Map;
22 import java.util.Set;
23 
24 /**
25  * Utility class for handling device ABIs
26  */
27 public class AbiUtils {
28 
29     // List of supported abi
30     public static final String ABI_ARM_V7A = "armeabi-v7a";
31     public static final String ABI_ARM_64_V8A = "arm64-v8a";
32     public static final String ABI_X86 = "x86";
33     public static final String ABI_X86_64 = "x86_64";
34     public static final String ABI_MIPS = "mips";
35     public static final String ABI_MIPS64 = "mips64";
36 
37     // List of supported architectures
38     public static final String BASE_ARCH_ARM = "arm";
39     public static final String ARCH_ARM64 = BASE_ARCH_ARM + "64";
40     public static final String BASE_ARCH_X86 = "x86";
41     public static final String ARCH_X86_64 = BASE_ARCH_X86 + "_64";
42     public static final String BASE_ARCH_MIPS = "mips";
43     public static final String ARCH_MIPS64 = BASE_ARCH_MIPS + "64";
44 
45     /**
46      * The set of 32Bit ABIs.
47      */
48     private static final Set<String> ABIS_32BIT = new HashSet<String>();
49 
50     /**
51      * The set of 64Bit ABIs.
52      */
53     private static final Set<String> ABIS_64BIT = new HashSet<String>();
54 
55     /**
56      * The set of ARM ABIs.
57      */
58     protected static final Set<String> ARM_ABIS = new HashSet<String>();
59 
60     /**
61      * The set of Intel ABIs.
62      */
63     private static final Set<String> INTEL_ABIS = new HashSet<String>();
64 
65     /**
66      * The set of Mips ABIs.
67      */
68     private static final Set<String> MIPS_ABIS = new HashSet<String>();
69 
70     /** The set of ABI names which Compatibility supports. */
71     protected static final Set<String> ABIS_SUPPORTED_BY_COMPATIBILITY = new LinkedHashSet<>();
72 
73     /** The set of Architecture supported. */
74     private static final Set<String> ARCH_SUPPORTED = new LinkedHashSet<>();
75 
76     /** The map of architecture to ABI. */
77     private static final Map<String, Set<String>> ARCH_TO_ABIS =
78             new LinkedHashMap<String, Set<String>>();
79 
80     private static final Map<String, String> ABI_TO_ARCH = new LinkedHashMap<String, String>();
81 
82     private static final Map<String, String> ABI_TO_BASE_ARCH = new LinkedHashMap<String, String>();
83 
84     static {
85         ABIS_32BIT.add(ABI_ARM_V7A);
86         ABIS_32BIT.add(ABI_X86);
87         ABIS_32BIT.add(ABI_MIPS);
88 
89         ABIS_64BIT.add(ABI_ARM_64_V8A);
90         ABIS_64BIT.add(ABI_X86_64);
91         ABIS_64BIT.add(ABI_MIPS64);
92 
93         ARM_ABIS.add(ABI_ARM_V7A);
94         ARM_ABIS.add(ABI_ARM_64_V8A);
95 
96         INTEL_ABIS.add(ABI_X86);
97         INTEL_ABIS.add(ABI_X86_64);
98 
99         MIPS_ABIS.add(ABI_MIPS);
100         MIPS_ABIS.add(ABI_MIPS64);
101 
ARCH_TO_ABIS.put(BASE_ARCH_ARM, ARM_ABIS)102         ARCH_TO_ABIS.put(BASE_ARCH_ARM, ARM_ABIS);
ARCH_TO_ABIS.put(ARCH_ARM64, ARM_ABIS)103         ARCH_TO_ABIS.put(ARCH_ARM64, ARM_ABIS);
ARCH_TO_ABIS.put(BASE_ARCH_X86, INTEL_ABIS)104         ARCH_TO_ABIS.put(BASE_ARCH_X86, INTEL_ABIS);
ARCH_TO_ABIS.put(ARCH_X86_64, INTEL_ABIS)105         ARCH_TO_ABIS.put(ARCH_X86_64, INTEL_ABIS);
ARCH_TO_ABIS.put(BASE_ARCH_MIPS, MIPS_ABIS)106         ARCH_TO_ABIS.put(BASE_ARCH_MIPS, MIPS_ABIS);
ARCH_TO_ABIS.put(ARCH_MIPS64, MIPS_ABIS)107         ARCH_TO_ABIS.put(ARCH_MIPS64, MIPS_ABIS);
108 
109         ABIS_SUPPORTED_BY_COMPATIBILITY.addAll(ARM_ABIS);
110         ABIS_SUPPORTED_BY_COMPATIBILITY.addAll(INTEL_ABIS);
111         ABIS_SUPPORTED_BY_COMPATIBILITY.addAll(MIPS_ABIS);
112 
ABI_TO_ARCH.put(ABI_ARM_V7A, BASE_ARCH_ARM)113         ABI_TO_ARCH.put(ABI_ARM_V7A, BASE_ARCH_ARM);
ABI_TO_ARCH.put(ABI_ARM_64_V8A, ARCH_ARM64)114         ABI_TO_ARCH.put(ABI_ARM_64_V8A, ARCH_ARM64);
ABI_TO_ARCH.put(ABI_X86, BASE_ARCH_X86)115         ABI_TO_ARCH.put(ABI_X86, BASE_ARCH_X86);
ABI_TO_ARCH.put(ABI_X86_64, ARCH_X86_64)116         ABI_TO_ARCH.put(ABI_X86_64, ARCH_X86_64);
ABI_TO_ARCH.put(ABI_MIPS, BASE_ARCH_MIPS)117         ABI_TO_ARCH.put(ABI_MIPS, BASE_ARCH_MIPS);
ABI_TO_ARCH.put(ABI_MIPS64, ARCH_MIPS64)118         ABI_TO_ARCH.put(ABI_MIPS64, ARCH_MIPS64);
119 
ABI_TO_BASE_ARCH.put(ABI_ARM_V7A, BASE_ARCH_ARM)120         ABI_TO_BASE_ARCH.put(ABI_ARM_V7A, BASE_ARCH_ARM);
ABI_TO_BASE_ARCH.put(ABI_ARM_64_V8A, BASE_ARCH_ARM)121         ABI_TO_BASE_ARCH.put(ABI_ARM_64_V8A, BASE_ARCH_ARM);
ABI_TO_BASE_ARCH.put(ABI_X86, BASE_ARCH_X86)122         ABI_TO_BASE_ARCH.put(ABI_X86, BASE_ARCH_X86);
ABI_TO_BASE_ARCH.put(ABI_X86_64, BASE_ARCH_X86)123         ABI_TO_BASE_ARCH.put(ABI_X86_64, BASE_ARCH_X86);
ABI_TO_BASE_ARCH.put(ABI_MIPS, BASE_ARCH_MIPS)124         ABI_TO_BASE_ARCH.put(ABI_MIPS, BASE_ARCH_MIPS);
ABI_TO_BASE_ARCH.put(ABI_MIPS64, BASE_ARCH_MIPS)125         ABI_TO_BASE_ARCH.put(ABI_MIPS64, BASE_ARCH_MIPS);
126 
127         ARCH_SUPPORTED.add(BASE_ARCH_ARM);
128         ARCH_SUPPORTED.add(ARCH_ARM64);
129         ARCH_SUPPORTED.add(BASE_ARCH_X86);
130         ARCH_SUPPORTED.add(ARCH_X86_64);
131         ARCH_SUPPORTED.add(BASE_ARCH_MIPS);
132         ARCH_SUPPORTED.add(ARCH_MIPS64);
133     }
134 
135     /**
136      * Private constructor to avoid instantiation.
137      */
AbiUtils()138     private AbiUtils() {}
139 
140     /**
141      * Returns the set of ABIs associated with the given architecture.
142      * @param arch The architecture to look up.
143      * @return a new Set containing the ABIs.
144      */
getAbisForArch(String arch)145     public static Set<String> getAbisForArch(String arch) {
146         if (arch == null || arch.isEmpty() || !ARCH_TO_ABIS.containsKey(arch)) {
147             return getAbisSupportedByCompatibility();
148         }
149         return new LinkedHashSet<String>(ARCH_TO_ABIS.get(arch));
150     }
151 
152     /**
153      * Returns the architecture matching the abi.
154      */
getArchForAbi(String abi)155     public static String getArchForAbi(String abi) {
156         if (abi == null || abi.isEmpty()) {
157             throw new IllegalArgumentException("Abi cannot be null or empty");
158         }
159         return ABI_TO_ARCH.get(abi);
160     }
161 
162     /** Returns the base architecture matching the abi. */
getBaseArchForAbi(String abi)163     public static String getBaseArchForAbi(String abi) {
164         if (abi == null || abi.isEmpty()) {
165             throw new IllegalArgumentException("Abi cannot be null or empty");
166         }
167         return ABI_TO_BASE_ARCH.get(abi);
168     }
169 
170     /**
171      * Returns the set of ABIs supported by Compatibility.
172      *
173      * @return a new Set containing the supported ABIs.
174      */
getAbisSupportedByCompatibility()175     public static Set<String> getAbisSupportedByCompatibility() {
176         return new LinkedHashSet<String>(ABIS_SUPPORTED_BY_COMPATIBILITY);
177     }
178 
179     /** Returns the set of supported architecture representations. */
getArchSupported()180     public static Set<String> getArchSupported() {
181         return new LinkedHashSet<String>(ARCH_SUPPORTED);
182     }
183 
184     /**
185      * @param abi The ABI name to test.
186      * @return true if the given ABI is supported by Compatibility.
187      */
isAbiSupportedByCompatibility(String abi)188     public static boolean isAbiSupportedByCompatibility(String abi) {
189         return ABIS_SUPPORTED_BY_COMPATIBILITY.contains(abi);
190     }
191 
192     /**
193      * Creates a flag for the given ABI.
194      * @param abi the ABI to create the flag for.
195      * @return a string which can be add to a command sent to ADB.
196      */
createAbiFlag(String abi)197     public static String createAbiFlag(String abi) {
198         if (abi == null || abi.isEmpty() || !isAbiSupportedByCompatibility(abi)) {
199             return "";
200         }
201         return String.format("--abi %s ", abi);
202     }
203 
204     /**
205      * Creates a unique id from the given ABI and name.
206      * @param abi The ABI to use.
207      * @param name The name to use.
208      * @return a string which uniquely identifies a run.
209      */
createId(String abi, String name)210     public static String createId(String abi, String name) {
211         return String.format("%s %s", abi, name);
212     }
213 
214     /**
215      * Parses a unique id into the ABI and name.
216      * @param id The id to parse.
217      * @return a string array containing the ABI and name.
218      */
parseId(String id)219     public static String[] parseId(String id) {
220         if (id == null || !id.contains(" ")) {
221             return new String[] {"", ""};
222         }
223         return id.split(" ");
224     }
225 
226     /**
227      * @return the test name portion of the test id.
228      *         e.g. armeabi-v7a android.mytest = android.mytest
229      */
parseTestName(String id)230     public static String parseTestName(String id) {
231         return parseId(id)[1];
232     }
233 
234     /**
235      * @return the abi portion of the test id.
236      *         e.g. armeabi-v7a android.mytest = armeabi-v7a
237      */
parseAbi(String id)238     public static String parseAbi(String id) {
239         return parseId(id)[0];
240     }
241 
242     /**
243      * @param abi The name of the ABI.
244      * @return The bitness of the ABI with the given name
245      */
getBitness(String abi)246     public static String getBitness(String abi) {
247         return ABIS_32BIT.contains(abi) ? "32" : "64";
248     }
249 
250     /**
251      * @param unsupportedAbiDescription A comma separated string containing abis.
252      * @return A List of Strings containing valid ABIs.
253      */
parseAbiList(String unsupportedAbiDescription)254     public static Set<String> parseAbiList(String unsupportedAbiDescription) {
255         Set<String> abiSet = new HashSet<>();
256         String[] descSegments = unsupportedAbiDescription.split(":");
257         if (descSegments.length == 2) {
258             for (String abi : descSegments[1].split(",")) {
259                 String trimmedAbi = abi.trim();
260                 if (isAbiSupportedByCompatibility(trimmedAbi)) {
261                     abiSet.add(trimmedAbi);
262                 }
263             }
264         }
265         return abiSet;
266     }
267 
268     /**
269      * @param abiListProp A comma separated list containing abis coming from the device property.
270      * @return A List of Strings containing valid ABIs.
271      */
parseAbiListFromProperty(String abiListProp)272     public static Set<String> parseAbiListFromProperty(String abiListProp) {
273         Set<String> abiSet = new HashSet<>();
274         String[] abiList = abiListProp.split(",");
275         for (String abi : abiList) {
276             String trimmedAbi = abi.trim();
277             if (isAbiSupportedByCompatibility(trimmedAbi)) {
278                 abiSet.add(trimmedAbi);
279             }
280         }
281         return abiSet;
282     }
283 
284     /** Returns the Set of abis supported by the host machine. */
getHostAbi()285     public static Set<String> getHostAbi() {
286         CommandResult commandResult = RunUtil.getDefault().runTimedCmd(5000L, "uname", "-m");
287         String mainAbi = commandResult.getStdout().trim();
288         return getAbisForArch(mainAbi);
289     }
290 }
291