Gracefully stop the vm
Bug: 381815559
Test: click 'close' in the notification
Change-Id: Ic000bb7e62b5e5ec39b3c89b9cd9a05aee17588b
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.java b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.java
index d167da3..9cf6093 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.java
@@ -30,6 +30,8 @@
import com.android.virtualization.terminal.proto.ReportVmActivePortsRequest;
import com.android.virtualization.terminal.proto.ReportVmActivePortsResponse;
import com.android.virtualization.terminal.proto.ReportVmIpAddrResponse;
+import com.android.virtualization.terminal.proto.ShutdownQueueOpeningRequest;
+import com.android.virtualization.terminal.proto.ShutdownRequestItem;
import io.grpc.stub.StreamObserver;
@@ -41,6 +43,7 @@
private final PortsStateManager mPortsStateManager;
private PortsStateManager.Listener mPortsStateListener;
private final DebianServiceCallback mCallback;
+ private Runnable mShutdownRunnable;
static {
System.loadLibrary("forwarder_host_jni");
@@ -93,6 +96,28 @@
responseObserver.onCompleted();
}
+ public boolean shutdownDebian() {
+ if (mShutdownRunnable == null) {
+ Log.d(TAG, "mShutdownRunnable is not ready.");
+ return false;
+ }
+ mShutdownRunnable.run();
+ return true;
+ }
+
+ @Override
+ public void openShutdownRequestQueue(
+ ShutdownQueueOpeningRequest request,
+ StreamObserver<ShutdownRequestItem> responseObserver) {
+ Log.d(TAG, "openShutdownRequestQueue");
+ mShutdownRunnable =
+ () -> {
+ responseObserver.onNext(ShutdownRequestItem.newBuilder().build());
+ responseObserver.onCompleted();
+ mShutdownRunnable = null;
+ };
+ }
+
@Keep
private static class ForwarderHostCallback {
private StreamObserver<ForwardingRequestItem> mResponseObserver;
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.java b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.java
index ee2a6b8..6d2c5bd 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.java
@@ -54,7 +54,6 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
-import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -144,7 +143,10 @@
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Objects.equals(intent.getAction(), ACTION_STOP_VM_LAUNCHER_SERVICE)) {
- stopSelf();
+ // If there is no Debian service or it fails to shutdown, just stop the service.
+ if (mDebianService == null || !mDebianService.shutdownDebian()) {
+ stopSelf();
+ }
return START_NOT_STICKY;
}
if (mVirtualMachine != null) {
@@ -293,7 +295,8 @@
public static void stop(Context context) {
Intent i = getMyIntent(context);
- context.stopService(i);
+ i.setAction(VmLauncherService.ACTION_STOP_VM_LAUNCHER_SERVICE);
+ context.startService(i);
}
@Override
diff --git a/build/debian/build.sh b/build/debian/build.sh
index 9104adc..19894c2 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -192,6 +192,7 @@
build_rust_binary_and_copy forwarder_guest
build_rust_binary_and_copy forwarder_guest_launcher
build_rust_binary_and_copy ip_addr_reporter
+ build_rust_binary_and_copy shutdown_runner
}
run_fai() {
diff --git a/build/debian/fai_config/files/etc/systemd/system/shutdown_runner.service/AVF b/build/debian/fai_config/files/etc/systemd/system/shutdown_runner.service/AVF
new file mode 100644
index 0000000..bfb8afb
--- /dev/null
+++ b/build/debian/fai_config/files/etc/systemd/system/shutdown_runner.service/AVF
@@ -0,0 +1,11 @@
+[Unit]
+After=syslog.target
+After=network.target
+After=virtiofs_internal.service
+[Service]
+ExecStart=/usr/bin/bash -c '/usr/local/bin/shutdown_runner --grpc_port $(cat /mnt/internal/debian_service_port)'
+Type=simple
+User=root
+Group=root
+[Install]
+WantedBy=multi-user.target
diff --git a/build/debian/fai_config/scripts/AVF/10-systemd b/build/debian/fai_config/scripts/AVF/10-systemd
index 94838bc..119bec7 100755
--- a/build/debian/fai_config/scripts/AVF/10-systemd
+++ b/build/debian/fai_config/scripts/AVF/10-systemd
@@ -3,6 +3,7 @@
chmod +x $target/usr/local/bin/forwarder_guest
chmod +x $target/usr/local/bin/forwarder_guest_launcher
chmod +x $target/usr/local/bin/ip_addr_reporter
+chmod +x $target/usr/local/bin/shutdown_runner
chmod +x $target/usr/local/bin/ttyd
ln -s /etc/systemd/system/ttyd.service $target/etc/systemd/system/multi-user.target.wants/ttyd.service
ln -s /etc/systemd/system/ip_addr_reporter.service $target/etc/systemd/system/multi-user.target.wants/ip_addr_reporter.service
@@ -10,5 +11,6 @@
ln -s /etc/systemd/system/forwarder_guest_launcher.service $target/etc/systemd/system/multi-user.target.wants/forwarder_guest_launcher.service
ln -s /etc/systemd/system/virtiofs_internal.service $target/etc/systemd/system/multi-user.target.wants/virtiofs_internal.service
ln -s /etc/systemd/system/backup_mount.service $target/etc/systemd/system/multi-user.target.wants/backup_mount.service
+ln -s /etc/systemd/system/shutdown_runner.service $target/etc/systemd/system/multi-user.target.wants/shutdown_runner.service
sed -i 's/#LLMNR=yes/LLMNR=no/' $target/etc/systemd/resolved.conf
diff --git a/guest/shutdown_runner/.gitignore b/guest/shutdown_runner/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/guest/shutdown_runner/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/guest/shutdown_runner/Cargo.toml b/guest/shutdown_runner/Cargo.toml
new file mode 100644
index 0000000..b74e7ee
--- /dev/null
+++ b/guest/shutdown_runner/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "shutdown_runner"
+version = "0.1.0"
+edition = "2021"
+license = "Apache-2.0"
+
+[dependencies]
+anyhow = "1.0.94"
+clap = { version = "4.5.20", features = ["derive"] }
+log = "0.4.22"
+netdev = "0.31.0"
+prost = "0.13.3"
+tokio = { version = "1.40.0", features = ["rt-multi-thread"] }
+tonic = "0.12.3"
+
+[build-dependencies]
+tonic-build = "0.12.3"
diff --git a/guest/shutdown_runner/build.rs b/guest/shutdown_runner/build.rs
new file mode 100644
index 0000000..e3939d4
--- /dev/null
+++ b/guest/shutdown_runner/build.rs
@@ -0,0 +1,7 @@
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let proto_file = "../../libs/debian_service/proto/DebianService.proto";
+
+ tonic_build::compile_protos(proto_file).unwrap();
+
+ Ok(())
+}
diff --git a/guest/shutdown_runner/src/main.rs b/guest/shutdown_runner/src/main.rs
new file mode 100644
index 0000000..19e9883
--- /dev/null
+++ b/guest/shutdown_runner/src/main.rs
@@ -0,0 +1,46 @@
+use api::debian_service_client::DebianServiceClient;
+use api::ShutdownQueueOpeningRequest;
+use std::process::Command;
+
+use anyhow::anyhow;
+use clap::Parser;
+use log::debug;
+pub mod api {
+ tonic::include_proto!("com.android.virtualization.terminal.proto");
+}
+
+#[derive(Parser)]
+/// Flags for running command
+pub struct Args {
+ /// grpc port number
+ #[arg(long)]
+ #[arg(alias = "grpc_port")]
+ grpc_port: String,
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ 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);
+
+ debug!("connect to grpc server {}", server_addr);
+
+ let mut client = DebianServiceClient::connect(server_addr).await.map_err(|e| e.to_string())?;
+
+ let mut res_stream = client
+ .open_shutdown_request_queue(tonic::Request::new(ShutdownQueueOpeningRequest {}))
+ .await?
+ .into_inner();
+
+ while let Some(_response) = res_stream.message().await? {
+ let status = Command::new("poweroff").status().expect("power off");
+ if !status.success() {
+ return Err(anyhow!("Failed to power off: {status}").into());
+ }
+ debug!("poweroff");
+ break;
+ }
+ Ok(())
+}
diff --git a/libs/debian_service/proto/DebianService.proto b/libs/debian_service/proto/DebianService.proto
index 61bcece..739f0ac 100644
--- a/libs/debian_service/proto/DebianService.proto
+++ b/libs/debian_service/proto/DebianService.proto
@@ -25,6 +25,7 @@
rpc ReportVmActivePorts (ReportVmActivePortsRequest) returns (ReportVmActivePortsResponse) {}
rpc ReportVmIpAddr (IpAddr) returns (ReportVmIpAddrResponse) {}
rpc OpenForwardingRequestQueue (QueueOpeningRequest) returns (stream ForwardingRequestItem) {}
+ rpc OpenShutdownRequestQueue (ShutdownQueueOpeningRequest) returns (stream ShutdownRequestItem) {}
}
message QueueOpeningRequest {
@@ -51,3 +52,7 @@
int32 guest_tcp_port = 1;
int32 vsock_port = 2;
}
+
+message ShutdownQueueOpeningRequest {}
+
+message ShutdownRequestItem {}
\ No newline at end of file