Stop VM immediately with stop() call
Rather than waiting GC to drop the handle, immediately stops the VM by
sending signal to crosvm process.
Bug: 207766487
Test: atest MicrodroidTests
Change-Id: I892d8a60238e7156609e21e9939d4e90038c396d
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachine.java b/javalib/src/android/system/virtualmachine/VirtualMachine.java
index 8d74f5e..0ce7991 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachine.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachine.java
@@ -484,8 +484,13 @@
* #run()}.
*/
public void stop() throws VirtualMachineException {
- // Dropping the IVirtualMachine handle stops the VM
- mVirtualMachine = null;
+ if (mVirtualMachine == null) return;
+ try {
+ mVirtualMachine.stop();
+ mVirtualMachine = null;
+ } catch (RemoteException e) {
+ throw new VirtualMachineException(e);
+ }
}
/**
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
index 6f3d4f0..d9d9a61 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
@@ -34,6 +34,13 @@
/** Starts running the VM. */
void start();
+ /**
+ * Stops this virtual machine. Stopping a virtual machine is like pulling the plug on a real
+ * computer; the machine halts immediately. Software running on the virtual machine is not
+ * notified with the event.
+ */
+ void stop();
+
/** Open a vsock connection to the CID of the VM on the given port. */
ParcelFileDescriptor connectVsock(int port);
}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 4135253..0078736 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -823,6 +823,13 @@
})
}
+ fn stop(&self) -> binder::Result<()> {
+ self.instance.kill().map_err(|e| {
+ error!("Error stopping VM with CID {}: {:?}", self.instance.cid, e);
+ new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, e.to_string())
+ })
+ }
+
fn connectVsock(&self, port: i32) -> binder::Result<ParcelFileDescriptor> {
if !matches!(&*self.instance.vm_state.lock().unwrap(), VmState::Running { .. }) {
return Err(new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, "VM is not running"));
@@ -841,7 +848,9 @@
impl Drop for VirtualMachine {
fn drop(&mut self) {
debug!("Dropping {:?}", self);
- self.instance.kill();
+ if let Err(e) = self.instance.kill() {
+ debug!("Error stopping dropped VM with CID {}: {:?}", self.instance.cid, e);
+ }
}
}
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index 46ad6b3..b6e62fe 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -241,7 +241,9 @@
"Microdroid failed to start payload within {} secs timeout. Shutting down",
BOOT_HANGUP_TIMEOUT.as_secs()
);
- self.kill();
+ if let Err(e) = self.kill() {
+ error!("Error stopping timed-out VM with CID {}: {:?}", self.cid, e);
+ }
true
} else {
false
@@ -304,15 +306,19 @@
}
/// Kills the crosvm instance, if it is running.
- pub fn kill(&self) {
+ pub fn kill(&self) -> Result<(), Error> {
let vm_state = &*self.vm_state.lock().unwrap();
if let VmState::Running { child } = vm_state {
let id = child.id();
debug!("Killing crosvm({})", id);
// TODO: Talk to crosvm to shutdown cleanly.
if let Err(e) = child.kill() {
- error!("Error killing crosvm({}) instance: {}", id, e);
+ bail!("Error killing crosvm({}) instance: {}", id, e);
+ } else {
+ Ok(())
}
+ } else {
+ bail!("VM is not running")
}
}