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

Commit 9f111f84 authored by Myles Watson's avatar Myles Watson
Browse files

HCI: Add LeScanningManager

Bug: 139080884
Test: bluetooth_test_gd
Change-Id: Ie0aee4042330e2789727aaffda818279b71e02ca
parent b5233896
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ filegroup {
        "device_database.cc",
        "hci_layer.cc",
        "le_advertising_manager.cc",
        "le_scanning_manager.cc",
    ],
}

@@ -29,6 +30,7 @@ filegroup {
        "dual_device_test.cc",
        "hci_layer_test.cc",
        "hci_packets_test.cc",
        "le_scanning_manager_test.cc",
    ],
}

+83 −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"

namespace bluetooth::hci {

class LeReport {
 public:
  explicit LeReport(const LeAdvertisingReport& advertisement)
      : report_type_(ReportType::ADVERTISING_EVENT), advertising_event_type_(advertisement.event_type_),
        address_(advertisement.address_), address_type_(advertisement.address_type_), rssi_(advertisement.rssi_),
        gap_data_(advertisement.advertising_data_) {}
  explicit LeReport(const LeDirectedAdvertisingReport& advertisement)
      : report_type_(ReportType::DIRECTED_ADVERTISING_EVENT), address_(advertisement.address_),
        rssi_(advertisement.rssi_) {}
  explicit LeReport(const LeExtendedAdvertisingReport& advertisement)
      : report_type_(ReportType::EXTENDED_ADVERTISING_EVENT), address_(advertisement.address_),
        rssi_(advertisement.rssi_), gap_data_(advertisement.advertising_data_) {}
  virtual ~LeReport() = default;

  enum class ReportType {
    ADVERTISING_EVENT = 1,
    DIRECTED_ADVERTISING_EVENT = 2,
    EXTENDED_ADVERTISING_EVENT = 3,
  };
  const ReportType report_type_;

  ReportType GetReportType() const {
    return report_type_;
  }

  // Advertising Event
  const AdvertisingEventType advertising_event_type_{};
  const Address address_{};
  const AddressType address_type_{};
  const uint8_t rssi_;
  const std::vector<GapData> gap_data_{};
};

class DirectedLeReport : public LeReport {
 public:
  explicit DirectedLeReport(const LeDirectedAdvertisingReport& advertisement)
      : LeReport(advertisement), direct_address_type_(advertisement.address_type_) {}
  explicit DirectedLeReport(const LeExtendedAdvertisingReport& advertisement)
      : LeReport(advertisement), direct_address_type_(advertisement.address_type_) {}

  const DirectAdvertisingAddressType direct_address_type_{};
};

class ExtendedLeReport : public DirectedLeReport {
 public:
  explicit ExtendedLeReport(const LeExtendedAdvertisingReport& advertisement)
      : DirectedLeReport(advertisement), connectable_(advertisement.connectable_), scannable_(advertisement.scannable_),
        directed_(advertisement.directed_), scan_response_(advertisement.scan_response_),
        complete_(advertisement.data_status_ == DataStatus::COMPLETE),
        truncated_(advertisement.data_status_ == DataStatus::TRUNCATED) {}

  // Extended
  bool connectable_;
  bool scannable_;
  bool directed_;
  bool scan_response_;
  bool complete_;
  bool truncated_;
};
}  // namespace bluetooth::hci
 No newline at end of file
+6 −0
Original line number Diff line number Diff line
@@ -38,6 +38,12 @@ class LeScanningInterface {

  static constexpr hci::SubeventCode LeScanningEvents[] = {
      hci::SubeventCode::SCAN_TIMEOUT,
      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,
  };
};
}  // namespace hci
+247 −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 <set>

#include "hci/controller.h"
#include "hci/hci_layer.h"
#include "hci/hci_packets.h"
#include "hci/le_scanning_interface.h"
#include "hci/le_scanning_manager.h"
#include "module.h"
#include "os/handler.h"
#include "os/log.h"

namespace bluetooth {
namespace hci {

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

enum class ScanApiType {
  LE_4_0 = 1,
  ANDROID_HCI = 2,
  LE_5_0 = 3,
};

struct LeScanningManager::impl {
  impl(Module* module) : module_(module), le_scanning_interface_(nullptr) {}

  void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) {
    module_handler_ = handler;
    hci_layer_ = hci_layer;
    controller_ = controller;
    le_scanning_interface_ = hci_layer_->GetLeScanningInterface(
        common::Bind(&LeScanningManager::impl::handle_scan_results, common::Unretained(this)), module_handler_);
    if (controller_->IsSupported(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS)) {
      api_type_ = ScanApiType::LE_5_0;
    } else if (controller_->IsSupported(OpCode::LE_EXTENDED_SCAN_PARAMS)) {
      api_type_ = ScanApiType::ANDROID_HCI;
    } else {
      api_type_ = ScanApiType::LE_4_0;
    }
    configure_scan();
  }

  void handle_scan_results(LeMetaEventView event) {
    switch (event.GetSubeventCode()) {
      case hci::SubeventCode::ADVERTISING_REPORT:
        handle_advertising_report<LeAdvertisingReportView, LeAdvertisingReport, LeReport>(
            LeAdvertisingReportView::Create(event));
        break;
      case hci::SubeventCode::DIRECTED_ADVERTISING_REPORT:
        handle_advertising_report<LeDirectedAdvertisingReportView, LeDirectedAdvertisingReport, DirectedLeReport>(
            LeDirectedAdvertisingReportView::Create(event));
        break;
      case hci::SubeventCode::EXTENDED_ADVERTISING_REPORT:
        handle_advertising_report<LeExtendedAdvertisingReportView, LeExtendedAdvertisingReport, ExtendedLeReport>(
            LeExtendedAdvertisingReportView::Create(event));
        break;
      case hci::SubeventCode::SCAN_TIMEOUT:
        if (registered_callback_ != nullptr) {
          registered_callback_->handler->Post(
              common::BindOnce(&LeScanningManagerCallbacks::on_timeout, common::Unretained(registered_callback_)));
          registered_callback_ = nullptr;
        }
        break;
      default:
        LOG_ALWAYS_FATAL("Unknown advertising subevent %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str());
    }
  }

  template <class EventType, class ReportStructType, class ReportType>
  void handle_advertising_report(EventType event_view) {
    if (registered_callback_ == nullptr) {
      LOG_INFO("Dropping advertising event (no registered handler)");
      return;
    }
    if (!event_view.IsValid()) {
      LOG_INFO("Dropping invalid advertising event");
      return;
    }
    std::vector<ReportStructType> report_vector = event_view.GetAdvertisingReports();
    if (report_vector.empty()) {
      LOG_INFO("Zero results in advertising event");
      return;
    }
    std::vector<std::shared_ptr<LeReport>> param;
    param.reserve(report_vector.size());
    for (const ReportStructType& report : report_vector) {
      param.push_back(std::shared_ptr<LeReport>(static_cast<LeReport*>(new ReportType(report))));
    }
    registered_callback_->handler->Post(common::BindOnce(&LeScanningManagerCallbacks::on_advertisements,
                                                         common::Unretained(registered_callback_), param));
  }

  void configure_scan() {
    switch (api_type_) {
      case ScanApiType::LE_5_0:
        le_scanning_interface_->EnqueueCommand(
            hci::LeSetExtendedScanParametersBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_,
                                                            own_address_type_, filter_policy_),
            common::BindOnce(impl::check_status), module_handler_);
        break;
      case ScanApiType::ANDROID_HCI:
        le_scanning_interface_->EnqueueCommand(
            hci::LeExtendedScanParamsBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_,
                                                     filter_policy_),
            common::BindOnce(impl::check_status), module_handler_);

        break;
      case ScanApiType::LE_4_0:
        le_scanning_interface_->EnqueueCommand(
            hci::LeSetScanParametersBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_,
                                                    filter_policy_),
            common::BindOnce(impl::check_status), module_handler_);
        break;
    }
  }

  void start_scan(LeScanningManagerCallbacks* le_scanning_manager_callbacks) {
    registered_callback_ = le_scanning_manager_callbacks;
    switch (api_type_) {
      case ScanApiType::LE_5_0:
        le_scanning_interface_->EnqueueCommand(
            hci::LeSetExtendedScanEnableBuilder::Create(Enable::ENABLED,
                                                        FilterDuplicates::DISABLED /* filter duplicates */, 0, 0),
            common::BindOnce(impl::check_status), module_handler_);
        break;
      case ScanApiType::ANDROID_HCI:
      case ScanApiType::LE_4_0:
        le_scanning_interface_->EnqueueCommand(
            hci::LeSetScanEnableBuilder::Create(Enable::ENABLED, Enable::DISABLED /* filter duplicates */),
            common::BindOnce(impl::check_status), module_handler_);
        break;
    }
  }

  void stop_scan(common::Callback<void()> on_stopped) {
    if (registered_callback_ == nullptr) {
      return;
    }
    registered_callback_->handler->Post(std::move(on_stopped));
    switch (api_type_) {
      case ScanApiType::LE_5_0:
        le_scanning_interface_->EnqueueCommand(
            hci::LeSetExtendedScanEnableBuilder::Create(Enable::DISABLED,
                                                        FilterDuplicates::DISABLED /* filter duplicates */, 0, 0),
            common::BindOnce(impl::check_status), module_handler_);
        registered_callback_->handler = nullptr;
        break;
      case ScanApiType::ANDROID_HCI:
      case ScanApiType::LE_4_0:
        le_scanning_interface_->EnqueueCommand(
            hci::LeSetScanEnableBuilder::Create(Enable::DISABLED, Enable::DISABLED /* filter duplicates */),
            common::BindOnce(impl::check_status), module_handler_);
        registered_callback_->handler = nullptr;
        break;
    }
  }

  ScanApiType api_type_;

  LeScanningManagerCallbacks* registered_callback_;
  Module* module_;
  os::Handler* module_handler_;
  hci::HciLayer* hci_layer_;
  hci::Controller* controller_;
  hci::LeScanningInterface* le_scanning_interface_;

  uint32_t interval_ms_{1000};
  uint16_t window_ms_{1000};
  AddressType own_address_type_{AddressType::PUBLIC_DEVICE_ADDRESS};
  LeSetScanningFilterPolicy filter_policy_{LeSetScanningFilterPolicy::ACCEPT_ALL};

  static void check_status(CommandCompleteView view) {
    switch (view.GetCommandOpCode()) {
      case (OpCode::LE_SET_SCAN_ENABLE): {
        auto status_view = LeSetScanEnableCompleteView::Create(view);
        ASSERT(status_view.IsValid());
        ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
      } break;
      case (OpCode::LE_SET_EXTENDED_SCAN_ENABLE): {
        auto status_view = LeSetExtendedScanEnableCompleteView::Create(view);
        ASSERT(status_view.IsValid());
        ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
      } break;
      case (OpCode::LE_SET_SCAN_PARAMETERS): {
        auto status_view = LeSetScanParametersCompleteView::Create(view);
        ASSERT(status_view.IsValid());
        ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
      } break;
      case (OpCode::LE_EXTENDED_SCAN_PARAMS): {
        auto status_view = LeExtendedScanParamsCompleteView::Create(view);
        ASSERT(status_view.IsValid());
        ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
      } break;
      case (OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS): {
        auto status_view = LeSetExtendedScanParametersCompleteView::Create(view);
        ASSERT(status_view.IsValid());
        ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
      } break;
      default:
        LOG_ALWAYS_FATAL("Unhandled event %s", OpCodeText(view.GetCommandOpCode()).c_str());
    }
  }
};

LeScanningManager::LeScanningManager() {
  pimpl_ = std::make_unique<impl>(this);
}

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

void LeScanningManager::Start() {
  pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>());
}

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

void LeScanningManager::StartScan(LeScanningManagerCallbacks* callbacks) {
  GetHandler()->Post(common::Bind(&impl::start_scan, common::Unretained(pimpl_.get()), callbacks));
}

void LeScanningManager::StopScan(common::Callback<void()> on_stopped) {
  GetHandler()->Post(common::Bind(&impl::stop_scan, common::Unretained(pimpl_.get()), on_stopped));
}

}  // namespace hci
}  // namespace bluetooth
 No newline at end of file
+60 −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 "common/callback.h"
#include "hci/hci_packets.h"
#include "hci/le_report.h"
#include "module.h"

namespace bluetooth {
namespace hci {

class LeScanningManagerCallbacks {
 public:
  virtual ~LeScanningManagerCallbacks() = default;
  virtual void on_advertisements(std::vector<std::shared_ptr<LeReport>>) = 0;
  virtual void on_timeout() = 0;
  os::Handler* handler;
};

class LeScanningManager : public bluetooth::Module {
 public:
  LeScanningManager();

  void StartScan(LeScanningManagerCallbacks* callbacks);

  void StopScan(common::Callback<void()> on_stopped);

  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(LeScanningManager);
};

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