• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use lazy_static::lazy_static;
2 use log::{error, info};
3 use paste::paste;
4 use std::collections::{BTreeMap, HashMap};
5 use std::convert::TryFrom;
6 use std::fmt;
7 use std::sync::Mutex;
8 
9 // Fallback to bool when type is not specified
10 macro_rules! type_expand {
11     () => {
12         bool
13     };
14     ($type:ty) => {
15         $type
16     };
17 }
18 
19 macro_rules! default_value {
20     () => {
21         false
22     };
23     ($type:ty) => {
24         <$type>::default()
25     };
26     ($($type:ty)? = $default:tt) => {
27         $default
28     };
29 }
30 
31 macro_rules! test_value {
32     () => {
33         true
34     };
35     ($type:ty) => {
36         <$type>::default()
37     };
38 }
39 
40 #[cfg(test)]
41 macro_rules! call_getter_fn {
42     ($flag:ident) => {
43         paste! {
44             [<$flag _is_enabled>]()
45         }
46     };
47     ($flag:ident $type:ty) => {
48         paste! {
49             [<get_ $flag>]()
50         }
51     };
52 }
53 
54 macro_rules! create_getter_fn {
55     ($flag:ident) => {
56         paste! {
57             #[doc = concat!(" Return true if ", stringify!($flag), " is enabled")]
58             pub fn [<$flag _is_enabled>]() -> bool {
59                 FLAGS.lock().unwrap().$flag
60             }
61         }
62     };
63     ($flag:ident $type:ty) => {
64         paste! {
65             #[doc = concat!(" Return the flag value of ", stringify!($flag))]
66             pub fn [<get_ $flag>]() -> $type {
67                 FLAGS.lock().unwrap().$flag
68             }
69         }
70     };
71 }
72 
73 macro_rules! create_setter_fn {
74     ($flag:ident) => {
75         paste! {
76             #[doc = concat!(" Update value of ", stringify!($flag), " at runtime")]
77             pub fn [<update_ $flag>](value: bool) {
78                 FLAGS.lock().unwrap().$flag = value;
79             }
80         }
81     };
82     ($flag:ident $type:ty) => {
83         paste! {
84             #[doc = concat!(" Update value of ", stringify!($flag), " at runtime")]
85             pub fn [<update_ $flag>](value: $type) {
86                 FLAGS.lock().unwrap().$flag = value;
87             }
88         }
89     };
90 }
91 
92 macro_rules! init_flags {
93     (
94         name: $name:ident
95         $($args:tt)*
96     ) => {
97         init_flags_struct! {
98             name: $name
99             $($args)*
100         }
101 
102         init_flags_getters! {
103             $($args)*
104         }
105     }
106 }
107 
108 trait FlagHolder: Default {
get_defaults_for_test() -> Self109     fn get_defaults_for_test() -> Self;
parse(flags: Vec<String>) -> Self110     fn parse(flags: Vec<String>) -> Self;
dump(&self) -> BTreeMap<&'static str, String>111     fn dump(&self) -> BTreeMap<&'static str, String>;
reconcile(self) -> Self112     fn reconcile(self) -> Self;
113 }
114 
115 macro_rules! init_flags_struct {
116     (
117      name: $name:ident
118      flags: { $($flag:ident $(: $type:ty)? $(= $default:tt)?,)* }
119      dynamic_flags: { $($dy_flag:ident $(: $dy_type:ty)? $(= $dy_default:tt)?,)* }
120      extra_fields: { $($extra_field:ident : $extra_field_type:ty $(= $extra_default:tt)?,)* }
121      extra_parsed_flags: { $($extra_flag:tt => $extra_flag_fn:ident(_, _ $(,$extra_args:tt)*),)*}
122      dependencies: { $($parent:ident => $child:ident),* }) => {
123 
124         struct $name {
125             $($flag : type_expand!($($type)?),)*
126             $($dy_flag : type_expand!($($dy_type)?),)*
127             $($extra_field : $extra_field_type,)*
128         }
129 
130         impl Default for $name {
131             fn default() -> Self {
132                 Self {
133                     $($flag : default_value!($($type)? $(= $default)?),)*
134                     $($dy_flag : default_value!($($dy_type)? $(= $dy_default)?),)*
135                     $($extra_field : default_value!($extra_field_type $(= $extra_default)?),)*
136                 }
137             }
138         }
139 
140         impl FlagHolder for $name {
141             fn get_defaults_for_test() -> Self {
142                 Self {
143                     $($flag: test_value!($($type)?),)*
144                     $($dy_flag: test_value!($($dy_type)?),)*
145                     $($extra_field: test_value!($extra_field_type),)*
146                 }
147             }
148 
149             fn dump(&self) -> BTreeMap<&'static str, String> {
150                 [
151                     $((stringify!($flag), format!("{}", self.$flag)),)*
152                     $((stringify!($dy_flag), format!("{}", self.$dy_flag)),)*
153                     $((stringify!($extra_field), format!("{}", self.$extra_field)),)*
154                 ].into()
155             }
156 
157             fn parse(flags: Vec<String>) -> Self {
158                 let mut init_flags = Self::default();
159 
160                 for flag in flags {
161                     let values: Vec<&str> = flag.split("=").collect();
162                     if values.len() != 2 {
163                         error!("Bad flag {}, must be in <FLAG>=<VALUE> format", flag);
164                         continue;
165                     }
166 
167                     match values[0] {
168                         $(concat!("INIT_", stringify!($flag)) =>
169                             init_flags.$flag = values[1].parse().unwrap_or_else(|e| {
170                                 error!("Parse failure on '{}': {}", flag, e);
171                                 default_value!($($type)? $(= $default)?)}),)*
172                         $(concat!("INIT_", stringify!($dy_flag)) =>
173                             init_flags.$dy_flag = values[1].parse().unwrap_or_else(|e| {
174                                 error!("Parse failure on '{}': {}", flag, e);
175                                 default_value!($($dy_type)? $(= $dy_default)?)}),)*
176                         $($extra_flag => $extra_flag_fn(&mut init_flags, values $(, $extra_args)*),)*
177                         _ => error!("Unsaved flag: {} = {}", values[0], values[1])
178                     }
179                 }
180 
181                 init_flags.reconcile()
182             }
183 
184             #[allow(unused_mut)]
185             fn reconcile(mut self) -> Self {
186                 loop {
187                     // dependencies can be specified in any order
188                     $(if self.$parent && !self.$child {
189                         self.$child = true;
190                         continue;
191                     })*
192                     break;
193                 }
194                 self
195             }
196         }
197 
198         impl fmt::Display for $name {
199             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200                 write!(f, concat!(
201                     concat!($(concat!(stringify!($flag), "={}")),*),
202                     concat!($(concat!(stringify!($dy_flag), "={}")),*),
203                     $(concat!(stringify!($extra_field), "={}")),*),
204                     $(self.$flag),*,
205                     $(self.$dy_flag),*,
206                     $(self.$extra_field),*)
207             }
208         }
209 
210     }
211 }
212 
213 macro_rules! init_flags_getters {
214     (
215      flags: { $($flag:ident $(: $type:ty)? $(= $default:tt)?,)* }
216      dynamic_flags: { $($dy_flag:ident $(: $dy_type:ty)? $(= $dy_default:tt)?,)* }
217      extra_fields: { $($extra_field:ident : $extra_field_type:ty $(= $extra_default:tt)?,)* }
218      extra_parsed_flags: { $($extra_flag:tt => $extra_flag_fn:ident(_, _ $(,$extra_args:tt)*),)*}
219      dependencies: { $($parent:ident => $child:ident),* }) => {
220 
221         $(create_getter_fn!($flag $($type)?);)*
222 
223         $(create_getter_fn!($dy_flag $($dy_type)?);)*
224         $(create_setter_fn!($dy_flag $($dy_type)?);)*
225 
226         #[cfg(test)]
227         mod tests_autogenerated {
228             use super::*;
229             $(paste! {
230                 #[test]
231                 pub fn [<test_get_ $flag>]() {
232                     let _guard = tests::ASYNC_LOCK.lock().unwrap();
233                     tests::test_load(vec![
234                         &*format!(concat!(concat!("INIT_", stringify!($flag)), "={}"), test_value!($($type)?))
235                     ]);
236                     let get_value = call_getter_fn!($flag $($type)?);
237                     drop(_guard); // Prevent poisonning other tests if a panic occurs
238                     assert_eq!(get_value, test_value!($($type)?));
239                 }
240             })*
241 
242             $(paste! {
243                 #[test]
244                 pub fn [<test_dynamic_get_ $dy_flag>]() {
245                     let _guard = tests::ASYNC_LOCK.lock().unwrap();
246                     tests::test_load(vec![
247                         &*format!(concat!(concat!("INIT_", stringify!($dy_flag)), "={}"), test_value!($($dy_type)?))
248                     ]);
249                     let get_value = call_getter_fn!($dy_flag $($dy_type)?);
250                     drop(_guard); // Prevent poisonning other tests if a panic occurs
251                     assert_eq!(get_value, test_value!($($dy_type)?));
252                 }
253             })*
254         }
255     }
256 }
257 
258 #[derive(Default)]
259 struct ExplicitTagSettings {
260     map: HashMap<String, i32>,
261 }
262 
263 impl fmt::Display for ExplicitTagSettings {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result264     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
265         write!(f, "{:?}", self.map)
266     }
267 }
268 
269 struct LogLevel(i32);
270 
271 impl TryFrom<&str> for LogLevel {
272     type Error = &'static str;
273 
try_from(tag_value: &str) -> Result<Self, Self::Error>274     fn try_from(tag_value: &str) -> Result<Self, Self::Error> {
275         match tag_value {
276             "LOG_FATAL" => Ok(LogLevel(LOG_TAG_FATAL)),
277             "LOG_ERROR" => Ok(LogLevel(LOG_TAG_ERROR)),
278             "LOG_WARN" => Ok(LogLevel(LOG_TAG_WARN)),
279             "LOG_NOTICE" => Ok(LogLevel(LOG_TAG_NOTICE)),
280             "LOG_INFO" => Ok(LogLevel(LOG_TAG_INFO)),
281             "LOG_DEBUG" => Ok(LogLevel(LOG_TAG_DEBUG)),
282             "LOG_VERBOSE" => Ok(LogLevel(LOG_TAG_VERBOSE)),
283             _ => Err("Invalid tag value"),
284         }
285     }
286 }
287 
deprecated_set_debug_logging_enabled_for_all(flags: &mut InitFlags, values: Vec<&str>)288 fn deprecated_set_debug_logging_enabled_for_all(flags: &mut InitFlags, values: Vec<&str>) {
289     let truthy: bool = values[1].parse().unwrap_or(false);
290     flags.default_log_level = if truthy { LOG_TAG_VERBOSE } else { LOG_TAG_INFO };
291 
292     // Leave a note that this flag is deprecated in the logs.
293     log::error!(
294         "DEPRECATED flag used: INIT_logging_debug_enabled_for_all. Use INIT_default_log_level_str=LOG_VERBOSE instead.",
295     );
296 }
297 
parse_log_level(flags: &mut InitFlags, values: Vec<&str>)298 fn parse_log_level(flags: &mut InitFlags, values: Vec<&str>) {
299     if let Ok(v) = LogLevel::try_from(values[1]) {
300         flags.default_log_level = v.0;
301     }
302 }
303 
parse_logging_tag(flags: &mut InitFlags, values: Vec<&str>)304 fn parse_logging_tag(flags: &mut InitFlags, values: Vec<&str>) {
305     for tag in values[1].split(',') {
306         let tagstr = tag.to_string();
307         let pair = tagstr.split(':').collect::<Vec<&str>>();
308         if pair.len() == 2 {
309             if let Ok(v) = LogLevel::try_from(pair[1]) {
310                 flags.logging_explicit_tag_settings.map.insert(pair[0].into(), v.0);
311             }
312         }
313     }
314 }
315 
parse_debug_logging_tag(flags: &mut InitFlags, values: Vec<&str>, enabled: bool)316 fn parse_debug_logging_tag(flags: &mut InitFlags, values: Vec<&str>, enabled: bool) {
317     let log_level: i32 = if enabled { LOG_TAG_VERBOSE } else { LOG_TAG_INFO };
318 
319     for tag in values[1].split(',') {
320         flags.logging_explicit_tag_settings.map.insert(tag.to_string(), log_level);
321     }
322 }
323 
parse_hci_adapter(flags: &mut InitFlags, values: Vec<&str>)324 fn parse_hci_adapter(flags: &mut InitFlags, values: Vec<&str>) {
325     flags.hci_adapter = values[1].parse().unwrap_or(0);
326 }
327 
328 /// Returns the log level for given flag.
get_log_level_for_tag(tag: &str) -> i32329 pub fn get_log_level_for_tag(tag: &str) -> i32 {
330     let guard = FLAGS.lock().unwrap();
331     *guard.logging_explicit_tag_settings.map.get(tag).unwrap_or(&guard.default_log_level)
332 }
333 
334 /// Sets all bool flags to true
335 /// Set all other flags and extra fields to their default type value
set_all_for_testing()336 pub fn set_all_for_testing() {
337     *FLAGS.lock().unwrap() = InitFlags::get_defaults_for_test();
338 }
339 
340 // Keep these values in sync with the values in gd/os/log_tags.h
341 // They are used to control the log level for each tag.
342 
343 /// Fatal log level.
344 pub const LOG_TAG_FATAL: i32 = 0;
345 /// Error log level.
346 pub const LOG_TAG_ERROR: i32 = 1;
347 /// Warning log level.
348 pub const LOG_TAG_WARN: i32 = 2;
349 /// Notice log level.
350 pub const LOG_TAG_NOTICE: i32 = 3;
351 /// Info log level. This is usually the default log level on most systems.
352 pub const LOG_TAG_INFO: i32 = 4;
353 /// Debug log level.
354 pub const LOG_TAG_DEBUG: i32 = 5;
355 /// Verbose log level.
356 pub const LOG_TAG_VERBOSE: i32 = 6;
357 
358 init_flags!(
359     name: InitFlags
360     flags: {
361         asha_packet_drop_frequency_threshold: i32 = 60,
362         asha_phy_update_retry_limit: i32 = 5,
363         always_send_services_if_gatt_disc_done = true,
364         always_use_private_gatt_for_debugging,
365         asynchronously_start_l2cap_coc = true,
366         btaa_hci = true,
367         bta_dm_clear_conn_id_on_client_close = true,
368         btm_dm_flush_discovery_queue_on_search_cancel,
369         classic_discovery_only,
370         clear_hidd_interrupt_cid_on_disconnect = true,
371         delay_hidh_cleanup_until_hidh_ready_start = true,
372         device_iot_config_logging,
373         dynamic_avrcp_version_enhancement = true,
374         finite_att_timeout = true,
375         gatt_robust_caching_client = true,
376         gatt_robust_caching_server,
377         gd_core,
378         gd_hal_snoop_logger_socket = true,
379         gd_hal_snoop_logger_filtering = true,
380         gd_l2cap,
381         gd_link_policy,
382         gd_remote_name_request,
383         gd_rust,
384         hci_adapter: i32,
385         hfp_dynamic_version = true,
386         irk_rotation,
387         leaudio_targeted_announcement_reconnection_mode = true,
388         pass_phy_update_callback = true,
389         pbap_pse_dynamic_version_upgrade = false,
390         periodic_advertising_adi = true,
391         private_gatt = true,
392         queue_l2cap_coc_while_encrypting = true,
393         read_encryption_key_size = true,
394         redact_log = true,
395         rust_event_loop = true,
396         sco_codec_select_lc3,
397         sco_codec_timeout_clear,
398         sdp_serialization = true,
399         sdp_skip_rnr_if_known = true,
400         bluetooth_quality_report_callback = true,
401         set_min_encryption = true,
402         subrating = true,
403         trigger_advertising_callbacks_on_first_resume_after_pause = true,
404         use_unified_connection_manager,
405         sdp_return_classic_services_when_le_discovery_fails = true,
406     }
407     // dynamic flags can be updated at runtime and should be accessed directly
408     // to check.
409     dynamic_flags: {
410         default_log_level : i32 = LOG_TAG_INFO,
411     }
412     // extra_fields are not a 1 to 1 match with "INIT_*" flags
413     extra_fields: {
414         logging_explicit_tag_settings: ExplicitTagSettings,
415     }
416     extra_parsed_flags: {
417         "INIT_default_log_level_str" => parse_log_level(_, _),
418         "INIT_log_level_for_tags" => parse_logging_tag(_, _),
419         "INIT_logging_debug_enabled_for_all" => deprecated_set_debug_logging_enabled_for_all(_, _),
420         "INIT_logging_debug_enabled_for_tags" => parse_debug_logging_tag(_, _, true),
421         "INIT_logging_debug_disabled_for_tags" => parse_debug_logging_tag(_, _, false),
422         "--hci" => parse_hci_adapter(_, _),
423     }
424     dependencies: {
425         always_use_private_gatt_for_debugging => private_gatt,
426         private_gatt => rust_event_loop
427     }
428 );
429 
430 lazy_static! {
431     /// Store some flag values
432     static ref FLAGS: Mutex<InitFlags> = Mutex::new(InitFlags::default());
433     /// Store the uid of bluetooth
434     pub static ref AID_BLUETOOTH: Mutex<u32> = Mutex::new(1002);
435     /// Store the prefix for file system
436     pub static ref MISC: Mutex<String> = Mutex::new("/data/misc/".to_string());
437 }
438 
439 /// Loads the flag values from the passed-in vector of string values
load(raw_flags: Vec<String>)440 pub fn load(raw_flags: Vec<String>) {
441     crate::init_logging();
442 
443     let flags = InitFlags::parse(raw_flags);
444     info!("Flags loaded: {}", flags);
445     *FLAGS.lock().unwrap() = flags;
446 
447     // re-init to respect log levels set by flags
448     crate::init_logging();
449 }
450 
451 /// Dumps all flag K-V pairs, storing values as strings
dump() -> BTreeMap<&'static str, String>452 pub fn dump() -> BTreeMap<&'static str, String> {
453     FLAGS.lock().unwrap().dump()
454 }
455 
456 #[cfg(test)]
457 mod tests {
458     use super::*;
459     lazy_static! {
460         /// do not run concurrent tests as they all use the same global init_flag struct and
461         /// accessor
462         pub(super) static ref ASYNC_LOCK: Mutex<bool> = Mutex::new(false);
463     }
464 
test_load(raw_flags: Vec<&str>)465     pub(super) fn test_load(raw_flags: Vec<&str>) {
466         let raw_flags = raw_flags.into_iter().map(|x| x.to_string()).collect();
467         load(raw_flags);
468     }
469 
470     #[test]
simple_flag()471     fn simple_flag() {
472         let _guard = ASYNC_LOCK.lock().unwrap();
473         test_load(vec![
474             "INIT_btaa_hci=false", //override a default flag
475             "INIT_gatt_robust_caching_server=true",
476         ]);
477         assert!(!btaa_hci_is_enabled());
478         assert!(gatt_robust_caching_server_is_enabled());
479     }
480     #[test]
parsing_failure()481     fn parsing_failure() {
482         let _guard = ASYNC_LOCK.lock().unwrap();
483         test_load(vec![
484             "foo=bar=?",                                // vec length
485             "foo=bar",                                  // flag not save
486             "INIT_btaa_hci=not_false",                  // parse error but has default value
487             "INIT_gatt_robust_caching_server=not_true", // parse error
488         ]);
489         assert!(btaa_hci_is_enabled());
490         assert!(!gatt_robust_caching_server_is_enabled());
491     }
492     #[test]
int_flag()493     fn int_flag() {
494         let _guard = ASYNC_LOCK.lock().unwrap();
495         test_load(vec!["--hci=2"]);
496         assert_eq!(get_hci_adapter(), 2);
497     }
498     #[test]
explicit_flag()499     fn explicit_flag() {
500         let _guard = ASYNC_LOCK.lock().unwrap();
501         test_load(vec![
502             "INIT_default_log_level_str=LOG_VERBOSE",
503             "INIT_logging_debug_enabled_for_tags=foo,bar",
504             "INIT_logging_debug_disabled_for_tags=foo,bar2,fizz",
505             "INIT_logging_debug_enabled_for_tags=bar2",
506             "INIT_log_level_for_tags=fizz:LOG_WARN,buzz:LOG_NOTICE",
507         ]);
508 
509         assert!(get_log_level_for_tag("foo") == LOG_TAG_INFO);
510         assert!(get_log_level_for_tag("bar") == LOG_TAG_VERBOSE);
511         assert!(get_log_level_for_tag("bar2") == LOG_TAG_VERBOSE);
512         assert!(get_log_level_for_tag("unknown_flag") == LOG_TAG_VERBOSE);
513         assert!(get_default_log_level() == LOG_TAG_VERBOSE);
514         FLAGS.lock().unwrap().default_log_level = LOG_TAG_INFO;
515         assert!(get_log_level_for_tag("foo") == LOG_TAG_INFO);
516         assert!(get_log_level_for_tag("bar") == LOG_TAG_VERBOSE);
517         assert!(get_log_level_for_tag("bar2") == LOG_TAG_VERBOSE);
518         assert!(get_log_level_for_tag("unknown_flag") == LOG_TAG_INFO);
519         assert!(get_default_log_level() == LOG_TAG_INFO);
520     }
521     #[test]
test_redact_logging()522     fn test_redact_logging() {
523         let _guard = ASYNC_LOCK.lock().unwrap();
524         assert!(redact_log_is_enabled()); // default is true
525         test_load(vec!["INIT_redact_log=false"]);
526         assert!(!redact_log_is_enabled()); // turned off
527         test_load(vec!["INIT_redact_log=foo"]);
528         assert!(redact_log_is_enabled()); // invalid value, interpreted as default, true
529         test_load(vec!["INIT_redact_log=true"]);
530         assert!(redact_log_is_enabled()); // turned on
531     }
532     #[test]
test_runtime_update()533     fn test_runtime_update() {
534         let _guard = ASYNC_LOCK.lock().unwrap();
535         test_load(vec!["INIT_btaa_hci=true", "INIT_default_log_level_str=LOG_WARN"]);
536         assert!(btaa_hci_is_enabled());
537         assert!(get_default_log_level() == LOG_TAG_WARN);
538 
539         update_default_log_level(LOG_TAG_DEBUG);
540         assert!(get_default_log_level() == LOG_TAG_DEBUG);
541         update_default_log_level(LOG_TAG_ERROR);
542         assert!(get_default_log_level() == LOG_TAG_ERROR);
543     }
544     #[test]
test_default_log_level()545     fn test_default_log_level() {
546         // Default log level can be provided via int value or string.
547         // The string version is just for ease-of-use.
548         let _guard = ASYNC_LOCK.lock().unwrap();
549         test_load(vec!["INIT_default_log_level=1"]);
550         assert!(get_default_log_level() == LOG_TAG_ERROR);
551         test_load(vec!["INIT_default_log_level_str=LOG_VERBOSE"]);
552         assert!(get_default_log_level() == LOG_TAG_VERBOSE);
553         test_load(vec!["INIT_default_log_level_str=LOG_VERBOSE", "INIT_default_log_level=0"]);
554         assert!(get_default_log_level() == LOG_TAG_FATAL);
555     }
556     #[test]
test_deprecated_logging_flag()557     fn test_deprecated_logging_flag() {
558         let _guard = ASYNC_LOCK.lock().unwrap();
559         test_load(vec!["INIT_default_log_level_str=1", "INIT_logging_debug_enabled_for_all=true"]);
560         assert!(get_default_log_level() == LOG_TAG_VERBOSE);
561         test_load(vec!["INIT_logging_debug_enabled_for_all=false"]);
562         assert!(get_default_log_level() == LOG_TAG_INFO);
563     }
564 
565     init_flags_struct!(
566         name: InitFlagsForTest
567         flags: {
568             cat,
569         }
570         dynamic_flags: {
571             dog: i32 = 8,
572         }
573         extra_fields: {
574             elephant: String,
575         }
576         extra_parsed_flags: {}
577         dependencies: {}
578     );
579 
580     #[test]
test_dumpsys()581     fn test_dumpsys() {
582         let flags = InitFlagsForTest { dog: 3, elephant: "Go bears!".into(), ..Default::default() };
583 
584         let out = flags.dump();
585 
586         assert_eq!(out.len(), 3);
587         assert_eq!(out["cat"], "false");
588         assert_eq!(out["dog"], "3");
589         assert_eq!(out["elephant"], "Go bears!");
590     }
591 }
592