Merge "Update tab title whenever ttyd session title changes" 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 4162247..ba03716 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
@@ -47,6 +47,10 @@
}
try {
+ if (Files.isRegularFile(dir)) {
+ Log.i(tag, "Removed legacy log file: $dir")
+ Files.delete(dir)
+ }
Files.createDirectories(dir)
deleteOldLogs(dir, 10)
val logPath = dir.resolve(LocalDateTime.now().toString() + ".txt")
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Runner.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Runner.kt
index 6454cbd..642cb26 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Runner.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Runner.kt
@@ -27,7 +27,7 @@
import java.util.concurrent.ForkJoinPool
/** Utility class for creating a VM and waiting for it to finish. */
-internal class Runner private constructor(val vm: VirtualMachine?, callback: Callback) {
+internal class Runner private constructor(val vm: VirtualMachine, callback: Callback) {
/** Get future about VM's exit status. */
val exitStatus = callback.finishedSuccessfully
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
index e5cabbf..067d540 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -63,7 +63,10 @@
import java.util.concurrent.TimeUnit
class VmLauncherService : Service() {
- private lateinit var executorService: ExecutorService
+ // Thread pool
+ private lateinit var bgThreads: ExecutorService
+ // Single thread
+ private lateinit var mainWorkerThread: ExecutorService
private lateinit var image: InstalledImage
// TODO: using lateinit for some fields to avoid null
@@ -89,7 +92,9 @@
override fun onCreate() {
super.onCreate()
- executorService = Executors.newCachedThreadPool(TerminalThreadFactory(applicationContext))
+ val threadFactory = TerminalThreadFactory(getApplicationContext())
+ bgThreads = Executors.newCachedThreadPool(threadFactory)
+ mainWorkerThread = Executors.newSingleThreadExecutor(threadFactory)
image = InstalledImage.getDefault(this)
}
@@ -116,11 +121,15 @@
// done.
val diskSize = intent.getLongExtra(EXTRA_DISK_SIZE, image.getSize())
- executorService.submit({
+ mainWorkerThread.submit({
doStart(notification, displayInfo, diskSize, resultReceiver)
})
+
+ // Do this outside of the main worker thread, so that we don't cause
+ // ForegroundServiceDidNotStartInTimeException
+ startForeground(this.hashCode(), notification)
}
- ACTION_SHUTDOWN_VM -> executorService.submit({ doShutdown(resultReceiver) })
+ ACTION_SHUTDOWN_VM -> mainWorkerThread.submit({ doShutdown(resultReceiver) })
else -> {
Log.e(TAG, "Unknown command " + intent.action)
stopSelf()
@@ -137,11 +146,6 @@
diskSize: Long,
resultReceiver: ResultReceiver,
) {
- if (virtualMachine != null) {
- Log.d(TAG, "VM instance is already started")
- return
- }
-
val image = InstalledImage.getDefault(this)
val json = ConfigJson.from(this, image.configPath)
val configBuilder = json.toConfigBuilder(this)
@@ -163,8 +167,8 @@
throw RuntimeException("cannot create runner", e)
}
- virtualMachine = runner!!.vm
- val mbc = MemBalloonController(this, virtualMachine!!)
+ val virtualMachine = runner!!.vm
+ val mbc = MemBalloonController(this, virtualMachine)
mbc.start()
runner!!.exitStatus.thenAcceptAsync { success: Boolean ->
@@ -172,10 +176,8 @@
resultReceiver.send(if (success) RESULT_STOP else RESULT_ERROR, null)
stopSelf()
}
- val logDir = getFileStreamPath(virtualMachine!!.name + ".log").toPath()
- Logger.setup(virtualMachine!!, logDir, executorService)
-
- startForeground(this.hashCode(), notification)
+ val logDir = getFileStreamPath(virtualMachine.name + ".log").toPath()
+ Logger.setup(virtualMachine, logDir, bgThreads)
resultReceiver.send(RESULT_START, null)
@@ -192,7 +194,7 @@
resultReceiver.send(RESULT_TERMINAL_AVAIL, bundle)
startDebianServer(ipAddress)
},
- executorService,
+ bgThreads,
)
.exceptionallyAsync(
{ e ->
@@ -201,7 +203,7 @@
stopSelf()
null
},
- executorService,
+ bgThreads,
)
}
@@ -368,7 +370,7 @@
return
}
- executorService.execute(
+ bgThreads.execute(
Runnable {
// TODO(b/373533555): we can use mDNS for that.
val debianServicePortFile = File(filesDir, "debian_service_port")
@@ -388,18 +390,21 @@
}
@WorkerThread
- private fun doShutdown(resultReceiver: ResultReceiver) {
+ private fun doShutdown(resultReceiver: ResultReceiver?) {
+ stopForeground(STOP_FOREGROUND_REMOVE)
if (debianService != null && debianService!!.shutdownDebian()) {
// During shutdown, change the notification content to indicate that it's closing
val notification = createNotificationForTerminalClose()
getSystemService<NotificationManager?>(NotificationManager::class.java)
.notify(this.hashCode(), notification)
runner?.exitStatus?.thenAcceptAsync { success: Boolean ->
- resultReceiver.send(if (success) RESULT_STOP else RESULT_ERROR, null)
+ resultReceiver?.send(if (success) RESULT_STOP else RESULT_ERROR, null)
stopSelf()
}
+ runner = null
} else {
// If there is no Debian service or it fails to shutdown, just stop the service.
+ runner?.vm?.stop()
stopSelf()
}
}
@@ -411,21 +416,16 @@
}
override fun onDestroy() {
+ mainWorkerThread.submit({
+ if (runner?.vm?.getStatus() == VirtualMachine.STATUS_RUNNING) {
+ doShutdown(null)
+ }
+ })
portNotifier?.stop()
getSystemService<NotificationManager?>(NotificationManager::class.java).cancelAll()
stopDebianServer()
- if (virtualMachine != null) {
- if (virtualMachine!!.getStatus() == VirtualMachine.STATUS_RUNNING) {
- try {
- virtualMachine!!.stop()
- stopForeground(STOP_FOREGROUND_REMOVE)
- } catch (e: VirtualMachineException) {
- Log.e(TAG, "failed to stop a VM instance", e)
- }
- }
- virtualMachine = null
- }
- executorService.shutdownNow()
+ bgThreads.shutdownNow()
+ mainWorkerThread.shutdown()
super.onDestroy()
}