Snap for 13190096 from e635c66c4e611f1e28be3f57bcaf12ba79c4d770 to 25Q2-release
Change-Id: I1b89877691968f5273ee362fb437041028b70b0f
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
index 9f4909d..c427337 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
@@ -97,14 +97,6 @@
super.onStop(owner)
}
- override fun onDestroy(owner: LifecycleOwner) {
- if (vmLauncherService != null) {
- this@Application.unbindService(connection)
- vmLauncherService = null
- }
- super.onDestroy(owner)
- }
-
fun bindToVmLauncherService() {
val intent = Intent(this@Application, VmLauncherService::class.java)
this@Application.bindService(intent, connection, 0) // No BIND_AUTO_CREATE
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
index 547f1a7..d02491b 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() + ".txt")
val console = vm.getConsoleOutput()
- val file = Files.newOutputStream(path, StandardOpenOption.CREATE)
+ val file =
+ Files.newOutputStream(logPath, StandardOpenOption.CREATE)
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 eee0ada..aa1898f 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -188,10 +188,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())
@@ -219,8 +216,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)
diff --git a/guest/forwarder_guest_launcher/debian/service b/guest/forwarder_guest_launcher/debian/service
index ad57a26..7812d67 100644
--- a/guest/forwarder_guest_launcher/debian/service
+++ b/guest/forwarder_guest_launcher/debian/service
@@ -5,7 +5,7 @@
After=virtiofs_internal.service
[Service]
-ExecStart=/usr/bin/bash -c '/usr/bin/forwarder_guest_launcher --grpc_port $(cat /mnt/internal/debian_service_port)'
+ExecStart=/usr/bin/bash -c '/usr/bin/forwarder_guest_launcher --grpc-port-file /mnt/internal/debian_service_port'
Type=simple
Restart=on-failure
RestartSec=1
diff --git a/guest/forwarder_guest_launcher/src/main.rs b/guest/forwarder_guest_launcher/src/main.rs
index f4c8ca9..3cb557a 100644
--- a/guest/forwarder_guest_launcher/src/main.rs
+++ b/guest/forwarder_guest_launcher/src/main.rs
@@ -52,10 +52,9 @@
#[derive(Parser)]
/// Flags for running command
pub struct Args {
- /// grpc port number
+ /// path to a file where grpc port number is written
#[arg(long)]
- #[arg(alias = "grpc_port")]
- grpc_port: String,
+ grpc_port_file: String,
}
async fn process_forwarding_request_queue(
@@ -163,11 +162,23 @@
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
- env_logger::init();
+ env_logger::builder().filter_level(log::LevelFilter::Debug).init();
debug!("Starting forwarder_guest_launcher");
let args = Args::parse();
let gateway_ip_addr = netdev::get_default_gateway()?.ipv4[0];
- let addr = format!("https://{}:{}", gateway_ip_addr.to_string(), args.grpc_port);
+
+ // Wait for `grpc_port_file` becomes available.
+ const GRPC_PORT_MAX_RETRY_COUNT: u32 = 10;
+ for _ in 0..GRPC_PORT_MAX_RETRY_COUNT {
+ if std::path::Path::new(&args.grpc_port_file).exists() {
+ break;
+ }
+ debug!("{} does not exist. Wait 1 second", args.grpc_port_file);
+ tokio::time::sleep(std::time::Duration::from_secs(1)).await;
+ }
+ let grpc_port = std::fs::read_to_string(&args.grpc_port_file)?.trim().to_string();
+
+ let addr = format!("https://{}:{}", gateway_ip_addr.to_string(), grpc_port);
let channel = Endpoint::from_shared(addr)?.connect().await?;
let client = DebianServiceClient::new(channel);
diff --git a/guest/shutdown_runner/Cargo.toml b/guest/shutdown_runner/Cargo.toml
index 0b44baa..92f8762 100644
--- a/guest/shutdown_runner/Cargo.toml
+++ b/guest/shutdown_runner/Cargo.toml
@@ -7,6 +7,7 @@
[dependencies]
anyhow = "1.0.94"
clap = { version = "4.5.20", features = ["derive"] }
+env_logger = "0.11.5"
log = "0.4.22"
netdev = "0.31.0"
prost = "0.13.3"
diff --git a/guest/shutdown_runner/debian/service b/guest/shutdown_runner/debian/service
index 2668930..a5249d0 100644
--- a/guest/shutdown_runner/debian/service
+++ b/guest/shutdown_runner/debian/service
@@ -4,7 +4,7 @@
After=virtiofs_internal.service
[Service]
-ExecStart=/usr/bin/bash -c '/usr/bin/shutdown_runner --grpc_port $(cat /mnt/internal/debian_service_port)'
+ExecStart=/usr/bin/bash -c '/usr/bin/shutdown_runner --grpc-port-file /mnt/internal/debian_service_port'
Type=simple
Restart=on-failure
RestartSec=1
diff --git a/guest/shutdown_runner/src/main.rs b/guest/shutdown_runner/src/main.rs
index 19e9883..4043002 100644
--- a/guest/shutdown_runner/src/main.rs
+++ b/guest/shutdown_runner/src/main.rs
@@ -1,3 +1,17 @@
+// Copyright 2024 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.
+
use api::debian_service_client::DebianServiceClient;
use api::ShutdownQueueOpeningRequest;
use std::process::Command;
@@ -12,18 +26,28 @@
#[derive(Parser)]
/// Flags for running command
pub struct Args {
- /// grpc port number
+ /// Path to a file where grpc port number is written
#[arg(long)]
- #[arg(alias = "grpc_port")]
- grpc_port: String,
+ grpc_port_file: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ env_logger::builder().filter_level(log::LevelFilter::Debug).init();
let args = Args::parse();
let gateway_ip_addr = netdev::get_default_gateway()?.ipv4[0];
- let server_addr = format!("http://{}:{}", gateway_ip_addr.to_string(), args.grpc_port);
+ // Wait for `grpc_port_file` becomes available.
+ const GRPC_PORT_MAX_RETRY_COUNT: u32 = 10;
+ for _ in 0..GRPC_PORT_MAX_RETRY_COUNT {
+ if std::path::Path::new(&args.grpc_port_file).exists() {
+ break;
+ }
+ debug!("{} does not exist. Wait 1 second", args.grpc_port_file);
+ tokio::time::sleep(std::time::Duration::from_secs(1)).await;
+ }
+ let grpc_port = std::fs::read_to_string(&args.grpc_port_file)?.trim().to_string();
+ let server_addr = format!("http://{}:{}", gateway_ip_addr.to_string(), grpc_port);
debug!("connect to grpc server {}", server_addr);