1 //
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 
19 use anyhow::Result;
20 use lazy_static::lazy_static;
21 use macaddr::MacAddr6;
22 use rand::Rng;
23 use serde::{Deserialize, Serialize};
24 use std::error::Error;
25 use std::path::Path;
26 use std::str::FromStr;
27 use std::time::Duration;
28 
29 const PROFCOLLECT_CONFIG_NAMESPACE: &str = "profcollect_native_boot";
30 const PROFCOLLECT_NODE_ID_PROPERTY: &str = "persist.profcollectd.node_id";
31 
32 pub const REPORT_RETENTION_SECS: u64 = 14 * 24 * 60 * 60; // 14 days.
33 
34 lazy_static! {
35     pub static ref TRACE_OUTPUT_DIR: &'static Path = Path::new("/data/misc/profcollectd/trace/");
36     pub static ref PROFILE_OUTPUT_DIR: &'static Path = Path::new("/data/misc/profcollectd/output/");
37     pub static ref REPORT_OUTPUT_DIR: &'static Path = Path::new("/data/misc/profcollectd/report/");
38     pub static ref BETTERBUG_CACHE_DIR_PREFIX: &'static Path = Path::new("/data/user/");
39     pub static ref BETTERBUG_CACHE_DIR_SUFFIX: &'static Path =
40         Path::new("com.google.android.apps.internal.betterbug/cache/");
41     pub static ref CONFIG_FILE: &'static Path =
42         Path::new("/data/misc/profcollectd/output/config.json");
43 }
44 
45 #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
46 pub struct Config {
47     /// Version of config file scheme, always equals to 1.
48     version: u32,
49     /// Application specific node ID.
50     pub node_id: MacAddr6,
51     /// Device build fingerprint.
52     pub build_fingerprint: String,
53     /// Interval between collections.
54     pub collection_interval: Duration,
55     /// Length of time each collection lasts for.
56     pub sampling_period: Duration,
57     /// An optional filter to limit which binaries to or not to profile.
58     pub binary_filter: String,
59 }
60 
61 impl Config {
from_env() -> Result<Self>62     pub fn from_env() -> Result<Self> {
63         Ok(Config {
64             version: 1,
65             node_id: get_or_initialise_node_id()?,
66             build_fingerprint: get_build_fingerprint()?,
67             collection_interval: Duration::from_secs(get_device_config(
68                 "collection_interval",
69                 600,
70             )?),
71             sampling_period: Duration::from_millis(get_device_config("sampling_period", 500)?),
72             binary_filter: get_device_config("binary_filter", "".to_string())?,
73         })
74     }
75 }
76 
77 impl ToString for Config {
to_string(&self) -> String78     fn to_string(&self) -> String {
79         serde_json::to_string(self).expect("Failed to deserialise configuration.")
80     }
81 }
82 
83 impl FromStr for Config {
84     type Err = serde_json::Error;
from_str(s: &str) -> Result<Self, Self::Err>85     fn from_str(s: &str) -> Result<Self, Self::Err> {
86         serde_json::from_str::<Config>(s)
87     }
88 }
89 
get_or_initialise_node_id() -> Result<MacAddr6>90 fn get_or_initialise_node_id() -> Result<MacAddr6> {
91     let mut node_id = get_property(&PROFCOLLECT_NODE_ID_PROPERTY, MacAddr6::nil())?;
92     if node_id.is_nil() {
93         node_id = generate_random_node_id();
94         set_property(&PROFCOLLECT_NODE_ID_PROPERTY, node_id);
95     }
96 
97     Ok(node_id)
98 }
99 
get_build_fingerprint() -> Result<String>100 fn get_build_fingerprint() -> Result<String> {
101     get_property("ro.build.fingerprint", "unknown".to_string())
102 }
103 
get_device_config<T>(key: &str, default_value: T) -> Result<T> where T: FromStr + ToString, T::Err: Error + Send + Sync + 'static,104 fn get_device_config<T>(key: &str, default_value: T) -> Result<T>
105 where
106     T: FromStr + ToString,
107     T::Err: Error + Send + Sync + 'static,
108 {
109     let default_value = default_value.to_string();
110     let config = profcollect_libflags_rust::GetServerConfigurableFlag(
111         &PROFCOLLECT_CONFIG_NAMESPACE,
112         &key,
113         &default_value,
114     );
115     Ok(T::from_str(&config)?)
116 }
117 
get_property<T>(key: &str, default_value: T) -> Result<T> where T: FromStr + ToString, T::Err: Error + Send + Sync + 'static,118 fn get_property<T>(key: &str, default_value: T) -> Result<T>
119 where
120     T: FromStr + ToString,
121     T::Err: Error + Send + Sync + 'static,
122 {
123     let default_value = default_value.to_string();
124     let value = profcollect_libbase_rust::GetProperty(&key, &default_value);
125     Ok(T::from_str(&value)?)
126 }
127 
set_property<T>(key: &str, value: T) where T: ToString,128 fn set_property<T>(key: &str, value: T)
129 where
130     T: ToString,
131 {
132     let value = value.to_string();
133     profcollect_libbase_rust::SetProperty(&key, &value);
134 }
135 
generate_random_node_id() -> MacAddr6136 fn generate_random_node_id() -> MacAddr6 {
137     let mut node_id = rand::thread_rng().gen::<[u8; 6]>();
138     node_id[0] |= 0x1;
139     MacAddr6::from(node_id)
140 }
141