As of today there’s no public implementation of the java ProcessBuilder.startPipeline in Android.
So I came out with this quick solution, using Kotlin, to pipe multiple processes in Android:
object ProcessUtil { private fun check(process: Process, error: (() -> String)) { try { if (process.errorStream.available() > 0) { process.errorStream.bufferedReader().use { it.readText().also { errorText -> check(errorText.isBlank()) { "${error.invoke()} failed with error: $errorText" } } } } } catch (_: IOException) { // ignore } } @Throws(IOException::class, IllegalStateException::class) fun pipe(vararg processes: ProcessBuilder): String { check(processes.size > 1) { "At least 2 processes are required" } var previous: Process? = null var result: String = "" processes.forEachIndexed { index, builder -> val cmdString = builder.command().joinToString(" ") println("Executing command $index -> $cmdString") if (index > 0) { check(builder.redirectInput() == Redirect.PIPE) { "Builder redirectInput must be PIPE except for the first builder" } } else if (index < processes.size - 1) { check(builder.redirectOutput() == Redirect.PIPE) { "Builder redirectOutput must be PIPE except for the last builder" } } val current: Process = builder.start() check(current) { cmdString } previous?.let { prevProcess -> prevProcess.inputStream.bufferedReader().use { reader -> current.outputStream.bufferedWriter().use { writer -> reader.readLines().forEach { line -> println("writing --> $line") writer.write(line) writer.newLine() } check(current) { cmdString } } // writer if (index == processes.size - 1) { current.inputStream.bufferedReader().use { reader2 -> result = reader2.readText() } } } // reader } previous = current } return result } fun pipe(vararg commands: List<String>) = pipe(*commands.map { ProcessBuilder(it) }.toTypedArray()) fun pipe(vararg commands: String) = pipe(*commands.map { ProcessBuilder(it) }.toTypedArray()) }
And it can be used like this:
@Test fun testPipe() { val packageName = context.packageName val result = ProcessUtil.pipe(listOf("ps", "-A"), listOf("grep", packageName), listOf("awk", "{ print $9 }")) println("result = '$result'") Assert.assertTrue(result.contains(packageName)) }