Send atoms via VirtualizationServiceInternal
In preparation for spliting VS into two services (global and
UID-specific), forward all statsd atoms via
VirtualizationServiceInternal. This is necessary because statsd
will not accept atoms from the client-specific VS instance, as it only
accepts atoms from known UIDs.
Bug: 245727626
Test: atest MicrodroidHostTestCases
Change-Id: I779bbc77a83665a88c9e12d3ad25824e7857514b
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index a35c2ac..3e7eca1 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -14,15 +14,19 @@
//! Implementation of the AIDL interface of the VirtualizationService.
-use crate::atom::{write_vm_booted_stats, write_vm_creation_stats};
+use crate::atom::{
+ forward_vm_booted_atom, forward_vm_creation_atom, forward_vm_exited_atom,
+ write_vm_booted_stats, write_vm_creation_stats};
use crate::composite::make_composite_image;
use crate::crosvm::{CrosvmConfig, DiskFile, PayloadState, VmContext, VmInstance, VmState};
use crate::payload::{add_microdroid_payload_images, add_microdroid_system_images};
use crate::selinux::{getfilecon, SeContext};
use android_os_permissions_aidl::aidl::android::os::IPermissionController;
-use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::ErrorCode::ErrorCode;
-use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
+use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::{
DeathReason::DeathReason,
+ ErrorCode::ErrorCode,
+};
+use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
DiskImage::DiskImage,
IVirtualMachine::{BnVirtualMachine, IVirtualMachine},
IVirtualMachineCallback::IVirtualMachineCallback,
@@ -38,6 +42,9 @@
VirtualMachineState::VirtualMachineState,
};
use android_system_virtualizationservice_internal::aidl::android::system::virtualizationservice_internal::{
+ AtomVmBooted::AtomVmBooted,
+ AtomVmCreationRequested::AtomVmCreationRequested,
+ AtomVmExited::AtomVmExited,
IGlobalVmContext::{BnGlobalVmContext, IGlobalVmContext},
IVirtualizationServiceInternal::{BnVirtualizationServiceInternal, IVirtualizationServiceInternal},
};
@@ -51,6 +58,7 @@
Status, StatusCode, Strong, ThreadState,
};
use disk::QcowFile;
+use lazy_static::lazy_static;
use libc::VMADDR_CID_HOST;
use log::{debug, error, info, warn};
use microdroid_payload_config::{OsConfig, Task, TaskType, VmPayloadConfig};
@@ -102,6 +110,13 @@
const UNFORMATTED_STORAGE_MAGIC: &str = "UNFORMATTED-STORAGE";
+lazy_static! {
+ pub static ref GLOBAL_SERVICE: Strong<dyn IVirtualizationServiceInternal> = {
+ let service = VirtualizationServiceInternal::init();
+ BnVirtualizationServiceInternal::new_binder(service, BinderFeatures::default())
+ };
+}
+
fn is_valid_guest_cid(cid: Cid) -> bool {
(GUEST_CID_MIN..=GUEST_CID_MAX).contains(&cid)
}
@@ -164,6 +179,21 @@
})?;
Ok(GlobalVmContext::create(cid))
}
+
+ fn atomVmBooted(&self, atom: &AtomVmBooted) -> Result<(), Status> {
+ forward_vm_booted_atom(atom);
+ Ok(())
+ }
+
+ fn atomVmCreationRequested(&self, atom: &AtomVmCreationRequested) -> Result<(), Status> {
+ forward_vm_creation_atom(atom);
+ Ok(())
+ }
+
+ fn atomVmExited(&self, atom: &AtomVmExited) -> Result<(), Status> {
+ forward_vm_exited_atom(atom);
+ Ok(())
+ }
}
/// The mutable state of the VirtualizationServiceInternal. There should only be one instance
@@ -257,10 +287,9 @@
}
/// Implementation of `IVirtualizationService`, the entry point of the AIDL service.
-#[derive(Debug)]
+#[derive(Debug, Default)]
pub struct VirtualizationService {
state: Arc<Mutex<State>>,
- global_service: Strong<dyn IVirtualizationServiceInternal>,
}
impl Interface for VirtualizationService {
@@ -461,18 +490,14 @@
impl VirtualizationService {
pub fn init() -> VirtualizationService {
- let global_service = VirtualizationServiceInternal::init();
- let global_service =
- BnVirtualizationServiceInternal::new_binder(global_service, BinderFeatures::default());
-
- VirtualizationService { global_service, state: Default::default() }
+ VirtualizationService::default()
}
fn create_vm_context(&self) -> Result<(VmContext, Cid)> {
const NUM_ATTEMPTS: usize = 5;
for _ in 0..NUM_ATTEMPTS {
- let global_context = self.global_service.allocateGlobalVmContext()?;
+ let global_context = GLOBAL_SERVICE.allocateGlobalVmContext()?;
let cid = global_context.getCid()? as Cid;
let service = VirtualMachineService::new_binder(self.state.clone(), cid).as_binder();
diff --git a/virtualizationservice/src/atom.rs b/virtualizationservice/src/atom.rs
index a880d60..698dbca 100644
--- a/virtualizationservice/src/atom.rs
+++ b/virtualizationservice/src/atom.rs
@@ -14,15 +14,20 @@
//! Functions for creating and collecting atoms.
-use crate::aidl::clone_file;
+use crate::aidl::{clone_file, GLOBAL_SERVICE};
use crate::crosvm::VmMetric;
+use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::DeathReason::DeathReason;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
- DeathReason::DeathReason,
IVirtualMachine::IVirtualMachine,
VirtualMachineAppConfig::{Payload::Payload, VirtualMachineAppConfig},
VirtualMachineConfig::VirtualMachineConfig,
};
use android_system_virtualizationservice::binder::{Status, Strong};
+use android_system_virtualizationservice_internal::aidl::android::system::virtualizationservice_internal::{
+ AtomVmBooted::AtomVmBooted,
+ AtomVmCreationRequested::AtomVmCreationRequested,
+ AtomVmExited::AtomVmExited,
+};
use anyhow::{anyhow, Result};
use binder::{ParcelFileDescriptor, ThreadState};
use log::{trace, warn};
@@ -106,34 +111,58 @@
),
};
- let uid = ThreadState::get_calling_uid() as i32;
- thread::spawn(move || {
- let vm_creation_requested = vm_creation_requested::VmCreationRequested {
- uid,
- vm_identifier: &vm_identifier,
- hypervisor: vm_creation_requested::Hypervisor::Pkvm,
- is_protected,
- creation_succeeded,
- binder_exception_code,
- config_type,
- num_cpus,
- cpu_affinity: "", // deprecated
- memory_mib,
- apexes: &apexes,
- // TODO(seungjaeyoo) Fill information about task_profile
- // TODO(seungjaeyoo) Fill information about disk_image for raw config
- };
+ let atom = AtomVmCreationRequested {
+ uid: ThreadState::get_calling_uid() as i32,
+ vmIdentifier: vm_identifier,
+ isProtected: is_protected,
+ creationSucceeded: creation_succeeded,
+ binderExceptionCode: binder_exception_code,
+ configType: config_type as i32,
+ numCpus: num_cpus,
+ memoryMib: memory_mib,
+ apexes,
+ };
- wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
- match vm_creation_requested.stats_write() {
- Err(e) => {
- warn!("statslog_rust failed with error: {}", e);
- }
- Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
- }
+ thread::spawn(move || {
+ GLOBAL_SERVICE.atomVmCreationRequested(&atom).unwrap_or_else(|e| {
+ warn!("Failed to write VmCreationRequested atom: {e}");
+ });
});
}
+pub fn forward_vm_creation_atom(atom: &AtomVmCreationRequested) {
+ let config_type = match atom.configType {
+ x if x == vm_creation_requested::ConfigType::VirtualMachineAppConfig as i32 => {
+ vm_creation_requested::ConfigType::VirtualMachineAppConfig
+ }
+ x if x == vm_creation_requested::ConfigType::VirtualMachineRawConfig as i32 => {
+ vm_creation_requested::ConfigType::VirtualMachineRawConfig
+ }
+ _ => vm_creation_requested::ConfigType::UnknownConfig,
+ };
+ let vm_creation_requested = vm_creation_requested::VmCreationRequested {
+ uid: atom.uid,
+ vm_identifier: &atom.vmIdentifier,
+ hypervisor: vm_creation_requested::Hypervisor::Pkvm,
+ is_protected: atom.isProtected,
+ creation_succeeded: atom.creationSucceeded,
+ binder_exception_code: atom.binderExceptionCode,
+ config_type,
+ num_cpus: atom.numCpus,
+ cpu_affinity: "", // deprecated
+ memory_mib: atom.memoryMib,
+ apexes: &atom.apexes,
+ // TODO(seungjaeyoo) Fill information about task_profile
+ // TODO(seungjaeyoo) Fill information about disk_image for raw config
+ };
+
+ wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
+ match vm_creation_requested.stats_write() {
+ Err(e) => warn!("statslog_rust failed with error: {}", e),
+ Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
+ }
+}
+
/// Write the stats of VM boot to statsd
/// The function creates a separate thread which waits fro statsd to start to push atom
pub fn write_vm_booted_stats(
@@ -143,22 +172,34 @@
) {
let vm_identifier = vm_identifier.to_owned();
let duration = get_duration(vm_start_timestamp);
+
+ let atom = AtomVmBooted {
+ uid,
+ vmIdentifier: vm_identifier,
+ elapsedTimeMillis: duration.as_millis() as i64,
+ };
+
thread::spawn(move || {
- let vm_booted = vm_booted::VmBooted {
- uid,
- vm_identifier: &vm_identifier,
- elapsed_time_millis: duration.as_millis() as i64,
- };
- wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
- match vm_booted.stats_write() {
- Err(e) => {
- warn!("statslog_rust failed with error: {}", e);
- }
- Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
- }
+ GLOBAL_SERVICE.atomVmBooted(&atom).unwrap_or_else(|e| {
+ warn!("Failed to write VmCreationRequested atom: {e}");
+ });
});
}
+pub fn forward_vm_booted_atom(atom: &AtomVmBooted) {
+ let vm_booted = vm_booted::VmBooted {
+ uid: atom.uid,
+ vm_identifier: &atom.vmIdentifier,
+ elapsed_time_millis: atom.elapsedTimeMillis,
+ };
+
+ wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
+ match vm_booted.stats_write() {
+ Err(e) => warn!("statslog_rust failed with error: {}", e),
+ Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
+ }
+}
+
/// Write the stats of VM exit to statsd
/// The function creates a separate thread which waits fro statsd to start to push atom
pub fn write_vm_exited_stats(
@@ -173,64 +214,82 @@
let guest_time_millis = vm_metric.cpu_guest_time.unwrap_or_default();
let rss = vm_metric.rss.unwrap_or_default();
+ let atom = AtomVmExited {
+ uid,
+ vmIdentifier: vm_identifier,
+ elapsedTimeMillis: elapsed_time_millis,
+ deathReason: reason,
+ guestTimeMillis: guest_time_millis,
+ rssVmKb: rss.vm,
+ rssCrosvmKb: rss.crosvm,
+ exitSignal: exit_signal.unwrap_or_default(),
+ };
+
thread::spawn(move || {
- let vm_exited = vm_exited::VmExited {
- uid,
- vm_identifier: &vm_identifier,
- elapsed_time_millis,
- death_reason: match reason {
- DeathReason::INFRASTRUCTURE_ERROR => vm_exited::DeathReason::InfrastructureError,
- DeathReason::KILLED => vm_exited::DeathReason::Killed,
- DeathReason::UNKNOWN => vm_exited::DeathReason::Unknown,
- DeathReason::SHUTDOWN => vm_exited::DeathReason::Shutdown,
- DeathReason::START_FAILED => vm_exited::DeathReason::Error,
- DeathReason::REBOOT => vm_exited::DeathReason::Reboot,
- DeathReason::CRASH => vm_exited::DeathReason::Crash,
- DeathReason::PVM_FIRMWARE_PUBLIC_KEY_MISMATCH => {
- vm_exited::DeathReason::PvmFirmwarePublicKeyMismatch
- }
- DeathReason::PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED => {
- vm_exited::DeathReason::PvmFirmwareInstanceImageChanged
- }
- DeathReason::BOOTLOADER_PUBLIC_KEY_MISMATCH => {
- vm_exited::DeathReason::BootloaderPublicKeyMismatch
- }
- DeathReason::BOOTLOADER_INSTANCE_IMAGE_CHANGED => {
- vm_exited::DeathReason::BootloaderInstanceImageChanged
- }
- DeathReason::MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE => {
- vm_exited::DeathReason::MicrodroidFailedToConnectToVirtualizationService
- }
- DeathReason::MICRODROID_PAYLOAD_HAS_CHANGED => {
- vm_exited::DeathReason::MicrodroidPayloadHasChanged
- }
- DeathReason::MICRODROID_PAYLOAD_VERIFICATION_FAILED => {
- vm_exited::DeathReason::MicrodroidPayloadVerificationFailed
- }
- DeathReason::MICRODROID_INVALID_PAYLOAD_CONFIG => {
- vm_exited::DeathReason::MicrodroidInvalidPayloadConfig
- }
- DeathReason::MICRODROID_UNKNOWN_RUNTIME_ERROR => {
- vm_exited::DeathReason::MicrodroidUnknownRuntimeError
- }
- DeathReason::HANGUP => vm_exited::DeathReason::Hangup,
- _ => vm_exited::DeathReason::Unknown,
- },
- guest_time_millis,
- rss_vm_kb: rss.vm,
- rss_crosvm_kb: rss.crosvm,
- exit_signal: exit_signal.unwrap_or_default(),
- };
- wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
- match vm_exited.stats_write() {
- Err(e) => {
- warn!("statslog_rust failed with error: {}", e);
- }
- Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
- }
+ GLOBAL_SERVICE.atomVmExited(&atom).unwrap_or_else(|e| {
+ warn!("Failed to write VmExited atom: {e}");
+ });
});
}
+pub fn forward_vm_exited_atom(atom: &AtomVmExited) {
+ let death_reason = match atom.deathReason {
+ DeathReason::INFRASTRUCTURE_ERROR => vm_exited::DeathReason::InfrastructureError,
+ DeathReason::KILLED => vm_exited::DeathReason::Killed,
+ DeathReason::UNKNOWN => vm_exited::DeathReason::Unknown,
+ DeathReason::SHUTDOWN => vm_exited::DeathReason::Shutdown,
+ DeathReason::START_FAILED => vm_exited::DeathReason::Error,
+ DeathReason::REBOOT => vm_exited::DeathReason::Reboot,
+ DeathReason::CRASH => vm_exited::DeathReason::Crash,
+ DeathReason::PVM_FIRMWARE_PUBLIC_KEY_MISMATCH => {
+ vm_exited::DeathReason::PvmFirmwarePublicKeyMismatch
+ }
+ DeathReason::PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED => {
+ vm_exited::DeathReason::PvmFirmwareInstanceImageChanged
+ }
+ DeathReason::BOOTLOADER_PUBLIC_KEY_MISMATCH => {
+ vm_exited::DeathReason::BootloaderPublicKeyMismatch
+ }
+ DeathReason::BOOTLOADER_INSTANCE_IMAGE_CHANGED => {
+ vm_exited::DeathReason::BootloaderInstanceImageChanged
+ }
+ DeathReason::MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE => {
+ vm_exited::DeathReason::MicrodroidFailedToConnectToVirtualizationService
+ }
+ DeathReason::MICRODROID_PAYLOAD_HAS_CHANGED => {
+ vm_exited::DeathReason::MicrodroidPayloadHasChanged
+ }
+ DeathReason::MICRODROID_PAYLOAD_VERIFICATION_FAILED => {
+ vm_exited::DeathReason::MicrodroidPayloadVerificationFailed
+ }
+ DeathReason::MICRODROID_INVALID_PAYLOAD_CONFIG => {
+ vm_exited::DeathReason::MicrodroidInvalidPayloadConfig
+ }
+ DeathReason::MICRODROID_UNKNOWN_RUNTIME_ERROR => {
+ vm_exited::DeathReason::MicrodroidUnknownRuntimeError
+ }
+ DeathReason::HANGUP => vm_exited::DeathReason::Hangup,
+ _ => vm_exited::DeathReason::Unknown,
+ };
+
+ let vm_exited = vm_exited::VmExited {
+ uid: atom.uid,
+ vm_identifier: &atom.vmIdentifier,
+ elapsed_time_millis: atom.elapsedTimeMillis,
+ death_reason,
+ guest_time_millis: atom.guestTimeMillis,
+ rss_vm_kb: atom.rssVmKb,
+ rss_crosvm_kb: atom.rssCrosvmKb,
+ exit_signal: atom.exitSignal,
+ };
+
+ wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
+ match vm_exited.stats_write() {
+ Err(e) => warn!("statslog_rust failed with error: {}", e),
+ Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
+ }
+}
+
fn wait_for_statsd() -> Result<()> {
let mut prop = system_properties::PropertyWatcher::new("init.svc.statsd")?;
loop {
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index 2c6e370..94248f8 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -40,10 +40,8 @@
use std::sync::{Arc, Condvar, Mutex};
use std::time::{Duration, SystemTime};
use std::thread::{self, JoinHandle};
-use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
- DeathReason::DeathReason,
- MemoryTrimLevel::MemoryTrimLevel,
-};
+use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::DeathReason::DeathReason;
+use android_system_virtualizationservice::aidl::android::system::virtualizationservice::MemoryTrimLevel::MemoryTrimLevel;
use android_system_virtualizationservice_internal::aidl::android::system::virtualizationservice_internal::IGlobalVmContext::IGlobalVmContext;
use binder::Strong;
use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::IVirtualMachineService;