blob: 84964fd17d77731b6fa511a58513b3b791731fcc [file] [log] [blame]
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +00001// Copyright 2022, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Functions for creating and collecting atoms.
16
17use crate::aidl::clone_file;
Seungjae Yoo6d265d92022-11-15 10:51:33 +090018use crate::crosvm::VmMetric;
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000019use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
Alan Stokes0d1ef782022-09-27 13:46:35 +010020 DeathReason::DeathReason,
21 IVirtualMachine::IVirtualMachine,
22 VirtualMachineAppConfig::{Payload::Payload, VirtualMachineAppConfig},
23 VirtualMachineConfig::VirtualMachineConfig,
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000024};
25use android_system_virtualizationservice::binder::{Status, Strong};
26use anyhow::{anyhow, Result};
Alan Stokes0d1ef782022-09-27 13:46:35 +010027use binder::{ParcelFileDescriptor, ThreadState};
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000028use log::{trace, warn};
29use microdroid_payload_config::VmPayloadConfig;
Shikha Panwarc93a42b2022-11-09 14:12:25 +000030use rustutils::system_properties;
Seungjae Yoodd91f0f2022-11-09 15:25:21 +090031use statslog_virtualization_rust::{vm_booted, vm_creation_requested, vm_exited};
Shikha Panwarc93a42b2022-11-09 14:12:25 +000032use std::thread;
Seungjae Yoo2e7beea2022-08-24 16:09:12 +090033use std::time::{Duration, SystemTime};
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000034use zip::ZipArchive;
35
Alan Stokes0d1ef782022-09-27 13:46:35 +010036fn get_apex_list(config: &VirtualMachineAppConfig) -> String {
37 match &config.payload {
38 Payload::PayloadConfig(_) => String::new(),
39 Payload::ConfigPath(config_path) => {
40 let vm_payload_config = get_vm_payload_config(&config.apk, config_path);
41 if let Ok(vm_payload_config) = vm_payload_config {
42 vm_payload_config
43 .apexes
44 .iter()
45 .map(|x| x.name.clone())
46 .collect::<Vec<String>>()
47 .join(":")
48 } else {
49 "INFO: Can't get VmPayloadConfig".to_owned()
50 }
51 }
52 }
53}
54
55fn get_vm_payload_config(
56 apk_fd: &Option<ParcelFileDescriptor>,
57 config_path: &str,
58) -> Result<VmPayloadConfig> {
59 let apk = apk_fd.as_ref().ok_or_else(|| anyhow!("APK is none"))?;
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000060 let apk_file = clone_file(apk)?;
61 let mut apk_zip = ZipArchive::new(&apk_file)?;
Alan Stokes0d1ef782022-09-27 13:46:35 +010062 let config_file = apk_zip.by_name(config_path)?;
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000063 let vm_payload_config: VmPayloadConfig = serde_json::from_reader(config_file)?;
64 Ok(vm_payload_config)
65}
66
Seungjae Yoo2e7beea2022-08-24 16:09:12 +090067fn get_duration(vm_start_timestamp: Option<SystemTime>) -> Duration {
68 match vm_start_timestamp {
69 Some(vm_start_timestamp) => vm_start_timestamp.elapsed().unwrap_or_default(),
70 None => Duration::default(),
71 }
72}
73
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000074/// Write the stats of VMCreation to statsd
75pub fn write_vm_creation_stats(
76 config: &VirtualMachineConfig,
77 is_protected: bool,
78 ret: &binder::Result<Strong<dyn IVirtualMachine>>,
79) {
80 let creation_succeeded;
81 let binder_exception_code;
82 match ret {
83 Ok(_) => {
84 creation_succeeded = true;
85 binder_exception_code = Status::ok().exception_code() as i32;
86 }
87 Err(ref e) => {
88 creation_succeeded = false;
89 binder_exception_code = e.exception_code() as i32;
90 }
91 }
Alan Stokes0d1ef782022-09-27 13:46:35 +010092 let (vm_identifier, config_type, num_cpus, memory_mib, apexes) = match config {
93 VirtualMachineConfig::AppConfig(config) => (
Shikha Panwarc93a42b2022-11-09 14:12:25 +000094 config.name.clone(),
Alan Stokes0d1ef782022-09-27 13:46:35 +010095 vm_creation_requested::ConfigType::VirtualMachineAppConfig,
96 config.numCpus,
97 config.memoryMib,
98 get_apex_list(config),
99 ),
100 VirtualMachineConfig::RawConfig(config) => (
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000101 config.name.clone(),
Alan Stokes0d1ef782022-09-27 13:46:35 +0100102 vm_creation_requested::ConfigType::VirtualMachineRawConfig,
103 config.numCpus,
104 config.memoryMib,
105 String::new(),
106 ),
107 };
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000108
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000109 let uid = ThreadState::get_calling_uid() as i32;
110 thread::spawn(move || {
111 let vm_creation_requested = vm_creation_requested::VmCreationRequested {
112 uid,
113 vm_identifier: &vm_identifier,
114 hypervisor: vm_creation_requested::Hypervisor::Pkvm,
115 is_protected,
116 creation_succeeded,
117 binder_exception_code,
118 config_type,
119 num_cpus,
120 cpu_affinity: "", // deprecated
121 memory_mib,
122 apexes: &apexes,
123 // TODO(seungjaeyoo) Fill information about task_profile
124 // TODO(seungjaeyoo) Fill information about disk_image for raw config
125 };
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000126
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000127 wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
128 match vm_creation_requested.stats_write() {
129 Err(e) => {
130 warn!("statslog_rust failed with error: {}", e);
131 }
132 Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000133 }
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000134 });
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000135}
Seungjae Yooacf559a2022-08-12 04:44:51 +0000136
137/// Write the stats of VM boot to statsd
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000138/// The function creates a separate thread which waits fro statsd to start to push atom
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900139pub fn write_vm_booted_stats(
140 uid: i32,
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000141 vm_identifier: &str,
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900142 vm_start_timestamp: Option<SystemTime>,
143) {
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000144 let vm_identifier = vm_identifier.to_owned();
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900145 let duration = get_duration(vm_start_timestamp);
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000146 thread::spawn(move || {
147 let vm_booted = vm_booted::VmBooted {
148 uid,
149 vm_identifier: &vm_identifier,
150 elapsed_time_millis: duration.as_millis() as i64,
151 };
152 wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
153 match vm_booted.stats_write() {
154 Err(e) => {
155 warn!("statslog_rust failed with error: {}", e);
156 }
157 Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
Seungjae Yooacf559a2022-08-12 04:44:51 +0000158 }
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000159 });
Seungjae Yooacf559a2022-08-12 04:44:51 +0000160}
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000161
162/// Write the stats of VM exit to statsd
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000163/// The function creates a separate thread which waits fro statsd to start to push atom
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900164pub fn write_vm_exited_stats(
165 uid: i32,
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000166 vm_identifier: &str,
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900167 reason: DeathReason,
Seungjae Yoo93430e82022-12-05 16:37:42 +0900168 exit_signal: Option<i32>,
Seungjae Yoo6d265d92022-11-15 10:51:33 +0900169 vm_metric: &VmMetric,
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900170) {
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000171 let vm_identifier = vm_identifier.to_owned();
Seungjae Yoo6d265d92022-11-15 10:51:33 +0900172 let elapsed_time_millis = get_duration(vm_metric.start_timestamp).as_millis() as i64;
173 let guest_time_millis = vm_metric.cpu_guest_time.unwrap_or_default();
174 let rss = vm_metric.rss.unwrap_or_default();
175
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000176 thread::spawn(move || {
177 let vm_exited = vm_exited::VmExited {
178 uid,
179 vm_identifier: &vm_identifier,
Seungjae Yoo6d265d92022-11-15 10:51:33 +0900180 elapsed_time_millis,
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000181 death_reason: match reason {
182 DeathReason::INFRASTRUCTURE_ERROR => vm_exited::DeathReason::InfrastructureError,
183 DeathReason::KILLED => vm_exited::DeathReason::Killed,
184 DeathReason::UNKNOWN => vm_exited::DeathReason::Unknown,
185 DeathReason::SHUTDOWN => vm_exited::DeathReason::Shutdown,
186 DeathReason::ERROR => vm_exited::DeathReason::Error,
187 DeathReason::REBOOT => vm_exited::DeathReason::Reboot,
188 DeathReason::CRASH => vm_exited::DeathReason::Crash,
189 DeathReason::PVM_FIRMWARE_PUBLIC_KEY_MISMATCH => {
190 vm_exited::DeathReason::PvmFirmwarePublicKeyMismatch
191 }
192 DeathReason::PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED => {
193 vm_exited::DeathReason::PvmFirmwareInstanceImageChanged
194 }
195 DeathReason::BOOTLOADER_PUBLIC_KEY_MISMATCH => {
196 vm_exited::DeathReason::BootloaderPublicKeyMismatch
197 }
198 DeathReason::BOOTLOADER_INSTANCE_IMAGE_CHANGED => {
199 vm_exited::DeathReason::BootloaderInstanceImageChanged
200 }
201 DeathReason::MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE => {
202 vm_exited::DeathReason::MicrodroidFailedToConnectToVirtualizationService
203 }
204 DeathReason::MICRODROID_PAYLOAD_HAS_CHANGED => {
205 vm_exited::DeathReason::MicrodroidPayloadHasChanged
206 }
207 DeathReason::MICRODROID_PAYLOAD_VERIFICATION_FAILED => {
208 vm_exited::DeathReason::MicrodroidPayloadVerificationFailed
209 }
210 DeathReason::MICRODROID_INVALID_PAYLOAD_CONFIG => {
211 vm_exited::DeathReason::MicrodroidInvalidPayloadConfig
212 }
213 DeathReason::MICRODROID_UNKNOWN_RUNTIME_ERROR => {
214 vm_exited::DeathReason::MicrodroidUnknownRuntimeError
215 }
216 DeathReason::HANGUP => vm_exited::DeathReason::Hangup,
217 _ => vm_exited::DeathReason::Unknown,
218 },
Seungjae Yoo6d265d92022-11-15 10:51:33 +0900219 guest_time_millis,
220 rss_vm_kb: rss.vm,
221 rss_crosvm_kb: rss.crosvm,
Seungjae Yoo93430e82022-12-05 16:37:42 +0900222 exit_signal: exit_signal.unwrap_or_default(),
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000223 };
224 wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
225 match vm_exited.stats_write() {
226 Err(e) => {
227 warn!("statslog_rust failed with error: {}", e);
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000228 }
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000229 Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000230 }
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000231 });
232}
233
234fn wait_for_statsd() -> Result<()> {
235 let mut prop = system_properties::PropertyWatcher::new("init.svc.statsd")?;
236 loop {
237 prop.wait()?;
238 match system_properties::read("init.svc.statsd")? {
239 Some(s) => {
240 if s == "running" {
241 break;
242 }
243 }
244 None => {
245 // This case never really happens because
246 // prop.wait() waits for property to be non-null.
247 break;
248 }
249 }
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000250 }
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000251 Ok(())
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000252}