xref: /aosp_15_r20/cts/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1 /*
2  * Copyright (C) 2018 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 android.angle.cts;
17 
18 import com.android.tradefed.device.ITestDevice;
19 import com.android.tradefed.device.PackageInfo;
20 import com.android.tradefed.result.TestDescription;
21 
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.StringTokenizer;
25 
26 class CtsAngleCommon {
27     // General
28     static final int NUM_ATTEMPTS = 5;
29     static final int REATTEMPT_SLEEP_MSEC = 5000;
30 
31     static final String PERSIST_DRIVER_SUFFIX_PROPERTY = "persist.graphics.egl";
32     static final String RO_DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl";
33 
34     // Settings.Global
35     static final String SETTINGS_GLOBAL_ALL_USE_ANGLE = "angle_gl_driver_all_angle";
36     static final String SETTINGS_GLOBAL_DRIVER_PKGS = "angle_gl_driver_selection_pkgs";
37     static final String SETTINGS_GLOBAL_DRIVER_VALUES = "angle_gl_driver_selection_values";
38     static final String SETTINGS_GLOBAL_ALLOWLIST = "angle_allowlist";
39     static final String SETTINGS_GLOBAL_ANGLE_IN_USE_DIALOG_BOX = "show_angle_in_use_dialog_box";
40 
41     // Vulkan Feature
42     static final int VULKAN_1_1 = 0x00401000; // 1.1.0
43     static final String VULKAN_VERSION_FEATURE = "feature:android.hardware.vulkan.version";
44     static final String VULKAN_LEVEL_FEATURE = "feature:android.hardware.vulkan.level";
45 
46     // ANGLE
47     static final String ANGLE_PACKAGE_NAME = "com.android.angle";
48 
49     static final String ANGLE_DRIVER_TEST_PKG = "com.android.angleintegrationtest.drivertest";
50     static final String ANGLE_DRIVER_TEST_APP = "CtsAngleDriverTestCases.apk";
51 
52     static final String ANGLE_DRIVER_TEST_SEC_PKG =
53             "com.android.angleintegrationtest.drivertestsecondary";
54     static final String ANGLE_DRIVER_TEST_SEC_APP = "CtsAngleDriverTestCasesSecondary.apk";
55 
56     static final String ANGLE_DUMPSYS_GPU_TEST_PKG =
57             "com.android.angleintegrationtest.dumpsysgputest";
58     static final String ANGLE_DUMPSYS_GPU_TEST_CLASS = "AngleDumpsysGpuTestActivity";
59     static final String ANGLE_DUMPSYS_GPU_TEST_APP = "CtsAngleDumpsysGpuTestApp.apk";
60 
61     static final String ANGLE_DRIVER_TEST_CLASS = "AngleDriverTest";
62     static final String ANGLE_DRIVER_TEST_DEFAULT_METHOD = "testUseDefaultDriver";
63     static final String ANGLE_DRIVER_TEST_ANGLE_METHOD = "testUseAngleDriver";
64     static final String ANGLE_DRIVER_TEST_NATIVE_METHOD = "testUseNativeDriver";
65 
66     static final String ANGLE_NATIVE_DRIVER_CHECK_PKG =
67             "com.android.angleintegrationtest.nativedrivercheck";
68     static final String ANGLE_NATIVE_DRIVER_CHECK_APP = "CtsAngleNativeDriverCheck.apk";
69     static final String ANGLE_NATIVE_DRIVER_CHECK_CLASS = "NativeDriverCheckTest";
70     static final String ANGLE_NATIVE_DRIVER_CHECK_METHOD = "checkNativeDriver";
71     static final String NATIVE_GL_RENDERER = "NATIVE_GL_RENDERER";
72     static final TestDescription NATIVE_DRIVER_CHECK_TEST_DESCRIPTION =
73             new TestDescription(ANGLE_NATIVE_DRIVER_CHECK_PKG + "."
74                                 + ANGLE_NATIVE_DRIVER_CHECK_CLASS,
75                                 ANGLE_NATIVE_DRIVER_CHECK_METHOD);
76 
77     enum OpenGlDriverChoice {
78         DEFAULT,
79         NATIVE,
80         ANGLE
81     }
82 
83     static final Map<OpenGlDriverChoice, String> sDriverGlobalSettingMap =
84             buildDriverGlobalSettingMap();
85 
buildDriverGlobalSettingMap()86     static Map<OpenGlDriverChoice, String> buildDriverGlobalSettingMap() {
87         Map<OpenGlDriverChoice, String> map = new HashMap<>();
88         map.put(OpenGlDriverChoice.DEFAULT, "default");
89         map.put(OpenGlDriverChoice.ANGLE, "angle");
90         map.put(OpenGlDriverChoice.NATIVE, "native");
91 
92         return map;
93     }
94 
95     static final Map<OpenGlDriverChoice, String> sDriverTestMethodMap = buildDriverTestMethodMap();
96 
buildDriverTestMethodMap()97     static Map<OpenGlDriverChoice, String> buildDriverTestMethodMap() {
98         Map<OpenGlDriverChoice, String> map = new HashMap<>();
99         map.put(OpenGlDriverChoice.DEFAULT, ANGLE_DRIVER_TEST_DEFAULT_METHOD);
100         map.put(OpenGlDriverChoice.ANGLE, ANGLE_DRIVER_TEST_ANGLE_METHOD);
101         map.put(OpenGlDriverChoice.NATIVE, ANGLE_DRIVER_TEST_NATIVE_METHOD);
102 
103         return map;
104     }
105 
getGlobalSetting(ITestDevice device, String globalSetting)106     static String getGlobalSetting(ITestDevice device, String globalSetting) throws Exception {
107         return device.getSetting("global", globalSetting);
108     }
109 
setGlobalSetting(ITestDevice device, String globalSetting, String value)110     static void setGlobalSetting(ITestDevice device, String globalSetting, String value)
111             throws Exception {
112         device.setSetting("global", globalSetting, value);
113         device.executeShellCommand("am refresh-settings-cache");
114     }
115 
clearSettings(ITestDevice device)116     static void clearSettings(ITestDevice device) throws Exception {
117         // Cached Activity Manager settings
118         setGlobalSetting(device, SETTINGS_GLOBAL_ALL_USE_ANGLE, "0");
119         setGlobalSetting(device, SETTINGS_GLOBAL_ANGLE_IN_USE_DIALOG_BOX, "0");
120         setGlobalSetting(device, SETTINGS_GLOBAL_DRIVER_PKGS, "\"\"");
121         setGlobalSetting(device, SETTINGS_GLOBAL_DRIVER_VALUES, "\"\"");
122         setGlobalSetting(device, SETTINGS_GLOBAL_ALLOWLIST, "\"\"");
123     }
124 
isAngleApkInstalled(ITestDevice device)125     static boolean isAngleApkInstalled(ITestDevice device) throws Exception {
126         PackageInfo info = device.getAppPackageInfo(ANGLE_PACKAGE_NAME);
127 
128         return info != null && info.isSystemApp();
129     }
130 
isAnglePresentAsNonDefault(ITestDevice device)131     static boolean isAnglePresentAsNonDefault(ITestDevice device) throws Exception {
132         return isAngleApkInstalled(device) || !isAngleDefaultDriver(device);
133     }
134 
isAngleDefaultDriver(ITestDevice device)135     static boolean isAngleDefaultDriver(ITestDevice device) throws Exception {
136         String driverSuffix = device.getProperty(PERSIST_DRIVER_SUFFIX_PROPERTY);
137 
138         return (driverSuffix != null) && (driverSuffix.equals("angle"));
139     }
140 
isAnglePresent(ITestDevice device)141     static boolean isAnglePresent(ITestDevice device) throws Exception {
142         return isAnglePresentAsNonDefault(device) || isAngleDefaultDriver(device);
143     }
144 
145     // Check if device supports vulkan 1.1.
146     // If the device includes a Vulkan driver, feature list returned by
147     // "adb shell pm list features" should contain
148     // "feature:android.hardware.vulkan.level" (FEATURE_VULKAN_HARDWARE_LEVEL) and
149     // "feature:android.hardware.vulkan.version" (FEATURE_VULKAN_HARDWARE_VERSION)
150     // reference: https://source.android.com/docs/core/graphics/implement-vulkan
isVulkan11Supported(ITestDevice device)151     static boolean isVulkan11Supported(ITestDevice device) throws Exception {
152         final String features = device.executeShellCommand("pm list features");
153 
154         StringTokenizer featureToken = new StringTokenizer(features, "\n");
155 
156         boolean isVulkanLevelFeatureSupported = false;
157 
158         boolean isVulkanVersionFeatureSupported = false;
159 
160         boolean isVulkan_1_1_Supported = false;
161 
162         while (featureToken.hasMoreTokens()) {
163             String currentFeature = featureToken.nextToken();
164 
165             // Check if currentFeature strings starts with "feature:android.hardware.vulkan.level"
166             // Check that currentFeature string length is at least the length of
167             // "feature:android.hardware.vulkan.level" before calling substring so that the endIndex
168             // is not out of bound.
169             if (currentFeature.length() >= VULKAN_LEVEL_FEATURE.length()
170                     && currentFeature
171                             .substring(0, VULKAN_LEVEL_FEATURE.length())
172                             .equals(VULKAN_LEVEL_FEATURE)) {
173                 isVulkanLevelFeatureSupported = true;
174             }
175 
176             // Check if currentFeature strings starts with "feature:android.hardware.vulkan.version"
177             // Check that currentFeature string length is at least the length of
178             // "feature:android.hardware.vulkan.version" before calling substring so that the
179             // endIndex is not out of bound.
180             if (currentFeature.length() >= VULKAN_VERSION_FEATURE.length()
181                     && currentFeature
182                             .substring(0, VULKAN_VERSION_FEATURE.length())
183                             .equals(VULKAN_VERSION_FEATURE)) {
184                 isVulkanVersionFeatureSupported = true;
185 
186                 // If android.hardware.vulkan.version feature is supported by the device,
187                 // check if the vulkan version supported is at least vulkan 1.1.
188                 // ANGLE is only intended to work properly with vulkan version >= vulkan 1.1
189                 String[] currentFeatureAndValue = currentFeature.split("=");
190                 if (currentFeatureAndValue.length > 1) {
191                     int vulkanVersionLevelSupported = Integer.parseInt(currentFeatureAndValue[1]);
192                     isVulkan_1_1_Supported = vulkanVersionLevelSupported >= VULKAN_1_1;
193                 }
194             }
195 
196             if (isVulkanLevelFeatureSupported
197                     && isVulkanVersionFeatureSupported
198                     && isVulkan_1_1_Supported) {
199                 return true;
200             }
201         }
202 
203         return false;
204     }
205 
206     // If ANGLE is the default GLES driver, then the test method for default GLES driver should
207     // validate ANGLE and hence return the testUseAngleDriver method. If ANGLE is not default
208     // GLES driver, then the test method for default GLES driver should validate non ANGLE, hence
209     // return the testUseDefaultDriver method.
getTestMethod(ITestDevice device)210     static String getTestMethod(ITestDevice device) throws Exception {
211         return isAngleDefaultDriver(device) ? ANGLE_DRIVER_TEST_ANGLE_METHOD
212                                            : ANGLE_DRIVER_TEST_DEFAULT_METHOD;
213     }
214 
skipOverDefault(OpenGlDriverChoice driver)215     static boolean skipOverDefault(OpenGlDriverChoice driver) throws Exception {
216         // The tests that loop over all of the OpenGlDriverChoice's are trying to explicitly test
217         // "native" and "angle".  Since the meaning of "default" changes based on whether the system
218         // driver is "native" and "angle", skip over "default".
219         return (driver == OpenGlDriverChoice.DEFAULT) ? true : false;
220     }
221 
startActivity(ITestDevice device, String pkgName, String className)222     static void startActivity(ITestDevice device, String pkgName, String className)
223             throws Exception {
224         String startCommand = String.format(
225                 "am start -W -a android.intent.action.MAIN -n %s/.%s", pkgName, className);
226         device.executeShellCommand(startCommand);
227     }
228 
stopPackage(ITestDevice device, String pkgName)229     static void stopPackage(ITestDevice device, String pkgName) throws Exception {
230         device.executeShellCommand("am force-stop " + pkgName);
231     }
232 
233     /**
234      * Find and parse the `dumpsys gpu` output for the specified package.
235      *
236      * Sample output:
237      *      appPackageName = com.android.angleIntegrationTest.dumpsysGpuTest
238      *      driverVersionCode = 0
239      *      cpuVulkanInUse = 0
240      *      falsePrerotation = 0
241      *      gles1InUse = 0
242      *      angleInUse = 1
243      *      glDriverLoadingTime:
244      *      angleDriverLoadingTime:
245      *      vkDriverLoadingTime: 37390096
246      *
247      * @return angleInUse, -1 on error
248      */
getDumpsysGpuAngleInUse(ITestDevice device, String packageName)249     static int getDumpsysGpuAngleInUse(ITestDevice device, String packageName) throws Exception {
250         String dumpSysGpu = device.executeShellCommand("dumpsys gpu");
251         String[] lines = dumpSysGpu.split("\n");
252 
253         boolean foundPackage = false;
254         for (String s : lines) {
255             String line = s.trim();
256             if (!foundPackage && line.contains(packageName)) {
257                 foundPackage = true;
258                 continue;
259             }
260 
261             if (foundPackage) {
262                 if (line.contains("angleInUse")) {
263                     String[] tokens = line.split(" ");
264                     if (tokens.length != 3) {
265                         throw new IllegalArgumentException(
266                                 "Malformed result: tokens.length = " + tokens.length);
267                     }
268 
269                     return Integer.parseInt(tokens[2]);
270                 } else if (line.contains("appPackageName")) {
271                     // We've moved to another block for a different package without finding the
272                     // 'angleInUse' field, so return an error.
273                     throw new IllegalArgumentException("Failed to find field: angleInUse");
274                 }
275             }
276         }
277 
278         // Didn't find the specified package, return an error.
279         return -1;
280     }
281 }
282