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))
}




