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

Commit 23de661b authored by Henri Chataing's avatar Henri Chataing
Browse files

RootCanal: Convert the controller configuration to protobuf

The proto configuration is reduced to simplify tweaking
the controller for one behavior.

The user can now configure multiple controllers served on
different HCI ports with different configurations.

The user can choose a default configuration from a list of
presets and edit the features and quirks to test a particular
behavior.

Example configuration:
```
controllers: [
  {
    tcp_port: 1234,
    preset: DEFAULT,
    quirks: {
      has_default_random_address: true,
    },
    features: {
      le_extended_advertising: false,
      le_periodic_advertising: false,
    },
  },
  {
    tcp_port: 1235,
  }
]
```

Test: m && launch_cvd
Bug: 253525123
Bug: 253524429
Bug: 279443791
Change-Id: Ic6fb9aceab9c2246e8aae1f90d51d419d42c5f37
parent eb8c7147
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@ cc_binary {
        "libhidlbase",
        "libjsoncpp",
        "liblog",
        "libprotobuf-cpp-lite",
        "libprotobuf-cpp-full",
        "libutils",
    ],
    cflags: [
@@ -96,7 +96,7 @@ cc_library_shared {
        "libhidlbase",
        "libjsoncpp",
        "liblog",
        "libprotobuf-cpp-lite",
        "libprotobuf-cpp-full",
        "libutils",
    ],
    generated_headers: [
+20 −5
Original line number Diff line number Diff line
@@ -113,19 +113,34 @@ cc_library_static {
        "rootcanal_hci_packets_cxx_gen",
        "rootcanal_link_layer_packets_cxx_gen",
    ],
    export_static_lib_headers: [
        "librootcanal_config",
    ],
    whole_static_libs: [
        "librootcanal_rs",
        "librootcanal_config",
    ],
    shared_libs: [
        "libbase",
        "libcrypto",
    ],
    static_libs: [
        "libjsoncpp",
        "libscriptedbeaconpayload-protos-lite",
    ],
}

// This library contains the generated headers for the
// RootCanal configuration file / parameter.
cc_library_static {
    name: "librootcanal_config",
    host_supported: true,
    vendor_available: true,
    proto: {
        export_proto_headers: true,
    },
    srcs: ["config.proto"],
}

// This library implements a foreigh function interface over DualModeController
// compatible with Python or Rust.
cc_library_host_shared {
@@ -155,7 +170,8 @@ cc_library_host_shared {
    stl: "libc++_static",
    static_libs: [
        "libcrypto",
        "libjsoncpp",
        "librootcanal_config",
        "libprotobuf-cpp-full",
    ],
    whole_static_libs: [
        "libbase",
@@ -257,10 +273,10 @@ cc_test_host {
    shared_libs: [
        "libbase",
        "libcrypto",
        "libprotobuf-cpp-full",
    ],
    static_libs: [
        "libbt-rootcanal",
        "libjsoncpp",
    ],
}

@@ -352,8 +368,7 @@ cc_binary_host {
        "libc++fs",
        "libcrypto",
        "libgflags",
        "libjsoncpp",
        "libprotobuf-cpp-lite",
        "libprotobuf-cpp-full",
        "libscriptedbeaconpayload-protos-lite",
    ],
    sanitize: {
+21 −2
Original line number Diff line number Diff line
@@ -182,6 +182,24 @@ target_include_directories(
target_link_libraries(libscriptedbeaconpayload-protos-lite
                      PRIVATE protobuf::libprotobuf)

android_add_library(
  TARGET librootcanal_config LICENSE Apache-2.0
  SOURCE_DIR ${ROOTCANAL_ROOT} SRC ${librootcanal_config_src})

protobuf_generate_with_plugin(
  TARGET librootcanal_config
  PROTOS ${ROOTCANAL_ROOT}/config.proto
  APPEND_PATH
  PROTOPATH -I${AOSP_ROOT}/external/protobuf/src
  PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/config)

target_include_directories(
  librootcanal_config
  PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/config ${AOSP_ROOT}/external/protobuf/src)

target_link_libraries(librootcanal_config
                      PRIVATE protobuf::libprotobuf)

add_library(libbt-rootcanal.headers INTERFACE)
target_include_directories(libbt-rootcanal.headers INTERFACE ${ROOTCANAL_ROOT})
target_link_libraries(libbt-rootcanal.headers
@@ -262,7 +280,7 @@ android_add_library(
       android-emu-base-logging
       BluetoothPacketSources
       crypto
       jsoncpp
       librootcanal_config
       libscriptedbeaconpayload-protos-lite)

target_include_directories(
@@ -273,7 +291,8 @@ target_include_directories(
         ${ROOTCANAL_ROOT}
         ${BT_ROOT}/gd
         ${BT_ROOT}
         ${CMAKE_CURRENT_BINARY_DIR}/packet_gen)
         ${CMAKE_CURRENT_BINARY_DIR}/packet_gen
         ${CMAKE_CURRENT_BINARY_DIR}/config)

target_compile_options(libbt-rootcanal
                       PUBLIC -Wno-inconsistent-missing-override)
+47 −0
Original line number Diff line number Diff line
syntax = "proto2";

package rootcanal.configuration;
option optimize_for = CODE_SIZE;

enum ControllerPreset {
  // Version 5.3, all features enabled, all quirks disabled.
  DEFAULT = 0;
}

message ControllerFeatures {
  optional bool le_extended_advertising = 1;
  optional bool le_periodic_advertising = 2;
  optional bool ll_privacy = 3;
  optional bool le_2m_phy = 4;
  optional bool le_coded_phy = 5;
}

message ControllerQuirks {
  // Randomly send ACL payloads before the Connection Complete event
  // is sent to the Host stack.
  optional bool send_acl_data_before_connection_complete = 1;
  // Configure a default value for the LE random address.
  optional bool has_default_random_address = 2;
  // Send the Role Change event before the Connection Complete event
  // in the case where a role switch is initiated at connection establishment.
  optional bool send_role_change_before_connection_complete = 3;
}

message Controller {
  // Configure the TCP port on which the controller with this defined
  // configuration will be served.
  required int32 tcp_port = 1;
  // Configure the controller preset. Presets come with a pre-selection
  // of features and quirks, but these can be overridden with the next fields.
  optional ControllerPreset preset = 2;
  // Configure support for controller features.
  optional ControllerFeatures features = 3;
  // Enable controller quirks.
  // Quirks are behaviors observed in real controllers that are not valid
  // according to the specification.
  optional ControllerQuirks quirks = 4;
}

message Configuration {
  repeated Controller controllers = 1;
}
+27 −15
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <gflags/gflags.h>
#include <unwindstack/AndroidUnwinder.h>

#include <fstream>
#include <future>
#include <optional>

@@ -37,8 +38,10 @@ using ::android::net::PosixAsyncSocketConnector;
using ::android::net::PosixAsyncSocketServer;
using rootcanal::AsyncManager;

DEFINE_string(controller_properties_file, "",
              "controller_properties.json file path");
DEFINE_string(controller_properties_file, "", "deprecated");
DEFINE_string(configuration, "", "controller configuration (see config.proto)");
DEFINE_string(configuration_file, "",
              "controller configuration file path (see config.proto)");
DEFINE_string(default_commands_file, "",
              "commands file which root-canal runs it as default");
DEFINE_bool(enable_hci_sniffer, false, "enable hci sniffer");
@@ -115,20 +118,29 @@ int main(int argc, char** argv) {
    return -1;
  }

  AsyncManager am;
  std::string configuration_str;
  if (!FLAGS_configuration.empty()) {
    configuration_str = FLAGS_configuration;
  } else if (!FLAGS_configuration_file.empty()) {
    std::ifstream file(FLAGS_configuration_file);
    std::stringstream buffer;
    buffer << file.rdbuf();
    configuration_str.assign(buffer.str());
  }

  TestEnvironment root_canal(
      std::make_shared<PosixAsyncSocketServer>(
          static_cast<int>(FLAGS_test_port), &am),
      std::make_shared<PosixAsyncSocketServer>(static_cast<int>(FLAGS_hci_port),
                                               &am),
      std::make_shared<PosixAsyncSocketServer>(
          static_cast<int>(FLAGS_link_port), &am),
      std::make_shared<PosixAsyncSocketServer>(
          static_cast<int>(FLAGS_link_ble_port), &am),
      std::make_shared<PosixAsyncSocketConnector>(&am),
      FLAGS_controller_properties_file, FLAGS_default_commands_file,
      FLAGS_enable_hci_sniffer, FLAGS_enable_baseband_sniffer,
      FLAGS_enable_pcap_filter, FLAGS_disable_address_reuse);
      [](AsyncManager* am, int port) {
        return std::make_shared<PosixAsyncSocketServer>(port, am);
      },
      [](AsyncManager* am) {
        return std::make_shared<PosixAsyncSocketConnector>(am);
      },
      static_cast<int>(FLAGS_test_port), static_cast<int>(FLAGS_hci_port),
      static_cast<int>(FLAGS_link_port), static_cast<int>(FLAGS_link_ble_port),
      configuration_str, FLAGS_default_commands_file, FLAGS_enable_hci_sniffer,
      FLAGS_enable_baseband_sniffer, FLAGS_enable_pcap_filter,
      FLAGS_disable_address_reuse);

  std::promise<void> barrier;
  std::future<void> barrier_future = barrier.get_future();
  root_canal.initialize(std::move(barrier));
Loading