blob: c33f2620523083e63732b503c18db2682d88654b [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
David Brazdil49f96f52022-12-16 21:29:13 +000017use crate::aidl::{clone_file, GLOBAL_SERVICE};
Seungjae Yoo6d265d92022-11-15 10:51:33 +090018use crate::crosvm::VmMetric;
David Brazdil1f530702022-10-03 12:18:10 +010019use crate::get_calling_uid;
David Brazdil49f96f52022-12-16 21:29:13 +000020use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::DeathReason::DeathReason;
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000021use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
Alan Stokes0d1ef782022-09-27 13:46:35 +010022 IVirtualMachine::IVirtualMachine,
23 VirtualMachineAppConfig::{Payload::Payload, VirtualMachineAppConfig},
24 VirtualMachineConfig::VirtualMachineConfig,
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000025};
26use android_system_virtualizationservice::binder::{Status, Strong};
David Brazdil49f96f52022-12-16 21:29:13 +000027use android_system_virtualizationservice_internal::aidl::android::system::virtualizationservice_internal::{
28 AtomVmBooted::AtomVmBooted,
29 AtomVmCreationRequested::AtomVmCreationRequested,
30 AtomVmExited::AtomVmExited,
31};
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000032use anyhow::{anyhow, Result};
David Brazdil1f530702022-10-03 12:18:10 +010033use binder::ParcelFileDescriptor;
David Brazdilafc9a9e2023-01-12 16:08:10 +000034use log::warn;
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000035use microdroid_payload_config::VmPayloadConfig;
David Brazdilafc9a9e2023-01-12 16:08:10 +000036use statslog_virtualization_rust::vm_creation_requested;
Shikha Panwarc93a42b2022-11-09 14:12:25 +000037use std::thread;
Seungjae Yoo2e7beea2022-08-24 16:09:12 +090038use std::time::{Duration, SystemTime};
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000039use zip::ZipArchive;
40
Alan Stokes0d1ef782022-09-27 13:46:35 +010041fn get_apex_list(config: &VirtualMachineAppConfig) -> String {
42 match &config.payload {
43 Payload::PayloadConfig(_) => String::new(),
44 Payload::ConfigPath(config_path) => {
45 let vm_payload_config = get_vm_payload_config(&config.apk, config_path);
46 if let Ok(vm_payload_config) = vm_payload_config {
47 vm_payload_config
48 .apexes
49 .iter()
50 .map(|x| x.name.clone())
51 .collect::<Vec<String>>()
52 .join(":")
53 } else {
54 "INFO: Can't get VmPayloadConfig".to_owned()
55 }
56 }
57 }
58}
59
60fn get_vm_payload_config(
61 apk_fd: &Option<ParcelFileDescriptor>,
62 config_path: &str,
63) -> Result<VmPayloadConfig> {
64 let apk = apk_fd.as_ref().ok_or_else(|| anyhow!("APK is none"))?;
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000065 let apk_file = clone_file(apk)?;
66 let mut apk_zip = ZipArchive::new(&apk_file)?;
Alan Stokes0d1ef782022-09-27 13:46:35 +010067 let config_file = apk_zip.by_name(config_path)?;
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000068 let vm_payload_config: VmPayloadConfig = serde_json::from_reader(config_file)?;
69 Ok(vm_payload_config)
70}
71
Seungjae Yoo2e7beea2022-08-24 16:09:12 +090072fn get_duration(vm_start_timestamp: Option<SystemTime>) -> Duration {
73 match vm_start_timestamp {
74 Some(vm_start_timestamp) => vm_start_timestamp.elapsed().unwrap_or_default(),
75 None => Duration::default(),
76 }
77}
78
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +000079/// Write the stats of VMCreation to statsd
80pub fn write_vm_creation_stats(
81 config: &VirtualMachineConfig,
82 is_protected: bool,
83 ret: &binder::Result<Strong<dyn IVirtualMachine>>,
84) {
85 let creation_succeeded;
86 let binder_exception_code;
87 match ret {
88 Ok(_) => {
89 creation_succeeded = true;
90 binder_exception_code = Status::ok().exception_code() as i32;
91 }
92 Err(ref e) => {
93 creation_succeeded = false;
94 binder_exception_code = e.exception_code() as i32;
95 }
96 }
Alan Stokes0d1ef782022-09-27 13:46:35 +010097 let (vm_identifier, config_type, num_cpus, memory_mib, apexes) = match config {
98 VirtualMachineConfig::AppConfig(config) => (
Shikha Panwarc93a42b2022-11-09 14:12:25 +000099 config.name.clone(),
Alan Stokes0d1ef782022-09-27 13:46:35 +0100100 vm_creation_requested::ConfigType::VirtualMachineAppConfig,
101 config.numCpus,
102 config.memoryMib,
103 get_apex_list(config),
104 ),
105 VirtualMachineConfig::RawConfig(config) => (
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000106 config.name.clone(),
Alan Stokes0d1ef782022-09-27 13:46:35 +0100107 vm_creation_requested::ConfigType::VirtualMachineRawConfig,
108 config.numCpus,
109 config.memoryMib,
110 String::new(),
111 ),
112 };
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000113
David Brazdil49f96f52022-12-16 21:29:13 +0000114 let atom = AtomVmCreationRequested {
David Brazdil1f530702022-10-03 12:18:10 +0100115 uid: get_calling_uid() as i32,
David Brazdil49f96f52022-12-16 21:29:13 +0000116 vmIdentifier: vm_identifier,
117 isProtected: is_protected,
118 creationSucceeded: creation_succeeded,
119 binderExceptionCode: binder_exception_code,
120 configType: config_type as i32,
121 numCpus: num_cpus,
122 memoryMib: memory_mib,
123 apexes,
124 };
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000125
David Brazdil49f96f52022-12-16 21:29:13 +0000126 thread::spawn(move || {
127 GLOBAL_SERVICE.atomVmCreationRequested(&atom).unwrap_or_else(|e| {
128 warn!("Failed to write VmCreationRequested atom: {e}");
129 });
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000130 });
Seungjae Yoo0a8c84c2022-07-11 08:19:15 +0000131}
Seungjae Yooacf559a2022-08-12 04:44:51 +0000132
133/// Write the stats of VM boot to statsd
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000134/// The function creates a separate thread which waits fro statsd to start to push atom
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900135pub fn write_vm_booted_stats(
136 uid: i32,
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000137 vm_identifier: &str,
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900138 vm_start_timestamp: Option<SystemTime>,
139) {
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000140 let vm_identifier = vm_identifier.to_owned();
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900141 let duration = get_duration(vm_start_timestamp);
David Brazdil49f96f52022-12-16 21:29:13 +0000142
143 let atom = AtomVmBooted {
144 uid,
145 vmIdentifier: vm_identifier,
146 elapsedTimeMillis: duration.as_millis() as i64,
147 };
148
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000149 thread::spawn(move || {
David Brazdil49f96f52022-12-16 21:29:13 +0000150 GLOBAL_SERVICE.atomVmBooted(&atom).unwrap_or_else(|e| {
151 warn!("Failed to write VmCreationRequested atom: {e}");
152 });
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000153 });
Seungjae Yooacf559a2022-08-12 04:44:51 +0000154}
Seungjae Yoob4c07ba2022-08-12 04:44:52 +0000155
156/// Write the stats of VM exit to statsd
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000157/// The function creates a separate thread which waits fro statsd to start to push atom
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900158pub fn write_vm_exited_stats(
159 uid: i32,
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000160 vm_identifier: &str,
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900161 reason: DeathReason,
Seungjae Yoo93430e82022-12-05 16:37:42 +0900162 exit_signal: Option<i32>,
Seungjae Yoo6d265d92022-11-15 10:51:33 +0900163 vm_metric: &VmMetric,
Seungjae Yoo2e7beea2022-08-24 16:09:12 +0900164) {
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000165 let vm_identifier = vm_identifier.to_owned();
Seungjae Yoo6d265d92022-11-15 10:51:33 +0900166 let elapsed_time_millis = get_duration(vm_metric.start_timestamp).as_millis() as i64;
167 let guest_time_millis = vm_metric.cpu_guest_time.unwrap_or_default();
168 let rss = vm_metric.rss.unwrap_or_default();
169
David Brazdil49f96f52022-12-16 21:29:13 +0000170 let atom = AtomVmExited {
171 uid,
172 vmIdentifier: vm_identifier,
173 elapsedTimeMillis: elapsed_time_millis,
174 deathReason: reason,
175 guestTimeMillis: guest_time_millis,
176 rssVmKb: rss.vm,
177 rssCrosvmKb: rss.crosvm,
178 exitSignal: exit_signal.unwrap_or_default(),
179 };
180
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000181 thread::spawn(move || {
David Brazdil49f96f52022-12-16 21:29:13 +0000182 GLOBAL_SERVICE.atomVmExited(&atom).unwrap_or_else(|e| {
183 warn!("Failed to write VmExited atom: {e}");
184 });
Shikha Panwarc93a42b2022-11-09 14:12:25 +0000185 });
186}