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

Commit 479531cd authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 6601700 from 281b30c2 to rvc-release

Change-Id: Ia1310aa0b5e106fce0472017388e96757741fa9f
parents 1d551651 281b30c2
Loading
Loading
Loading
Loading
+23 −15
Original line number Diff line number Diff line
@@ -164,8 +164,17 @@ Return<void> BluetoothHci::initialize_impl(
      [this](AsyncTaskId task) { async_manager_.CancelAsyncTask(task); });

  test_model_.Reset();

  // Add the controller as a device in the model.
  test_model_.Add(controller_);
  size_t controller_index = test_model_.Add(controller_);
  size_t low_energy_phy_index =
      test_model_.AddPhy(test_vendor_lib::Phy::Type::LOW_ENERGY);
  size_t classic_phy_index =
      test_model_.AddPhy(test_vendor_lib::Phy::Type::BR_EDR);
  test_model_.AddDeviceToPhy(controller_index, low_energy_phy_index);
  test_model_.AddDeviceToPhy(controller_index, classic_phy_index);
  test_model_.SetTimerPeriod(std::chrono::milliseconds(10));
  test_model_.StartTimer();

  // Send responses to logcat if the test channel is not configured.
  test_channel_.RegisterSendResponse([](const std::string& response) {
@@ -178,21 +187,20 @@ Return<void> BluetoothHci::initialize_impl(
                   [this](int fd) { test_model_.IncomingHciConnection(fd); });
    SetUpLinkLayerServer(
        6311, [this](int fd) { test_model_.IncomingLinkLayerConnection(fd); });
  }

  // Add some default devices for easier debugging
  test_channel_.AddDefaults();

  } else {
    // This should be configurable in the future.
    LOG_INFO("Adding Beacons so the scan list is not empty.");
    test_channel_.Add({"beacon", "be:ac:10:00:00:01", "1000"});
  test_channel_.AddDeviceToPhy({"2", "1"});
    test_model_.AddDeviceToPhy(controller_index + 1, low_energy_phy_index);
    test_channel_.Add({"beacon", "be:ac:10:00:00:02", "1000"});
  test_channel_.AddDeviceToPhy({"3", "1"});
    test_model_.AddDeviceToPhy(controller_index + 2, low_energy_phy_index);
    test_channel_.Add(
        {"scripted_beacon", "5b:ea:c1:00:00:03",
       "/data/vendor/bluetooth/bluetooth_sim_ble_playback_file"});
  test_channel_.AddDeviceToPhy({"4", "1"});
         "/data/vendor/bluetooth/bluetooth_sim_ble_playback_file",
         "/data/vendor/bluetooth/bluetooth_sim_ble_playback_events"});
    test_model_.AddDeviceToPhy(controller_index + 3, low_energy_phy_index);
    test_channel_.List({});
  }

  unlink_cb_ = [this, cb](sp<BluetoothDeathRecipient>& death_recipient) {
    if (death_recipient->getHasDied())
+124 −96
Original line number Diff line number Diff line
@@ -19,16 +19,14 @@
#include <fstream>
#include <cstdint>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>

#include "model/devices/scripted_beacon_ble_payload.pb.h"
#include "model/setup/device_boutique.h"
#include "os/log.h"

using std::vector;
using std::chrono::steady_clock;
using std::chrono::system_clock;

namespace test_vendor_lib {
bool ScriptedBeacon::registered_ =
@@ -70,109 +68,138 @@ ScriptedBeacon::ScriptedBeacon() {
  properties_.SetLeScanResponse({0x05,  // Length
                                 0x08,  // TYPE_NAME_SHORT
                                 'g', 'b', 'e', 'a'});
  LOG_INFO("Scripted_beacon registered %s", registered_ ? "true" : "false");
}

bool ScriptedBeacon::is_config_file_ready() {
  static bool file_absence_logged = false;
  if (access(config_file_.c_str(), F_OK) == -1) {
   if (!file_absence_logged) {
     LOG_INFO("%s: playback file %s not available",
              __func__,
              config_file_.c_str());
     file_absence_logged = true;
   }
   return false;
 }

 if (access(config_file_.c_str(), R_OK) == -1) {
   LOG_ERROR("%s: playback file %s is not readable",
            __func__,
            config_file_.c_str());
   return false;
 }
 LOG_INFO("%s: playback file %s is available and readable",
            __func__,
            config_file_.c_str());
 return true;
}

bool has_time_elapsed(std::chrono::steady_clock::time_point time_point) {
  std::chrono::steady_clock::time_point now =
        std::chrono::steady_clock::now();
  if (now > time_point) {
    return true;
  } else {
    return false;
  }
bool has_time_elapsed(steady_clock::time_point time_point) {
  return steady_clock::now() > time_point;
}

void ScriptedBeacon::Initialize(const vector<std::string>& args) {
  if (args.size() < 2) return;
  if (args.size() < 2) {
    LOG_ERROR(
        "Initialization failed, need mac address, playback and playback events "
        "file arguments");
    return;
  }

  Address addr{};
  if (Address::FromString(args[1], addr)) properties_.SetLeAddress(addr);

  if (args.size() < 3) return;

  if (args.size() < 4) {
    LOG_ERROR(
        "Initialization failed, need playback and playback events file "
        "arguments");
  }
  config_file_ = args[2];
  events_file_ = args[3];
  set_state(PlaybackEvent::INITIALIZED);
}

void ScriptedBeacon::populate_event(PlaybackEvent * event, PlaybackEvent::PlaybackEventType type) {
  LOG_INFO("Adding event: %d", type);
  event->set_type(type);
  event->set_secs_since_epoch(system_clock::now().time_since_epoch().count());
}

// Adds events to events file; we won't be able to post anything to the file
// until we set to permissive mode in tests. No events are posted until then.
void ScriptedBeacon::set_state(PlaybackEvent::PlaybackEventType state) {
  PlaybackEvent event;
  current_state_ = state;
  if (!events_ostream_.is_open()) {
    events_ostream_.open(events_file_, std::ios::out | std::ios::binary | std::ios::trunc);
    if (!events_ostream_.is_open()) {
      LOG_INFO("Events file not opened yet, for event: %d", state);
      return;
    }
  }
  populate_event(&event, state);
  event.SerializeToOstream(&events_ostream_);
  events_ostream_.flush();
}

void ScriptedBeacon::TimerTick() {
  if (!scanned_once_) {
  switch (current_state_) {
    case PlaybackEvent::INITIALIZED:
      Beacon::TimerTick();
  } else {
    static std::chrono::steady_clock::time_point next_check_time =
      std::chrono::steady_clock::now();
    if (!play_back_on_) {
      if (!has_time_elapsed(next_check_time)) {
      break;
    case PlaybackEvent::SCANNED_ONCE:
      next_check_time_ =
          steady_clock::now() + steady_clock::duration(std::chrono::seconds(1));
      set_state(PlaybackEvent::WAITING_FOR_FILE);
      break;
    case PlaybackEvent::WAITING_FOR_FILE:
      if (!has_time_elapsed(next_check_time_)) {
        return;
      }
      if (!is_config_file_ready()) {
        next_check_time = std::chrono::steady_clock::now() +
            std::chrono::steady_clock::duration(std::chrono::seconds(1));
      next_check_time_ =
          steady_clock::now() + steady_clock::duration(std::chrono::seconds(1));
      if (access(config_file_.c_str(), F_OK) == -1) {
        return;
      }
      // Give time for the file to be written completely before being read
      {
        static std::chrono::steady_clock::time_point write_delay_next_check_time =
            std::chrono::steady_clock::now() +
            std::chrono::steady_clock::duration(std::chrono::seconds(1));
         if (!has_time_elapsed(write_delay_next_check_time)) {
      set_state(PlaybackEvent::WAITING_FOR_FILE_TO_BE_READABLE);
      break;
    case PlaybackEvent::WAITING_FOR_FILE_TO_BE_READABLE:
      if (access(config_file_.c_str(), R_OK) == -1) {
        return;
      }
      set_state(PlaybackEvent::PARSING_FILE);
      break;
    case PlaybackEvent::PARSING_FILE: {
      if (!has_time_elapsed(next_check_time_)) {
        return;
      }

      std::fstream input(config_file_, std::ios::in | std::ios::binary);
      if (!ble_ad_list_.ParseFromIstream(&input)) {
        LOG_ERROR("%s: Cannot parse playback file %s", __func__, config_file_.c_str());
        LOG_ERROR("Cannot parse playback file %s", config_file_.c_str());
        set_state(PlaybackEvent::FILE_PARSING_FAILED);
        return;
      }
      LOG_INFO("%s: Starting Ble advertisement playback from file: %s", __func__, config_file_.c_str());
      play_back_on_ = true;
      } else {
        set_state(PlaybackEvent::PLAYBACK_STARTED);
        LOG_INFO("Starting Ble advertisement playback from file: %s",
                 config_file_.c_str());
        next_ad_.ad_time = steady_clock::now();
        get_next_advertisement();
        input.close();
      }
    } break;
    case PlaybackEvent::PLAYBACK_STARTED: {
      std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send;
    std::chrono::steady_clock::time_point now =
        std::chrono::steady_clock::now();
    elapsed_time_ += now - last_timer_tick_;
    while (play_back_on_ && !play_back_complete_ && next_ad_.ad_time < now) {
      while (has_time_elapsed(next_ad_.ad_time)) {
        auto ad = model::packets::LeAdvertisementBuilder::Create(
            next_ad_.address, Address::kEmpty /* Destination */,
            model::packets::AddressType::RANDOM,
            model::packets::AdvertisementType::ADV_NONCONN_IND, next_ad_.ad);
        to_send = std::move(ad);
      for (auto phy : phy_layers_[Phy::Type::LOW_ENERGY]) {
        for (const auto& phy : phy_layers_[Phy::Type::LOW_ENERGY]) {
          phy->Send(to_send);
        }
        if (packet_num_ < ble_ad_list_.advertisements().size()) {
          get_next_advertisement();
        } else {
          set_state(PlaybackEvent::PLAYBACK_ENDED);
          if (events_ostream_.is_open()) {
            events_ostream_.close();
          }
    last_timer_tick_ = now;
          LOG_INFO(
              "Completed Ble advertisement playback from file: %s with %d "
              "packets",
              config_file_.c_str(), packet_num_);
          break;
        }
      }
    } break;
    case PlaybackEvent::FILE_PARSING_FAILED:
    case PlaybackEvent::PLAYBACK_ENDED:
    case PlaybackEvent::UNKNOWN:
      return;
  }
}

void ScriptedBeacon::IncomingPacket(
    model::packets::LinkLayerPacketView packet) {
  if (!scanned_once_) {
  if (current_state_ == PlaybackEvent::INITIALIZED) {
    if (packet.GetDestinationAddress() == properties_.GetLeAddress() &&
        packet.GetType() == model::packets::PacketType::LE_SCAN) {
      auto scan_response = model::packets::LeScanResponseBuilder::Create(
@@ -183,9 +210,8 @@ void ScriptedBeacon::IncomingPacket(
          properties_.GetLeScanResponse());
      std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send =
          std::move(scan_response);
      scanned_once_ = true;
      Address::FromString("12:34:56:78:9A:BC", next_ad_.address);
      for (auto phy : phy_layers_[Phy::Type::LOW_ENERGY]) {
      set_state(PlaybackEvent::SCANNED_ONCE);
      for (const auto& phy : phy_layers_[Phy::Type::LOW_ENERGY]) {
        phy->Send(to_send);
      }
    }
@@ -193,22 +219,24 @@ void ScriptedBeacon::IncomingPacket(
}

void ScriptedBeacon::get_next_advertisement() {
  static int packet_num = 0;

  if (packet_num < ble_ad_list_.advertisements().size()) {
    std::string payload = ble_ad_list_.advertisements(packet_num).payload();
    std::string mac_address = ble_ad_list_.advertisements(packet_num).mac_address();
  std::string payload = ble_ad_list_.advertisements(packet_num_).payload();
  std::string mac_address =
      ble_ad_list_.advertisements(packet_num_).mac_address();
  uint32_t delay_before_send_ms =
        ble_ad_list_.advertisements(packet_num).delay_before_send_ms();
      ble_ad_list_.advertisements(packet_num_).delay_before_send_ms();
  next_ad_.ad.assign(payload.begin(), payload.end());
  if (Address::IsValidAddress(mac_address)) {
    // formatted string with colons like "12:34:56:78:9a:bc"
    Address::FromString(mac_address, next_ad_.address);
    next_ad_.ad_time = std::chrono::steady_clock::now() +
                      std::chrono::steady_clock::duration(
                          std::chrono::milliseconds(delay_before_send_ms));
    packet_num++;
  } else if (mac_address.size() == Address::kLength) {
    // six-byte binary address
    std::vector<uint8_t> mac_vector(mac_address.cbegin(), mac_address.cend());
    next_ad_.address.Address::FromOctets(mac_vector.data());
  } else {
    play_back_complete_ = true;
    LOG_INFO("%s: Completed Ble advertisement playback from file: %s", __func__, config_file_.c_str());
    Address::FromString("BA:D0:AD:BA:D0:AD", next_ad_.address);
  }
  next_ad_.ad_time +=
      steady_clock::duration(std::chrono::milliseconds(delay_before_send_ms));
  packet_num_++;
}
}  // namespace test_vendor_lib
+13 −9
Original line number Diff line number Diff line
@@ -18,10 +18,13 @@

#include <cstdint>
#include <vector>
#include <fstream>

#include "model/devices/scripted_beacon_ble_payload.pb.h"
#include "beacon.h"

using android::bluetooth::test_vendor_lib::model::devices::ScriptedBeaconBleAdProto::PlaybackEvent;

namespace test_vendor_lib {
// Pretend to be a lot of beacons by advertising from a file.
class ScriptedBeacon : public Beacon {
@@ -51,26 +54,27 @@ class ScriptedBeacon : public Beacon {

 private:
  static bool registered_;
  bool scanned_once_{false};
  std::chrono::steady_clock::duration elapsed_time_{};
  std::chrono::steady_clock::time_point last_timer_tick_{};
  std::string config_file_{};
  std::string events_file_{};
  std::ofstream events_ostream_;
  struct Advertisement {
    std::vector<uint8_t> ad;
    Address address;
    std::chrono::steady_clock::time_point ad_time;
  };

  void populate_event(PlaybackEvent * event, PlaybackEvent::PlaybackEventType type);

  void get_next_advertisement();

  bool is_config_file_ready();
  void set_state(
      android::bluetooth::test_vendor_lib::model::devices::
          ScriptedBeaconBleAdProto::PlaybackEvent::PlaybackEventType type);

  Advertisement next_ad_{};

  int packet_num_{0};
  PlaybackEvent::PlaybackEventType current_state_{PlaybackEvent::UNKNOWN};
  std::chrono::steady_clock::time_point next_check_time_{};
  android::bluetooth::test_vendor_lib::model::devices::ScriptedBeaconBleAdProto::BleAdvertisementList ble_ad_list_;

  bool play_back_on_{false};

  bool play_back_complete_{false};
};
}  // namespace test_vendor_lib
+18 −0
Original line number Diff line number Diff line
@@ -13,3 +13,21 @@ message BleAdvertisement {
message BleAdvertisementList {
  repeated BleAdvertisement advertisements = 1;
}

message PlaybackEvent {
  // These events should occur in order, starting from INITIALIZED
  enum PlaybackEventType {
    UNKNOWN = 0;
    INITIALIZED = 1;
    SCANNED_ONCE = 2;
    WAITING_FOR_FILE = 3;
    WAITING_FOR_FILE_TO_BE_READABLE = 4;
    PARSING_FILE = 5;
    PLAYBACK_STARTED = 6;
    PLAYBACK_ENDED = 7;
    // Error conditions
    FILE_PARSING_FAILED = 8;
  }
  optional PlaybackEventType type = 1;
  optional uint64 secs_since_epoch = 2;
}