1 /* 2 * Copyright (C) 2019 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.gputools.cts; 17 18 import com.android.tradefed.util.RunUtil; 19 import com.android.compatibility.common.util.CddTest; 20 import com.android.tradefed.device.ITestDevice; 21 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 22 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 23 24 import java.util.Scanner; 25 26 import org.junit.After; 27 import org.junit.Before; 28 import org.junit.Assert; 29 import org.junit.Test; 30 import org.junit.runner.RunWith; 31 32 /** 33 * Tests that exercise Rootless GPU Debug functionality supported by the loader. 34 */ 35 @RunWith(DeviceJUnit4ClassRunner.class) 36 public class CtsRootlessGpuDebugHostTest extends BaseHostJUnit4Test { 37 38 public static final String TAG = "RootlessGpuDebugService"; 39 40 // This test ensures that the Vulkan and GLES loaders can use Settings to load layers 41 // from the base directory of debuggable applications. Is also tests several 42 // positive and negative scenarios we want to cover (listed below). 43 // 44 // There are three APKs; DEBUG and RELEASE are practically identical with one 45 // being flagged as debuggable. The LAYERS APK is mainly a conduit for getting 46 // layers onto the device without affecting the other APKs. 47 // 48 // The RELEASE APK does contain one layer to ensure using Settings to enable 49 // layers does not interfere with legacy methods using system properties. 50 // 51 // The layers themselves are practically null, only enough functionality to 52 // satisfy loader enumerating and loading. They don't actually chain together. 53 // 54 // Positive Vulkan tests 55 // - Ensure we can toggle the Enable Setting on and off (testDebugLayerLoadVulkan) 56 // - Ensure we can set the debuggable app (testDebugLayerLoadVulkan) 57 // - Ensure we can set the layer list (testDebugLayerLoadVulkan) 58 // - Ensure we can push a layer to debuggable app (testDebugLayerLoadVulkan) 59 // - Ensure we can specify the app to load layers (testDebugLayerLoadVulkan) 60 // - Ensure we can load a layer from app's data directory (testDebugLayerLoadVulkan) 61 // - Ensure we can load multiple layers, in order, from app's data directory (testDebugLayerLoadVulkan) 62 // - Ensure we can still use system properties if no layers loaded via Settings (testSystemPropertyEnableVulkan) 63 // - Ensure we can find layers in separate specified app and load them in a debuggable app (testDebugLayerLoadExternalVulkan) 64 // - Ensure we can find layers in separate specified app and load them in an injectLayers app (testInjectLayerLoadExternalVulkan) 65 // - Ensure we can enumerate the instance extension advertised by implicitly enabled layer (testInstanceExtensionPropertiesFromImplicitLayerVulkanBasic) 66 // - Ensure we can only enumerate first instance extension closest to application 67 // when multiple implicitly enabled layers advertise the same extension (testInstanceExtensionPropertiesFromImplicitLayerVulkanMultipleLayers) 68 // Negative Vulkan tests 69 // - Ensure we cannot push a layer to non-debuggable app (testReleaseLayerLoadVulkan) 70 // - Ensure non-debuggable app ignores the new Settings (testReleaseLayerLoadVulkan) 71 // - Ensure we cannot push a layer to an injectLayers app (testInjectLayerLoadVulkan) 72 // - Ensure we cannot enumerate layers from debuggable app's data directory if Setting not specified (testDebugNoEnumerateVulkan) 73 // - Ensure we cannot enumerate layers without specifying the debuggable app (testDebugNoEnumerateVulkan) 74 // - Ensure we cannot use system properties when layer is found via Settings with debuggable app (testSystemPropertyIgnoreVulkan) 75 // 76 // Positive GLES tests 77 // - Ensure we can toggle the Enable Setting on and off (testDebugLayerLoadGLES) 78 // - Ensure we can set the debuggable app (testDebugLayerLoadGLES) 79 // - Ensure we can set the layer list (testDebugLayerLoadGLES) 80 // - Ensure we can push a layer to debuggable app (testDebugLayerLoadGLES) 81 // - Ensure we can specify the app to load layers (testDebugLayerLoadGLES) 82 // - Ensure we can load a layer from app's data directory (testDebugLayerLoadGLES) 83 // - Ensure we can load multiple layers, in order, from app's data directory (testDebugLayerLoadGLES) 84 // - Ensure we can find layers in separate specified app and load them in a debuggable app (testDebugLayerLoadExternalGLES) 85 // - Ensure we can find layers in separate specified app and load them in an injectLayers app (testInjectLayerLoadExternalGLES) 86 // Negative GLES tests 87 // - Ensure we cannot push a layer to non-debuggable app (testReleaseLayerLoadGLES) 88 // - Ensure non-debuggable app ignores the new Settings (testReleaseLayerLoadGLES) 89 // - Ensure we cannot enumerate layers from debuggable app's data directory if Setting not specified (testDebugNoEnumerateGLES) 90 // - Ensure we cannot enumerate layers without specifying the debuggable app (testDebugNoEnumerateGLES) 91 // 92 // Positive combined tests 93 // - Ensure we can load Vulkan and GLES layers at the same time, from multiple external apps (testMultipleExternalApps) 94 95 private static final String API_VULKAN = "Vulkan"; 96 private static final String API_GLES = "GLES"; 97 private static final String API_BOTH = "Both"; 98 private static final String VK_LAYER_LIB_PREFIX = "libVkLayer_nullLayer"; 99 private static final String VK_LAYER_A_LIB = VK_LAYER_LIB_PREFIX + "A.so"; 100 private static final String VK_LAYER_B_LIB = VK_LAYER_LIB_PREFIX + "B.so"; 101 private static final String VK_LAYER_C_LIB = VK_LAYER_LIB_PREFIX + "C.so"; 102 private static final String VK_LAYER_D_LIB = VK_LAYER_LIB_PREFIX + "D.so"; 103 private static final String VK_LAYER_E_LIB = VK_LAYER_LIB_PREFIX + "E.so"; 104 private static final String VK_LAYER_NAME_PREFIX = "VK_LAYER_ANDROID_nullLayer"; 105 private static final String VK_LAYER_A = VK_LAYER_NAME_PREFIX + "A"; 106 private static final String VK_LAYER_B = VK_LAYER_NAME_PREFIX + "B"; 107 private static final String VK_LAYER_C = VK_LAYER_NAME_PREFIX + "C"; 108 private static final String VK_LAYER_D = VK_LAYER_NAME_PREFIX + "D"; 109 private static final String VK_LAYER_E = VK_LAYER_NAME_PREFIX + "E"; 110 private static final String DEBUG_APP = "android.rootlessgpudebug.DEBUG.app"; 111 private static final String RELEASE_APP = "android.rootlessgpudebug.RELEASE.app"; 112 private static final String INJECT_APP = "android.rootlessgpudebug.INJECT.app"; 113 private static final String LAYERS_APP = "android.rootlessgpudebug.LAYERS.app"; 114 private static final String GLES_LAYERS_APP = "android.rootlessgpudebug.GLES_LAYERS.app"; 115 private static final String DEBUG_APK = "CtsGpuToolsRootlessGpuDebugApp-DEBUG.apk"; 116 private static final String RELEASE_APK = "CtsGpuToolsRootlessGpuDebugApp-RELEASE.apk"; 117 private static final String INJECT_APK = "CtsGpuToolsRootlessGpuDebugApp-INJECT.apk"; 118 private static final String LAYERS_APK = "CtsGpuToolsRootlessGpuDebugApp-LAYERS.apk"; 119 private static final String GLES_LAYERS_APK = "CtsGpuToolsRootlessGpuDebugApp-GLES_LAYERS.apk"; 120 private static final String GLES_LAYER_A = "glesLayerA"; 121 private static final String GLES_LAYER_B = "glesLayerB"; 122 private static final String GLES_LAYER_C = "glesLayerC"; 123 private static final String GLES_LAYER_A_LIB = "libGLES_" + GLES_LAYER_A + ".so"; 124 private static final String GLES_LAYER_B_LIB = "libGLES_" + GLES_LAYER_B + ".so"; 125 private static final String GLES_LAYER_C_LIB = "libGLES_" + GLES_LAYER_C + ".so"; 126 127 // This is how long we'll scan the log for a result before giving up. This limit will only 128 // be reached if something has gone wrong 129 private static final long LOG_SEARCH_TIMEOUT_MS = 5000; 130 private static final long SETTING_APPLY_TIMEOUT_MS = 5000; 131 132 private static boolean initialized = false; 133 removeWhitespace(String input)134 private String removeWhitespace(String input) { 135 return input.replaceAll(System.getProperty("line.separator"), "").trim(); 136 } 137 138 /** 139 * Return current timestamp in format accepted by logcat 140 */ getTime()141 private String getTime() throws Exception { 142 // logcat will accept "MM-DD hh:mm:ss.mmm" 143 return getDevice().executeShellCommand("date +\"%m-%d %H:%M:%S.%3N\""); 144 } 145 146 /** 147 * Apply a setting and refresh the platform's cache 148 */ applySetting(String setting, String value)149 private void applySetting(String setting, String value) throws Exception { 150 getDevice().executeShellCommand("settings put global " + setting + " " + value); 151 getDevice().executeShellCommand("am refresh-settings-cache"); 152 } 153 154 /** 155 * Delete a setting and refresh the platform's cache 156 */ deleteSetting(String setting)157 private void deleteSetting(String setting) throws Exception { 158 getDevice().executeShellCommand("settings delete global " + setting); 159 getDevice().executeShellCommand("am refresh-settings-cache"); 160 } 161 162 /** 163 * Extract the requested layer from APK and copy to tmp 164 */ setupLayer(String layer, String layerApp)165 private void setupLayer(String layer, String layerApp) throws Exception { 166 167 // We use the LAYERS apk to facilitate getting layers onto the device for mixing and matching 168 String libPath = getDevice().executeAdbCommand("shell", "pm", "path", layerApp); 169 libPath = libPath.replaceAll("package:", ""); 170 libPath = libPath.replaceAll("base.apk", ""); 171 libPath = removeWhitespace(libPath); 172 libPath += "lib/"; 173 174 // Use find to get the .so so we can ignore ABI 175 String layerPath = getDevice().executeAdbCommand("shell", "find", libPath + " -name " + layer); 176 layerPath = removeWhitespace(layerPath); 177 getDevice().executeAdbCommand("shell", "cp", layerPath + " /data/local/tmp"); 178 } 179 180 /** 181 * Check that the layer is loaded by only checking the log after startTime. 182 */ assertVkLayerLoading(String startTime, String layerName, boolean loaded)183 private void assertVkLayerLoading(String startTime, String layerName, boolean loaded) throws Exception { 184 String searchString = "nullCreateInstance called in " + layerName; 185 LogScanResult result = scanLog(TAG + "," + layerName, searchString, startTime); 186 if (loaded) { 187 Assert.assertTrue(layerName + " was not loaded", result.found); 188 } else { 189 Assert.assertFalse(layerName + " was loaded", result.found); 190 } 191 } 192 193 /** 194 * Check that the layer is enumerated by only checking the log after startTime. 195 */ assertVkLayerEnumeration(String startTime, String layerName, boolean enumerated)196 private void assertVkLayerEnumeration(String startTime, String layerName, boolean enumerated) throws Exception { 197 String searchString = layerName + " loaded"; 198 LogScanResult result = scanLog(TAG + "," + layerName, searchString, startTime); 199 if (enumerated) { 200 Assert.assertTrue(layerName + " was not enumerated", result.found); 201 } else { 202 Assert.assertFalse(layerName + " was enumerated", result.found); 203 } 204 } 205 206 /** 207 * Check whether an extension is properly advertised by only checking the log after startTime. 208 */ assertVkExtension(String startTime, String extensionName, int specVersion)209 private void assertVkExtension(String startTime, String extensionName, int specVersion) throws Exception { 210 String searchString = extensionName + ": " + specVersion; 211 LogScanResult result = scanLog(TAG + ",RootlessGpuDebug", searchString, startTime); 212 Assert.assertTrue(extensionName + "with spec version: " + specVersion + " was not advertised", result.found); 213 } 214 215 /** 216 * Simple helper class for returning multiple results 217 */ 218 public class LogScanResult { 219 public boolean found; 220 public int lineNumber; 221 } 222 scanLog(String tag, String searchString, String appStartTime)223 private LogScanResult scanLog(String tag, String searchString, String appStartTime) throws Exception { 224 return scanLog(tag, searchString, "", appStartTime); 225 } 226 227 /** 228 * Scan the logcat for requested layer tag, returning if found and which line 229 */ scanLog(String tag, String searchString, String endString, String appStartTime)230 private LogScanResult scanLog(String tag, String searchString, String endString, String appStartTime) throws Exception { 231 232 LogScanResult result = new LogScanResult(); 233 result.found = false; 234 result.lineNumber = -1; 235 236 // Scan until output from app is found 237 boolean scanComplete= false; 238 239 // Let the test run a reasonable amount of time before moving on 240 long hostStartTime = System.currentTimeMillis(); 241 242 while (!scanComplete && ((System.currentTimeMillis() - hostStartTime) < LOG_SEARCH_TIMEOUT_MS)) { 243 244 // Give our activity a chance to run and fill the log 245 RunUtil.getDefault().sleep(1000); 246 247 // Pull the logcat since the app started, filter for tags 248 // This command should look something like this: 249 // adb logcat -d -t '03-27 21:35:05.392' -s "RootlessGpuDebugDeviceActivity,nullLayerC" 250 String logcat = getDevice().executeShellCommand( 251 "logcat -d " + 252 "-t '" + removeWhitespace(appStartTime) + "' " + 253 "-s \"" + tag + "\""); 254 int lineNumber = 0; 255 Scanner apkIn = new Scanner(logcat); 256 while (apkIn.hasNextLine()) { 257 lineNumber++; 258 String line = apkIn.nextLine(); 259 if (line.contains(searchString) && line.endsWith(endString)) { 260 result.found = true; 261 result.lineNumber = lineNumber; 262 } 263 if (line.contains("RootlessGpuDebugService complete")) { 264 // Once we've got output from the app, we've collected what we need 265 scanComplete= true; 266 } 267 } 268 apkIn.close(); 269 } 270 271 // If this assert fires , try increasing the timeout 272 Assert.assertTrue("Log scanning did not complete before timout (" + 273 LOG_SEARCH_TIMEOUT_MS + "ms)", scanComplete); 274 275 return result; 276 } 277 278 /** 279 * Remove any temporary files on the device, clear any settings, kill the apps after each test 280 */ 281 @After cleanup()282 public void cleanup() throws Exception { 283 getDevice().executeAdbCommand("shell", "am", "force-stop", DEBUG_APP); 284 getDevice().executeAdbCommand("shell", "am", "force-stop", RELEASE_APP); 285 getDevice().executeAdbCommand("shell", "am", "force-stop", INJECT_APP); 286 getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + VK_LAYER_A_LIB); 287 getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + VK_LAYER_B_LIB); 288 getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + VK_LAYER_C_LIB); 289 getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_A_LIB); 290 getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_B_LIB); 291 getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_C_LIB); 292 getDevice().executeAdbCommand("shell", "settings", "delete", "global", "enable_gpu_debug_layers"); 293 getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_app"); 294 getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers"); 295 getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers_gles"); 296 getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layer_app"); 297 getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers", "\'\'"); 298 getDevice().executeAdbCommand("shell", "setprop", "debug.gles.layers", "\'\'"); 299 } 300 301 /** 302 * Clean up before starting any tests, and ensure supporting packages are installed 303 */ 304 @Before init()305 public void init() throws Exception { 306 installPackage(DEBUG_APK); 307 installPackage(RELEASE_APK); 308 installPackage(LAYERS_APK); 309 installPackage(GLES_LAYERS_APK); 310 if (!initialized) { 311 cleanup(); 312 initialized = true; 313 } 314 } 315 316 /** 317 * Launch our test as a background service, avoiding any platform rendering code 318 */ launchBackgroundService(String appName, String Api)319 private void launchBackgroundService(String appName, String Api) throws Exception { 320 321 // Allow the app to be launched as a background service 322 getDevice().executeAdbCommand("shell", "cmd", "deviceidle", "tempwhitelist", appName); 323 324 // Start the service and tell it to init Vulkan/GLES/Both 325 getDevice().executeAdbCommand("shell", "am", "startservice", "-a", "android.service.action.TARGET_API_SERVICE", 326 "--es", "API", Api, appName); 327 } 328 329 330 /** 331 * This is the primary test of the feature. It pushes layers to our debuggable app and ensures they are 332 * loaded in the correct order. 333 */ 334 @CddTest(requirements = "7.1.4.2/C-1-4") 335 @Test testDebugLayerLoadVulkan()336 public void testDebugLayerLoadVulkan() throws Exception { 337 338 // Set up layers to be loaded 339 applySetting("enable_gpu_debug_layers", "1"); 340 applySetting("gpu_debug_app", DEBUG_APP); 341 applySetting("gpu_debug_layers", VK_LAYER_A + ":" + VK_LAYER_B); 342 343 // Copy the layers from our LAYERS APK to tmp 344 setupLayer(VK_LAYER_A_LIB, LAYERS_APP); 345 setupLayer(VK_LAYER_B_LIB, LAYERS_APP); 346 347 // Copy them over to our DEBUG app 348 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|", 349 "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()), 350 "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'"); 351 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_B_LIB, "|", 352 "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()), 353 "sh", "-c", "\'cat", ">", VK_LAYER_B_LIB, ";", "chmod", "700", VK_LAYER_B_LIB + "\'"); 354 355 // Kick off our DEBUG app 356 String appStartTime = getTime(); 357 launchBackgroundService(DEBUG_APP, API_VULKAN); 358 359 // Check that both layers were loaded, in the correct order 360 String searchStringA = "nullCreateInstance called in " + VK_LAYER_A; 361 LogScanResult resultA = scanLog(TAG + "," + VK_LAYER_A + "," + VK_LAYER_B, searchStringA, appStartTime); 362 Assert.assertTrue("LayerA was not loaded", resultA.found); 363 364 String searchStringB = "nullCreateInstance called in " + VK_LAYER_B; 365 LogScanResult resultB = scanLog(TAG + "," + VK_LAYER_A + "," + VK_LAYER_B, searchStringB, appStartTime); 366 Assert.assertTrue("LayerB was not loaded", resultB.found); 367 368 Assert.assertTrue("LayerA should be loaded before LayerB", resultA.lineNumber < resultB.lineNumber); 369 } 370 testLayerNotLoadedVulkan(final String APP_NAME)371 public void testLayerNotLoadedVulkan(final String APP_NAME) throws Exception { 372 373 // Set up a layers to be loaded for RELEASE or INJECT app 374 applySetting("enable_gpu_debug_layers", "1"); 375 applySetting("gpu_debug_app", APP_NAME); 376 applySetting("gpu_debug_layers", VK_LAYER_A + ":" + VK_LAYER_B); 377 378 // Copy a layer from our LAYERS APK to tmp 379 setupLayer(VK_LAYER_A_LIB, LAYERS_APP); 380 381 // Attempt to copy them over to our RELEASE or INJECT app (this should fail) 382 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|", 383 "run-as", APP_NAME, "--user", Integer.toString(getDevice().getCurrentUser()), 384 "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'", "||", "echo", "run-as", "failed"); 385 386 // Kick off our app 387 String appStartTime = getTime(); 388 launchBackgroundService(APP_NAME, API_VULKAN); 389 390 // Ensure we don't load the layer in base dir 391 assertVkLayerEnumeration(appStartTime, VK_LAYER_A, false); 392 } 393 394 /** 395 * This test ensures that we cannot push a layer to a release app 396 * It also ensures non-debuggable apps ignore Settings and don't enumerate layers in the base directory. 397 */ 398 @CddTest(requirements = "7.1.4.2/C-1-5") 399 @Test testReleaseLayerLoadVulkan()400 public void testReleaseLayerLoadVulkan() throws Exception { 401 testLayerNotLoadedVulkan(RELEASE_APP); 402 } 403 404 /** 405 * This test ensures that we cannot push a layer to an injectable app 406 * It also ensures non-debuggable apps ignore Settings and don't enumerate layers in the base directory. 407 */ 408 @CddTest(requirements = "7.1.4.2/C-1-5") 409 @Test testInjectLayerLoadVulkan()410 public void testInjectLayerLoadVulkan() throws Exception { 411 testLayerNotLoadedVulkan(INJECT_APP); 412 } 413 414 /** 415 * This test ensures debuggable apps do not enumerate layers in base 416 * directory if enable_gpu_debug_layers is not enabled. 417 */ 418 @CddTest(requirements = "7.1.4.2/C-1-5") 419 @Test testDebugNotEnabledVulkan()420 public void testDebugNotEnabledVulkan() throws Exception { 421 422 // Ensure the global layer enable settings is NOT enabled 423 applySetting("enable_gpu_debug_layers", "0"); 424 applySetting("gpu_debug_app", DEBUG_APP); 425 applySetting("gpu_debug_layers", VK_LAYER_A); 426 427 // Copy a layer from our LAYERS APK to tmp 428 setupLayer(VK_LAYER_A_LIB, LAYERS_APP); 429 430 // Copy it over to our DEBUG app 431 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|", 432 "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()), 433 "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'"); 434 435 // Kick off our DEBUG app 436 String appStartTime = getTime(); 437 launchBackgroundService(DEBUG_APP, API_VULKAN); 438 439 // Ensure we don't load the layer in base dir 440 assertVkLayerEnumeration(appStartTime, VK_LAYER_A, false); 441 } 442 443 /** 444 * This test ensures debuggable apps do not enumerate layers in base 445 * directory if gpu_debug_app does not match. 446 */ 447 @CddTest(requirements = "7.1.4.2/C-1-5") 448 @Test testDebugWrongAppVulkan()449 public void testDebugWrongAppVulkan() throws Exception { 450 451 // Ensure the gpu_debug_app does not match what we launch 452 applySetting("enable_gpu_debug_layers", "1"); 453 applySetting("gpu_debug_app", RELEASE_APP); 454 applySetting("gpu_debug_layers", VK_LAYER_A); 455 456 // Copy a layer from our LAYERS APK to tmp 457 setupLayer(VK_LAYER_A_LIB, LAYERS_APP); 458 459 // Copy it over to our DEBUG app 460 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|", 461 "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()), 462 "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'"); 463 464 // Kick off our DEBUG app 465 String appStartTime = getTime(); 466 launchBackgroundService(DEBUG_APP, API_VULKAN); 467 468 // Ensure we don't load the layer in base dir 469 assertVkLayerEnumeration(appStartTime, VK_LAYER_A, false); 470 } 471 472 /** 473 * This test ensures debuggable apps do not enumerate layers in base 474 * directory if gpu_debug_layers are not set. 475 */ 476 @CddTest(requirements = "7.1.4.2/C-1-5") 477 @Test testDebugNoLayersEnabledVulkan()478 public void testDebugNoLayersEnabledVulkan() throws Exception { 479 480 // Ensure the global layer enable settings is NOT enabled 481 applySetting("enable_gpu_debug_layers", "1"); 482 applySetting("gpu_debug_app", DEBUG_APP); 483 applySetting("gpu_debug_layers", "foo"); 484 485 // Copy a layer from our LAYERS APK to tmp 486 setupLayer(VK_LAYER_A_LIB, LAYERS_APP); 487 488 // Copy it over to our DEBUG app 489 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|", 490 "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()), 491 "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'"); 492 493 // Kick off our DEBUG app 494 String appStartTime = getTime(); 495 launchBackgroundService(DEBUG_APP, API_VULKAN); 496 497 // Ensure layerA is not loaded 498 assertVkLayerLoading(appStartTime, VK_LAYER_A, false); 499 } 500 501 /** 502 * This test ensures we can still use properties if no layer specified via Settings 503 */ 504 @CddTest(requirements = "7.1.4.2/C-1-4") 505 @Test testSystemPropertyEnableVulkan()506 public void testSystemPropertyEnableVulkan() throws Exception { 507 508 // Don't enable any layers via settings 509 applySetting("enable_gpu_debug_layers", "1"); 510 applySetting("gpu_debug_app", RELEASE_APP); 511 deleteSetting("gpu_debug_layers"); 512 513 // Enable layerC (which is packaged with the RELEASE app) with system properties 514 getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + VK_LAYER_C); 515 516 // Kick off our RELEASE app 517 String appStartTime = getTime(); 518 launchBackgroundService(RELEASE_APP, API_VULKAN); 519 520 // Check that only layerC was loaded 521 assertVkLayerEnumeration(appStartTime, VK_LAYER_A, false); 522 assertVkLayerLoading(appStartTime, VK_LAYER_C, true); 523 } 524 525 /** 526 * This test ensures system properties are ignored if Settings load a layer 527 */ 528 @CddTest(requirements = "7.1.4.2/C-1-4") 529 @Test testSystemPropertyIgnoreVulkan()530 public void testSystemPropertyIgnoreVulkan() throws Exception { 531 532 // Set up layerA to be loaded, but not layerB 533 applySetting("enable_gpu_debug_layers", "1"); 534 applySetting("gpu_debug_app", DEBUG_APP); 535 applySetting("gpu_debug_layers", VK_LAYER_A); 536 537 // Copy the layers from our LAYERS APK 538 setupLayer(VK_LAYER_A_LIB, LAYERS_APP); 539 setupLayer(VK_LAYER_B_LIB, LAYERS_APP); 540 541 // Copy them over to our DEBUG app 542 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|", 543 "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()), 544 "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'"); 545 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_B_LIB, "|", 546 "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()), 547 "sh", "-c", "\'cat", ">", VK_LAYER_B_LIB, ";", "chmod", "700", VK_LAYER_B_LIB + "\'"); 548 549 // Enable layerB with system properties 550 getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + VK_LAYER_B); 551 552 // Kick off our DEBUG app 553 String appStartTime = getTime(); 554 launchBackgroundService(DEBUG_APP, API_VULKAN); 555 556 // Ensure only layerA is loaded 557 assertVkLayerLoading(appStartTime, VK_LAYER_A, true); 558 assertVkLayerLoading(appStartTime, VK_LAYER_B, false); 559 } 560 561 /** 562 * The common functionality to load layers from an external package. 563 * Returns the app start time. 564 */ testLayerLoadExternalVulkan(final String APP_NAME, String layers)565 public String testLayerLoadExternalVulkan(final String APP_NAME, String layers) throws Exception { 566 567 // Set up layers to be loaded 568 applySetting("enable_gpu_debug_layers", "1"); 569 applySetting("gpu_debug_app", APP_NAME); 570 applySetting("gpu_debug_layers", layers); 571 572 // Specify the external app that hosts layers 573 applySetting("gpu_debug_layer_app", LAYERS_APP); 574 575 // Kick off our app 576 String appStartTime = getTime(); 577 launchBackgroundService(APP_NAME, API_VULKAN); 578 579 String[] layerNames = layers.split(":"); 580 for (String layerName : layerNames) { 581 assertVkLayerLoading(appStartTime, layerName, true); 582 } 583 return appStartTime; 584 } 585 586 /** 587 * This test ensures a debuggable app can load layers from an external package 588 */ 589 @CddTest(requirements = "7.1.4.2/C-1-4") 590 @Test testDebugLayerLoadExternalVulkan()591 public void testDebugLayerLoadExternalVulkan() throws Exception { 592 testLayerLoadExternalVulkan(DEBUG_APP, VK_LAYER_C); 593 } 594 595 /** 596 * This test ensures an injectLayers app can load layers from an external package 597 */ 598 @CddTest(requirements = "7.1.4.2/C-1-4") 599 @Test testInjectLayerLoadExternalVulkan()600 public void testInjectLayerLoadExternalVulkan() throws Exception { 601 testLayerLoadExternalVulkan(INJECT_APP, VK_LAYER_C); 602 } 603 604 /** 605 * Test that the instance extension is advertised properly from the implicitly enabled layer. 606 */ 607 @CddTest(requirements = "7.1.4.2/C-1-4") 608 @Test testInstanceExtensionPropertiesFromImplicitLayerVulkanBasic()609 public void testInstanceExtensionPropertiesFromImplicitLayerVulkanBasic() throws Exception { 610 String appStartTime = testLayerLoadExternalVulkan(DEBUG_APP, VK_LAYER_D); 611 assertVkExtension(appStartTime, "VK_EXT_debug_utils", 1); 612 } 613 614 /** 615 * Test that when there are multiple implicit layers are enabled, if there are several instance 616 * extensions with the same extension names advertised by multiple layers, only the extension 617 * that is closer to the application is advertised by the loader. 618 */ 619 @CddTest(requirements = "7.1.4.2/C-1-4") 620 @Test testInstanceExtensionPropertiesFromImplicitLayerVulkanMultipleLayers()621 public void testInstanceExtensionPropertiesFromImplicitLayerVulkanMultipleLayers() throws Exception { 622 String appStartTime = testLayerLoadExternalVulkan(DEBUG_APP, VK_LAYER_E + ":" + VK_LAYER_D); 623 assertVkExtension(appStartTime, "VK_EXT_debug_utils", 2); 624 } 625 626 /** 627 * This test pushes GLES layers to our debuggable app and ensures they are 628 * loaded in the correct order. 629 */ 630 @Test testDebugLayerLoadGLES()631 public void testDebugLayerLoadGLES() throws Exception { 632 633 // Set up layers to be loaded 634 applySetting("enable_gpu_debug_layers", "1"); 635 applySetting("gpu_debug_app", DEBUG_APP); 636 applySetting("gpu_debug_layers_gles", GLES_LAYER_A_LIB + ":" + GLES_LAYER_B_LIB); 637 638 // Copy the layers from our LAYERS APK to tmp 639 setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP); 640 setupLayer(GLES_LAYER_B_LIB, GLES_LAYERS_APP); 641 642 // Copy them over to our DEBUG app 643 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", 644 "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()), 645 "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'"); 646 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_B_LIB, "|", 647 "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()), 648 "sh", "-c", "\'cat", ">", GLES_LAYER_B_LIB, ";", "chmod", "700", GLES_LAYER_B_LIB + "\'"); 649 650 // Kick off our DEBUG app 651 String appStartTime = getTime(); 652 launchBackgroundService(DEBUG_APP, API_GLES); 653 654 // Check that both layers were loaded, in the correct order 655 String searchStringA = "glesLayer_eglChooseConfig called in " + GLES_LAYER_A; 656 LogScanResult resultA = scanLog(TAG + "," + GLES_LAYER_A + "," + GLES_LAYER_B, searchStringA, appStartTime); 657 Assert.assertTrue(GLES_LAYER_A + " was not loaded", resultA.found); 658 659 String searchStringB = "glesLayer_eglChooseConfig called in " + GLES_LAYER_B; 660 LogScanResult resultB = scanLog(TAG + "," + GLES_LAYER_A + "," + GLES_LAYER_B, searchStringB, appStartTime); 661 Assert.assertTrue(GLES_LAYER_B + " was not loaded", resultB.found); 662 663 Assert.assertTrue(GLES_LAYER_A + " should be loaded before " + GLES_LAYER_B, resultA.lineNumber < resultB.lineNumber); 664 } 665 666 /** 667 * This test ensures that we cannot push a layer to a non-debuggable GLES app 668 * It also ensures non-debuggable apps ignore Settings and don't enumerate layers in the base directory. 669 */ 670 @Test testReleaseLayerLoadGLES()671 public void testReleaseLayerLoadGLES() throws Exception { 672 673 // Set up a layers to be loaded for RELEASE app 674 applySetting("enable_gpu_debug_layers", "1"); 675 applySetting("gpu_debug_app", RELEASE_APP); 676 applySetting("gpu_debug_layers_gles", GLES_LAYER_A_LIB + ":" + GLES_LAYER_B_LIB); 677 deleteSetting("gpu_debug_layer_app"); 678 679 // Copy a layer from our LAYERS APK to tmp 680 setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP); 681 682 // Attempt to copy them over to our RELEASE app (this should fail) 683 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", RELEASE_APP, 684 "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'", "||", "echo", "run-as", "failed"); 685 686 // Kick off our RELEASE app 687 String appStartTime = getTime(); 688 launchBackgroundService(RELEASE_APP, API_GLES); 689 690 // Ensure we don't load the layer in base dir 691 String searchStringA = GLES_LAYER_A + " loaded"; 692 LogScanResult resultA = scanLog(TAG + "," + GLES_LAYER_A, searchStringA, appStartTime); 693 Assert.assertFalse(GLES_LAYER_A + " was enumerated", resultA.found); 694 } 695 696 /** 697 * This test ensures debuggable GLES apps do not enumerate layers in base 698 * directory if enable_gpu_debug_layers is not enabled. 699 */ 700 @Test testDebugNotEnabledGLES()701 public void testDebugNotEnabledGLES() throws Exception { 702 703 // Ensure the global layer enable settings is NOT enabled 704 applySetting("enable_gpu_debug_layers", "0"); 705 applySetting("gpu_debug_app", DEBUG_APP); 706 applySetting("gpu_debug_layers_gles", GLES_LAYER_A_LIB); 707 708 // Copy a layer from our LAYERS APK to tmp 709 setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP); 710 711 // Copy it over to our DEBUG app 712 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP, 713 "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'"); 714 715 // Kick off our DEBUG app 716 String appStartTime = getTime(); 717 launchBackgroundService(DEBUG_APP, API_GLES); 718 719 // Ensure we don't load the layer in base dir 720 String searchStringA = GLES_LAYER_A + " loaded"; 721 LogScanResult resultA = scanLog(TAG + "," + GLES_LAYER_A, searchStringA, appStartTime); 722 Assert.assertFalse(GLES_LAYER_A + " was enumerated", resultA.found); 723 } 724 725 /** 726 * This test ensures debuggable GLES apps do not enumerate layers in base 727 * directory if gpu_debug_app does not match. 728 */ 729 @Test testDebugWrongAppGLES()730 public void testDebugWrongAppGLES() throws Exception { 731 732 // Ensure the gpu_debug_app does not match what we launch 733 applySetting("enable_gpu_debug_layers", "1"); 734 applySetting("gpu_debug_app", RELEASE_APP); 735 applySetting("gpu_debug_layers_gles", GLES_LAYER_A_LIB); 736 737 // Copy a layer from our LAYERS APK to tmp 738 setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP); 739 740 // Copy it over to our DEBUG app 741 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP, 742 "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'"); 743 744 // Kick off our DEBUG app 745 String appStartTime = getTime(); 746 launchBackgroundService(DEBUG_APP, API_GLES); 747 748 // Ensure we don't load the layer in base dir 749 String searchStringA = GLES_LAYER_A + " loaded"; 750 LogScanResult resultA = scanLog(TAG + "," + GLES_LAYER_A, searchStringA, appStartTime); 751 Assert.assertFalse(GLES_LAYER_A + " was enumerated", resultA.found); 752 } 753 754 /** 755 * This test ensures debuggable GLES apps do not enumerate layers in base 756 * directory if gpu_debug_layers are not set. 757 */ 758 @Test testDebugNoLayersEnabledGLES()759 public void testDebugNoLayersEnabledGLES() throws Exception { 760 761 // Ensure the global layer enable settings is NOT enabled 762 applySetting("enable_gpu_debug_layers", "1"); 763 applySetting("gpu_debug_app", DEBUG_APP); 764 applySetting("gpu_debug_layers_gles", "foo"); 765 766 // Copy a layer from our LAYERS APK to tmp 767 setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP); 768 769 // Copy it over to our DEBUG app 770 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP, 771 "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'"); 772 773 // Kick off our DEBUG app 774 String appStartTime = getTime(); 775 launchBackgroundService(DEBUG_APP, API_GLES); 776 777 // Ensure layerA is not loaded 778 String searchStringA = "glesLayer_eglChooseConfig called in " + GLES_LAYER_A; 779 LogScanResult resultA = scanLog(TAG + "," + GLES_LAYER_A, searchStringA, appStartTime); 780 Assert.assertFalse(GLES_LAYER_A + " was loaded", resultA.found); 781 } 782 783 /** 784 * This test ensures we can still use properties if no GLES layers are specified 785 */ 786 @Test testSystemPropertyEnableGLES()787 public void testSystemPropertyEnableGLES() throws Exception { 788 789 // Set up layerA to be loaded, but not layerB or layerC 790 applySetting("enable_gpu_debug_layers", "1"); 791 applySetting("gpu_debug_app", RELEASE_APP); 792 deleteSetting("gpu_debug_layers_gles"); 793 794 // Enable layerC (which is packaged with the RELEASE app) with system properties 795 getDevice().executeAdbCommand("shell", "setprop", "debug.gles.layers " + GLES_LAYER_C_LIB); 796 797 // Kick off our RELEASE app 798 String appStartTime = getTime(); 799 launchBackgroundService(RELEASE_APP, API_GLES); 800 801 // Check that both layers were loaded, in the correct order 802 String searchStringA = GLES_LAYER_A + "loaded"; 803 LogScanResult resultA = scanLog(TAG + "," + GLES_LAYER_A, searchStringA, appStartTime); 804 Assert.assertFalse(GLES_LAYER_A + " was enumerated", resultA.found); 805 806 String searchStringC = "glesLayer_eglChooseConfig called in " + GLES_LAYER_C; 807 LogScanResult resultC = scanLog(TAG + "," + GLES_LAYER_C, searchStringC, appStartTime); 808 Assert.assertTrue(GLES_LAYER_C + " was not loaded", resultC.found); 809 } 810 811 /** 812 * This test ensures system properties are ignored if Settings load a GLES layer 813 */ 814 @Test testSystemPropertyIgnoreGLES()815 public void testSystemPropertyIgnoreGLES() throws Exception { 816 817 // Set up layerA to be loaded, but not layerB 818 applySetting("enable_gpu_debug_layers", "1"); 819 applySetting("gpu_debug_app", DEBUG_APP); 820 applySetting("gpu_debug_layers_gles", GLES_LAYER_A_LIB); 821 822 // Copy the layers from our LAYERS APK 823 setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP); 824 setupLayer(GLES_LAYER_B_LIB, GLES_LAYERS_APP); 825 826 // Copy them over to our DEBUG app 827 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", 828 "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()), 829 "sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'"); 830 getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_B_LIB, "|", 831 "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()), 832 "sh", "-c", "\'cat", ">", GLES_LAYER_B_LIB, ";", "chmod", "700", GLES_LAYER_B_LIB + "\'"); 833 834 // Enable layerB with system properties 835 getDevice().executeAdbCommand("shell", "setprop", "debug.gles.layers " + GLES_LAYER_B_LIB); 836 837 // Kick off our DEBUG app 838 String appStartTime = getTime(); 839 launchBackgroundService(DEBUG_APP, API_GLES); 840 841 // Ensure only layerA is loaded 842 String searchStringA = "glesLayer_eglChooseConfig called in " + GLES_LAYER_A; 843 LogScanResult resultA = scanLog(TAG + "," + GLES_LAYER_A, searchStringA, appStartTime); 844 Assert.assertTrue(GLES_LAYER_A + " was not loaded", resultA.found); 845 846 String searchStringB = "glesLayer_eglChooseConfig called in " + GLES_LAYER_B; 847 LogScanResult resultB = scanLog(TAG + "," + GLES_LAYER_B, searchStringB, appStartTime); 848 Assert.assertFalse(GLES_LAYER_B + " was loaded", resultB.found); 849 } 850 testLayerLoadExternalGLES(final String APP_NAME)851 public void testLayerLoadExternalGLES(final String APP_NAME) throws Exception { 852 // Set up layers to be loaded 853 applySetting("enable_gpu_debug_layers", "1"); 854 applySetting("gpu_debug_app", APP_NAME); 855 applySetting("gpu_debug_layers_gles", GLES_LAYER_C_LIB); 856 857 // Specify the external app that hosts layers 858 applySetting("gpu_debug_layer_app", GLES_LAYERS_APP); 859 860 // Kick off our app 861 String appStartTime = getTime(); 862 launchBackgroundService(APP_NAME, API_GLES); 863 864 // Check that our external layer was loaded 865 String searchStringC = "glesLayer_eglChooseConfig called in " + GLES_LAYER_C; 866 LogScanResult resultC = scanLog(TAG + "," + GLES_LAYER_C, searchStringC, appStartTime); 867 Assert.assertTrue(GLES_LAYER_C + " was not loaded", resultC.found); 868 } 869 870 /** 871 * This test ensures that external GLES layers can be loaded by a debuggable app 872 */ 873 @Test testDebugLayerLoadExternalGLES()874 public void testDebugLayerLoadExternalGLES() throws Exception { 875 testLayerLoadExternalGLES(DEBUG_APP); 876 } 877 878 /** 879 * This test ensures that external GLES layers can be loaded by an injectLayers app 880 */ 881 @Test testInjectLayerLoadExternalGLES()882 public void testInjectLayerLoadExternalGLES() throws Exception { 883 testLayerLoadExternalGLES(INJECT_APP); 884 } 885 886 /** 887 * 888 */ 889 @Test testMultipleExternalApps()890 public void testMultipleExternalApps() throws Exception { 891 892 // Set up layers to be loaded 893 applySetting("enable_gpu_debug_layers", "1"); 894 applySetting("gpu_debug_app", DEBUG_APP); 895 applySetting("gpu_debug_layers", VK_LAYER_C); 896 applySetting("gpu_debug_layers_gles", GLES_LAYER_C_LIB); 897 898 // Specify multple external apps that host layers 899 applySetting("gpu_debug_layer_app", LAYERS_APP + ":" + GLES_LAYERS_APP); 900 901 // Kick off our DEBUG app 902 String appStartTime = getTime(); 903 launchBackgroundService(DEBUG_APP, API_BOTH); 904 905 // Check that external layers were loaded from both apps 906 assertVkLayerLoading(appStartTime, VK_LAYER_C, true); 907 908 String glesString = "glesLayer_eglChooseConfig called in " + GLES_LAYER_C; 909 LogScanResult glesResult = scanLog(TAG + "," + GLES_LAYER_C, glesString, appStartTime); 910 Assert.assertTrue(GLES_LAYER_C + " was not loaded", glesResult.found); 911 } 912 } 913