OSDN Git Service

gd: Implement Advertising Packet Content Filter
authorChienyuan <chienyuanhuang@google.com>
Sun, 17 Jan 2021 15:38:07 +0000 (23:38 +0800)
committerChienyuan <chienyuanhuang@google.com>
Wed, 20 Jan 2021 07:11:38 +0000 (15:11 +0800)
Tag: #gd-refactor
Bug: 177044452
Test: gd/cert/run --host
Test: run SL4A test, FilteringTest and UniqueFilteringTest
Change-Id: Ifb63c56f6e473d6bc43e46970937dc6873fd0a5c

gd/hci/facade/le_scanning_manager_facade.cc
gd/hci/hci_packets.pdl
gd/hci/le_scanning_manager.cc
gd/hci/le_scanning_manager.h
gd/hci/le_scanning_manager_test.cc
main/shim/btm.cc
main/shim/btm.h
main/shim/le_scanning_manager.cc

index fe429e3..448ec89 100644 (file)
@@ -91,6 +91,10 @@ class LeScanningManagerFacadeService : public LeScanningManagerFacade::Service,
   void OnTrackAdvFoundLost(){};
   void OnBatchScanReports(int client_if, int status, int report_format, int num_records, std::vector<uint8_t> data){};
   void OnTimeout(){};
+  void OnFilterEnable(Enable enable, uint8_t status){};
+  void OnFilterParamSetup(uint8_t available_spaces, ApcfAction action, uint8_t status){};
+  void OnFilterConfigCallback(
+      ApcfFilterType filter_type, uint8_t available_spaces, ApcfAction action, uint8_t status){};
 
   LeScanningManager* le_scanning_manager_;
   os::Handler* facade_handler_;
index 11f3dde..02cb3b7 100644 (file)
@@ -3987,6 +3987,7 @@ enum ApcfOpcode : 8 {
   SERVICE_DATA = 0x07,
 }
 
+// https://source.android.com/devices/bluetooth/hci_requirements#advertising-packet-content-filter
 packet LeAdvFilter : LeScanningCommand (op_code = LE_ADV_FILTER) {
   apcf_opcode : ApcfOpcode,
   _body_,
@@ -3995,8 +3996,151 @@ packet LeAdvFilter : LeScanningCommand (op_code = LE_ADV_FILTER) {
 packet LeAdvFilterComplete : CommandComplete (command_op_code = LE_ADV_FILTER) {
   status : ErrorCode,
   apcf_opcode : ApcfOpcode,
+  _body_,
+}
+
+packet LeAdvFilterEnable : LeAdvFilter (apcf_opcode = ENABLE) {
+  apcf_enable : Enable,
+}
+
+packet LeAdvFilterEnableComplete : LeAdvFilterComplete (apcf_opcode = ENABLE) {
+  apcf_enable : Enable,
+}
+
+enum ApcfAction : 8 {
+  ADD = 0x00,
+  DELETE = 0x01,
+  CLEAR = 0x02,
+}
+
+enum DeliveryMode : 8 {
+  IMMEDIATE = 0x00,
+  ONFOUND = 0x01,
+  BATCHED = 0x02,
+}
+
+// Bit masks for the selected features
+enum ApcfFilterType : 8 {
+  BROADCASTER_ADDRESS = 0x00,
+  SERVICE_DATA_CHANGE = 0x01,
+  SERVICE_UUID = 0x02,
+  SERVICE_SOLICITATION_UUID = 0x03,
+  LOCAL_NAME = 0x04,
+  MANUFACTURER_DATA = 0x05,
+  SERVICE_DATA = 0x06,
+}
+
+packet LeAdvFilterSetFilteringParameters : LeAdvFilter (apcf_opcode = SET_FILTERING_PARAMETERS) {
+  apcf_action : ApcfAction,
+  _body_,
+}
+
+packet LeAdvFilterAddFilteringParameters : LeAdvFilterSetFilteringParameters (apcf_action = ADD) {
+  apcf_filter_index : 8,
+  apcf_feature_selection : 16,
+  apcf_list_logic_type : 16,
+  apcf_filter_logic_type : 8,
+  rssi_high_thresh : 8,
+  delivery_mode : DeliveryMode,
+  onfound_timeout : 16,
+  onfound_timeout_cnt : 8,
+  rssi_low_thresh : 8,
+  onlost_timeout : 16,
+  num_of_tracking_entries : 16,
+}
+
+packet LeAdvFilterDeleteFilteringParameters : LeAdvFilterSetFilteringParameters (apcf_action = DELETE) {
+  apcf_filter_index : 8,
+}
+
+packet LeAdvFilterClearFilteringParameters : LeAdvFilterSetFilteringParameters (apcf_action = CLEAR) {
+}
+
+packet LeAdvFilterSetFilteringParametersComplete : LeAdvFilterComplete (apcf_opcode = SET_FILTERING_PARAMETERS) {
+  apcf_action : ApcfAction,
+  apcf_available_spaces : 8,
+}
+
+enum ApcfApplicationAddressType : 8 {
+  PUBLIC = 0x00,
+  RANDOM = 0x01,
+  NOT_APPLICABLE = 0x02,
 }
 
+packet LeAdvFilterBroadcasterAddress : LeAdvFilter (apcf_opcode = BROADCASTER_ADDRESS) {
+  apcf_action : ApcfAction,
+  apcf_filter_index : 8,
+  apcf_broadcaster_address : Address,
+  apcf_application_address_type : ApcfApplicationAddressType,
+}
+
+packet LeAdvFilterClearBroadcasterAddress : LeAdvFilter (apcf_opcode = BROADCASTER_ADDRESS) {
+  _fixed_ = 0x02 : 8,
+  apcf_filter_index : 8,
+}
+
+packet LeAdvFilterBroadcasterAddressComplete : LeAdvFilterComplete (apcf_opcode = BROADCASTER_ADDRESS) {
+  apcf_action : ApcfAction,
+  apcf_available_spaces : 8,
+}
+
+
+packet LeAdvFilterServiceUuid : LeAdvFilter (apcf_opcode = SERVICE_UUID) {
+  apcf_action : ApcfAction,
+  apcf_filter_index : 8,
+  acpf_uuid_data : 8[],
+}
+
+packet LeAdvFilterServiceUuidComplete : LeAdvFilterComplete (apcf_opcode = SERVICE_UUID) {
+  apcf_action : ApcfAction,
+  apcf_available_spaces : 8,
+}
+
+packet LeAdvFilterSolicitationUuid : LeAdvFilter (apcf_opcode = SERVICE_SOLICITATION_UUID) {
+  apcf_action : ApcfAction,
+  apcf_filter_index : 8,
+  acpf_uuid_data : 8[],
+}
+
+packet LeAdvFilterSolicitationUuidComplete : LeAdvFilterComplete (apcf_opcode = SERVICE_SOLICITATION_UUID) {
+  apcf_action : ApcfAction,
+  apcf_available_spaces : 8,
+}
+
+packet LeAdvFilterLocalName : LeAdvFilter (apcf_opcode = LOCAL_NAME) {
+  apcf_action : ApcfAction,
+  apcf_filter_index : 8,
+  apcf_local_name : 8[],
+}
+
+packet LeAdvFilterLocalNameComplete : LeAdvFilterComplete (apcf_opcode = LOCAL_NAME) {
+  apcf_action : ApcfAction,
+  apcf_available_spaces : 8,
+}
+
+packet LeAdvFilterManufacturerData : LeAdvFilter (apcf_opcode = MANUFACTURER_DATA) {
+  apcf_action : ApcfAction,
+  apcf_filter_index : 8,
+  apcf_manufacturer_data : 8[],
+}
+
+packet LeAdvFilterManufacturerDataComplete : LeAdvFilterComplete (apcf_opcode = MANUFACTURER_DATA) {
+  apcf_action : ApcfAction,
+  apcf_available_spaces : 8,
+}
+
+packet LeAdvFilterServiceData : LeAdvFilter (apcf_opcode = SERVICE_DATA) {
+  apcf_action : ApcfAction,
+  apcf_filter_index : 8,
+  apcf_service_data : 8[],
+}
+
+packet LeAdvFilterServiceDataComplete : LeAdvFilterComplete (apcf_opcode = SERVICE_DATA) {
+  apcf_action : ApcfAction,
+  apcf_available_spaces : 8,
+}
+
+
 packet LeTrackAdv : VendorCommand (op_code = LE_TRACK_ADV) {
   _payload_,  // placeholder (unimplemented)
 }
index 390c07c..8112b1f 100644 (file)
@@ -158,6 +158,7 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback
     } else {
       api_type_ = ScanApiType::LEGACY;
     }
+    is_filter_support_ = controller_->IsSupported(OpCode::LE_ADV_FILTER);
     scanners_ = std::vector<Scanner>(kMaxAppNum + 1);
     for (size_t i = 0; i < scanners_.size(); i++) {
       scanners_[i].app_uuid = Uuid::kEmpty;
@@ -528,10 +529,315 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback
     window_ms_ = scan_window;
   }
 
+  void scan_filter_enable(bool enable) {
+    if (!is_filter_support_) {
+      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));
+  }
+
+  void scan_filter_parameter_setup(
+      ApcfAction action, uint8_t filter_index, AdvertisingFilterParameter advertising_filter_parameter) {
+    if (!is_filter_support_) {
+      LOG_WARN("Advertising filter is not supported");
+      return;
+    }
+
+    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_thres,
+                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:
+        le_scanning_interface_->EnqueueCommand(
+            LeAdvFilterDeleteFilteringParametersBuilder::Create(filter_index),
+            module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
+        break;
+      case ApcfAction::CLEAR:
+        le_scanning_interface_->EnqueueCommand(
+            LeAdvFilterClearFilteringParametersBuilder::Create(),
+            module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
+        break;
+      default:
+        LOG_ERROR("Unknown action type: %d", (uint16_t)action);
+        break;
+    }
+  }
+
+  void scan_filter_add(uint8_t filter_index, std::vector<AdvertisingPacketContentFilterCommand> filters) {
+    if (!is_filter_support_) {
+      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);
+          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;
+        }
+        default:
+          LOG_ERROR("Unknown filter type: %d", (uint16_t)filter.filter_type);
+          break;
+      }
+    }
+  }
+
+  void update_address_filter(
+      ApcfAction action, uint8_t filter_index, Address address, ApcfApplicationAddressType address_type) {
+    if (action != ApcfAction::CLEAR) {
+      le_scanning_interface_->EnqueueCommand(
+          LeAdvFilterBroadcasterAddressBuilder::Create(action, filter_index, address, address_type),
+          module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
+    } else {
+      le_scanning_interface_->EnqueueCommand(
+          LeAdvFilterClearBroadcasterAddressBuilder::Create(filter_index),
+          module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
+    }
+  }
+
+  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) {
+        uint16_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: %d", (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) {
+          uint16_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 register_scanning_callback(ScanningCallback* scanning_callbacks) {
     scanning_callbacks_ = scanning_callbacks;
   }
 
+  void on_advertising_filter_complete(CommandCompleteView view) {
+    ASSERT(view.IsValid());
+    auto status_view = LeAdvFilterCompleteView::Create(view);
+    ASSERT(status_view.IsValid());
+    if (status_view.GetStatus() != ErrorCode::SUCCESS) {
+      LOG_INFO(
+          "Got a Command complete %s, status %s",
+          OpCodeText(view.GetCommandOpCode()).c_str(),
+          ErrorCodeText(status_view.GetStatus()).c_str());
+    }
+
+    ApcfOpcode apcf_opcode = status_view.GetApcfOpcode();
+    switch (apcf_opcode) {
+      case ApcfOpcode::ENABLE: {
+        auto complete_view = LeAdvFilterEnableCompleteView::Create(status_view);
+        ASSERT(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);
+        ASSERT(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);
+        ASSERT(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);
+        ASSERT(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);
+        ASSERT(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);
+        ASSERT(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);
+        ASSERT(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);
+        ASSERT(complete_view.IsValid());
+        scanning_callbacks_->OnFilterConfigCallback(
+            ApcfFilterType::SERVICE_DATA,
+            complete_view.GetApcfAvailableSpaces(),
+            complete_view.GetApcfAction(),
+            (uint8_t)complete_view.GetStatus());
+      } break;
+      default:
+        LOG_WARN("Unexpected event type %s", OpCodeText(view.GetCommandOpCode()).c_str());
+    }
+  }
+
   void OnPause() override {
     paused_ = true;
     scan_on_resume_ = is_scanning_;
@@ -566,6 +872,7 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback
   bool scan_on_resume_ = false;
   bool paused_ = false;
   AdvertisingCache advertising_cache_;
+  bool is_filter_support_ = false;
 
   LeScanType le_scan_type_ = LeScanType::ACTIVE;
   uint32_t interval_ms_{1000};
@@ -645,6 +952,20 @@ void LeScanningManager::SetScanParameters(LeScanType scan_type, uint16_t scan_in
   CallOn(pimpl_.get(), &impl::set_scan_parameters, scan_type, scan_interval, scan_window);
 }
 
+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::RegisterScanningCallback(ScanningCallback* scanning_callback) {
   CallOn(pimpl_.get(), &impl::register_scanning_callback, scanning_callback);
 }
index b04e3d8..751b7be 100644 (file)
@@ -18,6 +18,7 @@
 #include <memory>
 
 #include "common/callback.h"
+#include "hci/address_with_type.h"
 #include "hci/hci_packets.h"
 #include "hci/uuid.h"
 #include "module.h"
@@ -53,6 +54,38 @@ class ScanningCallback {
   virtual void OnBatchScanReports(
       int client_if, int status, int report_format, int num_records, std::vector<uint8_t> data) = 0;
   virtual void OnTimeout() = 0;
+  virtual void OnFilterEnable(Enable enable, uint8_t status) = 0;
+  virtual void OnFilterParamSetup(uint8_t available_spaces, ApcfAction action, uint8_t status) = 0;
+  virtual void OnFilterConfigCallback(
+      ApcfFilterType filter_type, uint8_t available_spaces, ApcfAction action, uint8_t status) = 0;
+};
+
+class AdvertisingPacketContentFilterCommand {
+ public:
+  ApcfFilterType filter_type;
+  Address address;
+  ApcfApplicationAddressType application_address_type;
+  Uuid uuid;
+  Uuid uuid_mask;
+  std::vector<uint8_t> name;
+  uint16_t company;
+  uint16_t company_mask;
+  std::vector<uint8_t> data;
+  std::vector<uint8_t> data_mask;
+};
+
+class AdvertisingFilterParameter {
+ public:
+  uint16_t feature_selection;
+  uint16_t list_logic_type;
+  uint8_t filter_logic_type;
+  uint8_t rssi_high_thresh;
+  DeliveryMode delivery_mode;
+  uint16_t onfound_timeout;
+  uint8_t onfound_timeout_cnt;
+  uint8_t rssi_low_thres;
+  uint16_t onlost_timeout;
+  uint16_t num_of_tracking_entries;
 };
 
 class LeScanningManager : public bluetooth::Module {
@@ -71,6 +104,14 @@ class LeScanningManager : public bluetooth::Module {
 
   void SetScanParameters(LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window);
 
+  /* Scan filter */
+  void ScanFilterEnable(bool enable);
+
+  void ScanFilterParameterSetup(
+      ApcfAction action, uint8_t filter_index, AdvertisingFilterParameter advertising_filter_parameter);
+
+  void ScanFilterAdd(uint8_t filter_index, std::vector<AdvertisingPacketContentFilterCommand> filters);
+
   void RegisterScanningCallback(ScanningCallback* scanning_callback);
 
   static const ModuleFactory Factory;
index 3d28d1d..821b12f 100644 (file)
@@ -232,10 +232,14 @@ class LeScanningManagerTest : public ::testing::Test {
     test_hci_layer_ = new TestHciLayer;  // Ownership is transferred to registry
     test_controller_ = new TestController;
     test_controller_->AddSupported(param_opcode_);
+    if (is_filter_support_) {
+      test_controller_->AddSupported(OpCode::LE_ADV_FILTER);
+    }
     test_acl_manager_ = new TestAclManager;
     fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
     fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
     fake_registry_.InjectTestModule(&AclManager::Factory, test_acl_manager_);
+    client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
     std::future<void> config_future = test_hci_layer_->GetCommandFuture();
     fake_registry_.Start<LeScanningManager>(&thread_);
     le_scanning_manager =
@@ -256,6 +260,14 @@ class LeScanningManagerTest : public ::testing::Test {
     test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(1, ErrorCode::SUCCESS));
   }
 
+  void sync_client_handler() {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    client_handler_->Call(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    auto future_status = future.wait_for(std::chrono::seconds(1));
+    ASSERT_EQ(future_status, std::future_status::ready);
+  }
+
   TestModuleRegistry fake_registry_;
   TestHciLayer* test_hci_layer_ = nullptr;
   TestController* test_controller_ = nullptr;
@@ -292,16 +304,26 @@ class LeScanningManagerTest : public ::testing::Test {
         (int client_if, int status, int report_format, int num_records, std::vector<uint8_t> data),
         (override));
     MOCK_METHOD(void, OnTimeout, (), (override));
+    MOCK_METHOD(void, OnFilterEnable, (Enable enable, uint8_t status), (override));
+    MOCK_METHOD(void, OnFilterParamSetup, (uint8_t available_spaces, ApcfAction action, uint8_t status), (override));
+    MOCK_METHOD(
+        void,
+        OnFilterConfigCallback,
+        (ApcfFilterType filter_type, uint8_t available_spaces, ApcfAction action, uint8_t status),
+        (override));
   } mock_callbacks_;
 
   OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS};
+  bool is_filter_support_ = false;
 };
 
 class LeAndroidHciScanningManagerTest : public LeScanningManagerTest {
  protected:
   void SetUp() override {
     param_opcode_ = OpCode::LE_EXTENDED_SCAN_PARAMS;
+    is_filter_support_ = true;
     LeScanningManagerTest::SetUp();
+    test_controller_->AddSupported(OpCode::LE_ADV_FILTER);
   }
 
   void HandleConfiguration() override {
@@ -379,6 +401,45 @@ TEST_F(LeAndroidHciScanningManagerTest, start_scan_test) {
   test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report}));
 }
 
+TEST_F(LeAndroidHciScanningManagerTest, scan_filter_enable_test) {
+  auto next_command_future = test_hci_layer_->GetCommandFuture();
+  le_scanning_manager->ScanFilterEnable(true);
+  auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+  ASSERT_EQ(std::future_status::ready, result);
+  EXPECT_CALL(mock_callbacks_, OnFilterEnable);
+  test_hci_layer_->IncomingEvent(
+      LeAdvFilterEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, Enable::ENABLED));
+  sync_client_handler();
+}
+
+TEST_F(LeAndroidHciScanningManagerTest, scan_filter_parameter_test) {
+  auto next_command_future = test_hci_layer_->GetCommandFuture();
+  AdvertisingFilterParameter advertising_filter_parameter{};
+  advertising_filter_parameter.delivery_mode = DeliveryMode::IMMEDIATE;
+  le_scanning_manager->ScanFilterParameterSetup(ApcfAction::ADD, 0x01, advertising_filter_parameter);
+  auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+  ASSERT_EQ(std::future_status::ready, result);
+  EXPECT_CALL(mock_callbacks_, OnFilterParamSetup);
+  test_hci_layer_->IncomingEvent(
+      LeAdvFilterSetFilteringParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a));
+  sync_client_handler();
+}
+
+TEST_F(LeAndroidHciScanningManagerTest, scan_filter_add_test) {
+  auto next_command_future = test_hci_layer_->GetCommandFuture();
+  std::vector<AdvertisingPacketContentFilterCommand> filters = {};
+  AdvertisingPacketContentFilterCommand filter{};
+  filter.filter_type = ApcfFilterType::BROADCASTER_ADDRESS;
+  filter.address = Address::kEmpty;
+  filter.application_address_type = ApcfApplicationAddressType::RANDOM;
+  filters.push_back(filter);
+  le_scanning_manager->ScanFilterAdd(0x01, filters);
+  EXPECT_CALL(mock_callbacks_, OnFilterConfigCallback);
+  test_hci_layer_->IncomingEvent(
+      LeAdvFilterBroadcasterAddressCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a));
+  sync_client_handler();
+}
+
 TEST_F(LeExtendedScanningManagerTest, start_scan_test) {
   auto next_command_future = test_hci_layer_->GetCommandFuture();
   le_scanning_manager->Scan(true);
index ca910d5..201504a 100644 (file)
@@ -145,6 +145,14 @@ void Btm::ScanningCallbacks::OnBatchScanReports(int client_if, int status,
                                                 int num_records,
                                                 std::vector<uint8_t> data){};
 void Btm::ScanningCallbacks::OnTimeout(){};
+void Btm::ScanningCallbacks::OnFilterEnable(bluetooth::hci::Enable enable,
+                                            uint8_t status){};
+void Btm::ScanningCallbacks::OnFilterParamSetup(
+    uint8_t available_spaces, bluetooth::hci::ApcfAction action,
+    uint8_t status){};
+void Btm::ScanningCallbacks::OnFilterConfigCallback(
+    bluetooth::hci::ApcfFilterType filter_type, uint8_t available_spaces,
+    bluetooth::hci::ApcfAction action, uint8_t status){};
 
 Btm::Btm(os::Handler* handler, neighbor::InquiryModule* inquiry)
     : scanning_timer_(handler), observing_timer_(handler) {
index b009c93..bdbc28f 100644 (file)
@@ -249,6 +249,13 @@ class Btm {
     void OnBatchScanReports(int client_if, int status, int report_format,
                             int num_records, std::vector<uint8_t> data);
     void OnTimeout();
+    void OnFilterEnable(bluetooth::hci::Enable enable, uint8_t status);
+    void OnFilterParamSetup(uint8_t available_spaces,
+                            bluetooth::hci::ApcfAction action, uint8_t status);
+    void OnFilterConfigCallback(bluetooth::hci::ApcfFilterType filter_type,
+                                uint8_t available_spaces,
+                                bluetooth::hci::ApcfAction action,
+                                uint8_t status);
   };
   ScanningCallbacks scanning_callbacks_;
 
index cddbac9..773f658 100644 (file)
@@ -59,26 +59,77 @@ class BleScannerInterfaceImpl : public BleScannerInterface,
 
   /** Setup scan filter params */
   void ScanFilterParamSetup(
-      uint8_t client_if, uint8_t action, uint8_t filt_index,
+      uint8_t client_if, uint8_t action, uint8_t filter_index,
       std::unique_ptr<btgatt_filt_param_setup_t> filt_param,
       FilterParamSetupCallback cb) {
     LOG(INFO) << __func__ << " in shim layer";
+
+    auto apcf_action = static_cast<bluetooth::hci::ApcfAction>(action);
+    bluetooth::hci::AdvertisingFilterParameter advertising_filter_parameter;
+
+    if (filt_param != nullptr) {
+      if (filt_param && filt_param->dely_mode == 1) {
+        // TODO refactor BTM_BleTrackAdvertiser
+      }
+      advertising_filter_parameter.feature_selection = filt_param->feat_seln;
+      advertising_filter_parameter.list_logic_type =
+          filt_param->list_logic_type;
+      advertising_filter_parameter.filter_logic_type =
+          filt_param->filt_logic_type;
+      advertising_filter_parameter.rssi_high_thresh =
+          filt_param->rssi_high_thres;
+      advertising_filter_parameter.delivery_mode =
+          static_cast<bluetooth::hci::DeliveryMode>(filt_param->dely_mode);
+      if (filt_param && filt_param->dely_mode == 1) {
+        advertising_filter_parameter.onfound_timeout =
+            filt_param->found_timeout;
+        advertising_filter_parameter.onfound_timeout_cnt =
+            filt_param->found_timeout_cnt;
+        advertising_filter_parameter.rssi_low_thres =
+            filt_param->rssi_low_thres;
+        advertising_filter_parameter.onlost_timeout = filt_param->lost_timeout;
+        advertising_filter_parameter.num_of_tracking_entries =
+            filt_param->num_of_tracking_entries;
+      }
+    }
+
+    bluetooth::shim::GetScanning()->ScanFilterParameterSetup(
+        apcf_action, filter_index, advertising_filter_parameter);
+    // TODO refactor callback mechanism
+    do_in_jni_thread(FROM_HERE, base::Bind(cb, 0, 0, 0));
   }
 
   /** Configure a scan filter condition  */
   void ScanFilterAdd(int filter_index, std::vector<ApcfCommand> filters,
                      FilterConfigCallback cb) {
     LOG(INFO) << __func__ << " in shim layer";
+    std::vector<bluetooth::hci::AdvertisingPacketContentFilterCommand>
+        new_filters = {};
+    for (size_t i = 0; i < filters.size(); i++) {
+      bluetooth::hci::AdvertisingPacketContentFilterCommand command{};
+      if (!parse_filter_command(command, filters[i])) {
+        LOG_ERROR("invalid apcf command");
+        return;
+      }
+      new_filters.push_back(command);
+    }
+    bluetooth::shim::GetScanning()->ScanFilterAdd(filter_index, new_filters);
+    do_in_jni_thread(FROM_HERE, base::Bind(cb, 0, 0, 0, 0));
   }
 
   /** Clear all scan filter conditions for specific filter index*/
-  void ScanFilterClear(int filt_index, FilterConfigCallback cb) {
+  void ScanFilterClear(int filter_index, FilterConfigCallback cb) {
     LOG(INFO) << __func__ << " in shim layer";
+    // This function doesn't used in java layer
   }
 
   /** Enable / disable scan filter feature*/
   void ScanFilterEnable(bool enable, EnableCallback cb) {
     LOG(INFO) << __func__ << " in shim layer";
+    bluetooth::shim::GetScanning()->ScanFilterEnable(enable);
+
+    uint8_t action = enable ? 1 : 0;
+    do_in_jni_thread(FROM_HERE, base::Bind(cb, action, 0));
   }
 
   /** Sets the LE scan interval and window in units of N*0.625 msec */
@@ -88,6 +139,7 @@ class BleScannerInterfaceImpl : public BleScannerInterface,
     auto scan_type = static_cast<bluetooth::hci::LeScanType>(0x01);
     bluetooth::shim::GetScanning()->SetScanParameters(scan_type, scan_interval,
                                                       scan_window);
+    do_in_jni_thread(FROM_HERE, base::Bind(cb, 0));
   }
 
   /* Configure the batchscan storage */
@@ -166,7 +218,88 @@ class BleScannerInterfaceImpl : public BleScannerInterface,
                           int num_records, std::vector<uint8_t> data) {}
   void OnTimeout() {}
 
+  void OnFilterEnable(bluetooth::hci::Enable enable, uint8_t status){};
+
+  void OnFilterParamSetup(uint8_t available_spaces,
+                          bluetooth::hci::ApcfAction action, uint8_t status){};
+
+  void OnFilterConfigCallback(bluetooth::hci::ApcfFilterType filter_type,
+                              uint8_t available_spaces,
+                              bluetooth::hci::ApcfAction action,
+                              uint8_t status){};
+
   ScanningCallbacks* scanning_callbacks_;
+
+ private:
+  bool parse_filter_command(
+      bluetooth::hci::AdvertisingPacketContentFilterCommand&
+          advertising_packet_content_filter_command,
+      ApcfCommand apcf_command) {
+    advertising_packet_content_filter_command.filter_type =
+        static_cast<bluetooth::hci::ApcfFilterType>(apcf_command.type);
+    bluetooth::hci::Address address;
+    bluetooth::hci::Address::FromString(apcf_command.address.ToString(),
+                                        address);
+    advertising_packet_content_filter_command.address = address;
+    advertising_packet_content_filter_command.application_address_type =
+        static_cast<bluetooth::hci::ApcfApplicationAddressType>(
+            apcf_command.addr_type);
+
+    if (!apcf_command.uuid.IsEmpty()) {
+      uint8_t uuid_len = apcf_command.uuid.GetShortestRepresentationSize();
+      switch (uuid_len) {
+        case bluetooth::Uuid::kNumBytes16: {
+          advertising_packet_content_filter_command.uuid =
+              bluetooth::hci::Uuid::From16Bit(apcf_command.uuid.As16Bit());
+        } break;
+        case bluetooth::Uuid::kNumBytes32: {
+          advertising_packet_content_filter_command.uuid =
+              bluetooth::hci::Uuid::From32Bit(apcf_command.uuid.As32Bit());
+        } break;
+        case bluetooth::Uuid::kNumBytes128: {
+          advertising_packet_content_filter_command.uuid =
+              bluetooth::hci::Uuid::From128BitBE(
+                  apcf_command.uuid.To128BitBE());
+        } break;
+        default:
+          LOG_WARN("illegal UUID length %d", (uint16_t)uuid_len);
+          return false;
+      }
+    }
+
+    if (!apcf_command.uuid_mask.IsEmpty()) {
+      uint8_t uuid_len = apcf_command.uuid.GetShortestRepresentationSize();
+      switch (uuid_len) {
+        case bluetooth::Uuid::kNumBytes16: {
+          advertising_packet_content_filter_command.uuid_mask =
+              bluetooth::hci::Uuid::From16Bit(apcf_command.uuid_mask.As16Bit());
+        } break;
+        case bluetooth::Uuid::kNumBytes32: {
+          advertising_packet_content_filter_command.uuid_mask =
+              bluetooth::hci::Uuid::From32Bit(apcf_command.uuid_mask.As32Bit());
+        } break;
+        case bluetooth::Uuid::kNumBytes128: {
+          advertising_packet_content_filter_command.uuid_mask =
+              bluetooth::hci::Uuid::From128BitBE(
+                  apcf_command.uuid_mask.To128BitBE());
+        } break;
+        default:
+          LOG_WARN("illegal UUID length %d", (uint16_t)uuid_len);
+          return false;
+      }
+    }
+
+    advertising_packet_content_filter_command.name.assign(
+        apcf_command.name.begin(), apcf_command.name.end());
+    advertising_packet_content_filter_command.company = apcf_command.company;
+    advertising_packet_content_filter_command.company_mask =
+        apcf_command.company_mask;
+    advertising_packet_content_filter_command.data.assign(
+        apcf_command.data.begin(), apcf_command.data.end());
+    advertising_packet_content_filter_command.data_mask.assign(
+        apcf_command.data_mask.begin(), apcf_command.data_mask.end());
+    return true;
+  }
 };
 
 BleScannerInterfaceImpl* bt_le_scanner_instance = nullptr;