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