blob: a8d9723577e183cf9cb43e845e4169d36ca1c4d1 [file] [log] [blame]
Yi Konge3aab142021-03-02 13:58:25 +08001//
2// Copyright (C) 2021 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17//! ProfCollect configurations.
18
19use anyhow::Result;
Yi Kong037bde82021-03-23 14:25:38 +080020use macaddr::MacAddr6;
21use rand::Rng;
Yi Konge3aab142021-03-02 13:58:25 +080022use serde::{Deserialize, Serialize};
23use std::error::Error;
Yi Kong34ebf872021-11-29 19:57:55 +080024use std::fs::{read_dir, remove_file};
Yi Konge3aab142021-03-02 13:58:25 +080025use std::path::Path;
Yabin Cuib9d24fc2024-05-10 14:15:22 -070026use std::process::Command;
Yi Konge3aab142021-03-02 13:58:25 +080027use std::str::FromStr;
Andrew Walbran692b2162024-09-20 15:17:16 +010028use std::sync::LazyLock;
Yi Konge3aab142021-03-02 13:58:25 +080029use std::time::Duration;
30
Yi Kongd22e1c72024-04-17 00:24:50 +000031const PROFCOLLECT_CONFIG_NAMESPACE: &str = "aconfig_flags.profcollect_native_boot";
Yi Kong037bde82021-03-23 14:25:38 +080032const PROFCOLLECT_NODE_ID_PROPERTY: &str = "persist.profcollectd.node_id";
Yi Konge3aab142021-03-02 13:58:25 +080033
Yi Kong4e1c58b2024-05-30 16:38:54 +090034const DEFAULT_BINARY_FILTER: &str = "(^/(system|apex/.+|vendor)/(bin|lib64)/.+)|\
Yi Kongf9cf0382024-05-22 06:45:56 +000035 (^/data/app/.+\\.so$)|kernel.kallsyms";
Yi Kong8dffc122021-07-20 16:55:39 +080036pub const REPORT_RETENTION_SECS: u64 = 14 * 24 * 60 * 60; // 14 days.
37
Yi Kong34ebf872021-11-29 19:57:55 +080038// Static configs that cannot be changed.
Andrew Walbran692b2162024-09-20 15:17:16 +010039pub static TRACE_OUTPUT_DIR: LazyLock<&'static Path> =
40 LazyLock::new(|| Path::new("/data/misc/profcollectd/trace/"));
41pub static PROFILE_OUTPUT_DIR: LazyLock<&'static Path> =
42 LazyLock::new(|| Path::new("/data/misc/profcollectd/output/"));
43pub static REPORT_OUTPUT_DIR: LazyLock<&'static Path> =
44 LazyLock::new(|| Path::new("/data/misc/profcollectd/report/"));
45pub static CONFIG_FILE: LazyLock<&'static Path> =
46 LazyLock::new(|| Path::new("/data/misc/profcollectd/output/config.json"));
47pub static LOG_FILE: LazyLock<&'static Path> =
48 LazyLock::new(|| Path::new("/data/misc/profcollectd/output/trace.log"));
Yi Konge3aab142021-03-02 13:58:25 +080049
Yi Kong34ebf872021-11-29 19:57:55 +080050/// Dynamic configs, stored in config.json.
Yi Konge3aab142021-03-02 13:58:25 +080051#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
52pub struct Config {
53 /// Version of config file scheme, always equals to 1.
54 version: u32,
Yi Kong037bde82021-03-23 14:25:38 +080055 /// Application specific node ID.
56 pub node_id: MacAddr6,
Yi Konge3aab142021-03-02 13:58:25 +080057 /// Device build fingerprint.
58 pub build_fingerprint: String,
59 /// Interval between collections.
60 pub collection_interval: Duration,
Yi Konge3aab142021-03-02 13:58:25 +080061 /// An optional filter to limit which binaries to or not to profile.
62 pub binary_filter: String,
Yi Kong581aa3a2021-11-24 00:19:30 +080063 /// Maximum size of the trace directory.
Yi Kong610ca1c2024-06-04 05:25:02 +000064 pub max_trace_limit_mb: u64,
Yabin Cuib9d24fc2024-05-10 14:15:22 -070065 /// The kernel release version
66 pub kernel_release: String,
Yi Konge3aab142021-03-02 13:58:25 +080067}
68
69impl Config {
70 pub fn from_env() -> Result<Self> {
71 Ok(Config {
72 version: 1,
Yi Kong037bde82021-03-23 14:25:38 +080073 node_id: get_or_initialise_node_id()?,
74 build_fingerprint: get_build_fingerprint()?,
Yi Konge3aab142021-03-02 13:58:25 +080075 collection_interval: Duration::from_secs(get_device_config(
76 "collection_interval",
77 600,
78 )?),
Yi Kong87d0a172021-12-09 01:37:57 +080079 binary_filter: get_device_config("binary_filter", DEFAULT_BINARY_FILTER.to_string())?,
Yi Kong610ca1c2024-06-04 05:25:02 +000080 max_trace_limit_mb: get_device_config("max_trace_limit_mb", 768)?,
Yabin Cuib9d24fc2024-05-10 14:15:22 -070081 kernel_release: get_kernel_release(),
Yi Konge3aab142021-03-02 13:58:25 +080082 })
83 }
84}
85
Chris Wailes6a5bd382024-05-09 15:24:18 -070086impl std::fmt::Display for Config {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 write!(f, "{}", serde_json::to_string(self).expect("Failed to deserialise configuration."))
Yi Konge3aab142021-03-02 13:58:25 +080089 }
90}
91
92impl FromStr for Config {
93 type Err = serde_json::Error;
94 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 serde_json::from_str::<Config>(s)
96 }
97}
98
Yi Kong037bde82021-03-23 14:25:38 +080099fn get_or_initialise_node_id() -> Result<MacAddr6> {
Chris Wailes8f571e12021-07-27 16:04:09 -0700100 let mut node_id = get_property(PROFCOLLECT_NODE_ID_PROPERTY, MacAddr6::nil())?;
Yi Kong037bde82021-03-23 14:25:38 +0800101 if node_id.is_nil() {
102 node_id = generate_random_node_id();
Chris Wailes8f571e12021-07-27 16:04:09 -0700103 set_property(PROFCOLLECT_NODE_ID_PROPERTY, node_id)?;
Yi Kong037bde82021-03-23 14:25:38 +0800104 }
105
106 Ok(node_id)
Yi Konge3aab142021-03-02 13:58:25 +0800107}
108
Yi Kong037bde82021-03-23 14:25:38 +0800109fn get_build_fingerprint() -> Result<String> {
110 get_property("ro.build.fingerprint", "unknown".to_string())
111}
112
113fn get_device_config<T>(key: &str, default_value: T) -> Result<T>
Yi Konge3aab142021-03-02 13:58:25 +0800114where
115 T: FromStr + ToString,
116 T::Err: Error + Send + Sync + 'static,
117{
Yi Kong037bde82021-03-23 14:25:38 +0800118 let default_value = default_value.to_string();
Luca Stefanice7ab9a2024-01-22 19:07:38 +0100119 let config =
120 flags_rust::GetServerConfigurableFlag(PROFCOLLECT_CONFIG_NAMESPACE, key, &default_value);
Yi Konge3aab142021-03-02 13:58:25 +0800121 Ok(T::from_str(&config)?)
122}
Yi Kong037bde82021-03-23 14:25:38 +0800123
Yi Kong0507c802024-04-08 06:56:57 +0000124pub fn get_sampling_period() -> Duration {
Yi Kongf2316452024-06-10 08:56:08 +0900125 let default_period = 1500;
Yi Kong0507c802024-04-08 06:56:57 +0000126 Duration::from_millis(
127 get_device_config("sampling_period", default_period).unwrap_or(default_period),
128 )
129}
130
Yi Kong037bde82021-03-23 14:25:38 +0800131fn get_property<T>(key: &str, default_value: T) -> Result<T>
132where
133 T: FromStr + ToString,
134 T::Err: Error + Send + Sync + 'static,
135{
136 let default_value = default_value.to_string();
Andrew Walbran0aaa3a22022-02-07 12:36:22 +0000137 let value = rustutils::system_properties::read(key).unwrap_or(None).unwrap_or(default_value);
Yi Kong037bde82021-03-23 14:25:38 +0800138 Ok(T::from_str(&value)?)
139}
140
Joel Galenson0ab91112021-07-20 14:51:42 -0700141fn set_property<T>(key: &str, value: T) -> Result<()>
Yi Kong037bde82021-03-23 14:25:38 +0800142where
143 T: ToString,
144{
145 let value = value.to_string();
Andrew Walbran0aaa3a22022-02-07 12:36:22 +0000146 Ok(rustutils::system_properties::write(key, &value)?)
Yi Kong037bde82021-03-23 14:25:38 +0800147}
148
149fn generate_random_node_id() -> MacAddr6 {
150 let mut node_id = rand::thread_rng().gen::<[u8; 6]>();
151 node_id[0] |= 0x1;
152 MacAddr6::from(node_id)
153}
Yi Kong34ebf872021-11-29 19:57:55 +0800154
Yabin Cuib9d24fc2024-05-10 14:15:22 -0700155fn get_kernel_release() -> String {
156 match Command::new("uname").args(["-r"]).output() {
157 Ok(output) if output.status.success() => {
158 String::from_utf8_lossy(&output.stdout).trim().to_string()
159 }
160 _ => String::new(),
161 }
162}
163
Yi Kong34ebf872021-11-29 19:57:55 +0800164pub fn clear_data() -> Result<()> {
165 fn remove_files(path: &Path) -> Result<()> {
166 read_dir(path)?
167 .filter_map(|e| e.ok())
168 .map(|e| e.path())
Yabin Cuif1d91d22023-04-27 12:50:59 -0700169 .filter(|e| e.is_file() && e != *LOG_FILE)
Yi Kong34ebf872021-11-29 19:57:55 +0800170 .try_for_each(remove_file)?;
171 Ok(())
172 }
173
174 remove_files(&TRACE_OUTPUT_DIR)?;
175 remove_files(&PROFILE_OUTPUT_DIR)?;
176 remove_files(&REPORT_OUTPUT_DIR)?;
177 Ok(())
178}
Abhishek Gadewarb67822c2024-05-01 10:59:24 -0700179pub fn clear_processed_files() -> Result<()> {
180 read_dir(&PROFILE_OUTPUT_DIR as &Path)?
181 .filter_map(|e| e.ok())
182 .map(|e| e.path())
183 .filter(|e| e.is_file() && e != (&CONFIG_FILE as &Path))
184 .try_for_each(remove_file)?;
185 Ok(())
186}