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)