• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use log::{error, info};
2 use paste::paste;
3 use std::collections::HashMap;
4 use std::fmt;
5 use std::sync::Mutex;
6 
7 // Fallback to bool when type is not specified
8 macro_rules! type_expand {
9     () => {
10         bool
11     };
12     ($type:ty) => {
13         $type
14     };
15 }
16 
17 macro_rules! default_value {
18     () => {
19         false
20     };
21     ($type:ty) => {
22         <$type>::default()
23     };
24     ($($type:ty)? = $default:tt) => {
25         $default
26     };
27 }
28 
29 macro_rules! test_value {
30     () => {
31         true
32     };
33     ($type:ty) => {
34         <$type>::default()
35     };
36 }
37 
38 #[cfg(test)]
39 macro_rules! call_getter_fn {
40     ($flag:ident) => {
41         paste! {
42             [<$flag _is_enabled>]()
43         }
44     };
45     ($flag:ident $type:ty) => {
46         paste! {
47             [<get_ $flag>]()
48         }
49     };
50 }
51 
52 macro_rules! create_getter_fn {
53     ($flag:ident) => {
54         paste! {
55             #[doc = concat!(" Return true if ", stringify!($flag), " is enabled")]
56             pub fn [<$flag _is_enabled>]() -> bool {
57                 FLAGS.lock().unwrap().$flag
58             }
59         }
60     };
61     ($flag:ident $type:ty) => {
62         paste! {
63             #[doc = concat!(" Return the flag value of ", stringify!($flag))]
64             pub fn [<get_ $flag>]() -> $type {
65                 FLAGS.lock().unwrap().$flag
66             }
67         }
68     };
69 }
70 
71 macro_rules! init_flags {
72     (flags: { $($flag:ident $(: $type:ty)? $(= $default:tt)?,)* }
73      extra_fields: { $($extra_field:ident : $extra_field_type:ty $(= $extra_default:tt)?,)* }
74      extra_parsed_flags: { $($extra_flag:tt => $extra_flag_fn:ident(_, _ $(,$extra_args:tt)*),)*}
75      dependencies: { $($parent:ident => $child:ident),* }) => {
76 
77         struct InitFlags {
78             $($flag : type_expand!($($type)?),)*
79             $($extra_field : $extra_field_type,)*
80         }
81 
82         impl Default for InitFlags {
83             fn default() -> Self {
84                 Self {
85                     $($flag : default_value!($($type)? $(= $default)?),)*
86                     $($extra_field : default_value!($extra_field_type $(= $extra_default)?),)*
87                 }
88             }
89         }
90 
91         /// Sets all bool flags to true
92         /// Set all other flags and extra fields to their default type value
93         pub fn set_all_for_testing() {
94             *FLAGS.lock().unwrap() = InitFlags {
95                 $($flag: test_value!($($type)?),)*
96                 $($extra_field: test_value!($extra_field_type),)*
97             };
98         }
99 
100         impl InitFlags {
101             fn parse(flags: Vec<String>) -> Self {
102                 let mut init_flags = Self::default();
103 
104                 for flag in flags {
105                     let values: Vec<&str> = flag.split("=").collect();
106                     if values.len() != 2 {
107                         error!("Bad flag {}, must be in <FLAG>=<VALUE> format", flag);
108                         continue;
109                     }
110 
111                     match values[0] {
112                         $(concat!("INIT_", stringify!($flag)) =>
113                             init_flags.$flag = values[1].parse().unwrap_or_else(|e| {
114                                 error!("Parse failure on '{}': {}", flag, e);
115                                 default_value!($($type)? $(= $default)?)}),)*
116                         $($extra_flag => $extra_flag_fn(&mut init_flags, values $(, $extra_args)*),)*
117                         _ => error!("Unsaved flag: {} = {}", values[0], values[1])
118                     }
119                 }
120 
121                 init_flags.reconcile()
122             }
123 
124             fn reconcile(mut self) -> Self {
125                 loop {
126                     // dependencies can be specified in any order
127                     $(if self.$parent && !self.$child {
128                         self.$child = true;
129                         continue;
130                     })*
131                     break;
132                 }
133 
134                 // TODO: acl should not be off if l2cap is on, but need to reconcile legacy code
135                 if self.gd_l2cap {
136                   // TODO This can never be turned off  self.gd_acl = false;
137                 }
138 
139                 self
140             }
141         }
142 
143         impl fmt::Display for InitFlags {
144             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145                 write!(f, concat!(
146                     concat!($(concat!(stringify!($flag), "={}")),*),
147                     $(concat!(stringify!($extra_field), "={}")),*),
148                     $(self.$flag),*,
149                     $(self.$extra_field),*)
150             }
151         }
152 
153         $(create_getter_fn!($flag $($type)?);)*
154 
155         #[cfg(test)]
156         mod tests_autogenerated {
157             use super::*;
158             $(paste! {
159                 #[test]
160                 pub fn [<test_get_ $flag>]() {
161                     let _guard = tests::ASYNC_LOCK.lock().unwrap();
162                     tests::test_load(vec![
163                         &*format!(concat!(concat!("INIT_", stringify!($flag)), "={}"), test_value!($($type)?))
164                     ]);
165                     let get_value = call_getter_fn!($flag $($type)?);
166                     drop(_guard); // Prevent poisonning other tests if a panic occurs
167                     assert_eq!(get_value, test_value!($($type)?));
168                 }
169             })*
170         }
171     }
172 }
173 
174 #[derive(Default)]
175 struct ExplicitTagSettings {
176     map: HashMap<String, bool>,
177 }
178 
179 impl fmt::Display for ExplicitTagSettings {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result180     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181         write!(f, "{:?}", self.map)
182     }
183 }
184 
parse_logging_tag(flags: &mut InitFlags, values: Vec<&str>, enabled: bool)185 fn parse_logging_tag(flags: &mut InitFlags, values: Vec<&str>, enabled: bool) {
186     for tag in values[1].split(',') {
187         flags.logging_debug_explicit_tag_settings.map.insert(tag.to_string(), enabled);
188     }
189 }
190 
191 /// Return true if `tag` is enabled in the flag
is_debug_logging_enabled_for_tag(tag: &str) -> bool192 pub fn is_debug_logging_enabled_for_tag(tag: &str) -> bool {
193     let guard = FLAGS.lock().unwrap();
194     *guard
195         .logging_debug_explicit_tag_settings
196         .map
197         .get(tag)
198         .unwrap_or(&guard.logging_debug_enabled_for_all)
199 }
200 
parse_hci_adapter(flags: &mut InitFlags, values: Vec<&str>)201 fn parse_hci_adapter(flags: &mut InitFlags, values: Vec<&str>) {
202     flags.hci_adapter = values[1].parse().unwrap_or(0);
203 }
204 
205 init_flags!(
206     // LINT.IfChange
207     flags: {
208         always_send_services_if_gatt_disc_done = true,
209         asynchronously_start_l2cap_coc = true,
210         btaa_hci = true,
211         bta_dm_clear_conn_id_on_client_close = true,
212         btm_dm_flush_discovery_queue_on_search_cancel,
213         clear_hidd_interrupt_cid_on_disconnect = true,
214         delay_hidh_cleanup_until_hidh_ready_start = true,
215         finite_att_timeout = true,
216         gatt_robust_caching_client = true,
217         gatt_robust_caching_server,
218         gd_core,
219         gd_l2cap,
220         gd_link_policy,
221         gd_rust,
222         gd_security,
223         hci_adapter: i32,
224         irk_rotation,
225         leaudio_targeted_announcement_reconnection_mode,
226         logging_debug_enabled_for_all,
227         pass_phy_update_callback = true,
228         queue_l2cap_coc_while_encrypting = true,
229         sdp_serialization = true,
230         sdp_skip_rnr_if_known = true,
231         trigger_advertising_callbacks_on_first_resume_after_pause = true,
232     }
233     // extra_fields are not a 1 to 1 match with "INIT_*" flags
234     extra_fields: {
235         logging_debug_explicit_tag_settings: ExplicitTagSettings,
236     }
237     // LINT.ThenChange(/system/gd/common/init_flags.fbs)
238     extra_parsed_flags: {
239         "INIT_logging_debug_enabled_for_tags" => parse_logging_tag(_, _, true),
240         "INIT_logging_debug_disabled_for_tags" => parse_logging_tag(_, _, false),
241         "--hci" => parse_hci_adapter(_, _),
242     }
243     dependencies: {
244         gd_core => gd_security
245     }
246 );
247 
248 lazy_static! {
249     static ref FLAGS: Mutex<InitFlags> = Mutex::new(InitFlags::default());
250 }
251 
252 /// Loads the flag values from the passed-in vector of string values
load(raw_flags: Vec<String>)253 pub fn load(raw_flags: Vec<String>) {
254     crate::init_logging();
255 
256     let flags = InitFlags::parse(raw_flags);
257     info!("Flags loaded: {}", flags);
258     *FLAGS.lock().unwrap() = flags;
259 }
260 
261 #[cfg(test)]
262 mod tests {
263     use super::*;
264     lazy_static! {
265         /// do not run concurrent tests as they all use the same global init_flag struct and
266         /// accessor
267         pub(super) static ref ASYNC_LOCK: Mutex<()> = Mutex::new(());
268     }
269 
test_load(raw_flags: Vec<&str>)270     pub(super) fn test_load(raw_flags: Vec<&str>) {
271         let raw_flags = raw_flags.into_iter().map(|x| x.to_string()).collect();
272         load(raw_flags);
273     }
274 
275     #[test]
simple_flag()276     fn simple_flag() {
277         let _guard = ASYNC_LOCK.lock().unwrap();
278         test_load(vec![
279             "INIT_btaa_hci=false", //override a default flag
280             "INIT_gatt_robust_caching_server=true",
281         ]);
282         assert!(!btaa_hci_is_enabled());
283         assert!(gatt_robust_caching_server_is_enabled());
284     }
285     #[test]
parsing_failure()286     fn parsing_failure() {
287         let _guard = ASYNC_LOCK.lock().unwrap();
288         test_load(vec![
289             "foo=bar=?",                                // vec length
290             "foo=bar",                                  // flag not save
291             "INIT_btaa_hci=not_false",                  // parse error but has default value
292             "INIT_gatt_robust_caching_server=not_true", // parse error
293         ]);
294         assert!(btaa_hci_is_enabled());
295         assert!(!gatt_robust_caching_server_is_enabled());
296     }
297     #[test]
int_flag()298     fn int_flag() {
299         let _guard = ASYNC_LOCK.lock().unwrap();
300         test_load(vec!["--hci=2"]);
301         assert_eq!(get_hci_adapter(), 2);
302     }
303     #[test]
explicit_flag()304     fn explicit_flag() {
305         let _guard = ASYNC_LOCK.lock().unwrap();
306         test_load(vec![
307             "INIT_logging_debug_enabled_for_all=true",
308             "INIT_logging_debug_enabled_for_tags=foo,bar",
309             "INIT_logging_debug_disabled_for_tags=foo,bar2",
310             "INIT_logging_debug_enabled_for_tags=bar2",
311         ]);
312         assert!(!is_debug_logging_enabled_for_tag("foo"));
313         assert!(is_debug_logging_enabled_for_tag("bar"));
314         assert!(is_debug_logging_enabled_for_tag("bar2"));
315         assert!(is_debug_logging_enabled_for_tag("unknown_flag"));
316         assert!(logging_debug_enabled_for_all_is_enabled());
317         FLAGS.lock().unwrap().logging_debug_enabled_for_all = false;
318         assert!(!is_debug_logging_enabled_for_tag("foo"));
319         assert!(is_debug_logging_enabled_for_tag("bar"));
320         assert!(is_debug_logging_enabled_for_tag("bar2"));
321         assert!(!is_debug_logging_enabled_for_tag("unknown_flag"));
322         assert!(!logging_debug_enabled_for_all_is_enabled());
323     }
324 }
325