blob: 20f88e768860a3ee52bdecb75e21205f9a891aa6 [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;
Shikha Panwarc93a42b2022-11-09 14:12:25 +000029use rustutils::system_properties;
Seungjae Yoodd91f0f2022-11-09 15:25:21 +090030use statslog_virtualization_rust::{vm_booted, vm_creation_requested, vm_exited};
Shikha Panwarc93a42b2022-11-09 14:12:25 +000031use std::thread;
Seungjae Yoo2e7beea2022-08-24 16:09:12 +090032use std::time::{Duration, SystemTime};
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000033use zip::ZipArchive;
34
Alan Stokes0d1ef782022-09-27 13:46:35 +010035fn get_apex_list(config: &VirtualMachineAppConfig) -> String {
36 match &config.payload {
37 Payload::PayloadConfig(_) => String::new(),
38 Payload::ConfigPath(config_path) => {
39 let vm_payload_config = get_vm_payload_config(&config.apk, config_path);
40 if let Ok(vm_payload_config) = vm_payload_config {
41 vm_payload_config
42 .apexes
43 .iter()
44 .map(|x| x.name.clone())
45 .collect::<Vec<String>>()
46 .join(":")
47 } else {
48 "INFO: Can't get VmPayloadConfig".to_owned()
49 }
50 }
51 }
52}
53
54fn get_vm_payload_config(
55 apk_fd: &Option<ParcelFileDescriptor>,
56 config_path: &str,
57) -> Result<VmPayloadConfig> {
58 let apk = apk_fd.as_ref().ok_or_else(|| anyhow!("APK is none"))?;
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000059 let apk_file = clone_file(apk)?;
60 let mut apk_zip = ZipArchive::new(&apk_file)?;
Alan Stokes0d1ef782022-09-27 13:46:35 +010061 let config_file = apk_zip.by_name(config_path)?;
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000062 let vm_payload_config: VmPayloadConfig = serde_json::from_reader(config_file)?;
63 Ok(vm_payload_config)
64}
65
Seungjae Yoo2e7beea2022-08-24 16:09:12 +090066fn get_duration(vm_start_timestamp: Option<SystemTime>) -> Duration {
67 match vm_start_timestamp {
68 Some(vm_start_timestamp) => vm_start_timestamp.elapsed().unwrap_or_default(),
69 None => Duration::default(),
70 }
71}
72
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000073/// Write the stats of VMCreation to statsd
74pub fn write_vm_creation_stats(
75 config: &VirtualMachineConfig,
76 is_protected: bool,
77 ret: &binder::Result<Strong<dyn IVirtualMachine>>,
78) {
79 let creation_succeeded;
80 let binder_exception_code;
81 match ret {
82 Ok(_) => {
83 creation_succeeded = true;
84 binder_exception_code = Status::ok().exception_code() as i32;
85 }
86 Err(ref e) => {
87 creation_succeeded = false;
88 binder_exception_code = e.exception_code() as i32;
89 }
90 }
Alan Stokes0d1ef782022-09-27 13:46:35 +010091 let (vm_identifier, config_type, num_cpus, memory_mib, apexes) = match config {
92 VirtualMachineConfig::AppConfig(config) => (
Shikha Panwarc93a42b2022-11-09 14:12:25 +000093 config.name.clone(),
Alan Stokes0d1ef782022-09-27 13:46:35 +010094 vm_creation_requested::ConfigType::VirtualMachineAppConfig,
95 config.numCpus,
96 config.memoryMib,
97 get_apex_list(config),
98 ),
99 VirtualMachineConfig::RawConfig(config) => (
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000100 config.name.clone(),
Alan Stokes0d1ef782022-09-27 13:46:35 +0100101 vm_creation_requested::ConfigType::VirtualMachineRawConfig,
102 config.numCpus,
103 config.memoryMib,
104 String::new(),
105 ),
106 };
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000107
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000108 let uid = ThreadState::get_calling_uid() as i32;
109 thread::spawn(move || {
110 let vm_creation_requested = vm_creation_requested::VmCreationRequested {
111 uid,
112 vm_identifier: &vm_identifier,
113 hypervisor: vm_creation_requested::Hypervisor::Pkvm,
114 is_protected,
115 creation_succeeded,
116 binder_exception_code,
117 config_type,
118 num_cpus,
119 cpu_affinity: "", // deprecated
120 memory_mib,
121 apexes: &apexes,
122 // TODO(seungjaeyoo) Fill information about task_profile
123 // TODO(seungjaeyoo) Fill information about disk_image for raw config
124 };
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000125
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000126 wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
127 match vm_creation_requested.stats_write() {
128 Err(e) => {
129 warn!("statslog_rust failed with error: {}", e);
130 }
131 Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000132 }
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000133 });
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000134}
Seungjae Yooacf559a2022-08-12 04:44:51 +0000135
136/// Write the stats of VM boot to statsd
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000137/// The function creates a separate thread which waits fro statsd to start to push atom
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900138pub fn write_vm_booted_stats(
139 uid: i32,
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000140 vm_identifier: &str,
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900141 vm_start_timestamp: Option<SystemTime>,
142) {
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000143 let vm_identifier = vm_identifier.to_owned();
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900144 let duration = get_duration(vm_start_timestamp);
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000145 thread::spawn(move || {
146 let vm_booted = vm_booted::VmBooted {
147 uid,
148 vm_identifier: &vm_identifier,
149 elapsed_time_millis: duration.as_millis() as i64,
150 };
151 wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
152 match vm_booted.stats_write() {
153 Err(e) => {
154 warn!("statslog_rust failed with error: {}", e);
155 }
156 Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
Seungjae Yooacf559a2022-08-12 04:44:51 +0000157 }
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000158 });
Seungjae Yooacf559a2022-08-12 04:44:51 +0000159}
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000160
161/// Write the stats of VM exit to statsd
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000162/// The function creates a separate thread which waits fro statsd to start to push atom
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900163pub fn write_vm_exited_stats(
164 uid: i32,
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000165 vm_identifier: &str,
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900166 reason: DeathReason,
167 vm_start_timestamp: Option<SystemTime>,
168) {
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000169 let vm_identifier = vm_identifier.to_owned();
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900170 let duration = get_duration(vm_start_timestamp);
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000171 thread::spawn(move || {
172 let vm_exited = vm_exited::VmExited {
173 uid,
174 vm_identifier: &vm_identifier,
175 elapsed_time_millis: duration.as_millis() as i64,
176 death_reason: match reason {
177 DeathReason::INFRASTRUCTURE_ERROR => vm_exited::DeathReason::InfrastructureError,
178 DeathReason::KILLED => vm_exited::DeathReason::Killed,
179 DeathReason::UNKNOWN => vm_exited::DeathReason::Unknown,
180 DeathReason::SHUTDOWN => vm_exited::DeathReason::Shutdown,
181 DeathReason::ERROR => vm_exited::DeathReason::Error,
182 DeathReason::REBOOT => vm_exited::DeathReason::Reboot,
183 DeathReason::CRASH => vm_exited::DeathReason::Crash,
184 DeathReason::PVM_FIRMWARE_PUBLIC_KEY_MISMATCH => {
185 vm_exited::DeathReason::PvmFirmwarePublicKeyMismatch
186 }
187 DeathReason::PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED => {
188 vm_exited::DeathReason::PvmFirmwareInstanceImageChanged
189 }
190 DeathReason::BOOTLOADER_PUBLIC_KEY_MISMATCH => {
191 vm_exited::DeathReason::BootloaderPublicKeyMismatch
192 }
193 DeathReason::BOOTLOADER_INSTANCE_IMAGE_CHANGED => {
194 vm_exited::DeathReason::BootloaderInstanceImageChanged
195 }
196 DeathReason::MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE => {
197 vm_exited::DeathReason::MicrodroidFailedToConnectToVirtualizationService
198 }
199 DeathReason::MICRODROID_PAYLOAD_HAS_CHANGED => {
200 vm_exited::DeathReason::MicrodroidPayloadHasChanged
201 }
202 DeathReason::MICRODROID_PAYLOAD_VERIFICATION_FAILED => {
203 vm_exited::DeathReason::MicrodroidPayloadVerificationFailed
204 }
205 DeathReason::MICRODROID_INVALID_PAYLOAD_CONFIG => {
206 vm_exited::DeathReason::MicrodroidInvalidPayloadConfig
207 }
208 DeathReason::MICRODROID_UNKNOWN_RUNTIME_ERROR => {
209 vm_exited::DeathReason::MicrodroidUnknownRuntimeError
210 }
211 DeathReason::HANGUP => vm_exited::DeathReason::Hangup,
212 _ => vm_exited::DeathReason::Unknown,
213 },
214 };
215 wait_for_statsd().unwrap_or_else(|e| warn!("failed to wait for statsd with error: {}", e));
216 match vm_exited.stats_write() {
217 Err(e) => {
218 warn!("statslog_rust failed with error: {}", e);
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000219 }
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000220 Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000221 }
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000222 });
223}
224
225fn wait_for_statsd() -> Result<()> {
226 let mut prop = system_properties::PropertyWatcher::new("init.svc.statsd")?;
227 loop {
228 prop.wait()?;
229 match system_properties::read("init.svc.statsd")? {
230 Some(s) => {
231 if s == "running" {
232 break;
233 }
234 }
235 None => {
236 // This case never really happens because
237 // prop.wait() waits for property to be non-null.
238 break;
239 }
240 }
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000241 }
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000242 Ok(())
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000243}