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