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

Commit 33522b87 authored by Myles Watson's avatar Myles Watson Committed by Sanjay Ramankandath
Browse files

RootCanal: Add a scripted beacon for testing

Bug: 154491371
Tag: #feature
Test: Scan for devices
Test: gd/cert/run --host
Change-Id: I3354d621d4253d051eb7b814de8d7889dcf99f64
parent a1fc0d3a
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -190,6 +190,9 @@ Return<void> BluetoothHci::initialize_impl(
  test_channel_.AddDeviceToPhy({"2", "1"});
  test_channel_.AddDeviceToPhy({"2", "1"});
  test_channel_.Add({"beacon", "be:ac:10:00:00:02", "1000"});
  test_channel_.Add({"beacon", "be:ac:10:00:00:02", "1000"});
  test_channel_.AddDeviceToPhy({"3", "1"});
  test_channel_.AddDeviceToPhy({"3", "1"});
  test_channel_.Add(
      {"scripted_beacon", "5b:ea:c1:00:00:03", "path_to_config.log"});
  test_channel_.AddDeviceToPhy({"4", "1"});


  unlink_cb_ = [this, cb](sp<BluetoothDeathRecipient>& death_recipient) {
  unlink_cb_ = [this, cb](sp<BluetoothDeathRecipient>& death_recipient) {
    if (death_recipient->getHasDied())
    if (death_recipient->getHasDied())
+1 −0
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ cc_library_static {
        "model/devices/loopback.cc",
        "model/devices/loopback.cc",
        "model/devices/polled_socket.cc",
        "model/devices/polled_socket.cc",
        "model/devices/remote_loopback_device.cc",
        "model/devices/remote_loopback_device.cc",
        "model/devices/scripted_beacon.cc",
        "model/devices/sniffer.cc",
        "model/devices/sniffer.cc",
        "model/setup/async_manager.cc",
        "model/setup/async_manager.cc",
        "model/setup/device_boutique.cc",
        "model/setup/device_boutique.cc",
+176 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2016 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 "scripted_beacon.h"

// #include "hci/hci_packets.h" // To use error-checking packets
#include "model/setup/device_boutique.h"

using std::vector;

namespace test_vendor_lib {
bool ScriptedBeacon::registered_ =
    DeviceBoutique::Register("scripted_beacon", &ScriptedBeacon::Create);

ScriptedBeacon::ScriptedBeacon() {
  advertising_interval_ms_ = std::chrono::milliseconds(1280);
  properties_.SetLeAdvertisementType(0x03 /* NON_CONNECT */);
  properties_.SetLeAdvertisement({
      0x18,  // Length
      0x09 /* TYPE_NAME_CMPL */,
      'g',
      'D',
      'e',
      'v',
      'i',
      'c',
      'e',
      '-',
      's',
      'c',
      'r',
      'i',
      'p',
      't',
      'e',
      'd',
      '-',
      'b',
      'e',
      'a',
      'c',
      'o',
      'n',
      0x02,  // Length
      0x01 /* TYPE_FLAG */,
      0x4 /* BREDR_NOT_SPT */ | 0x2 /* GEN_DISC_FLAG */,
  });

  properties_.SetLeScanResponse({0x06,  // Length
                                 0x07,  // TYPE_NAME_SHORT
                                 'g', 'b', 'e', 'a'});
}

void ScriptedBeacon::Initialize(const vector<std::string>& args) {
  if (args.size() < 2) return;

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

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

  config_file_ = args[2];
}

void ScriptedBeacon::TimerTick() {
  if (!scanned_once_) {
    Beacon::TimerTick();
  } else {
    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 (next_ad_.ad_time < now) {
      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]) {
        phy->Send(to_send);
      }
      get_next_advertisement();
    }
    last_timer_tick_ = now;
  }
}

void ScriptedBeacon::IncomingPacket(
    model::packets::LinkLayerPacketView packet) {
  if (!scanned_once_) {
    if (packet.GetDestinationAddress() == properties_.GetLeAddress() &&
        packet.GetType() == model::packets::PacketType::LE_SCAN) {
      auto scan_response = model::packets::LeScanResponseBuilder::Create(
          properties_.GetLeAddress(), packet.GetSourceAddress(),
          static_cast<model::packets::AddressType>(
              properties_.GetLeAddressType()),
          model::packets::AdvertisementType::SCAN_RESPONSE,
          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);
      open_config_file();
      for (auto phy : phy_layers_[Phy::Type::LOW_ENERGY]) {
        phy->Send(to_send);
      }
    }
  }
}

void ScriptedBeacon::get_next_advertisement() {
  next_ad_.address.address[2]++;
  /* For more recent versions:
   * using bluetooth::hci::GapData;
   * using bluetooth::hci::GapDataType;
   * GapData flags;
   * flags.data_type_ = GapDataType::FLAGS;
   * flags.data_ = {0x1A};
   * GapData service;
   * service.data_type_ = GapDataType::COMPLETE_LIST_16_BIT_UUIDS;
   * service.data_ = {0x6F, 0xFD}; // 0xFD6F Contact Detection Service
   * GapData proximity_id;
   * proximity_id.data_type = GapDataType::SERVICE_DATA_128_BIT_UUIDS;
   * proximity_id.data_ = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
   *                       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   *                       };
   */
  // For older/all versions:
  next_ad_.ad = {
      0x02,  // Size
      0x01,  // Flag
      0x1A,
      0x03,  // Size
      0x03,  // Complete 16-bit Service UUID
      0x6F,
      0xFD,
      0x13,  // Size
      0x16,  // Service Data - 16 bit UUID
      0x6F,  // FD6F
      0xFD,
      0x00,  // ID
      0x01,
      next_ad_.address.address[2],  // make it different from the others
      0x03,
      0x04,
      0x05,
      0x06,
      0x07,
      0x08,
      0x09,
      0x0a,
      0x0b,
      0x0c,
      0x0d,
      0x0e,
      0x0f,
  };
}

void ScriptedBeacon::open_config_file() {
  // Open the config file and read it all?
}
}  // namespace test_vendor_lib
+70 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2020 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.
 */

#pragma once

#include <cstdint>
#include <vector>

#include "beacon.h"

namespace test_vendor_lib {

// Pretend to be a lot of beacons by advertising from a file.
class ScriptedBeacon : public Beacon {
 public:
  ScriptedBeacon();
  virtual ~ScriptedBeacon() = default;

  static std::shared_ptr<Device> Create() {
    return std::make_shared<ScriptedBeacon>();
  }

  // Return a string representation of the type of device.
  virtual std::string GetTypeString() const override {
    return "scripted_beacon";
  }

  virtual std::string ToString() const override {
    return "scripted_beacon " + config_file_;
  }

  // Set the address and advertising interval from string args.
  void Initialize(const std::vector<std::string>& args) override;

  void TimerTick() override;

  void IncomingPacket(model::packets::LinkLayerPacketView packet_view) override;

 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_{};
  void open_config_file();
  struct Advertisement {
    std::vector<uint8_t> ad;
    Address address;
    std::chrono::steady_clock::time_point ad_time;
  };

  void get_next_advertisement();

  Advertisement next_ad_{};
};

}  // namespace test_vendor_lib
+2 −0
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@
#include "model/devices/classic.h"
#include "model/devices/classic.h"
#include "model/devices/keyboard.h"
#include "model/devices/keyboard.h"
#include "model/devices/remote_loopback_device.h"
#include "model/devices/remote_loopback_device.h"
#include "model/devices/scripted_beacon.h"
#include "model/devices/sniffer.h"
#include "model/devices/sniffer.h"


#include <memory>
#include <memory>
@@ -63,6 +64,7 @@ TestModel::TestModel(
  example_devices_.push_back(std::make_shared<CarKit>());
  example_devices_.push_back(std::make_shared<CarKit>());
  example_devices_.push_back(std::make_shared<Classic>());
  example_devices_.push_back(std::make_shared<Classic>());
  example_devices_.push_back(std::make_shared<Sniffer>());
  example_devices_.push_back(std::make_shared<Sniffer>());
  example_devices_.push_back(std::make_shared<ScriptedBeacon>());
  example_devices_.push_back(std::make_shared<RemoteLoopbackDevice>());
  example_devices_.push_back(std::make_shared<RemoteLoopbackDevice>());
}
}