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

Commit 2ef2d3ac authored by Myles Watson's avatar Myles Watson
Browse files

HCI: Add LeAdvertisingManager

Bug: 139080884
Test: builds
Change-Id: I40aa2b5f0cf85ce601c310020ed51a204cc0501b
parent 570c8dcc
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -2,13 +2,14 @@ filegroup {
    name: "BluetoothHciSources",
    srcs: [
        "acl_manager.cc",
        "classic_security_manager.cc",
        "controller.cc",
        "address.cc",
        "classic_security_manager.cc",
        "class_of_device.cc",
        "controller.cc",
        "device.cc",
        "device_database.cc",
        "hci_layer.cc",
        "le_advertising_manager.cc",
    ],
}

+1 −6
Original line number Diff line number Diff line
@@ -37,13 +37,8 @@ class LeAdvertisingInterface {
                              common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) = 0;

  static constexpr hci::SubeventCode LeAdvertisingEvents[] = {
      hci::SubeventCode::ADVERTISING_REPORT,
      hci::SubeventCode::DIRECTED_ADVERTISING_REPORT,
      hci::SubeventCode::EXTENDED_ADVERTISING_REPORT,
      hci::SubeventCode::PERIODIC_ADVERTISING_REPORT,
      hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED,
      hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST,
      hci::SubeventCode::SCAN_REQUEST_RECEIVED,
      hci::SubeventCode::ADVERTISING_SET_TERMINATED,
  };
};
}  // namespace hci
+262 −0
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 <memory>
#include <mutex>

#include "hci/controller.h"
#include "hci/hci_layer.h"
#include "hci/hci_packets.h"
#include "hci/le_advertising_interface.h"
#include "hci/le_advertising_manager.h"
#include "module.h"
#include "os/handler.h"
#include "os/log.h"

namespace bluetooth {
namespace hci {

const ModuleFactory LeAdvertisingManager::Factory = ModuleFactory([]() { return new LeAdvertisingManager(); });

struct Advertiser {
  os::Handler* handler;
  common::Callback<void(Address, AddressType)> scan_callback;
  common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback;
};

struct LeAdvertisingManager::impl {
  impl(Module* module, os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller)
      : registered_handler_(nullptr), module_(module), module_handler_(handler), hci_layer_(hci_layer),
        controller_(controller), le_advertising_interface_(nullptr), num_instances_(0) {}

  void start() {
    le_advertising_interface_ = hci_layer_->GetLeAdvertisingInterface(
        common::Bind(&LeAdvertisingManager::impl::handle_event, common::Unretained(this)), module_handler_);
    num_instances_ = controller_->GetControllerLeNumberOfSupportedAdverisingSets();
  }

  size_t GetNumberOfAdvertisingInstances() const {
    return num_instances_;
  }

  void handle_event(LeMetaEventView event) {
    switch (event.GetSubeventCode()) {
      case hci::SubeventCode::SCAN_REQUEST_RECEIVED:
        handle_scan_request(LeScanRequestReceivedView::Create(event));
        break;
      case hci::SubeventCode::ADVERTISING_SET_TERMINATED:
        handle_set_terminated(LeAdvertisingSetTerminatedView::Create(event));
        break;
      default:
        LOG_INFO("Unknown subevent in scanner %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str());
    }
  }

  void handle_scan_request(LeScanRequestReceivedView event_view) {
    if (!event_view.IsValid()) {
      LOG_INFO("Dropping invalid scan request event");
      return;
    }
    registered_handler_->Post(
        common::BindOnce(scan_callback_, event_view.GetScannerAddress(), event_view.GetScannerAddressType()));
  }

  void handle_set_terminated(LeAdvertisingSetTerminatedView event_view) {
    if (!event_view.IsValid()) {
      LOG_INFO("Dropping invalid advertising event");
      return;
    }
    registered_handler_->Post(common::BindOnce(set_terminated_callback_, event_view.GetStatus(),
                                               event_view.GetAdvertisingHandle(),
                                               event_view.GetNumCompletedExtendedAdvertisingEvents()));
  }

  AdvertiserId allocate_advertiser() {
    AdvertiserId id = 0;
    {
      std::unique_lock lock(id_mutex_);
      while (id < num_instances_ && advertising_sets_.count(id) == 0) {
        id++;
      }
    }
    if (id == num_instances_) {
      return kInvalidId;
    }
    return id;
  }

  void remove_advertiser(AdvertiserId id) {
    std::unique_lock lock(id_mutex_);
    if (advertising_sets_.count(id) == 0) {
      return;
    }
    advertising_sets_.erase(id);
  }

  void create_advertiser(AdvertiserId id, const AdvertisingConfig& config,
                         const common::Callback<void(Address, AddressType)>& scan_callback,
                         const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
                         os::Handler* handler) {
    advertising_sets_[id].scan_callback = scan_callback;
    advertising_sets_[id].set_terminated_callback = set_terminated_callback;
    advertising_sets_[id].handler = handler;
    if (!controller_->IsSupported(hci::OpCode::LE_MULTI_ADVT)) {
      le_advertising_interface_->EnqueueCommand(
          hci::LeSetAdvertisingParametersBuilder::Create(config.interval_min, config.interval_max, config.event_type,
                                                         config.address_type, config.peer_address_type,
                                                         config.peer_address, config.channel_map, config.filter_policy),
          common::BindOnce(impl::check_enable_status), module_handler_);
      le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingDataBuilder::Create(config.advertisement),
                                                common::BindOnce(impl::check_enable_status), module_handler_);
      le_advertising_interface_->EnqueueCommand(hci::LeSetRandomAddressBuilder::Create(config.random_address),
                                                common::BindOnce(impl::check_enable_status), module_handler_);
      if (!config.scan_response.empty()) {
        le_advertising_interface_->EnqueueCommand(hci::LeSetScanResponseDataBuilder::Create(config.scan_response),
                                                  common::BindOnce(impl::check_enable_status), module_handler_);
      }
      le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingDataBuilder::Create(config.advertisement),
                                                common::BindOnce(impl::check_enable_status), module_handler_);
      return;
    }
    le_advertising_interface_->EnqueueCommand(
        hci::LeMultiAdvtParamBuilder::Create(config.interval_min, config.interval_max, config.event_type,
                                             config.address_type, config.peer_address_type, config.peer_address,
                                             config.channel_map, config.filter_policy, id, config.tx_power),
        common::BindOnce(impl::check_enable_status), module_handler_);
    le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingEnableBuilder::Create(Enable::ENABLED),
                                              common::BindOnce(impl::check_enable_status), module_handler_);
  }

  void create_extended_advertiser(AdvertiserId id, const ExtendedAdvertisingConfig& config,
                                  const common::Callback<void(Address, AddressType)>& scan_callback,
                                  const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
                                  os::Handler* handler) {
    if (!controller_->IsSupported(hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS)) {
      create_advertiser(id, config, scan_callback, set_terminated_callback, handler);
      return;
    } else {
      LOG_ALWAYS_FATAL("LE_SET_EXTENDED_ADVERTISING_PARAMETERS isn't implemented.");
    }

    /*
    le_advertising_interface_->EnqueueCommand(hci::LeSetExtendedAdvertisingParametersBuilder::Create(config.interval_min,
    config.interval_max, config.event_type, config.address_type, config.peer_address_type, config.peer_address,
    config.channel_map, config.filter_policy, id, config.tx_power), common::BindOnce(impl::check_enable_status),
    module_handler_);
     */
    advertising_sets_[id].scan_callback = scan_callback;
    advertising_sets_[id].set_terminated_callback = set_terminated_callback;
    advertising_sets_[id].handler = handler;
  }

  void stop_advertising(AdvertiserId advertising_set) {
    if (advertising_sets_.find(advertising_set) == advertising_sets_.end()) {
      LOG_INFO("Unknown advertising set %u", advertising_set);
      return;
    }
    le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED),
                                              common::BindOnce(impl::check_enable_status), module_handler_);
    std::unique_lock lock(id_mutex_);
    advertising_sets_.erase(advertising_set);
  }

  common::Callback<void(Address, AddressType)> scan_callback_;
  common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback_;
  os::Handler* registered_handler_;
  Module* module_;
  os::Handler* module_handler_;
  hci::HciLayer* hci_layer_;
  hci::Controller* controller_;
  hci::LeAdvertisingInterface* le_advertising_interface_;
  std::map<AdvertiserId, Advertiser> advertising_sets_;

  std::mutex id_mutex_;
  size_t num_instances_;

  static void check_enable_status(CommandCompleteView view) {
    ASSERT(view.IsValid());
    auto status_view = LeSetAdvertisingEnableCompleteView::Create(view);
    ASSERT(status_view.IsValid());
    if (status_view.GetStatus() != ErrorCode::SUCCESS) {
      LOG_INFO("SetEnable returned status %s", ErrorCodeText(status_view.GetStatus()).c_str());
      return;
    }
  }
};

const AdvertiserId LeAdvertisingManager::kInvalidId = -1;

LeAdvertisingManager::LeAdvertisingManager() {
  pimpl_ = std::make_unique<impl>(this, GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>());
}

void LeAdvertisingManager::ListDependencies(ModuleList* list) {
  list->add<hci::HciLayer>();
  list->add<hci::Controller>();
}

void LeAdvertisingManager::Start() {
  pimpl_->start();
}

void LeAdvertisingManager::Stop() {
  pimpl_.reset();
}

size_t LeAdvertisingManager::GetNumberOfAdvertisingInstances() const {
  return pimpl_->GetNumberOfAdvertisingInstances();
}

AdvertiserId LeAdvertisingManager::CreateAdvertiser(
    const AdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback,
    const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) {
  if (config.peer_address == Address::kEmpty) {
    if (config.address_type == hci::AddressType::PUBLIC_IDENTITY_ADDRESS ||
        config.address_type == hci::AddressType::RANDOM_IDENTITY_ADDRESS) {
      return kInvalidId;
    }
    if (config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND ||
        config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND_LOW) {
      return kInvalidId;
    }
  }
  AdvertiserId id = pimpl_->allocate_advertiser();
  if (id == kInvalidId) {
    return id;
  }
  GetHandler()->Post(common::BindOnce(&impl::create_advertiser, common::Unretained(pimpl_.get()), id, config,
                                      scan_callback, set_terminated_callback, handler));
  return id;
}

AdvertiserId LeAdvertisingManager::CreateAdvertiser(
    const ExtendedAdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback,
    const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) {
  AdvertiserId id = pimpl_->allocate_advertiser();
  if (id == kInvalidId) {
    return id;
  }
  // Add error checking here
  GetHandler()->Post(common::BindOnce(&impl::create_extended_advertiser, common::Unretained(pimpl_.get()), id, config,
                                      scan_callback, set_terminated_callback, handler));
  return id;
}

void LeAdvertisingManager::RemoveAdvertiser(AdvertiserId id) {
  pimpl_->remove_advertiser(id);
}

}  // namespace hci
}  // namespace bluetooth
 No newline at end of file
+95 −0
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.
 */
#pragma once

#include <memory>

#include "hci/hci_packets.h"
#include "module.h"

namespace bluetooth {
namespace hci {

class AdvertisingConfig {
 public:
  std::vector<GapData> advertisement;
  std::vector<GapData> scan_response;
  Address random_address;
  uint16_t interval_min;
  uint16_t interval_max;
  AdvertisingEventType event_type;
  AddressType address_type;
  PeerAddressType peer_address_type;
  Address peer_address;
  uint8_t channel_map;
  AdvertisingFilterPolicy filter_policy;
  uint8_t tx_power;  // -127 to +20 (0x7f is no preference)
};

class ExtendedAdvertisingConfig : public AdvertisingConfig {
 public:
  bool connectable;
  bool scannable;
  bool directed;
  bool high_duty_directed_connectable;
  bool legacy_pdus;
  bool anonymous;
  bool include_tx_power;
  bool use_le_coded_phy;       // Primary advertisement PHY is LE Coded
  uint8_t secondary_max_skip;  // maximum advertising events to be skipped, 0x0 send AUX_ADV_IND prior ot the next event
  uint8_t secondary_advertising_phy;  // 1 = 1M, 2 = 2M, 3 = coded
  uint8_t sid;
  bool enable_scan_request_notifications;
};

using AdvertiserId = int32_t;

class LeAdvertisingManager : public bluetooth::Module {
 public:
  static const AdvertiserId kInvalidId;
  LeAdvertisingManager();

  size_t GetNumberOfAdvertisingInstances() const;

  // Return -1 if the advertiser was not created, otherwise the advertiser ID.
  AdvertiserId CreateAdvertiser(const AdvertisingConfig& config,
                                const common::Callback<void(Address, AddressType)>& scan_callback,
                                const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
                                os::Handler* handler);
  AdvertiserId CreateAdvertiser(const ExtendedAdvertisingConfig& config,
                                const common::Callback<void(Address, AddressType)>& scan_callback,
                                const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
                                os::Handler* handler);

  void RemoveAdvertiser(AdvertiserId id);

  static const ModuleFactory Factory;

 protected:
  void ListDependencies(ModuleList* list) override;

  void Start() override;

  void Stop() override;

 private:
  struct impl;
  std::unique_ptr<impl> pimpl_;
  DISALLOW_COPY_AND_ASSIGN(LeAdvertisingManager);
};

}  // namespace hci
}  // namespace bluetooth
 No newline at end of file