| /* |
| * 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 "hci/le_scanning_manager.h" |
| |
| #include <bluetooth/log.h> |
| #include <com_android_bluetooth_flags.h> |
| |
| #include <memory> |
| #include <unordered_map> |
| |
| #include "hci/acl_manager.h" |
| #include "hci/controller.h" |
| #include "hci/event_checkers.h" |
| #include "hci/hci_layer.h" |
| #include "hci/hci_packets.h" |
| #include "hci/le_periodic_sync_manager.h" |
| #include "hci/le_scanning_interface.h" |
| #include "hci/le_scanning_reassembler.h" |
| #include "main/shim/entry.h" |
| #include "module.h" |
| #include "os/handler.h" |
| #include "os/system_properties.h" |
| #include "storage/storage_module.h" |
| |
| namespace bluetooth { |
| namespace hci { |
| |
| constexpr uint16_t kLeScanWindowMin = 0x0004; |
| constexpr uint16_t kLeScanWindowMax = 0x4000; |
| constexpr int64_t kLeScanRssiMin = -127; |
| constexpr int64_t kLeScanRssiMax = 20; |
| constexpr int64_t kLeScanRssiUnknown = 127; |
| constexpr int64_t kLeRxPathLossCompMin = -128; |
| constexpr int64_t kLeRxPathLossCompMax = 127; |
| constexpr uint16_t kDefaultLeExtendedScanWindow = 4800; |
| constexpr uint16_t kLeExtendedScanWindowMax = 0xFFFF; |
| constexpr uint16_t kLeScanIntervalMin = 0x0004; |
| constexpr uint16_t kLeScanIntervalMax = 0x4000; |
| constexpr uint16_t kDefaultLeExtendedScanInterval = 4800; |
| constexpr uint16_t kLeExtendedScanIntervalMax = 0xFFFF; |
| |
| constexpr uint8_t kScannableBit = 1; |
| constexpr uint8_t kDirectedBit = 2; |
| constexpr uint8_t kScanResponseBit = 3; |
| constexpr uint8_t kLegacyBit = 4; |
| constexpr uint8_t kDataStatusBits = 5; |
| |
| constexpr uint8_t k1mPhyMask = 1; |
| constexpr uint8_t kCodedPhyMask = 1 << 2; |
| |
| // system properties |
| const std::string kLeRxPathLossCompProperty = "bluetooth.hardware.radio.le_rx_path_loss_comp_db"; |
| |
| const ModuleFactory LeScanningManager::Factory = |
| ModuleFactory([]() { return new LeScanningManager(); }); |
| |
| enum class ScanApiType { |
| LEGACY = 1, |
| ANDROID_HCI = 2, |
| EXTENDED = 3, |
| }; |
| |
| struct Scanner { |
| Uuid app_uuid; |
| bool in_use; |
| }; |
| |
| class NullScanningCallback : public ScanningCallback { |
| void OnScannerRegistered(const Uuid /* app_uuid */, ScannerId /* scanner_id */, |
| ScanningStatus /* status */) override { |
| log::info("OnScannerRegistered in NullScanningCallback"); |
| } |
| void OnSetScannerParameterComplete(ScannerId /* scanner_id */, |
| ScanningStatus /* status */) override { |
| log::info("OnSetScannerParameterComplete in NullScanningCallback"); |
| } |
| void OnScanResult(uint16_t /* event_type */, uint8_t /* address_type */, Address /* address */, |
| uint8_t /* primary_phy */, uint8_t /* secondary_phy */, |
| uint8_t /* advertising_sid */, int8_t /* tx_power */, int8_t /* rssi */, |
| uint16_t /* periodic_advertising_interval */, |
| std::vector<uint8_t> /* advertising_data */) override { |
| log::info("OnScanResult in NullScanningCallback"); |
| } |
| void OnTrackAdvFoundLost( |
| AdvertisingFilterOnFoundOnLostInfo /* on_found_on_lost_info */) override { |
| log::info("OnTrackAdvFoundLost in NullScanningCallback"); |
| } |
| void OnBatchScanReports(int /* client_if */, int /* status */, int /* report_format */, |
| int /* num_records */, std::vector<uint8_t> /* data */) override { |
| log::info("OnBatchScanReports in NullScanningCallback"); |
| } |
| void OnBatchScanThresholdCrossed(int /* client_if */) override { |
| log::info("OnBatchScanThresholdCrossed in NullScanningCallback"); |
| } |
| void OnTimeout() override { log::info("OnTimeout in NullScanningCallback"); } |
| void OnFilterEnable(Enable /* enable */, uint8_t /* status */) override { |
| log::info("OnFilterEnable in NullScanningCallback"); |
| } |
| void OnFilterParamSetup(uint8_t /* available_spaces */, ApcfAction /* action */, |
| uint8_t /* status */) override { |
| log::info("OnFilterParamSetup in NullScanningCallback"); |
| } |
| void OnFilterConfigCallback(ApcfFilterType /* filter_type */, uint8_t /* available_spaces */, |
| ApcfAction /* action */, uint8_t /* status */) override { |
| log::info("OnFilterConfigCallback in NullScanningCallback"); |
| } |
| void OnPeriodicSyncStarted(int /* reg_id */, uint8_t /* status */, uint16_t /* sync_handle */, |
| uint8_t /* advertising_sid */, AddressWithType /* address_with_type */, |
| uint8_t /* phy */, uint16_t /* interval */) override { |
| log::info("OnPeriodicSyncStarted in NullScanningCallback"); |
| } |
| void OnPeriodicSyncReport(uint16_t /* sync_handle */, int8_t /* tx_power */, int8_t /* rssi */, |
| uint8_t /* status */, std::vector<uint8_t> /* data */) override { |
| log::info("OnPeriodicSyncReport in NullScanningCallback"); |
| } |
| void OnPeriodicSyncLost(uint16_t /* sync_handle */) override { |
| log::info("OnPeriodicSyncLost in NullScanningCallback"); |
| } |
| void OnPeriodicSyncTransferred(int /* pa_source */, uint8_t /* status */, |
| Address /* address */) override { |
| log::info("OnPeriodicSyncTransferred in NullScanningCallback"); |
| } |
| void OnBigInfoReport(uint16_t /* sync_handle */, bool /* encrypted */) { |
| log::info("OnBigInfoReport in NullScanningCallback"); |
| } |
| }; |
| |
| enum class BatchScanState { |
| ERROR_STATE = 0, |
| ENABLE_CALLED = 1, |
| ENABLED_STATE = 2, |
| DISABLE_CALLED = 3, |
| DISABLED_STATE = 4, |
| }; |
| |
| #define BTM_BLE_BATCH_SCAN_MODE_DISABLE 0 |
| #define BTM_BLE_BATCH_SCAN_MODE_PASS 1 |
| #define BTM_BLE_BATCH_SCAN_MODE_ACTI 2 |
| #define BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI 3 |
| |
| struct BatchScanConfig { |
| BatchScanState current_state; |
| BatchScanMode scan_mode; |
| uint32_t scan_interval; |
| uint32_t scan_window; |
| BatchScanDiscardRule discard_rule; |
| ScannerId ref_value; |
| }; |
| |
| struct LeScanningManager::impl : public LeAddressManagerCallback { |
| impl(Module* module) : module_(module), le_scanning_interface_(nullptr) {} |
| |
| ~impl() { |
| if (address_manager_registered_) { |
| le_address_manager_->Unregister(this); |
| } |
| } |
| |
| void start(os::Handler* handler, HciLayer* hci_layer, Controller* controller, |
| AclManager* acl_manager, storage::StorageModule* storage_module) { |
| module_handler_ = handler; |
| hci_layer_ = hci_layer; |
| controller_ = controller; |
| acl_manager_ = acl_manager; |
| storage_module_ = storage_module; |
| le_address_manager_ = acl_manager->GetLeAddressManager(); |
| le_scanning_interface_ = hci_layer_->GetLeScanningInterface( |
| module_handler_->BindOn(this, &LeScanningManager::impl::handle_scan_results)); |
| periodic_sync_manager_.Init(le_scanning_interface_, module_handler_); |
| /* Check to see if the opcode is supported and C19 (support for extended advertising). */ |
| if (controller_->IsSupported(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS) && |
| controller->SupportsBleExtendedAdvertising()) { |
| api_type_ = ScanApiType::EXTENDED; |
| interval_ms_1m_ = kDefaultLeExtendedScanInterval; |
| window_ms_1m_ = kDefaultLeExtendedScanWindow; |
| phy_ = static_cast<uint8_t>(PhyType::LE_1M); |
| } else if (controller_->IsSupported(OpCode::LE_EXTENDED_SCAN_PARAMS)) { |
| api_type_ = ScanApiType::ANDROID_HCI; |
| } else { |
| api_type_ = ScanApiType::LEGACY; |
| } |
| is_filter_supported_ = controller_->IsSupported(OpCode::LE_ADV_FILTER); |
| if (is_filter_supported_) { |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterReadExtendedFeaturesBuilder::Create(), |
| module_handler_->BindOnceOn(this, &impl::on_apcf_read_extended_features_complete)); |
| } |
| is_batch_scan_supported_ = controller->IsSupported(OpCode::LE_BATCH_SCAN); |
| is_periodic_advertising_sync_transfer_sender_supported_ = |
| controller_->SupportsBlePeriodicAdvertisingSyncTransferSender(); |
| total_num_of_advt_tracked_ = controller->GetVendorCapabilities().total_num_of_advt_tracked_; |
| if (is_batch_scan_supported_) { |
| hci_layer_->RegisterVendorSpecificEventHandler( |
| VseSubeventCode::BLE_THRESHOLD, |
| handler->BindOn(this, &LeScanningManager::impl::on_storage_threshold_breach)); |
| hci_layer_->RegisterVendorSpecificEventHandler( |
| VseSubeventCode::BLE_TRACKING, |
| handler->BindOn(this, &LeScanningManager::impl::on_advertisement_tracking)); |
| } |
| scanners_ = std::vector<Scanner>(kMaxAppNum + 1); |
| for (size_t i = 0; i < scanners_.size(); i++) { |
| scanners_[i].app_uuid = Uuid::kEmpty; |
| scanners_[i].in_use = false; |
| } |
| batch_scan_config_.current_state = BatchScanState::DISABLED_STATE; |
| batch_scan_config_.ref_value = kInvalidScannerId; |
| le_rx_path_loss_comp_ = get_rx_path_loss_compensation(); |
| } |
| |
| void stop() { |
| for (auto subevent_code : LeScanningEvents) { |
| hci_layer_->UnregisterLeEventHandler(subevent_code); |
| } |
| if (is_batch_scan_supported_) { |
| // TODO implete vse module |
| // hci_layer_->UnregisterVesEventHandler(VseSubeventCode::BLE_THRESHOLD); |
| // hci_layer_->UnregisterVesEventHandler(VseSubeventCode::BLE_TRACKING); |
| } |
| batch_scan_config_.current_state = BatchScanState::DISABLED_STATE; |
| batch_scan_config_.ref_value = kInvalidScannerId; |
| scanning_callbacks_ = &null_scanning_callback_; |
| periodic_sync_manager_.SetScanningCallback(scanning_callbacks_); |
| } |
| |
| void handle_scan_results(LeMetaEventView event) { |
| switch (event.GetSubeventCode()) { |
| case SubeventCode::ADVERTISING_REPORT: |
| handle_advertising_report(LeAdvertisingReportRawView::Create(event)); |
| break; |
| case SubeventCode::DIRECTED_ADVERTISING_REPORT: |
| handle_directed_advertising_report(LeDirectedAdvertisingReportView::Create(event)); |
| break; |
| case SubeventCode::EXTENDED_ADVERTISING_REPORT: |
| handle_extended_advertising_report(LeExtendedAdvertisingReportRawView::Create(event)); |
| break; |
| case SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED: |
| LePeriodicAdvertisingSyncEstablishedView::Create(event); |
| periodic_sync_manager_.HandleLePeriodicAdvertisingSyncEstablished( |
| LePeriodicAdvertisingSyncEstablishedView::Create(event)); |
| break; |
| case SubeventCode::PERIODIC_ADVERTISING_REPORT: |
| periodic_sync_manager_.HandleLePeriodicAdvertisingReport( |
| LePeriodicAdvertisingReportView::Create(event)); |
| break; |
| case SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST: |
| periodic_sync_manager_.HandleLePeriodicAdvertisingSyncLost( |
| LePeriodicAdvertisingSyncLostView::Create(event)); |
| break; |
| case SubeventCode::PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED: |
| periodic_sync_manager_.HandleLePeriodicAdvertisingSyncTransferReceived( |
| LePeriodicAdvertisingSyncTransferReceivedView::Create(event)); |
| break; |
| case SubeventCode::SCAN_TIMEOUT: |
| scanning_callbacks_->OnTimeout(); |
| break; |
| case SubeventCode::BIG_INFO_ADVERTISING_REPORT: |
| periodic_sync_manager_.HandleLeBigInfoAdvertisingReport( |
| LeBigInfoAdvertisingReportView::Create(event)); |
| break; |
| default: |
| log::fatal("Unknown advertising subevent {}", SubeventCodeText(event.GetSubeventCode())); |
| } |
| } |
| |
| struct ExtendedEventTypeOptions { |
| bool connectable{false}; |
| bool scannable{false}; |
| bool directed{false}; |
| bool scan_response{false}; |
| bool legacy{false}; |
| bool continuing{false}; |
| bool truncated{false}; |
| }; |
| |
| int8_t get_rx_path_loss_compensation() { |
| int8_t compensation = 0; |
| auto compensation_prop = os::GetSystemProperty(kLeRxPathLossCompProperty); |
| if (compensation_prop) { |
| auto compensation_number = common::Int64FromString(compensation_prop.value()); |
| if (compensation_number) { |
| int64_t number = compensation_number.value(); |
| if (number < kLeRxPathLossCompMin || number > kLeRxPathLossCompMax) { |
| log::error("Invalid number for rx path loss compensation: {}", number); |
| } else { |
| compensation = number; |
| } |
| } |
| } |
| log::info("Rx path loss compensation: {}", compensation); |
| return compensation; |
| } |
| |
| int8_t get_rssi_after_calibration(int8_t rssi) { |
| if (le_rx_path_loss_comp_ == 0 || rssi == kLeScanRssiUnknown) { |
| return rssi; |
| } |
| int8_t calibrated_rssi = rssi; |
| int64_t number = rssi + le_rx_path_loss_comp_; |
| if (number < kLeScanRssiMin || number > kLeScanRssiMax) { |
| log::error("Invalid number for calibrated rssi: {}", number); |
| } else { |
| calibrated_rssi = number; |
| } |
| return calibrated_rssi; |
| } |
| |
| uint16_t transform_to_extended_event_type(ExtendedEventTypeOptions o) { |
| return (o.connectable ? 0x0001 << 0 : 0) | (o.scannable ? 0x0001 << 1 : 0) | |
| (o.directed ? 0x0001 << 2 : 0) | (o.scan_response ? 0x0001 << 3 : 0) | |
| (o.legacy ? 0x0001 << 4 : 0) | (o.continuing ? 0x0001 << 5 : 0) | |
| (o.truncated ? 0x0001 << 6 : 0); |
| } |
| |
| void handle_advertising_report(LeAdvertisingReportRawView event_view) { |
| if (!event_view.IsValid()) { |
| log::info("Dropping invalid advertising event"); |
| return; |
| } |
| std::vector<LeAdvertisingResponseRaw> reports = event_view.GetResponses(); |
| if (reports.empty()) { |
| log::info("Zero results in advertising event"); |
| return; |
| } |
| |
| for (LeAdvertisingResponseRaw report : reports) { |
| uint16_t extended_event_type = 0; |
| switch (report.event_type_) { |
| case AdvertisingEventType::ADV_IND: |
| extended_event_type = transform_to_extended_event_type( |
| {.connectable = true, .scannable = true, .legacy = true}); |
| break; |
| case AdvertisingEventType::ADV_DIRECT_IND: |
| extended_event_type = transform_to_extended_event_type( |
| {.connectable = true, .directed = true, .legacy = true}); |
| break; |
| case AdvertisingEventType::ADV_SCAN_IND: |
| extended_event_type = |
| transform_to_extended_event_type({.scannable = true, .legacy = true}); |
| break; |
| case AdvertisingEventType::ADV_NONCONN_IND: |
| extended_event_type = transform_to_extended_event_type({.legacy = true}); |
| break; |
| case AdvertisingEventType::SCAN_RESPONSE: |
| // We don't know if the initial advertising report was connectable or not. |
| // LeScanningReassembler fixes the connectable field. |
| extended_event_type = transform_to_extended_event_type( |
| {.scannable = true, .scan_response = true, .legacy = true}); |
| break; |
| default: |
| log::warn("Unsupported event type:{}", (uint16_t)report.event_type_); |
| return; |
| } |
| |
| process_advertising_package_content( |
| extended_event_type, (uint8_t)report.address_type_, report.address_, |
| (uint8_t)PrimaryPhyType::LE_1M, (uint8_t)SecondaryPhyType::NO_PACKETS, |
| kAdvertisingDataInfoNotPresent, kTxPowerInformationNotPresent, report.rssi_, |
| kNotPeriodicAdvertisement, report.advertising_data_); |
| } |
| } |
| |
| void handle_directed_advertising_report(LeDirectedAdvertisingReportView /*event_view*/) { |
| log::warn("HCI Directed Advertising Report events are not supported"); |
| } |
| |
| void handle_extended_advertising_report(LeExtendedAdvertisingReportRawView event_view) { |
| if (!event_view.IsValid()) { |
| log::info("Dropping invalid advertising event"); |
| return; |
| } |
| |
| std::vector<LeExtendedAdvertisingResponseRaw> reports = event_view.GetResponses(); |
| if (reports.empty()) { |
| log::info("Zero results in advertising event"); |
| return; |
| } |
| |
| for (LeExtendedAdvertisingResponseRaw& report : reports) { |
| uint16_t event_type = |
| report.connectable_ | (report.scannable_ << kScannableBit) | |
| (report.directed_ << kDirectedBit) | (report.scan_response_ << kScanResponseBit) | |
| (report.legacy_ << kLegacyBit) | ((uint16_t)report.data_status_ << kDataStatusBits); |
| process_advertising_package_content( |
| event_type, (uint8_t)report.address_type_, report.address_, |
| (uint8_t)report.primary_phy_, (uint8_t)report.secondary_phy_, report.advertising_sid_, |
| report.tx_power_, report.rssi_, report.periodic_advertising_interval_, |
| report.advertising_data_); |
| } |
| } |
| |
| void process_advertising_package_content(uint16_t event_type, uint8_t address_type, |
| Address address, uint8_t primary_phy, |
| uint8_t secondary_phy, uint8_t advertising_sid, |
| int8_t tx_power, int8_t rssi, |
| uint16_t periodic_advertising_interval, |
| const std::vector<uint8_t>& advertising_data) { |
| // When using the vendor command Le Set Extended Params to |
| // configure a filter accept list based e.g. on the service UUIDs |
| // found in the report, we ignore the scan responses as we cannot be |
| // certain that they will not be dropped by the filter. |
| // TODO(b/275754998): Improve the decision on what to do with scan responses: Only when used |
| // with hardware-filtering features should we ignore waiting for scan response, and make sure |
| // scan responses are still reported too. |
| scanning_reassembler_.SetIgnoreScanResponses( |
| le_scan_type_ == LeScanType::PASSIVE || |
| filter_policy_ == LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY); |
| |
| std::optional<LeScanningReassembler::CompleteAdvertisingData> processed_report = |
| scanning_reassembler_.ProcessAdvertisingReport(event_type, address_type, address, |
| advertising_sid, advertising_data); |
| |
| if (processed_report.has_value()) { |
| switch (address_type) { |
| case (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS: |
| case (uint8_t)AddressType::PUBLIC_IDENTITY_ADDRESS: |
| address_type = (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS; |
| break; |
| case (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS: |
| case (uint8_t)AddressType::RANDOM_IDENTITY_ADDRESS: |
| address_type = (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS; |
| break; |
| } |
| |
| scanning_callbacks_->OnScanResult( |
| processed_report->extended_event_type, address_type, address, primary_phy, |
| secondary_phy, advertising_sid, tx_power, get_rssi_after_calibration(rssi), |
| periodic_advertising_interval, std::move(processed_report->data)); |
| } |
| } |
| |
| void configure_scan() { |
| std::vector<PhyScanParameters> parameter_vector; |
| |
| // The Host shall not issue set scan parameter command when scanning is enabled |
| stop_scan(); |
| |
| if (le_address_manager_->GetAddressPolicy() != LeAddressManager::USE_PUBLIC_ADDRESS) { |
| if (controller_->IsRpaGenerationSupported()) { |
| log::info("Support RPA offload, set own address type RESOLVABLE_OR_RANDOM_ADDRESS"); |
| own_address_type_ = OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS; |
| } else { |
| own_address_type_ = OwnAddressType::RANDOM_DEVICE_ADDRESS; |
| } |
| } else { |
| own_address_type_ = OwnAddressType::PUBLIC_DEVICE_ADDRESS; |
| } |
| |
| switch (api_type_) { |
| case ScanApiType::EXTENDED: |
| if ((phy_ & k1mPhyMask) != 0) { |
| PhyScanParameters phy_scan_parameters; |
| phy_scan_parameters.le_scan_window_ = window_ms_1m_; |
| phy_scan_parameters.le_scan_interval_ = interval_ms_1m_; |
| phy_scan_parameters.le_scan_type_ = le_scan_type_; |
| parameter_vector.push_back(phy_scan_parameters); |
| } |
| if ((phy_ & kCodedPhyMask) != 0) { |
| PhyScanParameters phy_scan_parameters; |
| phy_scan_parameters.le_scan_window_ = window_ms_coded_; |
| phy_scan_parameters.le_scan_interval_ = interval_ms_coded_; |
| phy_scan_parameters.le_scan_type_ = le_scan_type_; |
| parameter_vector.push_back(phy_scan_parameters); |
| } |
| le_scanning_interface_->EnqueueCommand( |
| LeSetExtendedScanParametersBuilder::Create(own_address_type_, filter_policy_, phy_, |
| parameter_vector), |
| module_handler_->BindOnceOn(this, &impl::on_set_scan_parameter_complete)); |
| break; |
| case ScanApiType::ANDROID_HCI: |
| if ((phy_ & k1mPhyMask) == 0) { |
| log::warn("Only 1M phy supported"); |
| return; |
| } |
| le_scanning_interface_->EnqueueCommand( |
| LeExtendedScanParamsBuilder::Create(le_scan_type_, interval_ms_1m_, window_ms_1m_, |
| own_address_type_, filter_policy_), |
| module_handler_->BindOnceOn(this, &impl::on_set_scan_parameter_complete)); |
| |
| break; |
| case ScanApiType::LEGACY: |
| if ((phy_ & k1mPhyMask) == 0) { |
| log::warn("Only 1M phy supported"); |
| return; |
| } |
| le_scanning_interface_->EnqueueCommand( |
| |
| LeSetScanParametersBuilder::Create(le_scan_type_, interval_ms_1m_, window_ms_1m_, |
| own_address_type_, filter_policy_), |
| module_handler_->BindOnceOn(this, &impl::on_set_scan_parameter_complete)); |
| break; |
| } |
| } |
| |
| void register_scanner(const Uuid app_uuid) { |
| for (uint8_t i = 1; i <= kMaxAppNum; i++) { |
| if (scanners_[i].in_use && scanners_[i].app_uuid == app_uuid) { |
| log::error("Application already registered {}", app_uuid.ToString()); |
| scanning_callbacks_->OnScannerRegistered(app_uuid, 0x00, |
| ScanningCallback::ScanningStatus::INTERNAL_ERROR); |
| return; |
| } |
| } |
| |
| // valid value of scanner id : 1 ~ kMaxAppNum |
| for (uint8_t i = 1; i <= kMaxAppNum; i++) { |
| if (!scanners_[i].in_use) { |
| scanners_[i].app_uuid = app_uuid; |
| scanners_[i].in_use = true; |
| scanning_callbacks_->OnScannerRegistered(app_uuid, i, |
| ScanningCallback::ScanningStatus::SUCCESS); |
| return; |
| } |
| } |
| |
| log::error("Unable to register scanner, max client reached:{}", kMaxAppNum); |
| scanning_callbacks_->OnScannerRegistered(app_uuid, 0x00, |
| ScanningCallback::ScanningStatus::NO_RESOURCES); |
| } |
| |
| void unregister_scanner(ScannerId scanner_id) { |
| if (scanner_id <= 0 || scanner_id > kMaxAppNum) { |
| log::warn("Invalid scanner id"); |
| return; |
| } |
| |
| if (scanners_[scanner_id].in_use) { |
| scanners_[scanner_id].in_use = false; |
| scanners_[scanner_id].app_uuid = Uuid::kEmpty; |
| log::debug("Unregister scanner successful, scannerId={}", scanner_id); |
| } else { |
| log::warn("Unregister scanner with unused scanner id"); |
| } |
| } |
| |
| void scan(bool start) { |
| // On-resume flag should always be reset if there is an explicit start/stop call. |
| scan_on_resume_ = false; |
| if (start) { |
| configure_scan(); |
| start_scan(); |
| } else { |
| if (address_manager_registered_) { |
| le_address_manager_->Unregister(this); |
| address_manager_registered_ = false; |
| paused_ = false; |
| } |
| stop_scan(); |
| } |
| } |
| |
| void start_scan() { |
| // If we receive start_scan during paused, set scan_on_resume_ to true |
| if (paused_ && address_manager_registered_) { |
| scan_on_resume_ = true; |
| return; |
| } |
| is_scanning_ = true; |
| if (!address_manager_registered_) { |
| le_address_manager_->Register(this); |
| address_manager_registered_ = true; |
| } |
| |
| switch (api_type_) { |
| case ScanApiType::EXTENDED: |
| le_scanning_interface_->EnqueueCommand( |
| LeSetExtendedScanEnableBuilder::Create( |
| Enable::ENABLED, |
| #if TARGET_FLOSS |
| FilterDuplicates::ENABLED /* filter duplicates */, |
| #else |
| FilterDuplicates::DISABLED /* filter duplicates */, |
| #endif |
| 0, 0), |
| module_handler_->BindOnce(check_complete<LeSetExtendedScanEnableCompleteView>)); |
| break; |
| case ScanApiType::ANDROID_HCI: |
| case ScanApiType::LEGACY: |
| le_scanning_interface_->EnqueueCommand( |
| LeSetScanEnableBuilder::Create(Enable::ENABLED, |
| Enable::DISABLED /* filter duplicates */), |
| module_handler_->BindOnce(check_complete<LeSetScanEnableCompleteView>)); |
| break; |
| } |
| } |
| |
| void stop_scan() { |
| if (!is_scanning_) { |
| log::info("Scanning already stopped, return!"); |
| return; |
| } |
| is_scanning_ = false; |
| |
| switch (api_type_) { |
| case ScanApiType::EXTENDED: |
| le_scanning_interface_->EnqueueCommand( |
| LeSetExtendedScanEnableBuilder::Create( |
| Enable::DISABLED, |
| #if TARGET_FLOSS |
| FilterDuplicates::ENABLED /* filter duplicates */, |
| #else |
| FilterDuplicates::DISABLED /* filter duplicates */, |
| #endif |
| 0, 0), |
| module_handler_->BindOnce(check_complete<LeSetExtendedScanEnableCompleteView>)); |
| break; |
| case ScanApiType::ANDROID_HCI: |
| case ScanApiType::LEGACY: |
| le_scanning_interface_->EnqueueCommand( |
| LeSetScanEnableBuilder::Create(Enable::DISABLED, |
| Enable::DISABLED /* filter duplicates */), |
| module_handler_->BindOnce(check_complete<LeSetScanEnableCompleteView>)); |
| break; |
| } |
| } |
| |
| void set_scan_parameters(LeScanType scan_type, ScannerId scanner_id_1m, uint16_t scan_interval_1m, |
| uint16_t scan_window_1m, ScannerId scanner_id_coded, |
| uint16_t scan_interval_coded, uint16_t scan_window_coded, |
| uint8_t scan_phy) { |
| bool requested_1m = (scan_phy & k1mPhyMask) != 0; |
| bool requested_coded = (scan_phy & kCodedPhyMask) != 0; |
| if (requested_1m && |
| !validate_scan_params(scan_type, scanner_id_1m, scan_interval_1m, scan_window_1m)) { |
| return; |
| } |
| |
| if (requested_coded && !validate_scan_params(scan_type, scanner_id_coded, scan_interval_coded, |
| scan_window_coded)) { |
| return; |
| } |
| |
| le_scan_type_ = scan_type; |
| interval_ms_1m_ = scan_interval_1m; |
| window_ms_1m_ = scan_window_1m; |
| interval_ms_coded_ = scan_interval_coded; |
| window_ms_coded_ = scan_window_coded; |
| phy_ = scan_phy; |
| |
| if (requested_1m) { |
| scanning_callbacks_->OnSetScannerParameterComplete(scanner_id_1m, ScanningCallback::SUCCESS); |
| } |
| if (requested_coded) { |
| scanning_callbacks_->OnSetScannerParameterComplete(scanner_id_coded, |
| ScanningCallback::SUCCESS); |
| } |
| } |
| |
| bool validate_scan_params(LeScanType scan_type, ScannerId scanner_id, uint16_t scan_interval, |
| uint16_t scan_window) { |
| uint32_t max_scan_interval = kLeScanIntervalMax; |
| uint32_t max_scan_window = kLeScanWindowMax; |
| if (api_type_ == ScanApiType::EXTENDED) { |
| max_scan_interval = kLeExtendedScanIntervalMax; |
| max_scan_window = kLeExtendedScanWindowMax; |
| } |
| |
| if (scan_type != LeScanType::ACTIVE && scan_type != LeScanType::PASSIVE) { |
| log::error("Invalid scan type"); |
| scanning_callbacks_->OnSetScannerParameterComplete( |
| scanner_id, ScanningCallback::ScanningStatus::ILLEGAL_PARAMETER); |
| return false; |
| } |
| if (scan_interval > max_scan_interval || scan_interval < kLeScanIntervalMin) { |
| log::error("Invalid scan_interval {}", scan_interval); |
| scanning_callbacks_->OnSetScannerParameterComplete( |
| scanner_id, ScanningCallback::ScanningStatus::ILLEGAL_PARAMETER); |
| return false; |
| } |
| if (scan_window > max_scan_window || scan_window < kLeScanWindowMin) { |
| log::error("Invalid scan_window {}", scan_window); |
| scanning_callbacks_->OnSetScannerParameterComplete( |
| scanner_id, ScanningCallback::ScanningStatus::ILLEGAL_PARAMETER); |
| return false; |
| } |
| return true; |
| } |
| |
| void set_scan_filter_policy(LeScanningFilterPolicy filter_policy) { |
| filter_policy_ = filter_policy; |
| } |
| |
| void scan_filter_enable(bool enable) { |
| if (!is_filter_supported_) { |
| log::warn("Advertising filter is not supported"); |
| return; |
| } |
| |
| Enable apcf_enable = enable ? Enable::ENABLED : Enable::DISABLED; |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterEnableBuilder::Create(apcf_enable), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| } |
| |
| bool is_bonded(Address target_address) { |
| for (auto device : storage_module_->GetBondedDevices()) { |
| if (device.GetAddress() == target_address) { |
| log::debug("Addresses match!"); |
| return true; |
| } |
| } |
| log::debug("Addresse DON'Ts match!"); |
| return false; |
| } |
| |
| void scan_filter_parameter_setup(ApcfAction action, uint8_t filter_index, |
| AdvertisingFilterParameter advertising_filter_parameter) { |
| if (!is_filter_supported_) { |
| log::warn("Advertising filter is not supported"); |
| return; |
| } |
| |
| auto entry = remove_me_later_map_.find(filter_index); |
| switch (action) { |
| case ApcfAction::ADD: |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterAddFilteringParametersBuilder::Create( |
| filter_index, advertising_filter_parameter.feature_selection, |
| advertising_filter_parameter.list_logic_type, |
| advertising_filter_parameter.filter_logic_type, |
| advertising_filter_parameter.rssi_high_thresh, |
| advertising_filter_parameter.delivery_mode, |
| advertising_filter_parameter.onfound_timeout, |
| advertising_filter_parameter.onfound_timeout_cnt, |
| advertising_filter_parameter.rssi_low_thresh, |
| advertising_filter_parameter.onlost_timeout, |
| advertising_filter_parameter.num_of_tracking_entries), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| break; |
| case ApcfAction::DELETE: |
| tracker_id_map_.erase(filter_index); |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterDeleteFilteringParametersBuilder::Create(filter_index), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| |
| // IRK Scanning |
| if (entry != remove_me_later_map_.end()) { |
| // Don't want to remove for a bonded device |
| if (!is_bonded(entry->second.GetAddress())) { |
| le_address_manager_->RemoveDeviceFromResolvingList( |
| static_cast<PeerAddressType>(entry->second.GetAddressType()), |
| entry->second.GetAddress()); |
| } |
| remove_me_later_map_.erase(filter_index); |
| } |
| |
| break; |
| case ApcfAction::CLEAR: |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterClearFilteringParametersBuilder::Create(), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| |
| // IRK Scanning |
| if (entry != remove_me_later_map_.end()) { |
| // Don't want to remove for a bonded device |
| if (!is_bonded(entry->second.GetAddress())) { |
| le_address_manager_->RemoveDeviceFromResolvingList( |
| static_cast<PeerAddressType>(entry->second.GetAddressType()), |
| entry->second.GetAddress()); |
| } |
| remove_me_later_map_.erase(filter_index); |
| } |
| |
| break; |
| default: |
| log::error("Unknown action type: {}", (uint16_t)action); |
| break; |
| } |
| } |
| |
| void scan_filter_add(uint8_t filter_index, |
| std::vector<AdvertisingPacketContentFilterCommand> filters) { |
| if (!is_filter_supported_) { |
| log::warn("Advertising filter is not supported"); |
| return; |
| } |
| |
| ApcfAction apcf_action = ApcfAction::ADD; |
| for (auto filter : filters) { |
| /* If data is passed, both mask and data have to be the same length */ |
| if (filter.data.size() != filter.data_mask.size() && filter.data.size() != 0 && |
| filter.data_mask.size() != 0) { |
| log::error("data and data_mask are of different size"); |
| continue; |
| } |
| |
| switch (filter.filter_type) { |
| case ApcfFilterType::BROADCASTER_ADDRESS: { |
| update_address_filter(apcf_action, filter_index, filter.address, |
| filter.application_address_type, filter.irk); |
| break; |
| } |
| case ApcfFilterType::SERVICE_UUID: |
| case ApcfFilterType::SERVICE_SOLICITATION_UUID: { |
| update_uuid_filter(apcf_action, filter_index, filter.filter_type, filter.uuid, |
| filter.uuid_mask); |
| break; |
| } |
| case ApcfFilterType::LOCAL_NAME: { |
| update_local_name_filter(apcf_action, filter_index, filter.name); |
| break; |
| } |
| case ApcfFilterType::MANUFACTURER_DATA: { |
| update_manufacturer_data_filter(apcf_action, filter_index, filter.company, |
| filter.company_mask, filter.data, filter.data_mask); |
| break; |
| } |
| case ApcfFilterType::SERVICE_DATA: { |
| update_service_data_filter(apcf_action, filter_index, filter.data, filter.data_mask); |
| break; |
| } |
| case ApcfFilterType::TRANSPORT_DISCOVERY_DATA: { |
| update_transport_discovery_data_filter( |
| apcf_action, filter_index, filter.org_id, filter.tds_flags, filter.tds_flags_mask, |
| filter.data, filter.data_mask, filter.meta_data_type, filter.meta_data); |
| break; |
| } |
| case ApcfFilterType::AD_TYPE: { |
| update_ad_type_filter(apcf_action, filter_index, filter.ad_type, filter.data, |
| filter.data_mask); |
| break; |
| } |
| default: |
| log::error("Unknown filter type: {}", (uint16_t)filter.filter_type); |
| break; |
| } |
| } |
| } |
| |
| std::unordered_map<uint8_t, AddressWithType> remove_me_later_map_; |
| |
| void update_address_filter(ApcfAction action, uint8_t filter_index, Address address, |
| ApcfApplicationAddressType address_type, std::array<uint8_t, 16> irk) { |
| if (action != ApcfAction::CLEAR) { |
| /* |
| * The vendor command (APCF Filtering 0x0157) takes Public (0) or Random (1) |
| * or Addresses type not applicable (2). |
| * |
| * Advertising results have four types: |
| *  - Public = 0 |
| *  - Random = 1 |
| *  - Public ID = 2 |
| *  - Random ID = 3 |
| * |
| * e.g. specifying PUBLIC (0) will only return results with a public |
| * address. It will ignore resolved addresses, since they return PUBLIC |
| * IDENTITY (2). For this, Addresses type not applicable (0x02) must be specified. |
| * This should also cover if the RPA is derived from RANDOM STATIC. |
| */ |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterBroadcasterAddressBuilder::Create( |
| action, filter_index, address, ApcfApplicationAddressType::NOT_APPLICABLE), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| if (!is_empty_128bit(irk)) { |
| // If an entry exists for this filter index, replace data because the filter has been |
| // updated. |
| auto entry = remove_me_later_map_.find(filter_index); |
| // IRK Scanning |
| if (entry != remove_me_later_map_.end()) { |
| // Don't want to remove for a bonded device |
| if (!is_bonded(entry->second.GetAddress())) { |
| le_address_manager_->RemoveDeviceFromResolvingList( |
| static_cast<PeerAddressType>(entry->second.GetAddressType()), |
| entry->second.GetAddress()); |
| } |
| remove_me_later_map_.erase(filter_index); |
| } |
| |
| // Now replace it with a new one |
| std::array<uint8_t, 16> empty_irk; |
| le_address_manager_->AddDeviceToResolvingList(static_cast<PeerAddressType>(address_type), |
| address, irk, empty_irk); |
| remove_me_later_map_.emplace( |
| filter_index, AddressWithType(address, static_cast<AddressType>(address_type))); |
| } |
| } else { |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterClearBroadcasterAddressBuilder::Create(filter_index), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| auto entry = remove_me_later_map_.find(filter_index); |
| if (entry != remove_me_later_map_.end()) { |
| // TODO(optedoblivion): If not bonded |
| le_address_manager_->RemoveDeviceFromResolvingList( |
| static_cast<PeerAddressType>(address_type), address); |
| remove_me_later_map_.erase(filter_index); |
| } |
| } |
| } |
| |
| bool is_empty_128bit(const std::array<uint8_t, 16> data) { |
| for (int i = 0; i < 16; i++) { |
| if (data[i] != (uint8_t)0) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| void update_uuid_filter(ApcfAction action, uint8_t filter_index, ApcfFilterType filter_type, |
| Uuid uuid, Uuid uuid_mask) { |
| std::vector<uint8_t> combined_data = {}; |
| if (action != ApcfAction::CLEAR) { |
| uint8_t uuid_len = uuid.GetShortestRepresentationSize(); |
| if (uuid_len == Uuid::kNumBytes16) { |
| uint16_t data = uuid.As16Bit(); |
| combined_data.push_back((uint8_t)data); |
| combined_data.push_back((uint8_t)(data >> 8)); |
| } else if (uuid_len == Uuid::kNumBytes32) { |
| uint32_t data = uuid.As32Bit(); |
| combined_data.push_back((uint8_t)data); |
| combined_data.push_back((uint8_t)(data >> 8)); |
| combined_data.push_back((uint8_t)(data >> 16)); |
| combined_data.push_back((uint8_t)(data >> 24)); |
| } else if (uuid_len == Uuid::kNumBytes128) { |
| auto data = uuid.To128BitLE(); |
| combined_data.insert(combined_data.end(), data.begin(), data.end()); |
| } else { |
| log::error("illegal UUID length: {}", (uint16_t)uuid_len); |
| return; |
| } |
| |
| if (!uuid_mask.IsEmpty()) { |
| if (uuid_len == Uuid::kNumBytes16) { |
| uint16_t data = uuid_mask.As16Bit(); |
| combined_data.push_back((uint8_t)data); |
| combined_data.push_back((uint8_t)(data >> 8)); |
| } else if (uuid_len == Uuid::kNumBytes32) { |
| uint32_t data = uuid_mask.As32Bit(); |
| combined_data.push_back((uint8_t)data); |
| combined_data.push_back((uint8_t)(data >> 8)); |
| combined_data.push_back((uint8_t)(data >> 16)); |
| combined_data.push_back((uint8_t)(data >> 24)); |
| } else if (uuid_len == Uuid::kNumBytes128) { |
| auto data = uuid_mask.To128BitLE(); |
| combined_data.insert(combined_data.end(), data.begin(), data.end()); |
| } |
| } else { |
| std::vector<uint8_t> data(uuid_len, 0xFF); |
| combined_data.insert(combined_data.end(), data.begin(), data.end()); |
| } |
| } |
| |
| if (filter_type == ApcfFilterType::SERVICE_UUID) { |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterServiceUuidBuilder::Create(action, filter_index, combined_data), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| } else { |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterSolicitationUuidBuilder::Create(action, filter_index, combined_data), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| } |
| } |
| |
| void update_local_name_filter(ApcfAction action, uint8_t filter_index, |
| std::vector<uint8_t> name) { |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterLocalNameBuilder::Create(action, filter_index, name), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| } |
| |
| void update_manufacturer_data_filter(ApcfAction action, uint8_t filter_index, uint16_t company_id, |
| uint16_t company_id_mask, std::vector<uint8_t> data, |
| std::vector<uint8_t> data_mask) { |
| if (data.size() != data_mask.size()) { |
| log::error("manufacturer data mask should have the same length as manufacturer data"); |
| return; |
| } |
| std::vector<uint8_t> combined_data = {}; |
| if (action != ApcfAction::CLEAR) { |
| combined_data.push_back((uint8_t)company_id); |
| combined_data.push_back((uint8_t)(company_id >> 8)); |
| if (data.size() != 0) { |
| combined_data.insert(combined_data.end(), data.begin(), data.end()); |
| } |
| if (company_id_mask != 0) { |
| combined_data.push_back((uint8_t)company_id_mask); |
| combined_data.push_back((uint8_t)(company_id_mask >> 8)); |
| } else { |
| combined_data.push_back(0xFF); |
| combined_data.push_back(0xFF); |
| } |
| if (data_mask.size() != 0) { |
| combined_data.insert(combined_data.end(), data_mask.begin(), data_mask.end()); |
| } |
| } |
| |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterManufacturerDataBuilder::Create(action, filter_index, combined_data), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| } |
| |
| void update_service_data_filter(ApcfAction action, uint8_t filter_index, |
| std::vector<uint8_t> data, std::vector<uint8_t> data_mask) { |
| if (data.size() != data_mask.size()) { |
| log::error("service data mask should have the same length as service data"); |
| return; |
| } |
| std::vector<uint8_t> combined_data = {}; |
| if (action != ApcfAction::CLEAR && data.size() != 0) { |
| combined_data.insert(combined_data.end(), data.begin(), data.end()); |
| combined_data.insert(combined_data.end(), data_mask.begin(), data_mask.end()); |
| } |
| |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterServiceDataBuilder::Create(action, filter_index, combined_data), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| } |
| |
| void update_transport_discovery_data_filter(ApcfAction action, uint8_t filter_index, |
| uint8_t org_id, uint8_t tds_flags, |
| uint8_t tds_flags_mask, |
| std::vector<uint8_t> transport_data, |
| std::vector<uint8_t> transport_data_mask, |
| ApcfMetaDataType meta_data_type, |
| std::vector<uint8_t> meta_data) { |
| LocalVersionInformation local_version_information = controller_->GetLocalVersionInformation(); |
| |
| // In QTI controller, transport discovery data filter are supported by default. Check is added |
| // to keep backward compatibility. |
| if (!is_transport_discovery_data_filter_supported_ && |
| !(local_version_information.manufacturer_name_ == LMP_COMPID_QTI)) { |
| log::warn("transport discovery data filter isn't supported"); |
| return; |
| } |
| |
| log::info( |
| "org id: {}, tds_flags: {}, tds_flags_mask: {}, transport_data size: {}, " |
| "transport_data_mask size: {}, meta_data_type: {}, meta_data size: {}", |
| org_id, tds_flags, tds_flags_mask, transport_data.size(), transport_data_mask.size(), |
| (uint8_t)meta_data_type, meta_data.size()); |
| |
| // 0x02 Wi-Fi Alliance Neighbor Awareness Networking & meta_data_type is 0x01 for NAN Hash. |
| if (org_id == 0x02) { |
| // meta data contains WIFI NAN hash, reverse it before sending controller. |
| switch (meta_data_type) { |
| case ApcfMetaDataType::WIFI_NAN_HASH: |
| std::reverse(meta_data.begin(), meta_data.end()); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| if (is_transport_discovery_data_filter_supported_) { |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterTransportDiscoveryDataBuilder::Create( |
| action, filter_index, org_id, tds_flags, tds_flags_mask, transport_data, |
| transport_data_mask, meta_data_type, meta_data), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| } else { |
| // In QTI controller, transport discovery data filter are supported by default. |
| // keeping old version for backward compatibility |
| std::vector<uint8_t> combined_data = {}; |
| if (action != ApcfAction::CLEAR) { |
| combined_data.push_back((uint8_t)org_id); |
| combined_data.push_back((uint8_t)tds_flags); |
| combined_data.push_back((uint8_t)tds_flags_mask); |
| if (org_id == 0x02 && meta_data_type == ApcfMetaDataType::WIFI_NAN_HASH) { |
| // meta data contains WIFI NAN hash |
| combined_data.insert(combined_data.end(), meta_data.begin(), meta_data.end()); |
| } |
| } |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterTransportDiscoveryDataOldBuilder::Create(action, filter_index, |
| combined_data), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| } |
| } |
| |
| void update_ad_type_filter(ApcfAction action, uint8_t filter_index, uint8_t ad_type, |
| std::vector<uint8_t> data, std::vector<uint8_t> data_mask) { |
| if (!is_ad_type_filter_supported_) { |
| log::error("AD type filter isn't supported"); |
| return; |
| } |
| |
| if (data.size() != data_mask.size()) { |
| log::error("ad type mask should have the same length as ad type data"); |
| return; |
| } |
| std::vector<uint8_t> combined_data = {}; |
| if (action != ApcfAction::CLEAR) { |
| combined_data.push_back((uint8_t)ad_type); |
| combined_data.push_back((uint8_t)(data.size())); |
| if (data.size() != 0) { |
| combined_data.insert(combined_data.end(), data.begin(), data.end()); |
| combined_data.insert(combined_data.end(), data_mask.begin(), data_mask.end()); |
| } |
| } |
| |
| le_scanning_interface_->EnqueueCommand( |
| LeAdvFilterADTypeBuilder::Create(action, filter_index, combined_data), |
| module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); |
| } |
| |
| void batch_scan_set_storage_parameter(uint8_t batch_scan_full_max, |
| uint8_t batch_scan_truncated_max, |
| uint8_t batch_scan_notify_threshold, ScannerId scanner_id) { |
| if (!is_batch_scan_supported_) { |
| log::warn("Batch scan is not supported"); |
| return; |
| } |
| // scanner id for OnBatchScanThresholdCrossed |
| batch_scan_config_.ref_value = scanner_id; |
| |
| if (batch_scan_config_.current_state == BatchScanState::ERROR_STATE || |
| batch_scan_config_.current_state == BatchScanState::DISABLED_STATE || |
| batch_scan_config_.current_state == BatchScanState::DISABLE_CALLED) { |
| batch_scan_config_.current_state = BatchScanState::ENABLE_CALLED; |
| le_scanning_interface_->EnqueueCommand( |
| LeBatchScanEnableBuilder::Create(Enable::ENABLED), |
| module_handler_->BindOnceOn(this, &impl::on_batch_scan_enable_complete)); |
| } |
| |
| le_scanning_interface_->EnqueueCommand( |
| LeBatchScanSetStorageParametersBuilder::Create( |
| batch_scan_full_max, batch_scan_truncated_max, batch_scan_notify_threshold), |
| module_handler_->BindOnceOn(this, &impl::on_batch_scan_complete)); |
| } |
| |
| void batch_scan_enable(BatchScanMode scan_mode, uint32_t duty_cycle_scan_window_slots, |
| uint32_t duty_cycle_scan_interval_slots, |
| BatchScanDiscardRule batch_scan_discard_rule) { |
| if (!is_batch_scan_supported_) { |
| log::warn("Batch scan is not supported"); |
| return; |
| } |
| |
| if (batch_scan_config_.current_state == BatchScanState::ERROR_STATE || |
| batch_scan_config_.current_state == BatchScanState::DISABLED_STATE || |
| batch_scan_config_.current_state == BatchScanState::DISABLE_CALLED) { |
| batch_scan_config_.current_state = BatchScanState::ENABLE_CALLED; |
| le_scanning_interface_->EnqueueCommand( |
| LeBatchScanEnableBuilder::Create(Enable::ENABLED), |
| module_handler_->BindOnceOn(this, &impl::on_batch_scan_enable_complete)); |
| } |
| |
| batch_scan_config_.scan_mode = scan_mode; |
| batch_scan_config_.scan_interval = duty_cycle_scan_interval_slots; |
| batch_scan_config_.scan_window = duty_cycle_scan_window_slots; |
| batch_scan_config_.discard_rule = batch_scan_discard_rule; |
| /* This command starts batch scanning, if enabled */ |
| batch_scan_set_scan_parameter(scan_mode, duty_cycle_scan_window_slots, |
| duty_cycle_scan_interval_slots, batch_scan_discard_rule); |
| } |
| |
| void batch_scan_disable() { |
| if (!is_batch_scan_supported_) { |
| log::warn("Batch scan is not supported"); |
| return; |
| } |
| batch_scan_config_.current_state = BatchScanState::DISABLE_CALLED; |
| batch_scan_set_scan_parameter(BatchScanMode::DISABLE, batch_scan_config_.scan_window, |
| batch_scan_config_.scan_interval, |
| batch_scan_config_.discard_rule); |
| } |
| |
| void batch_scan_set_scan_parameter(BatchScanMode scan_mode, uint32_t duty_cycle_scan_window_slots, |
| uint32_t duty_cycle_scan_interval_slots, |
| BatchScanDiscardRule batch_scan_discard_rule) { |
| if (!is_batch_scan_supported_) { |
| log::warn("Batch scan is not supported"); |
| return; |
| } |
| PeerAddressType own_address_type = PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS; |
| if (own_address_type_ == OwnAddressType::RANDOM_DEVICE_ADDRESS || |
| own_address_type_ == OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS) { |
| own_address_type = PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS; |
| } |
| uint8_t truncated_mode_enabled = 0x00; |
| uint8_t full_mode_enabled = 0x00; |
| if (scan_mode == BatchScanMode::TRUNCATED || scan_mode == BatchScanMode::TRUNCATED_AND_FULL) { |
| truncated_mode_enabled = 0x01; |
| } |
| if (scan_mode == BatchScanMode::FULL || scan_mode == BatchScanMode::TRUNCATED_AND_FULL) { |
| full_mode_enabled = 0x01; |
| } |
| |
| if (scan_mode == BatchScanMode::DISABLE) { |
| le_scanning_interface_->EnqueueCommand( |
| LeBatchScanSetScanParametersBuilder::Create( |
| truncated_mode_enabled, full_mode_enabled, duty_cycle_scan_window_slots, |
| duty_cycle_scan_interval_slots, own_address_type, batch_scan_discard_rule), |
| module_handler_->BindOnceOn(this, &impl::on_batch_scan_disable_complete)); |
| } else { |
| le_scanning_interface_->EnqueueCommand( |
| LeBatchScanSetScanParametersBuilder::Create( |
| truncated_mode_enabled, full_mode_enabled, duty_cycle_scan_window_slots, |
| duty_cycle_scan_interval_slots, own_address_type, batch_scan_discard_rule), |
| module_handler_->BindOnceOn(this, &impl::on_batch_scan_complete)); |
| } |
| } |
| |
| void batch_scan_read_results(ScannerId scanner_id, uint16_t total_num_of_records, |
| BatchScanMode scan_mode) { |
| if (!is_batch_scan_supported_) { |
| log::warn("Batch scan is not supported"); |
| int status = static_cast<int>(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); |
| scanning_callbacks_->OnBatchScanReports(scanner_id, status, 0, 0, {}); |
| return; |
| } |
| |
| if (scan_mode != BatchScanMode::FULL && scan_mode != BatchScanMode::TRUNCATED) { |
| log::warn("Invalid scan mode {}", (uint16_t)scan_mode); |
| int status = static_cast<int>(ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); |
| scanning_callbacks_->OnBatchScanReports(scanner_id, status, 0, 0, {}); |
| return; |
| } |
| |
| if (batch_scan_result_cache_.find(scanner_id) == batch_scan_result_cache_.end()) { |
| std::vector<uint8_t> empty_data = {}; |
| batch_scan_result_cache_.emplace(scanner_id, empty_data); |
| } |
| |
| le_scanning_interface_->EnqueueCommand( |
| LeBatchScanReadResultParametersBuilder::Create( |
| static_cast<BatchScanDataRead>(scan_mode)), |
| module_handler_->BindOnceOn(this, &impl::on_batch_scan_read_result_complete, scanner_id, |
| total_num_of_records)); |
| } |
| |
| void start_sync(uint8_t sid, const AddressWithType& address_with_type, uint16_t skip, |
| uint16_t timeout, int request_id) { |
| if (!is_periodic_advertising_sync_transfer_sender_supported_) { |
| log::warn("PAST sender not supported on this device"); |
| int status = static_cast<int>(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); |
| scanning_callbacks_->OnPeriodicSyncStarted(request_id, status, -1, sid, address_with_type, 0, |
| 0); |
| return; |
| } |
| PeriodicSyncStates request{ |
| .request_id = request_id, |
| .advertiser_sid = sid, |
| .address_with_type = address_with_type, |
| .sync_handle = 0, |
| .sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE, |
| }; |
| periodic_sync_manager_.StartSync(request, skip, timeout); |
| } |
| |
| void stop_sync(uint16_t handle) { |
| if (!is_periodic_advertising_sync_transfer_sender_supported_) { |
| log::warn("PAST sender not supported on this device"); |
| return; |
| } |
| periodic_sync_manager_.StopSync(handle); |
| } |
| |
| void cancel_create_sync(uint8_t sid, const Address& address) { |
| if (!is_periodic_advertising_sync_transfer_sender_supported_) { |
| log::warn("PAST sender not supported on this device"); |
| return; |
| } |
| periodic_sync_manager_.CancelCreateSync(sid, address); |
| } |
| |
| void transfer_sync(const Address& address, uint16_t connection_handle, uint16_t service_data, |
| uint16_t sync_handle, int pa_source) { |
| if (!is_periodic_advertising_sync_transfer_sender_supported_) { |
| log::warn("PAST sender not supported on this device"); |
| int status = static_cast<int>(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); |
| scanning_callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); |
| return; |
| } |
| if (connection_handle == 0xFFFF) { |
| log::error("[PAST]: Invalid connection handle or no LE ACL link"); |
| int status = static_cast<int>(ErrorCode::UNKNOWN_CONNECTION); |
| scanning_callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); |
| return; |
| } |
| periodic_sync_manager_.TransferSync(address, service_data, sync_handle, pa_source, |
| connection_handle); |
| } |
| |
| void transfer_set_info(const Address& address, uint16_t connection_handle, uint16_t service_data, |
| uint8_t adv_handle, int pa_source) { |
| if (!is_periodic_advertising_sync_transfer_sender_supported_) { |
| log::warn("PAST sender not supported on this device"); |
| int status = static_cast<int>(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); |
| scanning_callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); |
| return; |
| } |
| if (connection_handle == 0xFFFF) { |
| log::error("[PAST]:Invalid connection handle or no LE ACL link"); |
| int status = static_cast<int>(ErrorCode::UNKNOWN_CONNECTION); |
| scanning_callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); |
| return; |
| } |
| periodic_sync_manager_.SyncSetInfo(address, service_data, adv_handle, pa_source, |
| connection_handle); |
| } |
| |
| void sync_tx_parameters(const Address& address, uint8_t mode, uint16_t skip, uint16_t timeout, |
| int reg_id) { |
| if (!is_periodic_advertising_sync_transfer_sender_supported_) { |
| log::warn("PAST sender not supported on this device"); |
| int status = static_cast<int>(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); |
| AddressWithType address_with_type(address, AddressType::RANDOM_DEVICE_ADDRESS); |
| scanning_callbacks_->OnPeriodicSyncStarted(reg_id, status, -1, -1, address_with_type, 0, 0); |
| return; |
| } |
| periodic_sync_manager_.SyncTxParameters(address, mode, skip, timeout, reg_id); |
| } |
| |
| void track_advertiser(uint8_t filter_index, ScannerId scanner_id) { |
| if (total_num_of_advt_tracked_ <= 0) { |
| log::warn("advertisement tracking is not supported"); |
| AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info = {}; |
| on_found_on_lost_info.scanner_id = scanner_id; |
| on_found_on_lost_info.advertiser_info_present = AdvtInfoPresent::NO_ADVT_INFO_PRESENT; |
| scanning_callbacks_->OnTrackAdvFoundLost(on_found_on_lost_info); |
| return; |
| } else if (tracker_id_map_.size() >= total_num_of_advt_tracked_) { |
| AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info = {}; |
| on_found_on_lost_info.scanner_id = scanner_id; |
| on_found_on_lost_info.advertiser_info_present = AdvtInfoPresent::NO_ADVT_INFO_PRESENT; |
| scanning_callbacks_->OnTrackAdvFoundLost(on_found_on_lost_info); |
| return; |
| } |
| log::info("track_advertiser scanner_id {}, filter_index {}", (uint16_t)scanner_id, |
| (uint16_t)filter_index); |
| tracker_id_map_[filter_index] = scanner_id; |
| } |
| |
| void register_scanning_callback(ScanningCallback* scanning_callbacks) { |
| scanning_callbacks_ = scanning_callbacks; |
| periodic_sync_manager_.SetScanningCallback(scanning_callbacks_); |
| } |
| |
| bool is_ad_type_filter_supported() { return is_ad_type_filter_supported_; } |
| |
| void on_set_scan_parameter_complete(CommandCompleteView view) { |
| switch (view.GetCommandOpCode()) { |
| case (OpCode::LE_SET_SCAN_PARAMETERS): { |
| auto status_view = LeSetScanParametersCompleteView::Create(view); |
| log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); |
| if (status_view.GetStatus() != ErrorCode::SUCCESS) { |
| log::info("Receive set scan parameter complete with error code {}", |
| ErrorCodeText(status_view.GetStatus())); |
| } |
| } break; |
| case (OpCode::LE_EXTENDED_SCAN_PARAMS): { |
| auto status_view = LeExtendedScanParamsCompleteView::Create(view); |
| log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); |
| if (status_view.GetStatus() != ErrorCode::SUCCESS) { |
| log::info("Receive extended scan parameter complete with error code {}", |
| ErrorCodeText(status_view.GetStatus())); |
| } |
| } break; |
| case (OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS): { |
| auto status_view = LeSetExtendedScanParametersCompleteView::Create(view); |
| log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); |
| if (status_view.GetStatus() != ErrorCode::SUCCESS) { |
| log::info("Receive set extended scan parameter complete with error code {}", |
| ErrorCodeText(status_view.GetStatus())); |
| } |
| } break; |
| default: |
| log::fatal("Unhandled event {}", OpCodeText(view.GetCommandOpCode())); |
| } |
| } |
| |
| void on_advertising_filter_complete(CommandCompleteView view) { |
| log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); |
| auto status_view = LeAdvFilterCompleteView::Create(view); |
| log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); |
| if (status_view.GetStatus() != ErrorCode::SUCCESS) { |
| log::info("Got a Command complete {}, status {}", OpCodeText(view.GetCommandOpCode()), |
| ErrorCodeText(status_view.GetStatus())); |
| } |
| |
| ApcfOpcode apcf_opcode = status_view.GetApcfOpcode(); |
| switch (apcf_opcode) { |
| case ApcfOpcode::ENABLE: { |
| auto complete_view = LeAdvFilterEnableCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| scanning_callbacks_->OnFilterEnable(complete_view.GetApcfEnable(), |
| (uint8_t)complete_view.GetStatus()); |
| } break; |
| case ApcfOpcode::SET_FILTERING_PARAMETERS: { |
| auto complete_view = LeAdvFilterSetFilteringParametersCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| scanning_callbacks_->OnFilterParamSetup(complete_view.GetApcfAvailableSpaces(), |
| complete_view.GetApcfAction(), |
| (uint8_t)complete_view.GetStatus()); |
| } break; |
| case ApcfOpcode::BROADCASTER_ADDRESS: { |
| auto complete_view = LeAdvFilterBroadcasterAddressCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| scanning_callbacks_->OnFilterConfigCallback( |
| ApcfFilterType::BROADCASTER_ADDRESS, complete_view.GetApcfAvailableSpaces(), |
| complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); |
| } break; |
| case ApcfOpcode::SERVICE_UUID: { |
| auto complete_view = LeAdvFilterServiceUuidCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| scanning_callbacks_->OnFilterConfigCallback( |
| ApcfFilterType::SERVICE_UUID, complete_view.GetApcfAvailableSpaces(), |
| complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); |
| } break; |
| case ApcfOpcode::SERVICE_SOLICITATION_UUID: { |
| auto complete_view = LeAdvFilterSolicitationUuidCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| scanning_callbacks_->OnFilterConfigCallback( |
| ApcfFilterType::SERVICE_SOLICITATION_UUID, complete_view.GetApcfAvailableSpaces(), |
| complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); |
| } break; |
| case ApcfOpcode::LOCAL_NAME: { |
| auto complete_view = LeAdvFilterLocalNameCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| scanning_callbacks_->OnFilterConfigCallback( |
| ApcfFilterType::LOCAL_NAME, complete_view.GetApcfAvailableSpaces(), |
| complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); |
| } break; |
| case ApcfOpcode::MANUFACTURER_DATA: { |
| auto complete_view = LeAdvFilterManufacturerDataCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| scanning_callbacks_->OnFilterConfigCallback( |
| ApcfFilterType::MANUFACTURER_DATA, complete_view.GetApcfAvailableSpaces(), |
| complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); |
| } break; |
| case ApcfOpcode::SERVICE_DATA: { |
| auto complete_view = LeAdvFilterServiceDataCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| scanning_callbacks_->OnFilterConfigCallback( |
| ApcfFilterType::SERVICE_DATA, complete_view.GetApcfAvailableSpaces(), |
| complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); |
| } break; |
| case ApcfOpcode::TRANSPORT_DISCOVERY_DATA: { |
| auto complete_view = LeAdvFilterTransportDiscoveryDataCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| scanning_callbacks_->OnFilterConfigCallback( |
| ApcfFilterType::TRANSPORT_DISCOVERY_DATA, complete_view.GetApcfAvailableSpaces(), |
| complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); |
| } break; |
| case ApcfOpcode::AD_TYPE: { |
| auto complete_view = LeAdvFilterADTypeCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| scanning_callbacks_->OnFilterConfigCallback( |
| ApcfFilterType::AD_TYPE, complete_view.GetApcfAvailableSpaces(), |
| complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); |
| } break; |
| default: |
| log::warn("Unexpected event type {}", OpCodeText(view.GetCommandOpCode())); |
| } |
| } |
| |
| void on_apcf_read_extended_features_complete(CommandCompleteView view) { |
| log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); |
| auto status_view = LeAdvFilterCompleteView::Create(view); |
| if (!status_view.IsValid()) { |
| log::warn("Can not get valid LeAdvFilterCompleteView, return"); |
| return; |
| } |
| if (status_view.GetStatus() != ErrorCode::SUCCESS) { |
| log::warn("Got a Command complete {}, status {}", OpCodeText(view.GetCommandOpCode()), |
| ErrorCodeText(status_view.GetStatus())); |
| return; |
| } |
| auto complete_view = LeAdvFilterReadExtendedFeaturesCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| is_transport_discovery_data_filter_supported_ = |
| complete_view.GetTransportDiscoveryDataFilter() == 1; |
| is_ad_type_filter_supported_ = complete_view.GetAdTypeFilter() == 1; |
| log::info( |
| "set is_ad_type_filter_supported_ to {} & " |
| "is_transport_discovery_data_filter_supported_ to {}", |
| is_ad_type_filter_supported_, is_transport_discovery_data_filter_supported_); |
| } |
| |
| void on_batch_scan_complete(CommandCompleteView view) { |
| log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); |
| auto status_view = LeBatchScanCompleteView::Create(view); |
| log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); |
| if (status_view.GetStatus() != ErrorCode::SUCCESS) { |
| log::info("Got a Command complete {}, status {}, batch_scan_opcode {}", |
| OpCodeText(view.GetCommandOpCode()), ErrorCodeText(status_view.GetStatus()), |
| BatchScanOpcodeText(status_view.GetBatchScanOpcode())); |
| } |
| } |
| |
| void on_batch_scan_enable_complete(CommandCompleteView view) { |
| log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); |
| auto status_view = LeBatchScanCompleteView::Create(view); |
| log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); |
| auto complete_view = LeBatchScanEnableCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| if (status_view.GetStatus() != ErrorCode::SUCCESS) { |
| log::info("Got batch scan enable complete, status {}", |
| ErrorCodeText(status_view.GetStatus())); |
| batch_scan_config_.current_state = BatchScanState::ERROR_STATE; |
| } else { |
| batch_scan_config_.current_state = BatchScanState::ENABLED_STATE; |
| } |
| } |
| |
| void on_batch_scan_disable_complete(CommandCompleteView view) { |
| log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); |
| auto status_view = LeBatchScanCompleteView::Create(view); |
| log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); |
| auto complete_view = LeBatchScanSetScanParametersCompleteView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| log::assert_that(status_view.GetStatus() == ErrorCode::SUCCESS, |
| "assert failed: status_view.GetStatus() == ErrorCode::SUCCESS"); |
| batch_scan_config_.current_state = BatchScanState::DISABLED_STATE; |
| } |
| |
| void on_batch_scan_read_result_complete(ScannerId scanner_id, uint16_t total_num_of_records, |
| CommandCompleteView view) { |
| log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); |
| auto status_view = LeBatchScanCompleteView::Create(view); |
| log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); |
| auto complete_view = LeBatchScanReadResultParametersCompleteRawView::Create(status_view); |
| log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); |
| if (complete_view.GetStatus() != ErrorCode::SUCCESS) { |
| log::info("Got batch scan read result complete, status {}", |
| ErrorCodeText(status_view.GetStatus())); |
| } |
| uint8_t num_of_records = complete_view.GetNumOfRecords(); |
| auto report_format = complete_view.GetBatchScanDataRead(); |
| if (num_of_records == 0) { |
| scanning_callbacks_->OnBatchScanReports(scanner_id, 0x00, (int)report_format, |
| total_num_of_records, |
| batch_scan_result_cache_[scanner_id]); |
| batch_scan_result_cache_.erase(scanner_id); |
| } else { |
| auto raw_data = complete_view.GetRawData(); |
| batch_scan_result_cache_[scanner_id].insert(batch_scan_result_cache_[scanner_id].end(), |
| raw_data.begin(), raw_data.end()); |
| total_num_of_records += num_of_records; |
| batch_scan_read_results(scanner_id, total_num_of_records, |
| static_cast<BatchScanMode>(report_format)); |
| } |
| } |
| |
| void on_storage_threshold_breach(VendorSpecificEventView /* event */) { |
| if (batch_scan_config_.ref_value == kInvalidScannerId) { |
| log::warn("storage threshold was not set !!"); |
| return; |
| } |
| scanning_callbacks_->OnBatchScanThresholdCrossed( |
| static_cast<int>(batch_scan_config_.ref_value)); |
| } |
| |
| void on_advertisement_tracking(VendorSpecificEventView event) { |
| auto view = LEAdvertisementTrackingEventView::Create(event); |
| log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); |
| uint8_t filter_index = view.GetApcfFilterIndex(); |
| if (tracker_id_map_.find(filter_index) == tracker_id_map_.end()) { |
| log::warn("Advertisement track for filter_index {} is not register", (uint16_t)filter_index); |
| return; |
| } |
| AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info = {}; |
| on_found_on_lost_info.scanner_id = tracker_id_map_[filter_index]; |
| on_found_on_lost_info.filter_index = filter_index; |
| on_found_on_lost_info.advertiser_state = view.GetAdvertiserState(); |
| on_found_on_lost_info.advertiser_address = view.GetAdvertiserAddress(); |
| on_found_on_lost_info.advertiser_address_type = view.GetAdvertiserAddressType(); |
| on_found_on_lost_info.advertiser_info_present = view.GetAdvtInfoPresent(); |
| /* Extract the adv info details */ |
| if (on_found_on_lost_info.advertiser_info_present == AdvtInfoPresent::ADVT_INFO_PRESENT) { |
| auto info_view = LEAdvertisementTrackingWithInfoEventView::Create(view); |
| log::assert_that(info_view.IsValid(), "assert failed: info_view.IsValid()"); |
| on_found_on_lost_info.tx_power = info_view.GetTxPower(); |
| on_found_on_lost_info.rssi = info_view.GetRssi(); |
| on_found_on_lost_info.time_stamp = info_view.GetTimestamp(); |
| auto adv_data = info_view.GetAdvPacket(); |
| on_found_on_lost_info.adv_packet.reserve(adv_data.size()); |
| on_found_on_lost_info.adv_packet.insert(on_found_on_lost_info.adv_packet.end(), |
| adv_data.begin(), adv_data.end()); |
| auto scan_rsp_data = info_view.GetScanResponse(); |
| on_found_on_lost_info.scan_response.reserve(scan_rsp_data.size()); |
| on_found_on_lost_info.scan_response.insert(on_found_on_lost_info.scan_response.end(), |
| scan_rsp_data.begin(), scan_rsp_data.end()); |
| } |
| scanning_callbacks_->OnTrackAdvFoundLost(on_found_on_lost_info); |
| } |
| |
| void OnPause() override { |
| if (!address_manager_registered_) { |
| log::warn("Unregistered!"); |
| return; |
| } |
| paused_ = true; |
| scan_on_resume_ = is_scanning_; |
| stop_scan(); |
| ack_pause(); |
| } |
| |
| void ack_pause() { le_address_manager_->AckPause(this); } |
| |
| void OnResume() override { |
| if (!address_manager_registered_) { |
| log::warn("Unregistered!"); |
| return; |
| } |
| paused_ = false; |
| if (scan_on_resume_) { |
| scan_on_resume_ = false; |
| if (com::android::bluetooth::flags::configure_scan_on_resume()) { |
| // This is a workaround for b/381010390. |
| // We'll eventually recover scan parameters which could be overridden by |
| // btm_send_hci_set_scan_params. |
| configure_scan(); |
| } |
| start_scan(); |
| } |
| le_address_manager_->AckResume(this); |
| } |
| |
| ScanApiType api_type_; |
| |
| Module* module_; |
| os::Handler* module_handler_; |
| HciLayer* hci_layer_; |
| Controller* controller_; |
| AclManager* acl_manager_; |
| storage::StorageModule* storage_module_; |
| LeScanningInterface* le_scanning_interface_; |
| LeAddressManager* le_address_manager_; |
| bool address_manager_registered_ = false; |
| NullScanningCallback null_scanning_callback_; |
| ScanningCallback* scanning_callbacks_ = &null_scanning_callback_; |
| PeriodicSyncManager periodic_sync_manager_{&null_scanning_callback_}; |
| std::vector<Scanner> scanners_; |
| bool is_scanning_ = false; |
| bool scan_on_resume_ = false; |
| bool paused_ = false; |
| LeScanningReassembler scanning_reassembler_; |
| bool is_filter_supported_ = false; |
| bool is_ad_type_filter_supported_ = false; |
| bool is_batch_scan_supported_ = false; |
| bool is_periodic_advertising_sync_transfer_sender_supported_ = false; |
| bool is_transport_discovery_data_filter_supported_ = false; |
| |
| LeScanType le_scan_type_ = LeScanType::ACTIVE; |
| uint32_t interval_ms_1m_{1000}; |
| uint16_t window_ms_1m_{1000}; |
| uint32_t interval_ms_coded_{1000}; |
| uint16_t window_ms_coded_{1000}; |
| uint8_t phy_{(uint8_t)PhyType::LE_1M}; |
| OwnAddressType own_address_type_{OwnAddressType::PUBLIC_DEVICE_ADDRESS}; |
| LeScanningFilterPolicy filter_policy_{LeScanningFilterPolicy::ACCEPT_ALL}; |
| BatchScanConfig batch_scan_config_; |
| std::map<ScannerId, std::vector<uint8_t>> batch_scan_result_cache_; |
| std::unordered_map<uint8_t, ScannerId> tracker_id_map_; |
| uint16_t total_num_of_advt_tracked_ = 0x00; |
| int8_t le_rx_path_loss_comp_ = 0; |
| }; |
| |
| LeScanningManager::LeScanningManager() { pimpl_ = std::make_unique<impl>(this); } |
| |
| void LeScanningManager::ListDependencies(ModuleList* list) const { |
| list->add<HciLayer>(); |
| list->add<Controller>(); |
| list->add<AclManager>(); |
| } |
| |
| void LeScanningManager::Start() { |
| pimpl_->start(GetHandler(), GetDependency<HciLayer>(), GetDependency<Controller>(), |
| GetDependency<AclManager>(), shim::GetStorage()); |
| } |
| |
| void LeScanningManager::Stop() { |
| pimpl_->stop(); |
| pimpl_.reset(); |
| } |
| |
| std::string LeScanningManager::ToString() const { return "Le Scanning Manager"; } |
| |
| void LeScanningManager::RegisterScanner(Uuid app_uuid) { |
| CallOn(pimpl_.get(), &impl::register_scanner, app_uuid); |
| } |
| |
| void LeScanningManager::Unregister(ScannerId scanner_id) { |
| CallOn(pimpl_.get(), &impl::unregister_scanner, scanner_id); |
| } |
| |
| void LeScanningManager::Scan(bool start) { CallOn(pimpl_.get(), &impl::scan, start); } |
| |
| void LeScanningManager::SetScanParameters(LeScanType scan_type, ScannerId scanner_id_1m, |
| uint16_t scan_interval_1m, uint16_t scan_window_1m, |
| ScannerId scanner_id_coded, uint16_t scan_interval_coded, |
| uint16_t scan_window_coded, uint8_t scan_phy) { |
| CallOn(pimpl_.get(), &impl::set_scan_parameters, scan_type, scanner_id_1m, scan_interval_1m, |
| scan_window_1m, scanner_id_coded, scan_interval_coded, scan_window_coded, scan_phy); |
| } |
| |
| void LeScanningManager::SetScanFilterPolicy(LeScanningFilterPolicy filter_policy) { |
| CallOn(pimpl_.get(), &impl::set_scan_filter_policy, filter_policy); |
| } |
| |
| void LeScanningManager::ScanFilterEnable(bool enable) { |
| CallOn(pimpl_.get(), &impl::scan_filter_enable, enable); |
| } |
| |
| void LeScanningManager::ScanFilterParameterSetup( |
| ApcfAction action, uint8_t filter_index, |
| AdvertisingFilterParameter advertising_filter_parameter) { |
| CallOn(pimpl_.get(), &impl::scan_filter_parameter_setup, action, filter_index, |
| advertising_filter_parameter); |
| } |
| |
| void LeScanningManager::ScanFilterAdd(uint8_t filter_index, |
| std::vector<AdvertisingPacketContentFilterCommand> filters) { |
| CallOn(pimpl_.get(), &impl::scan_filter_add, filter_index, filters); |
| } |
| |
| void LeScanningManager::BatchScanConifgStorage(uint8_t batch_scan_full_max, |
| uint8_t batch_scan_truncated_max, |
| uint8_t batch_scan_notify_threshold, |
| ScannerId scanner_id) { |
| CallOn(pimpl_.get(), &impl::batch_scan_set_storage_parameter, batch_scan_full_max, |
| batch_scan_truncated_max, batch_scan_notify_threshold, scanner_id); |
| } |
| |
| void LeScanningManager::BatchScanEnable(BatchScanMode scan_mode, |
| uint32_t duty_cycle_scan_window_slots, |
| uint32_t duty_cycle_scan_interval_slots, |
| BatchScanDiscardRule batch_scan_discard_rule) { |
| CallOn(pimpl_.get(), &impl::batch_scan_enable, scan_mode, duty_cycle_scan_window_slots, |
| duty_cycle_scan_interval_slots, batch_scan_discard_rule); |
| } |
| |
| void LeScanningManager::BatchScanDisable() { CallOn(pimpl_.get(), &impl::batch_scan_disable); } |
| |
| void LeScanningManager::BatchScanReadReport(ScannerId scanner_id, BatchScanMode scan_mode) { |
| CallOn(pimpl_.get(), &impl::batch_scan_read_results, scanner_id, 0, scan_mode); |
| } |
| |
| void LeScanningManager::StartSync(uint8_t sid, const AddressWithType& address_with_type, |
| uint16_t skip, uint16_t timeout, int reg_id) { |
| CallOn(pimpl_.get(), &impl::start_sync, sid, address_with_type, skip, timeout, reg_id); |
| } |
| |
| void LeScanningManager::StopSync(uint16_t handle) { |
| CallOn(pimpl_.get(), &impl::stop_sync, handle); |
| } |
| |
| void LeScanningManager::CancelCreateSync(uint8_t sid, const Address& address) { |
| CallOn(pimpl_.get(), &impl::cancel_create_sync, sid, address); |
| } |
| |
| void LeScanningManager::TransferSync(const Address& address, uint16_t handle, uint16_t service_data, |
| uint16_t sync_handle, int pa_source) { |
| CallOn(pimpl_.get(), &impl::transfer_sync, address, handle, service_data, sync_handle, pa_source); |
| } |
| |
| void LeScanningManager::TransferSetInfo(const Address& address, uint16_t handle, |
| uint16_t service_data, uint8_t adv_handle, int pa_source) { |
| CallOn(pimpl_.get(), &impl::transfer_set_info, address, handle, service_data, adv_handle, |
| pa_source); |
| } |
| |
| void LeScanningManager::SyncTxParameters(const Address& address, uint8_t mode, uint16_t skip, |
| uint16_t timeout, int reg_id) { |
| CallOn(pimpl_.get(), &impl::sync_tx_parameters, address, mode, skip, timeout, reg_id); |
| } |
| |
| void LeScanningManager::TrackAdvertiser(uint8_t filter_index, ScannerId scanner_id) { |
| CallOn(pimpl_.get(), &impl::track_advertiser, filter_index, scanner_id); |
| } |
| |
| void LeScanningManager::RegisterScanningCallback(ScanningCallback* scanning_callback) { |
| CallOn(pimpl_.get(), &impl::register_scanning_callback, scanning_callback); |
| } |
| |
| bool LeScanningManager::IsAdTypeFilterSupported() const { |
| return pimpl_->is_ad_type_filter_supported(); |
| } |
| |
| } // namespace hci |
| } // namespace bluetooth |