summaryrefslogtreecommitdiff
path: root/system/gd/rust/common/src/init_flags.rs
blob: 80fe6da399b9f1e30f8fc2d9c201c53842dd3f15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use log::{error, info};
use paste::paste;
use std::sync::Mutex;

macro_rules! init_flags {
    (flags: { $($flag:ident),* }, dependencies: { $($parent:ident => $child:ident),* }) => {
        #[derive(Default)]
        struct InitFlags {
            $($flag: bool,)*
        }

        /// Sets all flags to true, for testing
        pub fn set_all_for_testing() {
            *FLAGS.lock().unwrap() = InitFlags { $($flag: true,)* };
        }

        impl InitFlags {
            fn parse(flags: Vec<String>) -> Self {
                $(let mut $flag = false;)*

                for flag in flags {
                    let values: Vec<&str> = flag.split("=").collect();
                    if values.len() != 2 {
                        error!("Bad flag {}, must be in <FLAG>=<VALUE> format", flag);
                        continue;
                    }

                    match values[0] {
                        $(concat!("INIT_", stringify!($flag)) => $flag = values[1].parse().unwrap_or(false),)*
                        _ => {}
                    }
                }

                Self { $($flag,)* }.reconcile()
            }

            fn reconcile(mut self) -> Self {
                // Loop to ensure dependencies can be specified in any order
                loop {
                    let mut any_change = false;
                    $(if self.$parent && !self.$child {
                        self.$child = true;
                        any_change = true;
                    })*

                    if !any_change {
                        break;
                    }
                }

                // TODO: acl should not be off if l2cap is on, but need to reconcile legacy code
                if self.gd_l2cap {
                  // TODO This can never be turned off  self.gd_acl = false;
                }

                self
            }

            fn log(&self) {
                info!(concat!("Flags loaded: ", $(stringify!($flag), "={} ",)*), $(self.$flag,)*);
            }
        }

        paste! {
            $(
                #[allow(missing_docs)]
                pub fn [<$flag _is_enabled>]() -> bool {
                    FLAGS.lock().unwrap().$flag
                }
            )*
        }
    };
}

init_flags!(
    flags: {
        gd_core,
        gd_security,
        gd_l2cap,
        gatt_robust_caching,
        btaa_hci,
        gd_rust,
        gd_link_policy
    },
    dependencies: {
        gd_core => gd_security
    }
);

lazy_static! {
    static ref FLAGS: Mutex<InitFlags> = Mutex::new(InitFlags::default());
}

/// Loads the flag values from the passed-in vector of string values
pub fn load(flags: Vec<String>) {
    crate::init_logging();

    let flags = InitFlags::parse(flags);
    flags.log();
    *FLAGS.lock().unwrap() = flags;
}