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