Merge "VmTerminalApp: Do not use Executor#submit() when not necessary" into main
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
index ba03716..088744e 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
@@ -17,9 +17,7 @@
 
 import android.system.virtualmachine.VirtualMachine
 import android.system.virtualmachine.VirtualMachineConfig
-import android.system.virtualmachine.VirtualMachineException
 import android.util.Log
-import com.android.virtualization.terminal.Logger.LineBufferedOutputStream
 import java.io.BufferedOutputStream
 import java.io.BufferedReader
 import java.io.IOException
@@ -56,19 +54,29 @@
             val logPath = dir.resolve(LocalDateTime.now().toString() + ".txt")
             val console = vm.getConsoleOutput()
             val file = Files.newOutputStream(logPath, StandardOpenOption.CREATE)
-            executor.submit<Int?> {
-                console.use { console ->
-                    LineBufferedOutputStream(file).use { fileOutput ->
-                        Streams.copy(console, fileOutput)
+            executor.execute({
+                try {
+                    console.use { console ->
+                        LineBufferedOutputStream(file).use { fileOutput ->
+                            Streams.copy(console, fileOutput)
+                        }
                     }
+                } catch (e: Exception) {
+                    Log.w(tag, "Failed to log console output. VM may be shutting down", e)
                 }
-            }
+            })
 
             val log = vm.getLogOutput()
-            executor.submit<Unit> { log.use { writeToLogd(it, tag) } }
-        } catch (e: VirtualMachineException) {
-            throw RuntimeException(e)
-        } catch (e: IOException) {
+            executor.execute({
+                log.use {
+                    try {
+                        writeToLogd(it, tag)
+                    } catch (e: Exception) {
+                        Log.w(tag, "Failed to log VM log output. VM may be shutting down", e)
+                    }
+                }
+            })
+        } catch (e: Exception) {
             throw RuntimeException(e)
         }
     }
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MemBalloonController.kt b/android/TerminalApp/java/com/android/virtualization/terminal/MemBalloonController.kt
index 7647d9b..2ed7217 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MemBalloonController.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MemBalloonController.kt
@@ -58,7 +58,7 @@
             // available memory to the virtual machine
             override fun onResume(owner: LifecycleOwner) {
                 ongoingInflation?.cancel(false)
-                executor.submit({
+                executor.execute({
                     Log.v(TAG, "app resumed. deflating mem balloon to the minimum")
                     vm.setMemoryBalloonByPercent(0)
                 })
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
index 319a53b..654cb57 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
@@ -21,19 +21,23 @@
 import android.view.View
 import androidx.appcompat.app.AppCompatActivity
 import androidx.core.view.isVisible
-import androidx.lifecycle.lifecycleScope
 import com.android.virtualization.terminal.MainActivity.Companion.TAG
 import com.google.android.material.card.MaterialCardView
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.google.android.material.snackbar.Snackbar
 import java.io.IOException
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
 
 class SettingsRecoveryActivity : AppCompatActivity() {
+    private lateinit var executorService: ExecutorService
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+
+        executorService =
+            Executors.newSingleThreadExecutor(TerminalThreadFactory(applicationContext))
+
         setContentView(R.layout.settings_recovery)
 
         val resetCard = findViewById<MaterialCardView>(R.id.settings_recovery_reset_card)
@@ -81,6 +85,12 @@
         }
     }
 
+    override fun onDestroy() {
+        super.onDestroy()
+
+        executorService.shutdown()
+    }
+
     private fun removeBackup(): Unit {
         try {
             InstalledImage.getDefault(this).deleteBackup()
@@ -116,27 +126,22 @@
         }
     }
 
-    private fun runInBackgroundAndRestartApp(
-        backgroundWork: suspend CoroutineScope.() -> Unit
-    ): Unit {
+    private fun runInBackgroundAndRestartApp(backgroundWork: Runnable) {
         findViewById<View>(R.id.setting_recovery_card_container).visibility = View.INVISIBLE
         findViewById<View>(R.id.recovery_boot_progress).visibility = View.VISIBLE
-        lifecycleScope
-            .launch(Dispatchers.IO) { backgroundWork() }
-            .invokeOnCompletion {
-                runOnUiThread {
-                    findViewById<View>(R.id.setting_recovery_card_container).visibility =
-                        View.VISIBLE
-                    findViewById<View>(R.id.recovery_boot_progress).visibility = View.INVISIBLE
-                    // Restart terminal
-                    val intent =
-                        baseContext.packageManager.getLaunchIntentForPackage(
-                            baseContext.packageName
-                        )
-                    intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
-                    finish()
-                    startActivity(intent)
-                }
+        executorService.execute({
+            backgroundWork.run()
+
+            runOnUiThread {
+                findViewById<View>(R.id.setting_recovery_card_container).visibility = View.VISIBLE
+                findViewById<View>(R.id.recovery_boot_progress).visibility = View.INVISIBLE
+                // Restart terminal
+                val intent =
+                    baseContext.packageManager.getLaunchIntentForPackage(baseContext.packageName)
+                intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+                finish()
+                startActivity(intent)
             }
+        })
     }
 }
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
index 84168e5..0b34a8d 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -94,7 +94,7 @@
 
     override fun onCreate() {
         super.onCreate()
-        val threadFactory = TerminalThreadFactory(getApplicationContext())
+        val threadFactory = TerminalThreadFactory(applicationContext)
         bgThreads = Executors.newCachedThreadPool(threadFactory)
         mainWorkerThread = Executors.newSingleThreadExecutor(threadFactory)
         image = InstalledImage.getDefault(this)
@@ -123,7 +123,7 @@
                 // done.
                 val diskSize = intent.getLongExtra(EXTRA_DISK_SIZE, image.getApparentSize())
 
-                mainWorkerThread.submit({
+                mainWorkerThread.execute({
                     doStart(notification, displayInfo, diskSize, resultReceiver)
                 })
 
@@ -131,7 +131,7 @@
                 // ForegroundServiceDidNotStartInTimeException
                 startForeground(this.hashCode(), notification)
             }
-            ACTION_SHUTDOWN_VM -> mainWorkerThread.submit({ doShutdown(resultReceiver) })
+            ACTION_SHUTDOWN_VM -> mainWorkerThread.execute({ doShutdown(resultReceiver) })
             else -> {
                 Log.e(TAG, "Unknown command " + intent.action)
                 stopSelf()
@@ -505,7 +505,7 @@
     }
 
     override fun onDestroy() {
-        mainWorkerThread.submit({
+        mainWorkerThread.execute({
             if (runner?.vm?.getStatus() == VirtualMachine.STATUS_RUNNING) {
                 doShutdown(null)
             }