Logs from the terminal VM is accumulated
so that we can see logs from old invocations
Bug: N/A
Test: N/A
Change-Id: Ia4fa6559de895c25aa73754698d4c08c607a8eb8
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
index 547f1a7..15ddcde 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
@@ -30,6 +30,7 @@
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
+import java.time.LocalDateTime
import java.util.concurrent.ExecutorService
import libcore.io.Streams
@@ -37,14 +38,21 @@
* Forwards VM's console output to a file on the Android side, and VM's log output to Android logd.
*/
internal object Logger {
- fun setup(vm: VirtualMachine, path: Path, executor: ExecutorService) {
+ fun setup(vm: VirtualMachine, dir: Path, executor: ExecutorService) {
+ val tag = vm.name
+
if (vm.config.debugLevel != VirtualMachineConfig.DEBUG_LEVEL_FULL) {
+ Log.i(tag, "Logs are not captured. Non-debuggable VM.")
return
}
try {
+ Files.createDirectories(dir)
+ deleteOldLogs(dir, 10)
+ val logPath = dir.resolve(LocalDateTime.now().toString())
val console = vm.getConsoleOutput()
- val file = Files.newOutputStream(path, StandardOpenOption.CREATE)
+ val file =
+ Files.newOutputStream(logPath, StandardOpenOption.SYNC, StandardOpenOption.APPEND)
executor.submit<Int?> {
console.use { console ->
LineBufferedOutputStream(file).use { fileOutput ->
@@ -54,7 +62,7 @@
}
val log = vm.getLogOutput()
- executor.submit<Unit> { log.use { writeToLogd(it, vm.name) } }
+ executor.submit<Unit> { log.use { writeToLogd(it, tag) } }
} catch (e: VirtualMachineException) {
throw RuntimeException(e)
} catch (e: IOException) {
@@ -62,12 +70,32 @@
}
}
+ fun deleteOldLogs(dir: Path, numLogsToKeep: Long) {
+ Files.list(dir)
+ .filter { Files.isRegularFile(it) }
+ .sorted(
+ Comparator.comparingLong { f: Path ->
+ // for some reason, type inference didn't work here!
+ Files.getLastModifiedTime(f).toMillis()
+ }
+ .reversed()
+ )
+ .skip(numLogsToKeep)
+ .forEach {
+ try {
+ Files.delete(it)
+ } catch (e: IOException) {
+ // don't bother
+ }
+ }
+ }
+
@Throws(IOException::class)
- private fun writeToLogd(input: InputStream?, vmName: String?) {
+ private fun writeToLogd(input: InputStream?, tag: String?) {
val reader = BufferedReader(InputStreamReader(input))
reader
.useLines { lines -> lines.takeWhile { !Thread.interrupted() } }
- .forEach { Log.d(vmName, it) }
+ .forEach { Log.d(tag, it) }
}
private class LineBufferedOutputStream(out: OutputStream?) : BufferedOutputStream(out) {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
index 4bfad62..b61cccd 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -139,10 +139,7 @@
val displaySize = intent.getParcelableExtra(EXTRA_DISPLAY_INFO, DisplayInfo::class.java)
customImageConfigBuilder.setAudioConfig(
- AudioConfig.Builder()
- .setUseSpeaker(true)
- .setUseMicrophone(true)
- .build()
+ AudioConfig.Builder().setUseSpeaker(true).setUseMicrophone(true).build()
)
if (overrideConfigIfNecessary(customImageConfigBuilder, displaySize)) {
configBuilder.setCustomImageConfig(customImageConfigBuilder.build())
@@ -170,8 +167,8 @@
resultReceiver?.send(if (success) RESULT_STOP else RESULT_ERROR, null)
stopSelf()
}
- val logPath = getFileStreamPath(virtualMachine!!.name + ".log").toPath()
- Logger.setup(virtualMachine!!, logPath, executorService!!)
+ val logDir = getFileStreamPath(virtualMachine!!.name + ".log").toPath()
+ Logger.setup(virtualMachine!!, logDir, executorService!!)
val notification =
intent.getParcelableExtra<Notification?>(EXTRA_NOTIFICATION, Notification::class.java)