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