1*288bf522SAndroid Build Coastguard Worker //
2*288bf522SAndroid Build Coastguard Worker // Copyright (C) 2021 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker //
4*288bf522SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker //
8*288bf522SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker //
10*288bf522SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker // limitations under the License.
15*288bf522SAndroid Build Coastguard Worker //
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Worker //! ProfCollect configurations.
18*288bf522SAndroid Build Coastguard Worker
19*288bf522SAndroid Build Coastguard Worker use anyhow::Result;
20*288bf522SAndroid Build Coastguard Worker use macaddr::MacAddr6;
21*288bf522SAndroid Build Coastguard Worker use rand::Rng;
22*288bf522SAndroid Build Coastguard Worker use serde::{Deserialize, Serialize};
23*288bf522SAndroid Build Coastguard Worker use std::error::Error;
24*288bf522SAndroid Build Coastguard Worker use std::fs::{read_dir, remove_file};
25*288bf522SAndroid Build Coastguard Worker use std::path::Path;
26*288bf522SAndroid Build Coastguard Worker use std::process::Command;
27*288bf522SAndroid Build Coastguard Worker use std::str::FromStr;
28*288bf522SAndroid Build Coastguard Worker use std::sync::LazyLock;
29*288bf522SAndroid Build Coastguard Worker use std::time::Duration;
30*288bf522SAndroid Build Coastguard Worker
31*288bf522SAndroid Build Coastguard Worker const PROFCOLLECT_CONFIG_NAMESPACE: &str = "aconfig_flags.profcollect_native_boot";
32*288bf522SAndroid Build Coastguard Worker const PROFCOLLECT_NODE_ID_PROPERTY: &str = "persist.profcollectd.node_id";
33*288bf522SAndroid Build Coastguard Worker
34*288bf522SAndroid Build Coastguard Worker const DEFAULT_BINARY_FILTER: &str = "(^/(system|apex/.+|vendor)/(bin|lib64)/.+)|\
35*288bf522SAndroid Build Coastguard Worker (^/data/app/.+\\.so$)|kernel.kallsyms";
36*288bf522SAndroid Build Coastguard Worker pub const REPORT_RETENTION_SECS: u64 = 14 * 24 * 60 * 60; // 14 days.
37*288bf522SAndroid Build Coastguard Worker
38*288bf522SAndroid Build Coastguard Worker // Static configs that cannot be changed.
39*288bf522SAndroid Build Coastguard Worker pub static TRACE_OUTPUT_DIR: LazyLock<&'static Path> =
40*288bf522SAndroid Build Coastguard Worker LazyLock::new(|| Path::new("/data/misc/profcollectd/trace/"));
41*288bf522SAndroid Build Coastguard Worker pub static PROFILE_OUTPUT_DIR: LazyLock<&'static Path> =
42*288bf522SAndroid Build Coastguard Worker LazyLock::new(|| Path::new("/data/misc/profcollectd/output/"));
43*288bf522SAndroid Build Coastguard Worker pub static REPORT_OUTPUT_DIR: LazyLock<&'static Path> =
44*288bf522SAndroid Build Coastguard Worker LazyLock::new(|| Path::new("/data/misc/profcollectd/report/"));
45*288bf522SAndroid Build Coastguard Worker pub static CONFIG_FILE: LazyLock<&'static Path> =
46*288bf522SAndroid Build Coastguard Worker LazyLock::new(|| Path::new("/data/misc/profcollectd/output/config.json"));
47*288bf522SAndroid Build Coastguard Worker pub static LOG_FILE: LazyLock<&'static Path> =
48*288bf522SAndroid Build Coastguard Worker LazyLock::new(|| Path::new("/data/misc/profcollectd/output/trace.log"));
49*288bf522SAndroid Build Coastguard Worker
50*288bf522SAndroid Build Coastguard Worker /// Dynamic configs, stored in config.json.
51*288bf522SAndroid Build Coastguard Worker #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
52*288bf522SAndroid Build Coastguard Worker pub struct Config {
53*288bf522SAndroid Build Coastguard Worker /// Version of config file scheme, always equals to 1.
54*288bf522SAndroid Build Coastguard Worker version: u32,
55*288bf522SAndroid Build Coastguard Worker /// Application specific node ID.
56*288bf522SAndroid Build Coastguard Worker pub node_id: MacAddr6,
57*288bf522SAndroid Build Coastguard Worker /// Device build fingerprint.
58*288bf522SAndroid Build Coastguard Worker pub build_fingerprint: String,
59*288bf522SAndroid Build Coastguard Worker /// Interval between collections.
60*288bf522SAndroid Build Coastguard Worker pub collection_interval: Duration,
61*288bf522SAndroid Build Coastguard Worker /// An optional filter to limit which binaries to or not to profile.
62*288bf522SAndroid Build Coastguard Worker pub binary_filter: String,
63*288bf522SAndroid Build Coastguard Worker /// Maximum size of the trace directory.
64*288bf522SAndroid Build Coastguard Worker pub max_trace_limit_mb: u64,
65*288bf522SAndroid Build Coastguard Worker /// The kernel release version
66*288bf522SAndroid Build Coastguard Worker pub kernel_release: String,
67*288bf522SAndroid Build Coastguard Worker }
68*288bf522SAndroid Build Coastguard Worker
69*288bf522SAndroid Build Coastguard Worker impl Config {
from_env() -> Result<Self>70*288bf522SAndroid Build Coastguard Worker pub fn from_env() -> Result<Self> {
71*288bf522SAndroid Build Coastguard Worker Ok(Config {
72*288bf522SAndroid Build Coastguard Worker version: 1,
73*288bf522SAndroid Build Coastguard Worker node_id: get_or_initialise_node_id()?,
74*288bf522SAndroid Build Coastguard Worker build_fingerprint: get_build_fingerprint()?,
75*288bf522SAndroid Build Coastguard Worker collection_interval: Duration::from_secs(get_device_config(
76*288bf522SAndroid Build Coastguard Worker "collection_interval",
77*288bf522SAndroid Build Coastguard Worker 600,
78*288bf522SAndroid Build Coastguard Worker )?),
79*288bf522SAndroid Build Coastguard Worker binary_filter: get_device_config("binary_filter", DEFAULT_BINARY_FILTER.to_string())?,
80*288bf522SAndroid Build Coastguard Worker max_trace_limit_mb: get_device_config("max_trace_limit_mb", 768)?,
81*288bf522SAndroid Build Coastguard Worker kernel_release: get_kernel_release(),
82*288bf522SAndroid Build Coastguard Worker })
83*288bf522SAndroid Build Coastguard Worker }
84*288bf522SAndroid Build Coastguard Worker }
85*288bf522SAndroid Build Coastguard Worker
86*288bf522SAndroid Build Coastguard Worker impl std::fmt::Display for Config {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result87*288bf522SAndroid Build Coastguard Worker fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88*288bf522SAndroid Build Coastguard Worker write!(f, "{}", serde_json::to_string(self).expect("Failed to deserialise configuration."))
89*288bf522SAndroid Build Coastguard Worker }
90*288bf522SAndroid Build Coastguard Worker }
91*288bf522SAndroid Build Coastguard Worker
92*288bf522SAndroid Build Coastguard Worker impl FromStr for Config {
93*288bf522SAndroid Build Coastguard Worker type Err = serde_json::Error;
from_str(s: &str) -> Result<Self, Self::Err>94*288bf522SAndroid Build Coastguard Worker fn from_str(s: &str) -> Result<Self, Self::Err> {
95*288bf522SAndroid Build Coastguard Worker serde_json::from_str::<Config>(s)
96*288bf522SAndroid Build Coastguard Worker }
97*288bf522SAndroid Build Coastguard Worker }
98*288bf522SAndroid Build Coastguard Worker
get_or_initialise_node_id() -> Result<MacAddr6>99*288bf522SAndroid Build Coastguard Worker fn get_or_initialise_node_id() -> Result<MacAddr6> {
100*288bf522SAndroid Build Coastguard Worker let mut node_id = get_property(PROFCOLLECT_NODE_ID_PROPERTY, MacAddr6::nil())?;
101*288bf522SAndroid Build Coastguard Worker if node_id.is_nil() {
102*288bf522SAndroid Build Coastguard Worker node_id = generate_random_node_id();
103*288bf522SAndroid Build Coastguard Worker set_property(PROFCOLLECT_NODE_ID_PROPERTY, node_id)?;
104*288bf522SAndroid Build Coastguard Worker }
105*288bf522SAndroid Build Coastguard Worker
106*288bf522SAndroid Build Coastguard Worker Ok(node_id)
107*288bf522SAndroid Build Coastguard Worker }
108*288bf522SAndroid Build Coastguard Worker
get_build_fingerprint() -> Result<String>109*288bf522SAndroid Build Coastguard Worker fn get_build_fingerprint() -> Result<String> {
110*288bf522SAndroid Build Coastguard Worker get_property("ro.build.fingerprint", "unknown".to_string())
111*288bf522SAndroid Build Coastguard Worker }
112*288bf522SAndroid Build Coastguard Worker
get_device_config<T>(key: &str, default_value: T) -> Result<T> where T: FromStr + ToString, T::Err: Error + Send + Sync + 'static,113*288bf522SAndroid Build Coastguard Worker fn get_device_config<T>(key: &str, default_value: T) -> Result<T>
114*288bf522SAndroid Build Coastguard Worker where
115*288bf522SAndroid Build Coastguard Worker T: FromStr + ToString,
116*288bf522SAndroid Build Coastguard Worker T::Err: Error + Send + Sync + 'static,
117*288bf522SAndroid Build Coastguard Worker {
118*288bf522SAndroid Build Coastguard Worker let default_value = default_value.to_string();
119*288bf522SAndroid Build Coastguard Worker let config =
120*288bf522SAndroid Build Coastguard Worker flags_rust::GetServerConfigurableFlag(PROFCOLLECT_CONFIG_NAMESPACE, key, &default_value);
121*288bf522SAndroid Build Coastguard Worker Ok(T::from_str(&config)?)
122*288bf522SAndroid Build Coastguard Worker }
123*288bf522SAndroid Build Coastguard Worker
get_sampling_period() -> Duration124*288bf522SAndroid Build Coastguard Worker pub fn get_sampling_period() -> Duration {
125*288bf522SAndroid Build Coastguard Worker let default_period = 1500;
126*288bf522SAndroid Build Coastguard Worker Duration::from_millis(
127*288bf522SAndroid Build Coastguard Worker get_device_config("sampling_period", default_period).unwrap_or(default_period),
128*288bf522SAndroid Build Coastguard Worker )
129*288bf522SAndroid Build Coastguard Worker }
130*288bf522SAndroid Build Coastguard Worker
get_property<T>(key: &str, default_value: T) -> Result<T> where T: FromStr + ToString, T::Err: Error + Send + Sync + 'static,131*288bf522SAndroid Build Coastguard Worker fn get_property<T>(key: &str, default_value: T) -> Result<T>
132*288bf522SAndroid Build Coastguard Worker where
133*288bf522SAndroid Build Coastguard Worker T: FromStr + ToString,
134*288bf522SAndroid Build Coastguard Worker T::Err: Error + Send + Sync + 'static,
135*288bf522SAndroid Build Coastguard Worker {
136*288bf522SAndroid Build Coastguard Worker let default_value = default_value.to_string();
137*288bf522SAndroid Build Coastguard Worker let value = rustutils::system_properties::read(key).unwrap_or(None).unwrap_or(default_value);
138*288bf522SAndroid Build Coastguard Worker Ok(T::from_str(&value)?)
139*288bf522SAndroid Build Coastguard Worker }
140*288bf522SAndroid Build Coastguard Worker
set_property<T>(key: &str, value: T) -> Result<()> where T: ToString,141*288bf522SAndroid Build Coastguard Worker fn set_property<T>(key: &str, value: T) -> Result<()>
142*288bf522SAndroid Build Coastguard Worker where
143*288bf522SAndroid Build Coastguard Worker T: ToString,
144*288bf522SAndroid Build Coastguard Worker {
145*288bf522SAndroid Build Coastguard Worker let value = value.to_string();
146*288bf522SAndroid Build Coastguard Worker Ok(rustutils::system_properties::write(key, &value)?)
147*288bf522SAndroid Build Coastguard Worker }
148*288bf522SAndroid Build Coastguard Worker
generate_random_node_id() -> MacAddr6149*288bf522SAndroid Build Coastguard Worker fn generate_random_node_id() -> MacAddr6 {
150*288bf522SAndroid Build Coastguard Worker let mut node_id = rand::thread_rng().gen::<[u8; 6]>();
151*288bf522SAndroid Build Coastguard Worker node_id[0] |= 0x1;
152*288bf522SAndroid Build Coastguard Worker MacAddr6::from(node_id)
153*288bf522SAndroid Build Coastguard Worker }
154*288bf522SAndroid Build Coastguard Worker
get_kernel_release() -> String155*288bf522SAndroid Build Coastguard Worker fn get_kernel_release() -> String {
156*288bf522SAndroid Build Coastguard Worker match Command::new("uname").args(["-r"]).output() {
157*288bf522SAndroid Build Coastguard Worker Ok(output) if output.status.success() => {
158*288bf522SAndroid Build Coastguard Worker String::from_utf8_lossy(&output.stdout).trim().to_string()
159*288bf522SAndroid Build Coastguard Worker }
160*288bf522SAndroid Build Coastguard Worker _ => String::new(),
161*288bf522SAndroid Build Coastguard Worker }
162*288bf522SAndroid Build Coastguard Worker }
163*288bf522SAndroid Build Coastguard Worker
clear_data() -> Result<()>164*288bf522SAndroid Build Coastguard Worker pub fn clear_data() -> Result<()> {
165*288bf522SAndroid Build Coastguard Worker fn remove_files(path: &Path) -> Result<()> {
166*288bf522SAndroid Build Coastguard Worker read_dir(path)?
167*288bf522SAndroid Build Coastguard Worker .filter_map(|e| e.ok())
168*288bf522SAndroid Build Coastguard Worker .map(|e| e.path())
169*288bf522SAndroid Build Coastguard Worker .filter(|e| e.is_file() && e != *LOG_FILE)
170*288bf522SAndroid Build Coastguard Worker .try_for_each(remove_file)?;
171*288bf522SAndroid Build Coastguard Worker Ok(())
172*288bf522SAndroid Build Coastguard Worker }
173*288bf522SAndroid Build Coastguard Worker
174*288bf522SAndroid Build Coastguard Worker remove_files(&TRACE_OUTPUT_DIR)?;
175*288bf522SAndroid Build Coastguard Worker remove_files(&PROFILE_OUTPUT_DIR)?;
176*288bf522SAndroid Build Coastguard Worker remove_files(&REPORT_OUTPUT_DIR)?;
177*288bf522SAndroid Build Coastguard Worker Ok(())
178*288bf522SAndroid Build Coastguard Worker }
clear_processed_files() -> Result<()>179*288bf522SAndroid Build Coastguard Worker pub fn clear_processed_files() -> Result<()> {
180*288bf522SAndroid Build Coastguard Worker read_dir(&PROFILE_OUTPUT_DIR as &Path)?
181*288bf522SAndroid Build Coastguard Worker .filter_map(|e| e.ok())
182*288bf522SAndroid Build Coastguard Worker .map(|e| e.path())
183*288bf522SAndroid Build Coastguard Worker .filter(|e| e.is_file() && e != (&CONFIG_FILE as &Path))
184*288bf522SAndroid Build Coastguard Worker .try_for_each(remove_file)?;
185*288bf522SAndroid Build Coastguard Worker Ok(())
186*288bf522SAndroid Build Coastguard Worker }
187