blob: eabb4cc090dc9a0116fc9b988e5d4c3e0636ebf2 [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;
18use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
Alan Stokes0d1ef782022-09-27 13:46:35 +010019 DeathReason::DeathReason,
20 IVirtualMachine::IVirtualMachine,
21 VirtualMachineAppConfig::{Payload::Payload, VirtualMachineAppConfig},
22 VirtualMachineConfig::VirtualMachineConfig,
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000023};
24use android_system_virtualizationservice::binder::{Status, Strong};
25use anyhow::{anyhow, Result};
Alan Stokes0d1ef782022-09-27 13:46:35 +010026use binder::{ParcelFileDescriptor, ThreadState};
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000027use log::{trace, warn};
28use microdroid_payload_config::VmPayloadConfig;
Seungjae Yoodd91f0f2022-11-09 15:25:21 +090029use statslog_virtualization_rust::{vm_booted, vm_creation_requested, vm_exited};
Seungjae Yoo2e7beea2022-08-24 16:09:12 +090030use std::time::{Duration, SystemTime};
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000031use zip::ZipArchive;
32
Alan Stokes0d1ef782022-09-27 13:46:35 +010033fn get_apex_list(config: &VirtualMachineAppConfig) -> String {
34 match &config.payload {
35 Payload::PayloadConfig(_) => String::new(),
36 Payload::ConfigPath(config_path) => {
37 let vm_payload_config = get_vm_payload_config(&config.apk, config_path);
38 if let Ok(vm_payload_config) = vm_payload_config {
39 vm_payload_config
40 .apexes
41 .iter()
42 .map(|x| x.name.clone())
43 .collect::<Vec<String>>()
44 .join(":")
45 } else {
46 "INFO: Can't get VmPayloadConfig".to_owned()
47 }
48 }
49 }
50}
51
52fn get_vm_payload_config(
53 apk_fd: &Option<ParcelFileDescriptor>,
54 config_path: &str,
55) -> Result<VmPayloadConfig> {
56 let apk = apk_fd.as_ref().ok_or_else(|| anyhow!("APK is none"))?;
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000057 let apk_file = clone_file(apk)?;
58 let mut apk_zip = ZipArchive::new(&apk_file)?;
Alan Stokes0d1ef782022-09-27 13:46:35 +010059 let config_file = apk_zip.by_name(config_path)?;
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000060 let vm_payload_config: VmPayloadConfig = serde_json::from_reader(config_file)?;
61 Ok(vm_payload_config)
62}
63
Seungjae Yoo2e7beea2022-08-24 16:09:12 +090064fn get_duration(vm_start_timestamp: Option<SystemTime>) -> Duration {
65 match vm_start_timestamp {
66 Some(vm_start_timestamp) => vm_start_timestamp.elapsed().unwrap_or_default(),
67 None => Duration::default(),
68 }
69}
70
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000071/// Write the stats of VMCreation to statsd
72pub fn write_vm_creation_stats(
73 config: &VirtualMachineConfig,
74 is_protected: bool,
75 ret: &binder::Result<Strong<dyn IVirtualMachine>>,
76) {
77 let creation_succeeded;
78 let binder_exception_code;
79 match ret {
80 Ok(_) => {
81 creation_succeeded = true;
82 binder_exception_code = Status::ok().exception_code() as i32;
83 }
84 Err(ref e) => {
85 creation_succeeded = false;
86 binder_exception_code = e.exception_code() as i32;
87 }
88 }
89
Alan Stokes0d1ef782022-09-27 13:46:35 +010090 let (vm_identifier, config_type, num_cpus, memory_mib, apexes) = match config {
91 VirtualMachineConfig::AppConfig(config) => (
92 &config.name,
93 vm_creation_requested::ConfigType::VirtualMachineAppConfig,
94 config.numCpus,
95 config.memoryMib,
96 get_apex_list(config),
97 ),
98 VirtualMachineConfig::RawConfig(config) => (
99 &config.name,
100 vm_creation_requested::ConfigType::VirtualMachineRawConfig,
101 config.numCpus,
102 config.memoryMib,
103 String::new(),
104 ),
105 };
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000106
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000107 let vm_creation_requested = vm_creation_requested::VmCreationRequested {
Seungjae Yoo62085c02022-08-12 04:44:52 +0000108 uid: ThreadState::get_calling_uid() as i32,
109 vm_identifier,
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000110 hypervisor: vm_creation_requested::Hypervisor::Pkvm,
111 is_protected,
112 creation_succeeded,
113 binder_exception_code,
114 config_type,
115 num_cpus,
Victor Hsiehf219cd82022-09-09 13:13:11 -0700116 cpu_affinity: "", // deprecated
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000117 memory_mib,
118 apexes: &apexes,
119 // TODO(seungjaeyoo) Fill information about task_profile
120 // TODO(seungjaeyoo) Fill information about disk_image for raw config
121 };
122
123 match vm_creation_requested.stats_write() {
124 Err(e) => {
125 warn!("statslog_rust failed with error: {}", e);
126 }
127 Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
128 }
129}
Seungjae Yooacf559a2022-08-12 04:44:51 +0000130
131/// Write the stats of VM boot to statsd
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900132pub fn write_vm_booted_stats(
133 uid: i32,
134 vm_identifier: &String,
135 vm_start_timestamp: Option<SystemTime>,
136) {
137 let duration = get_duration(vm_start_timestamp);
138 let vm_booted = vm_booted::VmBooted {
139 uid,
140 vm_identifier,
141 elapsed_time_millis: duration.as_millis() as i64,
142 };
Seungjae Yooacf559a2022-08-12 04:44:51 +0000143 match vm_booted.stats_write() {
144 Err(e) => {
145 warn!("statslog_rust failed with error: {}", e);
146 }
147 Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
148 }
149}
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000150
151/// Write the stats of VM exit to statsd
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900152pub fn write_vm_exited_stats(
153 uid: i32,
154 vm_identifier: &String,
155 reason: DeathReason,
156 vm_start_timestamp: Option<SystemTime>,
157) {
158 let duration = get_duration(vm_start_timestamp);
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000159 let vm_exited = vm_exited::VmExited {
Seungjae Yoo62085c02022-08-12 04:44:52 +0000160 uid,
161 vm_identifier,
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900162 elapsed_time_millis: duration.as_millis() as i64,
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000163 death_reason: match reason {
164 DeathReason::INFRASTRUCTURE_ERROR => vm_exited::DeathReason::InfrastructureError,
165 DeathReason::KILLED => vm_exited::DeathReason::Killed,
166 DeathReason::UNKNOWN => vm_exited::DeathReason::Unknown,
167 DeathReason::SHUTDOWN => vm_exited::DeathReason::Shutdown,
168 DeathReason::ERROR => vm_exited::DeathReason::Error,
169 DeathReason::REBOOT => vm_exited::DeathReason::Reboot,
170 DeathReason::CRASH => vm_exited::DeathReason::Crash,
171 DeathReason::PVM_FIRMWARE_PUBLIC_KEY_MISMATCH => {
172 vm_exited::DeathReason::PvmFirmwarePublicKeyMismatch
173 }
174 DeathReason::PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED => {
175 vm_exited::DeathReason::PvmFirmwareInstanceImageChanged
176 }
177 DeathReason::BOOTLOADER_PUBLIC_KEY_MISMATCH => {
178 vm_exited::DeathReason::BootloaderPublicKeyMismatch
179 }
180 DeathReason::BOOTLOADER_INSTANCE_IMAGE_CHANGED => {
181 vm_exited::DeathReason::BootloaderInstanceImageChanged
182 }
183 DeathReason::MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE => {
184 vm_exited::DeathReason::MicrodroidFailedToConnectToVirtualizationService
185 }
186 DeathReason::MICRODROID_PAYLOAD_HAS_CHANGED => {
187 vm_exited::DeathReason::MicrodroidPayloadHasChanged
188 }
189 DeathReason::MICRODROID_PAYLOAD_VERIFICATION_FAILED => {
190 vm_exited::DeathReason::MicrodroidPayloadVerificationFailed
191 }
192 DeathReason::MICRODROID_INVALID_PAYLOAD_CONFIG => {
193 vm_exited::DeathReason::MicrodroidInvalidPayloadConfig
194 }
195 DeathReason::MICRODROID_UNKNOWN_RUNTIME_ERROR => {
196 vm_exited::DeathReason::MicrodroidUnknownRuntimeError
197 }
198 DeathReason::HANGUP => vm_exited::DeathReason::Hangup,
199 _ => vm_exited::DeathReason::Unknown,
200 },
201 };
202 match vm_exited.stats_write() {
203 Err(e) => {
204 warn!("statslog_rust failed with error: {}", e);
205 }
206 Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
207 }
208}