1 use lazy_static::lazy_static;
2 use log::{error, info};
3 use paste::paste;
4 use std::collections::{BTreeMap, HashMap};
5 use std::fmt;
6 use std::sync::Mutex;
7 
8 // Fallback to bool when type is not specified
9 macro_rules! type_expand {
10     () => {
11         bool
12     };
13     ($type:ty) => {
14         $type
15     };
16 }
17 
18 macro_rules! default_value {
19     () => {
20         false
21     };
22     ($type:ty) => {
23         <$type>::default()
24     };
25     ($($type:ty)? = $default:tt) => {
26         $default
27     };
28 }
29 
30 macro_rules! test_value {
31     () => {
32         true
33     };
34     ($type:ty) => {
35         <$type>::default()
36     };
37 }
38 
39 #[cfg(test)]
40 macro_rules! call_getter_fn {
41     ($flag:ident) => {
42         paste! {
43             [<$flag _is_enabled>]()
44         }
45     };
46     ($flag:ident $type:ty) => {
47         paste! {
48             [<get_ $flag>]()
49         }
50     };
51 }
52 
53 macro_rules! create_getter_fn {
54     ($flag:ident) => {
55         paste! {
56             #[doc = concat!(" Return true if ", stringify!($flag), " is enabled")]
57             pub fn [<$flag _is_enabled>]() -> bool {
58                 FLAGS.lock().unwrap().$flag
59             }
60         }
61     };
62     ($flag:ident $type:ty) => {
63         paste! {
64             #[doc = concat!(" Return the flag value of ", stringify!($flag))]
65             pub fn [<get_ $flag>]() -> $type {
66                 FLAGS.lock().unwrap().$flag
67             }
68         }
69     };
70 }
71 
72 macro_rules! init_flags {
73     (
74         name: $name:ident
75         $($args:tt)*
76     ) => {
77         init_flags_struct! {
78             name: $name
79             $($args)*
80         }
81 
82         init_flags_getters! {
83             $($args)*
84         }
85     }
86 }
87 
88 trait FlagHolder: Default {
get_defaults_for_test() -> Self89     fn get_defaults_for_test() -> Self;
parse(flags: Vec<String>) -> Self90     fn parse(flags: Vec<String>) -> Self;
dump(&self) -> BTreeMap<&'static str, String>91     fn dump(&self) -> BTreeMap<&'static str, String>;
92 }
93 
94 macro_rules! init_flags_struct {
95     (
96      name: $name:ident
97      flags: { $($flag:ident $(: $type:ty)? $(= $default:tt)?,)* }
98      extra_parsed_flags: { $($extra_flag:tt => $extra_flag_fn:ident(_, _ $(,$extra_args:tt)*),)*}) => {
99 
100         struct $name {
101             $($flag : type_expand!($($type)?),)*
102         }
103 
104         impl Default for $name {
105             fn default() -> Self {
106                 Self {
107                     $($flag : default_value!($($type)? $(= $default)?),)*
108                 }
109             }
110         }
111 
112         impl FlagHolder for $name {
113             fn get_defaults_for_test() -> Self {
114                 Self {
115                     $($flag: test_value!($($type)?),)*
116                 }
117             }
118 
119             fn dump(&self) -> BTreeMap<&'static str, String> {
120                 [
121                     $((stringify!($flag), format!("{}", self.$flag)),)*
122                 ].into()
123             }
124 
125             fn parse(flags: Vec<String>) -> Self {
126                 let mut init_flags = Self::default();
127 
128                 for flag in flags {
129                     let values: Vec<&str> = flag.split("=").collect();
130                     if values.len() != 2 {
131                         error!("Bad flag {}, must be in <FLAG>=<VALUE> format", flag);
132                         continue;
133                     }
134 
135                     match values[0] {
136                         $(concat!("INIT_", stringify!($flag)) =>
137                             init_flags.$flag = values[1].parse().unwrap_or_else(|e| {
138                                 error!("Parse failure on '{}': {}", flag, e);
139                                 default_value!($($type)? $(= $default)?)}),)*
140                         $($extra_flag => $extra_flag_fn(&mut init_flags, values $(, $extra_args)*),)*
141                         _ => error!("Unsaved flag: {} = {}", values[0], values[1])
142                     }
143                 }
144 
145                 init_flags
146             }
147         }
148 
149         impl fmt::Display for $name {
150             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151                 write!(f,
152                     concat!($(concat!(stringify!($flag), "={}")),*),
153                     $(self.$flag),*)
154             }
155         }
156 
157     }
158 }
159 
160 macro_rules! init_flags_getters {
161     (
162      flags: { $($flag:ident $(: $type:ty)? $(= $default:tt)?,)* }
163      extra_parsed_flags: { $($extra_flag:tt => $extra_flag_fn:ident(_, _ $(,$extra_args:tt)*),)*}) => {
164 
165         $(create_getter_fn!($flag $($type)?);)*
166 
167         #[cfg(test)]
168         mod tests_autogenerated {
169             use super::*;
170             $(paste! {
171                 #[test]
172                 pub fn [<test_get_ $flag>]() {
173                     let _guard = tests::ASYNC_LOCK.lock().unwrap();
174                     tests::test_load(vec![
175                         &*format!(concat!(concat!("INIT_", stringify!($flag)), "={}"), test_value!($($type)?))
176                     ]);
177                     let get_value = call_getter_fn!($flag $($type)?);
178                     drop(_guard); // Prevent poisonning other tests if a panic occurs
179                     assert_eq!(get_value, test_value!($($type)?));
180                 }
181             })*
182         }
183     }
184 }
185 
186 #[derive(Default)]
187 struct ExplicitTagSettings {
188     map: HashMap<String, i32>,
189 }
190 
191 impl fmt::Display for ExplicitTagSettings {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result192     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
193         write!(f, "{:?}", self.map)
194     }
195 }
196 
parse_hci_adapter(flags: &mut InitFlags, values: Vec<&str>)197 fn parse_hci_adapter(flags: &mut InitFlags, values: Vec<&str>) {
198     flags.hci_adapter = values[1].parse().unwrap_or(0);
199 }
200 
201 /// Sets all bool flags to true
202 /// Set all other flags and extra fields to their default type value
set_all_for_testing()203 pub fn set_all_for_testing() {
204     *FLAGS.lock().unwrap() = InitFlags::get_defaults_for_test();
205 }
206 
207 init_flags!(
208     name: InitFlags
209     flags: {
210         asha_packet_drop_frequency_threshold: i32 = 60,
211         asha_phy_update_retry_limit: i32 = 5,
212         always_send_services_if_gatt_disc_done = true,
213         always_use_private_gatt_for_debugging,
214         bluetooth_power_telemetry = false,
215         btm_dm_flush_discovery_queue_on_search_cancel,
216         classic_discovery_only,
217         dynamic_avrcp_version_enhancement = true,
218         gatt_robust_caching_server,
219         hci_adapter: i32,
220         hfp_dynamic_version = true,
221         irk_rotation,
222         leaudio_targeted_announcement_reconnection_mode = true,
223         pbap_pse_dynamic_version_upgrade = false,
224         redact_log = true,
225         sco_codec_timeout_clear,
226         sdp_serialization = true,
227         sdp_skip_rnr_if_known = true,
228         set_min_encryption = true,
229         subrating = true,
230         use_unified_connection_manager,
231         sdp_return_classic_services_when_le_discovery_fails = true,
232         use_rsi_from_cached_inqiry_results = false,
233         att_mtu_default: i32 = 517,
234         encryption_in_busy_state = true,
235     }
236     extra_parsed_flags: {
237         "--hci" => parse_hci_adapter(_, _),
238     }
239 );
240 
241 lazy_static! {
242     /// Store some flag values
243     static ref FLAGS: Mutex<InitFlags> = Mutex::new(InitFlags::default());
244     /// Store the uid of bluetooth
245     pub static ref AID_BLUETOOTH: Mutex<u32> = Mutex::new(1002);
246     /// Store the prefix for file system
247     pub static ref MISC: Mutex<String> = Mutex::new("/data/misc/".to_string());
248 }
249 
250 /// Loads the flag values from the passed-in vector of string values
load(raw_flags: Vec<String>)251 pub fn load(raw_flags: Vec<String>) {
252     crate::init_logging();
253 
254     let flags = InitFlags::parse(raw_flags);
255     info!("Flags loaded: {}", flags);
256     *FLAGS.lock().unwrap() = flags;
257 }
258 
259 /// Dumps all flag K-V pairs, storing values as strings
dump() -> BTreeMap<&'static str, String>260 pub fn dump() -> BTreeMap<&'static str, String> {
261     FLAGS.lock().unwrap().dump()
262 }
263 
264 #[cfg(test)]
265 mod tests {
266     use super::*;
267     lazy_static! {
268         /// do not run concurrent tests as they all use the same global init_flag struct and
269         /// accessor
270         pub(super) static ref ASYNC_LOCK: Mutex<bool> = Mutex::new(false);
271     }
272 
test_load(raw_flags: Vec<&str>)273     pub(super) fn test_load(raw_flags: Vec<&str>) {
274         let raw_flags = raw_flags.into_iter().map(|x| x.to_string()).collect();
275         load(raw_flags);
276     }
277 
278     #[test]
simple_flag()279     fn simple_flag() {
280         let _guard = ASYNC_LOCK.lock().unwrap();
281         test_load(vec!["INIT_gatt_robust_caching_server=true"]);
282         assert!(gatt_robust_caching_server_is_enabled());
283     }
284     #[test]
parsing_failure()285     fn parsing_failure() {
286         let _guard = ASYNC_LOCK.lock().unwrap();
287         test_load(vec![
288             "foo=bar=?",                                // vec length
289             "foo=bar",                                  // flag not save
290             "INIT_gatt_robust_caching_server=not_true", // parse error
291         ]);
292         assert!(!gatt_robust_caching_server_is_enabled());
293     }
294     #[test]
int_flag()295     fn int_flag() {
296         let _guard = ASYNC_LOCK.lock().unwrap();
297         test_load(vec!["--hci=2"]);
298         assert_eq!(get_hci_adapter(), 2);
299     }
300     #[test]
test_redact_logging()301     fn test_redact_logging() {
302         let _guard = ASYNC_LOCK.lock().unwrap();
303         assert!(redact_log_is_enabled()); // default is true
304         test_load(vec!["INIT_redact_log=false"]);
305         assert!(!redact_log_is_enabled()); // turned off
306         test_load(vec!["INIT_redact_log=foo"]);
307         assert!(redact_log_is_enabled()); // invalid value, interpreted as default, true
308         test_load(vec!["INIT_redact_log=true"]);
309         assert!(redact_log_is_enabled()); // turned on
310     }
311 
312     init_flags_struct!(
313         name: InitFlagsForTest
314         flags: {
315             cat,
316         }
317         extra_parsed_flags: {}
318     );
319 
320     #[test]
test_dumpsys()321     fn test_dumpsys() {
322         let flags = InitFlagsForTest { ..Default::default() };
323 
324         let out = flags.dump();
325 
326         assert_eq!(out.len(), 1);
327         assert_eq!(out["cat"], "false");
328     }
329 }
330