Merge "Handle new shader directory on U / API 34" into androidx-main am: 7a7663b93d

Original change: https://android-review.googlesource.com/c/platform/frameworks/support/+/2573042

Change-Id: I89511e027382c2892914a9b3896a7ee196499ca8
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
index 6e5d23e..4719b94 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
@@ -122,8 +122,16 @@
             val result = ShellImpl.executeCommandUnsafe("ls -l $path")
             if (result.isBlank()) "" else result.split(Regex("\\s+"))[3]
         }
-        check(sum.isNotBlank()) {
-            "Checksum for $path was blank"
+        if (sum.isBlank()) {
+            if (!ShellImpl.isSessionRooted) {
+                val lsOutput = ShellImpl.executeCommandUnsafe("ls -l $path")
+                throw IllegalStateException(
+                    "Checksum for $path was blank. Adb session is not rooted, if root owns file, " +
+                        "you may need to \"adb root\" and delete the file: $lsOutput"
+                )
+            } else {
+                throw IllegalStateException("Checksum for $path was blank.")
+            }
         }
         return sum
     }
@@ -690,7 +698,8 @@
          * Usage args: ```path/to/shellWrapper.sh <scriptFile> <stderrFile> [inputFile]```
          */
         private val scriptWrapperPath = Shell.createRunnableExecutable(
-            "shellWrapper.sh",
+            // use separate paths to prevent access errors after `adb unroot`
+            if (ShellImpl.isSessionRooted) "shellWrapper_root.sh" else "shellWrapper.sh",
             """
                 ### shell script which passes in stdin as needed, and captures stderr in a file
                 # $1 == script content (not executable)
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt
index a4adce9..f4771c8 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt
@@ -225,14 +225,16 @@
 
     private fun validateShaderCache(empty: Boolean, packageName: String) {
         val path = MacrobenchmarkScope.getShaderCachePath(packageName)
+
         println("validating shader path $path")
         val fileCount = Shell.executeScriptCaptureStdout("find $path -type f | wc -l")
             .trim()
             .toInt()
         if (empty) {
-            assertEquals(0, fileCount)
+            val files = Shell.executeScriptCaptureStdout("find $path -type f")
+            assertEquals(0, fileCount, "Expected 0 files in $path, saw $fileCount (files = $files)")
         } else {
-            assertNotEquals(0, fileCount)
+            assertNotEquals(0, fileCount, "Expected >0 files in $path, saw $fileCount")
         }
     }
 
@@ -280,6 +282,11 @@
     }
 
     @Test
+    fun dropShaderCacheRoot() = validateDropShaderCacheWithRoot {
+        assertTrue(dropShaderCacheRoot())
+    }
+
+    @Test
     fun dropKernelPageCache() {
         val scope = MacrobenchmarkScope(
             Packages.TARGET,
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
index 0d3280b..b8e6d86 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
@@ -23,12 +23,11 @@
 import androidx.annotation.RequiresApi
 import androidx.benchmark.DeviceInfo
 import androidx.benchmark.Shell
-import androidx.benchmark.macro.MacrobenchmarkScope.Companion.Api24Helper.shaderDir
+import androidx.benchmark.macro.MacrobenchmarkScope.Companion.Api24ContextHelper.createDeviceProtectedStorageContextCompat
 import androidx.benchmark.macro.perfetto.forceTrace
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import androidx.tracing.trace
-import java.io.File
 
 /**
  * Provides access to common operations in app automation, such as killing the app,
@@ -242,18 +241,31 @@
     public fun dropShaderCache() {
         Log.d(TAG, "Dropping shader cache for $packageName")
         val dropError = ProfileInstallBroadcast.dropShaderCache(packageName)
-        if (dropError != null) {
-            if (Shell.isSessionRooted()) {
-                // fall back to root approach
-                val path = getShaderCachePath(packageName)
-                Shell.executeScriptSilent("find $path -type f | xargs rm")
-            } else {
+        if (dropError != null && !DeviceInfo.isEmulator) {
+            if (!dropShaderCacheRoot()) {
                 throw IllegalStateException(dropError)
             }
         }
     }
 
     /**
+     * Returns true if rooted, and delete operation succeeded without error.
+     *
+     * Note that if no files are present in the shader dir, true will still be returned.
+     */
+    internal fun dropShaderCacheRoot(): Boolean {
+        if (Shell.isSessionRooted()) {
+            // fall back to root approach
+            val path = getShaderCachePath(packageName)
+
+            // Use -f to allow missing files, since app may not have generated shaders.
+            Shell.executeScriptSilent("find $path -type f | xargs rm -f")
+            return true
+        }
+        return false
+    }
+
+    /**
      * Drop caches via setprop added in API 31
      *
      * Feature for dropping caches without root added in 31: https://r.android.com/1584525
@@ -312,21 +324,24 @@
             val context = InstrumentationRegistry.getInstrumentation().context
 
             // Shader paths sourced from ActivityThread.java
-            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-                context.shaderDir
+            val shaderDirectory = if (Build.VERSION.SDK_INT >= 34) {
+                // U switched to cache dir, so it's not deleted on each app update
+                context.createDeviceProtectedStorageContextCompat().cacheDir
+            } else if (Build.VERSION.SDK_INT >= 24) {
+                // shaders started using device protected storage context once it was added in N
+                context.createDeviceProtectedStorageContextCompat().codeCacheDir
             } else {
                 // getCodeCacheDir was added in L, but not used by platform for shaders until M
                 // as M is minApi of this library, that's all we support here
                 context.codeCacheDir
-            }.absolutePath.replace(context.packageName, packageName)
+            }
+            return shaderDirectory.absolutePath.replace(context.packageName, packageName)
         }
 
         @RequiresApi(Build.VERSION_CODES.N)
-        internal object Api24Helper {
-            val Context.shaderDir: File
-                get() =
-                    // shaders started using device protected storage context once it was added in N
-                    createDeviceProtectedStorageContext().codeCacheDir
+        internal object Api24ContextHelper {
+            fun Context.createDeviceProtectedStorageContextCompat(): Context =
+                createDeviceProtectedStorageContext()
         }
     }
 }
diff --git a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/BenchmarkOperation.java b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/BenchmarkOperation.java
index c57f7b4..f9b60ea 100644
--- a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/BenchmarkOperation.java
+++ b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/BenchmarkOperation.java
@@ -32,10 +32,15 @@
             @NonNull ProfileInstallReceiver.ResultDiagnostics callback
     ) {
         File shaderDirectory;
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-            // shaders started using code cache dir once it was added in N
-            shaderDirectory = Api24ContextHelper.getDeviceProtectedCodeCacheDir(context);
-        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+        if (Build.VERSION.SDK_INT >= 34) {
+            // U switched to cache dir, so it's not deleted on each app update
+            shaderDirectory = Api24ContextHelper.createDeviceProtectedStorageContext(context)
+                    .getCacheDir();
+        } else if (Build.VERSION.SDK_INT >= 24) {
+            // shaders started using device protected storage context once it was added in N
+            shaderDirectory = Api21ContextHelper.getCodeCacheDir(
+                    Api24ContextHelper.createDeviceProtectedStorageContext(context));
+        } else if (Build.VERSION.SDK_INT == 23) {
             // getCodeCacheDir was added in L, but not used by platform for shaders until M
             shaderDirectory = Api21ContextHelper.getCodeCacheDir(context);
         } else {
@@ -82,9 +87,9 @@
 
     @RequiresApi(api = Build.VERSION_CODES.N)
     private static class Api24ContextHelper {
-        static File getDeviceProtectedCodeCacheDir(Context context) {
+        static Context createDeviceProtectedStorageContext(Context context) {
             // Code device protected storage added in 24
-            return context.createDeviceProtectedStorageContext().getCodeCacheDir();
+            return context.createDeviceProtectedStorageContext();
         }
     }
 }