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