Enable exporting of tombstones out of guest VMs
Microdroid init will start the tombstone_transmit service which will
connect to a server (thread of virtualization service).
virtualizationservice listens for incoming connections from guests VMs.
The client (tombstone_transmit in guest) sends each tombstone file
content through a separate stream.
For each received connection, handle_tombstone would send a connect
request to tombstoned(via libtombstoned_client_rust), which provide a
file to write the content in (actually managed by the client libary).
Once write is complete notify_completion() would send completion
notification to tombstoned (which then will close the file and rename it).
Test: atest MicrodroidHostTestCases and/or crash a process in microdroid, take and check bugreport
Bug: 202153827
Change-Id: Ifcaa5da968ef39fdd05612d3e0baca4fd1c5eaf1
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index 9b2b740..7a8da96 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -45,6 +45,7 @@
"libserde_xml_rs",
"libshared_child",
"libstatslog_virtualization_rust",
+ "libtombstoned_client_rust",
"libvmconfig",
"libzip",
"libvsock",
diff --git a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
index 1a16f2a..dff5d46 100644
--- a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
@@ -30,6 +30,12 @@
const int VM_BINDER_SERVICE_PORT = 5000;
/**
+ * Port number that VirtualMachineService listens on connections from the guest VMs for the
+ * tombtones
+ */
+ const int VM_TOMBSTONES_SERVICE_PORT = 2000;
+
+ /**
* Notifies that the payload has started.
*/
void notifyPayloadStarted();
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index d9825dc..73cbcfa 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -42,7 +42,7 @@
use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::{
IVirtualMachineService::{
BnVirtualMachineService, IVirtualMachineService, VM_BINDER_SERVICE_PORT,
- VM_STREAM_SERVICE_PORT,
+ VM_STREAM_SERVICE_PORT, VM_TOMBSTONES_SERVICE_PORT,
},
};
use anyhow::{anyhow, bail, Context, Result};
@@ -57,13 +57,14 @@
use std::convert::TryInto;
use std::ffi::CStr;
use std::fs::{create_dir, File, OpenOptions};
-use std::io::{Error, ErrorKind, Write};
+use std::io::{Error, ErrorKind, Write, Read};
use std::num::NonZeroU32;
use std::os::raw;
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::path::{Path, PathBuf};
use std::ptr::null_mut;
use std::sync::{Arc, Mutex, Weak};
+use tombstoned_client::{TombstonedConnection, DebuggerdDumpType};
use vmconfig::VmConfig;
use vsock::{SockAddr, VsockListener, VsockStream};
use zip::ZipArchive;
@@ -86,6 +87,8 @@
/// Version of the instance image format
const ANDROID_VM_INSTANCE_VERSION: u16 = 1;
+const CHUNK_RECV_MAX_LEN: usize = 1024;
+
/// Implementation of `IVirtualizationService`, the entry point of the AIDL service.
#[derive(Debug, Default)]
pub struct VirtualizationService {
@@ -371,6 +374,55 @@
}
}
+fn handle_stream_connection_tombstoned() -> Result<()> {
+ let listener =
+ VsockListener::bind_with_cid_port(VMADDR_CID_HOST, VM_TOMBSTONES_SERVICE_PORT as u32)?;
+ info!("Listening to tombstones from guests ...");
+ for incoming_stream in listener.incoming() {
+ let mut incoming_stream = match incoming_stream {
+ Err(e) => {
+ warn!("invalid incoming connection: {}", e);
+ continue;
+ }
+ Ok(s) => s,
+ };
+ std::thread::spawn(move || {
+ if let Err(e) = handle_tombstone(&mut incoming_stream) {
+ error!("Failed to write tombstone- {:?}", e);
+ }
+ });
+ }
+ Ok(())
+}
+
+fn handle_tombstone(stream: &mut VsockStream) -> Result<()> {
+ if let Ok(SockAddr::Vsock(addr)) = stream.peer_addr() {
+ info!("Vsock Stream connected to cid={} for tombstones", addr.cid());
+ }
+ let tb_connection =
+ TombstonedConnection::connect(std::process::id() as i32, DebuggerdDumpType::Tombstone)
+ .context("Failed to connect to tombstoned")?;
+ let mut text_output = tb_connection
+ .text_output
+ .as_ref()
+ .ok_or_else(|| anyhow!("Could not get file to write the tombstones on"))?;
+ let mut num_bytes_read = 0;
+ loop {
+ let mut chunk_recv = [0; CHUNK_RECV_MAX_LEN];
+ let n = stream
+ .read(&mut chunk_recv)
+ .context("Failed to read tombstone data from Vsock stream")?;
+ if n == 0 {
+ break;
+ }
+ num_bytes_read += n;
+ text_output.write_all(&chunk_recv[0..n]).context("Failed to write guests tombstones")?;
+ }
+ info!("Received {} bytes from guest & wrote to tombstone file", num_bytes_read);
+ tb_connection.notify_completion()?;
+ Ok(())
+}
+
impl VirtualizationService {
pub fn init() -> VirtualizationService {
let service = VirtualizationService::default();
@@ -381,8 +433,15 @@
handle_stream_connection_from_vm(state).unwrap();
});
+ std::thread::spawn(|| {
+ if let Err(e) = handle_stream_connection_tombstoned() {
+ warn!("Error receiving tombstone from guest or writing them. Error: {}", e);
+ }
+ });
+
// binder server for vm
- let mut state = service.state.clone(); // reference to state (not the state itself) is copied
+ // reference to state (not the state itself) is copied
+ let mut state = service.state.clone();
std::thread::spawn(move || {
let state_ptr = &mut state as *mut _ as *mut raw::c_void;