Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d2e4c960 authored by William Escande's avatar William Escande Committed by Gerrit Code Review
Browse files

Merge changes Id5f60e7a,I0244c598

* changes:
  GD: use one source as init_flag
  GD Rust: init_flag add remaining flags types
parents dbcaa57b 66b626e1
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -11,7 +11,6 @@ filegroup {
    name: "BluetoothCommonSources",
    srcs: [
        "audit_log.cc",
        "init_flags.cc",
        "metric_id_manager.cc",
        "strings.cc",
        "stop_watch.cc",
+0 −1
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
source_set("BluetoothCommonSources") {
  sources = [
    "audit_log.cc",
    "init_flags.cc",
    "metric_id_manager.cc",
    "stop_watch.cc",
    "strings.cc",

system/gd/common/init_flags.cc

deleted100644 → 0
+0 −122
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2019 The Android Open Source Project
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

#include "init_flags.h"

#include <cstdlib>
#include <string>

#include "common/strings.h"
#include "os/log.h"

namespace bluetooth {
namespace common {

bool InitFlags::logging_debug_enabled_for_all = false;
int InitFlags::hci_adapter = 0;
std::unordered_map<std::string, bool> InitFlags::logging_debug_explicit_tag_settings = {};

bool ParseBoolFlag(const std::vector<std::string>& flag_pair, const std::string& flag, bool* variable) {
  if (flag != flag_pair[0]) {
    return false;
  }
  auto value = BoolFromString(flag_pair[1]);
  if (!value) {
    return false;
  }
  *variable = *value;
  return true;
}

bool ParseIntFlag(const std::vector<std::string>& flag_pair, const std::string& flag, int* variable) {
  if (flag != flag_pair[0]) {
    return false;
  }
  auto value = Int64FromString(flag_pair[1]);
  if (!value || *value > INT32_MAX) {
    return false;
  }

  *variable = *value;
  return true;
}

void InitFlags::Load(const char** flags) {
  const char** flags_copy = flags;
  SetAll(false);
  while (flags != nullptr && *flags != nullptr) {
    std::string flag_element = *flags;
    auto flag_pair = StringSplit(flag_element, "=", 2);
    if (flag_pair.size() != 2) {
      flags++;
      continue;
    }

    // Parse adapter index (defaults to 0)
    ParseIntFlag(flag_pair, "--hci", &hci_adapter);

    ParseBoolFlag(flag_pair, "INIT_logging_debug_enabled_for_all", &logging_debug_enabled_for_all);
    if ("INIT_logging_debug_enabled_for_tags" == flag_pair[0]) {
      auto tags = StringSplit(flag_pair[1], ",");
      for (const auto& tag : tags) {
        auto setting = logging_debug_explicit_tag_settings.find(tag);
        if (setting == logging_debug_explicit_tag_settings.end()) {
          logging_debug_explicit_tag_settings.insert_or_assign(tag, true);
        }
      }
    }
    if ("INIT_logging_debug_disabled_for_tags" == flag_pair[0]) {
      auto tags = StringSplit(flag_pair[1], ",");
      for (const auto& tag : tags) {
        logging_debug_explicit_tag_settings.insert_or_assign(tag, false);
      }
    }
    flags++;
  }

  std::vector<std::string> logging_debug_enabled_tags;
  std::vector<std::string> logging_debug_disabled_tags;
  for (const auto& tag_setting : logging_debug_explicit_tag_settings) {
    if (tag_setting.second) {
      logging_debug_enabled_tags.emplace_back(tag_setting.first);
    } else {
      logging_debug_disabled_tags.emplace_back(tag_setting.first);
    }
  }

  flags = flags_copy;
  rust::Vec<rust::String> rusted_flags = rust::Vec<rust::String>();
  while (flags != nullptr && *flags != nullptr) {
    rusted_flags.push_back(rust::String(*flags));
    flags++;
  }
  init_flags::load(std::move(rusted_flags));
}

void InitFlags::SetAll(bool value) {
  logging_debug_enabled_for_all = value;
  logging_debug_explicit_tag_settings.clear();
}

void InitFlags::SetAllForTesting() {
  init_flags::set_all_for_testing();
  SetAll(true);
}

}  // namespace common
}  // namespace bluetooth
+14 −16
Original line number Diff line number Diff line
@@ -27,32 +27,30 @@ namespace common {

class InitFlags final {
 public:
  static void Load(const char** flags);
  inline static void Load(const char** flags) {
    rust::Vec<rust::String> rusted_flags = rust::Vec<rust::String>();
    while (flags != nullptr && *flags != nullptr) {
      rusted_flags.push_back(rust::String(*flags));
      flags++;
    }
    init_flags::load(std::move(rusted_flags));
  }

  inline static bool IsDebugLoggingEnabledForTag(const std::string& tag) {
    auto tag_setting = logging_debug_explicit_tag_settings.find(tag);
    if (tag_setting != logging_debug_explicit_tag_settings.end()) {
      return tag_setting->second;
    }
    return logging_debug_enabled_for_all;
    return init_flags::is_debug_logging_enabled_for_tag(tag);
  }

  inline static bool IsDebugLoggingEnabledForAll() {
    return logging_debug_enabled_for_all;
    return init_flags::logging_debug_enabled_for_all_is_enabled();
  }

  inline static int GetAdapterIndex() {
    return hci_adapter;
    return init_flags::get_hci_adapter();
  }

  static void SetAllForTesting();

 private:
  static void SetAll(bool value);
  static bool logging_debug_enabled_for_all;
  static int hci_adapter;
  // save both log allow list and block list in the map to save hashing time
  static std::unordered_map<std::string, bool> logging_debug_explicit_tag_settings;
  inline static void SetAllForTesting() {
    init_flags::set_all_for_testing();
  }
};

}  // namespace common
+184 −36
Original line number Diff line number Diff line
use log::{error, info, warn};
use log::{error, info};
use paste::paste;
use std::collections::HashMap;
use std::fmt;
use std::sync::Mutex;

// Fallback to bool when type is not specified
macro_rules! type_expand {
    () => {
        bool
    };
    ($type:ty) => {
        $type
    };
}

macro_rules! default_value {
    () => {
        false
    };
    ($default:tt) => {
    ($type:ty) => {
        <$type>::default()
    };
    ($($type:ty)? = $default:tt) => {
        $default
    };
}

macro_rules! default_flag {
macro_rules! test_value {
    () => {
        true
    };
    ($type:ty) => {
        <$type>::default()
    };
}

macro_rules! create_getter_fn {
    ($flag:ident) => {
        let $flag = false;
        paste! {
            #[doc = concat!(" Return true if ", stringify!($flag), " is enabled")]
            pub fn [<$flag _is_enabled>]() -> bool {
                FLAGS.lock().unwrap().$flag
            }
        }
    };
    ($flag:ident = $default:tt) => {
        let $flag = $default;
    ($flag:ident $type:ty) => {
        paste! {
            #[doc = concat!(" Return the flag value of ", stringify!($flag))]
            pub fn [<get_ $flag>]() -> $type {
                FLAGS.lock().unwrap().$flag
            }
        }
    };
}

macro_rules! init_flags {
    (flags: { $($flag:ident $(= $default:tt)?,)* }, dependencies: { $($parent:ident => $child:ident),* }) => {
    (flags: { $($flag:ident $(: $type:ty)? $(= $default:tt)?,)* }
     extra_fields: { $($extra_field:ident : $extra_field_type:ty $(= $extra_default:tt)?,)* }
     extra_parsed_flags: { $($extra_flag:tt => $extra_flag_fn:ident(_, _ $(,$extra_args:tt)*),)*}
     dependencies: { $($parent:ident => $child:ident),* }) => {

        struct InitFlags {
            $($flag: bool,)*
            $($flag : type_expand!($($type)?),)*
            $($extra_field : $extra_field_type,)*
        }

        impl Default for InitFlags {
            fn default() -> Self {
                $(default_flag!($flag $(= $default)?);)*
                Self { $($flag,)* }
                Self {
                    $($flag : default_value!($($type)? $(= $default)?),)*
                    $($extra_field : default_value!($extra_field_type $(= $extra_default)?),)*
                }
            }
        }

        /// Sets all flags to true, for testing
        /// Sets all bool flags to true
        /// Set all other flags and extra fields to their default type value
        pub fn set_all_for_testing() {
            *FLAGS.lock().unwrap() = InitFlags { $($flag: true,)* };
            *FLAGS.lock().unwrap() = InitFlags {
                $($flag: test_value!($($type)?),)*
                $($extra_field: test_value!($extra_field_type),)*
            };
        }

        impl InitFlags {
@@ -51,8 +96,9 @@ macro_rules! init_flags {

                    match values[0] {
                        $(concat!("INIT_", stringify!($flag)) =>
                            init_flags.$flag = values[1].parse().unwrap_or(default_value!($($default)?)),)*
                        _ => warn!("Unsaved flag: {} = {}", values[0], values[1])
                            init_flags.$flag = values[1].parse().unwrap_or(default_value!($($type)? $(= $default)?)),)*
                        $($extra_flag => $extra_flag_fn(&mut init_flags, values $(, $extra_args)*),)*
                        _ => error!("Unsaved flag: {} = {}", values[0], values[1])
                    }
                }

@@ -60,18 +106,14 @@ macro_rules! init_flags {
            }

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

                    if !any_change {
                    break;
                }
                }

                // TODO: acl should not be off if l2cap is on, but need to reconcile legacy code
                if self.gd_l2cap {
@@ -80,21 +122,51 @@ macro_rules! init_flags {

                self
            }
        }

            fn log(&self) {
                info!(concat!("Flags loaded: ", $(stringify!($flag), "={} ",)*), $(self.$flag,)*);
        impl fmt::Display for InitFlags {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, concat!(
                    concat!($(concat!(stringify!($flag), "={}")),*),
                    $(concat!(stringify!($extra_field), "={}")),*),
                    $(self.$flag),*,
                    $(self.$extra_field),*)
            }
        }

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

#[derive(Default)]
struct ExplicitTagSettings {
    map: HashMap<String, bool>,
}

impl fmt::Display for ExplicitTagSettings {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.map)
    }
}

fn parse_logging_tag(flags: &mut InitFlags, values: Vec<&str>, enabled: bool) {
    for tag in values[1].split(',') {
        flags.logging_debug_explicit_tag_settings.map.insert(tag.to_string(), enabled);
    }
}

/// Return true if `tag` is enabled in the flag
pub fn is_debug_logging_enabled_for_tag(tag: &str) -> bool {
    let guard = FLAGS.lock().unwrap();
    *guard
        .logging_debug_explicit_tag_settings
        .map
        .get(tag)
        .unwrap_or(&guard.logging_debug_enabled_for_all)
}

fn parse_hci_adapter(flags: &mut InitFlags, values: Vec<&str>) {
    flags.hci_adapter = values[1].parse().unwrap_or(0);
}

init_flags!(
@@ -107,9 +179,20 @@ init_flags!(
        gd_link_policy,
        gd_rust,
        gd_security,
        hci_adapter: i32,
        irk_rotation,
        logging_debug_enabled_for_all,
        sdp_serialization = true,
    },
    }
    // extra_fields are not a 1 to 1 match with "INIT_*" flags
    extra_fields: {
        logging_debug_explicit_tag_settings: ExplicitTagSettings,
    }
    extra_parsed_flags: {
        "INIT_logging_debug_enabled_for_tags" => parse_logging_tag(_, _, true),
        "INIT_logging_debug_disabled_for_tags" => parse_logging_tag(_, _, false),
        "--hci" => parse_hci_adapter(_, _),
    }
    dependencies: {
        gd_core => gd_security
    }
@@ -125,10 +208,75 @@ lazy_static! {
}

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

    let flags = InitFlags::parse(flags);
    flags.log();
    let flags = InitFlags::parse(raw_flags);
    info!("Flags loaded: {}", flags);
    *FLAGS.lock().unwrap() = flags;
}

#[cfg(test)]
mod tests {
    use super::*;
    lazy_static! {
        /// do not run concurrent tests as they all use the same global init_flag struct and
        /// accessor
        static ref ASYNC_LOCK: Mutex<bool> = Mutex::new(false);
    }

    fn test_load(raw_flags: Vec<&str>) {
        let raw_flags = raw_flags.into_iter().map(|x| x.to_string()).collect();
        load(raw_flags);
    }

    #[test]
    fn simple_flag() {
        let _guard = ASYNC_LOCK.lock().unwrap();
        test_load(vec![
            "INIT_btaa_hci=false", //override a default flag
            "INIT_gatt_robust_caching_server=true",
        ]);
        assert!(!btaa_hci_is_enabled());
        assert!(gatt_robust_caching_server_is_enabled());
    }
    #[test]
    fn parsing_failure() {
        let _guard = ASYNC_LOCK.lock().unwrap();
        test_load(vec![
            "foo=bar=?",                                // vec length
            "foo=bar",                                  // flag not save
            "INIT_btaa_hci=not_false",                  // parse error but has default value
            "INIT_gatt_robust_caching_server=not_true", // parse error
        ]);
        assert!(btaa_hci_is_enabled());
        assert!(!gatt_robust_caching_server_is_enabled());
    }
    #[test]
    fn int_flag() {
        let _guard = ASYNC_LOCK.lock().unwrap();
        test_load(vec!["--hci=2"]);
        assert_eq!(get_hci_adapter(), 2);
    }
    #[test]
    fn explicit_flag() {
        let _guard = ASYNC_LOCK.lock().unwrap();
        test_load(vec![
            "INIT_logging_debug_enabled_for_all=true",
            "INIT_logging_debug_enabled_for_tags=foo,bar",
            "INIT_logging_debug_disabled_for_tags=foo,bar2",
            "INIT_logging_debug_enabled_for_tags=bar2",
        ]);
        assert!(!is_debug_logging_enabled_for_tag("foo"));
        assert!(is_debug_logging_enabled_for_tag("bar"));
        assert!(is_debug_logging_enabled_for_tag("bar2"));
        assert!(is_debug_logging_enabled_for_tag("unknown_flag"));
        assert!(logging_debug_enabled_for_all_is_enabled());
        FLAGS.lock().unwrap().logging_debug_enabled_for_all = false;
        assert!(!is_debug_logging_enabled_for_tag("foo"));
        assert!(is_debug_logging_enabled_for_tag("bar"));
        assert!(is_debug_logging_enabled_for_tag("bar2"));
        assert!(!is_debug_logging_enabled_for_tag("unknown_flag"));
        assert!(!logging_debug_enabled_for_all_is_enabled());
    }
}
Loading