AidlCompiler.kt
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.privacysandbox.tools.core.generator
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Path
import java.util.concurrent.TimeUnit
import kotlin.io.path.deleteIfExists
import kotlin.io.path.writeText
class AidlCompiler(
private val aidlCompilerPath: Path,
private val frameworkAidlPath: Path?,
private val aidlCompileTimeoutMs: Long = 10_000,
) {
fun compile(workingDir: Path, sources: List<Path>) {
// TODO(b/269458005): Remove this fallback and make frameworkAidlPath non-nullable
// (dependent on our callers always providing the argument)
val bundleFile = Files.createTempFile("bundle", "aidl")
val preProcessedAidlPath = if (frameworkAidlPath != null) {
frameworkAidlPath
} else {
bundleFile.writeText("parcelable android.os.Bundle;")
bundleFile.toAbsolutePath()
}
try {
val command =
listOf(
aidlCompilerPath.toString(),
"--lang=java",
"--include=$workingDir",
"--preprocessed=$preProcessedAidlPath",
"--out=$workingDir",
*sources.map(Path::toString).toTypedArray()
)
val process = ProcessBuilder(command).start()
val timedOut = !process.waitFor(aidlCompileTimeoutMs, TimeUnit.MILLISECONDS)
if (timedOut) {
throw Exception("AIDL compiler timed out: $command")
}
if (process.exitValue() != 0) {
throw Exception(
"AIDL compiler didn't terminate successfully (exit code: " +
"${process.exitValue()}).\n" +
"Command: '$command'\n" +
"Errors: ${getProcessErrors(process)}"
)
}
} finally {
bundleFile.deleteIfExists()
}
}
private fun getProcessErrors(process: Process): String {
try {
process.errorStream.bufferedReader().use { outputReader ->
return outputReader.lines().toArray()
.joinToString(separator = "\n\t", prefix = "\n\t")
}
} catch (e: IOException) {
return "Error when printing output of command: ${e.message}"
}
}
}