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