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