diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt index 60285a8122..1db57655ad 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt @@ -36,6 +36,7 @@ import android.net.wifi.WifiInfo import android.net.wifi.WifiManager import android.os.Build import android.os.ParcelFileDescriptor +import android.os.ParcelFileDescriptor.AutoCloseInputStream import android.telephony.TelephonyManager import android.telephony.TelephonyManager.SIM_STATE_UNKNOWN import android.util.Log @@ -46,6 +47,7 @@ import java.io.ByteArrayOutputStream import java.io.CharArrayWriter import java.io.File import java.io.FileReader +import java.io.InputStream import java.io.OutputStream import java.io.OutputStreamWriter import java.io.PrintWriter @@ -438,13 +440,44 @@ class ConnectivityDiagnosticsCollector : BaseMetricListener() { *

The output will be collected immediately, and exported to a test artifact file when the * test ends. * @param cmd The command to run. Stdout of the command will be collected. - * @param shell The shell to run the command in. + * @param shell The shell to run the command in, for example "sh". + * @param exceptionContext An exception to write a stacktrace to the dump for context. + */ + @RequiresApi(Build.VERSION_CODES.S) + fun collectCommandOutput( + cmd: String, + shell: String, + exceptionContext: Throwable? = null + ) = collectCommandOutput(cmd, exceptionContext) { c, outputProcessor -> + runCommandInShell(c, shell, outputProcessor) + } + + /** + * Add the output of a command to the test data dump. + * + *

The output will be collected immediately, and exported to a test artifact file when the + * test ends. + * + *

Note this does not support shell pipes, redirections, or quoted arguments. See the S+ + * overload if that is needed. + * @param cmd The command to run. Stdout of the command will be collected. * @param exceptionContext An exception to write a stacktrace to the dump for context. */ fun collectCommandOutput( cmd: String, - shell: String = "sh", exceptionContext: Throwable? = null + ) = collectCommandOutput(cmd, exceptionContext) { c, outputProcessor -> + AutoCloseInputStream( + InstrumentationRegistry.getInstrumentation().uiAutomation.executeShellCommand(c) + ).use { + outputProcessor(it) + } + } + + private fun collectCommandOutput( + cmd: String, + exceptionContext: Throwable? = null, + commandRunner: (String, (InputStream) -> Unit) -> Unit ) { Log.i(TAG, "Collecting '$cmd' for test artifacts") PrintWriter(buffer).let { @@ -453,7 +486,7 @@ class ConnectivityDiagnosticsCollector : BaseMetricListener() { it.flush() } - runCommandInShell(cmd, shell) { stdout, _ -> + commandRunner(cmd) { stdout -> stdout.copyTo(buffer) } } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ShellUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/ShellUtil.kt index fadc2ab4e3..2b740360b9 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/ShellUtil.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/ShellUtil.kt @@ -19,8 +19,10 @@ package com.android.testutils import android.app.UiAutomation +import android.os.Build import android.os.ParcelFileDescriptor.AutoCloseInputStream import android.os.ParcelFileDescriptor.AutoCloseOutputStream +import androidx.annotation.RequiresApi import androidx.test.platform.app.InstrumentationRegistry import java.io.InputStream @@ -37,18 +39,17 @@ import java.io.InputStream * when this function returns. * @return Result of [outputProcessor]. */ +@RequiresApi(Build.VERSION_CODES.S) // executeShellCommandRw is 31+ fun runCommandInShell( cmd: String, shell: String = "sh", - outputProcessor: (InputStream, InputStream) -> T, + outputProcessor: (InputStream) -> T, ): T { - val (stdout, stdin, stderr) = InstrumentationRegistry.getInstrumentation().uiAutomation - .executeShellCommandRwe(shell) + val (stdout, stdin) = InstrumentationRegistry.getInstrumentation().uiAutomation + .executeShellCommandRw(shell) AutoCloseOutputStream(stdin).bufferedWriter().use { it.write(cmd) } AutoCloseInputStream(stdout).use { outStream -> - AutoCloseInputStream(stderr).use { errStream -> - return outputProcessor(outStream, errStream) - } + return outputProcessor(outStream) } } @@ -57,10 +58,11 @@ fun runCommandInShell( * * Overload of [runCommandInShell] that reads and returns stdout as String. */ +@RequiresApi(Build.VERSION_CODES.S) fun runCommandInShell( cmd: String, shell: String = "sh", -) = runCommandInShell(cmd, shell) { stdout, _ -> +) = runCommandInShell(cmd, shell) { stdout -> stdout.reader().use { it.readText() } } @@ -70,6 +72,7 @@ fun runCommandInShell( * This is generally only usable on devices on which [DeviceInfoUtils.isDebuggable] is true. * @see runCommandInShell */ +@RequiresApi(Build.VERSION_CODES.S) fun runCommandInRootShell( cmd: String ) = runCommandInShell(cmd, shell = "su root sh")