1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include <memory> 17 #include <mutex> 18 19 #include "hci/controller.h" 20 #include "hci/hci_layer.h" 21 #include "hci/hci_packets.h" 22 #include "hci/le_advertising_interface.h" 23 #include "hci/le_advertising_manager.h" 24 #include "module.h" 25 #include "os/handler.h" 26 #include "os/log.h" 27 28 namespace bluetooth { 29 namespace hci { 30 31 const ModuleFactory LeAdvertisingManager::Factory = ModuleFactory([]() { return new LeAdvertisingManager(); }); 32 33 enum class AdvertisingApiType { 34 LE_4_0 = 1, 35 ANDROID_HCI = 2, 36 LE_5_0 = 3, 37 }; 38 39 struct Advertiser { 40 os::Handler* handler; 41 common::Callback<void(Address, AddressType)> scan_callback; 42 common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback; 43 }; 44 45 ExtendedAdvertisingConfig::ExtendedAdvertisingConfig(const AdvertisingConfig& config) : AdvertisingConfig(config) { 46 switch (config.event_type) { 47 case AdvertisingEventType::ADV_IND: 48 connectable = true; 49 scannable = true; 50 break; 51 case AdvertisingEventType::ADV_DIRECT_IND: 52 connectable = true; 53 directed = true; 54 high_duty_directed_connectable = true; 55 break; 56 case AdvertisingEventType::ADV_SCAN_IND: 57 scannable = true; 58 break; 59 case AdvertisingEventType::ADV_NONCONN_IND: 60 break; 61 case AdvertisingEventType::ADV_DIRECT_IND_LOW: 62 connectable = true; 63 directed = true; 64 break; 65 default: 66 LOG_WARN("Unknown event type"); 67 break; 68 } 69 if (config.address_type == AddressType::PUBLIC_DEVICE_ADDRESS) { 70 own_address_type = OwnAddressType::PUBLIC_DEVICE_ADDRESS; 71 } else if (config.address_type == AddressType::RANDOM_DEVICE_ADDRESS) { 72 own_address_type = OwnAddressType::RANDOM_DEVICE_ADDRESS; 73 } 74 // TODO(b/149221472): Support fragmentation 75 operation = Operation::COMPLETE_ADVERTISEMENT; 76 } 77 78 struct LeAdvertisingManager::impl { 79 impl(Module* module) : module_(module), le_advertising_interface_(nullptr), num_instances_(0) {} 80 81 void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) { 82 module_handler_ = handler; 83 hci_layer_ = hci_layer; 84 controller_ = controller; 85 le_advertising_interface_ = hci_layer_->GetLeAdvertisingInterface( 86 common::Bind(&LeAdvertisingManager::impl::handle_event, common::Unretained(this)), module_handler_); 87 num_instances_ = controller_->GetControllerLeNumberOfSupportedAdverisingSets(); 88 enabled_sets_ = std::vector<EnabledSet>(num_instances_); 89 if (controller_->IsSupported(hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS)) { 90 advertising_api_type_ = AdvertisingApiType::LE_5_0; 91 } else if (controller_->IsSupported(hci::OpCode::LE_MULTI_ADVT)) { 92 advertising_api_type_ = AdvertisingApiType::ANDROID_HCI; 93 } else { 94 advertising_api_type_ = AdvertisingApiType::LE_4_0; 95 } 96 } 97 98 size_t GetNumberOfAdvertisingInstances() const { 99 return num_instances_; 100 } 101 102 void handle_event(LeMetaEventView event) { 103 switch (event.GetSubeventCode()) { 104 case hci::SubeventCode::SCAN_REQUEST_RECEIVED: 105 handle_scan_request(LeScanRequestReceivedView::Create(event)); 106 break; 107 case hci::SubeventCode::ADVERTISING_SET_TERMINATED: 108 handle_set_terminated(LeAdvertisingSetTerminatedView::Create(event)); 109 break; 110 default: 111 LOG_INFO("Unknown subevent in scanner %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str()); 112 } 113 } 114 115 void handle_scan_request(LeScanRequestReceivedView event_view) { 116 if (!event_view.IsValid()) { 117 LOG_INFO("Dropping invalid scan request event"); 118 return; 119 } 120 registered_handler_->Post( 121 common::BindOnce(scan_callback_, event_view.GetScannerAddress(), event_view.GetScannerAddressType())); 122 } 123 124 void handle_set_terminated(LeAdvertisingSetTerminatedView event_view) { 125 if (!event_view.IsValid()) { 126 LOG_INFO("Dropping invalid advertising event"); 127 return; 128 } 129 registered_handler_->Post(common::BindOnce(set_terminated_callback_, event_view.GetStatus(), 130 event_view.GetAdvertisingHandle(), 131 event_view.GetNumCompletedExtendedAdvertisingEvents())); 132 } 133 134 AdvertiserId allocate_advertiser() { 135 AdvertiserId id = 0; 136 { 137 std::unique_lock lock(id_mutex_); 138 while (id < num_instances_ && advertising_sets_.count(id) != 0) { 139 id++; 140 } 141 } 142 if (id == num_instances_) { 143 return kInvalidId; 144 } 145 return id; 146 } 147 148 void remove_advertiser(AdvertiserId id) { 149 stop_advertising(id); 150 std::unique_lock lock(id_mutex_); 151 if (advertising_sets_.count(id) == 0) { 152 return; 153 } 154 advertising_sets_.erase(id); 155 } 156 157 void create_advertiser(AdvertiserId id, const AdvertisingConfig& config, 158 const common::Callback<void(Address, AddressType)>& scan_callback, 159 const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, 160 os::Handler* handler) { 161 advertising_sets_[id].scan_callback = scan_callback; 162 advertising_sets_[id].set_terminated_callback = set_terminated_callback; 163 advertising_sets_[id].handler = handler; 164 switch (advertising_api_type_) { 165 case (AdvertisingApiType::LE_4_0): 166 le_advertising_interface_->EnqueueCommand( 167 hci::LeSetAdvertisingParametersBuilder::Create( 168 config.interval_min, config.interval_max, config.event_type, config.address_type, 169 config.peer_address_type, config.peer_address, config.channel_map, config.filter_policy), 170 common::BindOnce(impl::check_status<LeSetAdvertisingParametersCompleteView>), module_handler_); 171 le_advertising_interface_->EnqueueCommand(hci::LeSetRandomAddressBuilder::Create(config.random_address), 172 common::BindOnce(impl::check_status<LeSetRandomAddressCompleteView>), 173 module_handler_); 174 if (!config.scan_response.empty()) { 175 le_advertising_interface_->EnqueueCommand( 176 hci::LeSetScanResponseDataBuilder::Create(config.scan_response), 177 common::BindOnce(impl::check_status<LeSetScanResponseDataCompleteView>), module_handler_); 178 } 179 le_advertising_interface_->EnqueueCommand( 180 hci::LeSetAdvertisingDataBuilder::Create(config.advertisement), 181 common::BindOnce(impl::check_status<LeSetAdvertisingDataCompleteView>), module_handler_); 182 le_advertising_interface_->EnqueueCommand( 183 hci::LeSetAdvertisingEnableBuilder::Create(Enable::ENABLED), 184 common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), module_handler_); 185 break; 186 case (AdvertisingApiType::ANDROID_HCI): 187 le_advertising_interface_->EnqueueCommand( 188 hci::LeMultiAdvtParamBuilder::Create(config.interval_min, config.interval_max, config.event_type, 189 config.address_type, config.peer_address_type, config.peer_address, 190 config.channel_map, config.filter_policy, id, config.tx_power), 191 common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_); 192 le_advertising_interface_->EnqueueCommand(hci::LeMultiAdvtSetDataBuilder::Create(config.advertisement, id), 193 common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), 194 module_handler_); 195 if (!config.scan_response.empty()) { 196 le_advertising_interface_->EnqueueCommand( 197 hci::LeMultiAdvtSetScanRespBuilder::Create(config.scan_response, id), 198 common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_); 199 } 200 le_advertising_interface_->EnqueueCommand( 201 hci::LeMultiAdvtSetRandomAddrBuilder::Create(config.random_address, id), 202 common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_); 203 le_advertising_interface_->EnqueueCommand(hci::LeMultiAdvtSetEnableBuilder::Create(Enable::ENABLED, id), 204 common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), 205 module_handler_); 206 break; 207 case (AdvertisingApiType::LE_5_0): { 208 ExtendedAdvertisingConfig new_config = config; 209 new_config.legacy_pdus = true; 210 create_extended_advertiser(id, new_config, scan_callback, set_terminated_callback, handler); 211 } break; 212 } 213 } 214 215 void create_extended_advertiser(AdvertiserId id, const ExtendedAdvertisingConfig& config, 216 const common::Callback<void(Address, AddressType)>& scan_callback, 217 const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, 218 os::Handler* handler) { 219 if (advertising_api_type_ != AdvertisingApiType::LE_5_0) { 220 create_advertiser(id, config, scan_callback, set_terminated_callback, handler); 221 return; 222 } 223 224 if (config.legacy_pdus) { 225 LegacyAdvertisingProperties legacy_properties = LegacyAdvertisingProperties::ADV_IND; 226 if (config.connectable && config.directed) { 227 if (config.high_duty_directed_connectable) { 228 legacy_properties = LegacyAdvertisingProperties::ADV_DIRECT_IND_HIGH; 229 } else { 230 legacy_properties = LegacyAdvertisingProperties::ADV_DIRECT_IND_LOW; 231 } 232 } 233 if (config.scannable && !config.connectable) { 234 legacy_properties = LegacyAdvertisingProperties::ADV_SCAN_IND; 235 } 236 if (!config.scannable && !config.connectable) { 237 legacy_properties = LegacyAdvertisingProperties::ADV_NONCONN_IND; 238 } 239 240 le_advertising_interface_->EnqueueCommand( 241 LeSetExtendedAdvertisingLegacyParametersBuilder::Create( 242 id, legacy_properties, config.interval_min, config.interval_max, config.channel_map, 243 config.own_address_type, config.peer_address_type, config.peer_address, config.filter_policy, 244 config.tx_power, config.sid, config.enable_scan_request_notifications), 245 common::BindOnce(impl::check_status<LeSetExtendedAdvertisingParametersCompleteView>), module_handler_); 246 } else { 247 uint8_t legacy_properties = (config.connectable ? 0x1 : 0x00) | (config.scannable ? 0x2 : 0x00) | 248 (config.directed ? 0x4 : 0x00) | (config.high_duty_directed_connectable ? 0x8 : 0x00); 249 uint8_t extended_properties = (config.anonymous ? 0x20 : 0x00) | (config.include_tx_power ? 0x40 : 0x00); 250 251 le_advertising_interface_->EnqueueCommand( 252 hci::LeSetExtendedAdvertisingParametersBuilder::Create( 253 id, legacy_properties, extended_properties, config.interval_min, config.interval_max, config.channel_map, 254 config.own_address_type, config.peer_address_type, config.peer_address, config.filter_policy, 255 config.tx_power, (config.use_le_coded_phy ? PrimaryPhyType::LE_CODED : PrimaryPhyType::LE_1M), 256 config.secondary_max_skip, config.secondary_advertising_phy, config.sid, 257 config.enable_scan_request_notifications), 258 common::BindOnce(impl::check_status<LeSetExtendedAdvertisingParametersCompleteView>), module_handler_); 259 } 260 261 le_advertising_interface_->EnqueueCommand( 262 hci::LeSetExtendedAdvertisingRandomAddressBuilder::Create(id, config.random_address), 263 common::BindOnce(impl::check_status<LeSetExtendedAdvertisingRandomAddressCompleteView>), module_handler_); 264 if (!config.scan_response.empty()) { 265 le_advertising_interface_->EnqueueCommand( 266 hci::LeSetExtendedAdvertisingScanResponseBuilder::Create(id, config.operation, config.fragment_preference, 267 config.scan_response), 268 common::BindOnce(impl::check_status<LeSetExtendedAdvertisingScanResponseCompleteView>), module_handler_); 269 } 270 le_advertising_interface_->EnqueueCommand( 271 hci::LeSetExtendedAdvertisingDataBuilder::Create(id, config.operation, config.fragment_preference, 272 config.advertisement), 273 common::BindOnce(impl::check_status<LeSetExtendedAdvertisingDataCompleteView>), module_handler_); 274 275 EnabledSet curr_set; 276 curr_set.advertising_handle_ = id; 277 curr_set.duration_ = 0; // TODO: 0 means until the host disables it 278 curr_set.max_extended_advertising_events_ = 0; // TODO: 0 is no maximum 279 std::vector<EnabledSet> enabled_sets = {curr_set}; 280 281 enabled_sets_[id] = curr_set; 282 le_advertising_interface_->EnqueueCommand( 283 hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::ENABLED, enabled_sets), 284 common::BindOnce(impl::check_status<LeSetExtendedAdvertisingEnableCompleteView>), module_handler_); 285 286 advertising_sets_[id].scan_callback = scan_callback; 287 advertising_sets_[id].set_terminated_callback = set_terminated_callback; 288 advertising_sets_[id].handler = handler; 289 } 290 291 void stop_advertising(AdvertiserId advertising_set) { 292 if (advertising_sets_.find(advertising_set) == advertising_sets_.end()) { 293 LOG_INFO("Unknown advertising set %u", advertising_set); 294 return; 295 } 296 switch (advertising_api_type_) { 297 case (AdvertisingApiType::LE_4_0): 298 le_advertising_interface_->EnqueueCommand( 299 hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED), 300 common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), module_handler_); 301 break; 302 case (AdvertisingApiType::ANDROID_HCI): 303 le_advertising_interface_->EnqueueCommand( 304 hci::LeMultiAdvtSetEnableBuilder::Create(Enable::DISABLED, advertising_set), 305 common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_); 306 break; 307 case (AdvertisingApiType::LE_5_0): { 308 EnabledSet curr_set; 309 curr_set.advertising_handle_ = advertising_set; 310 std::vector<EnabledSet> enabled_vector{curr_set}; 311 le_advertising_interface_->EnqueueCommand( 312 hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::DISABLED, enabled_vector), 313 common::BindOnce(impl::check_status<LeSetExtendedAdvertisingEnableCompleteView>), module_handler_); 314 } break; 315 } 316 317 std::unique_lock lock(id_mutex_); 318 enabled_sets_[advertising_set].advertising_handle_ = -1; 319 advertising_sets_.erase(advertising_set); 320 } 321 322 common::Callback<void(Address, AddressType)> scan_callback_; 323 common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback_; 324 os::Handler* registered_handler_{nullptr}; 325 Module* module_; 326 os::Handler* module_handler_; 327 hci::HciLayer* hci_layer_; 328 hci::Controller* controller_; 329 hci::LeAdvertisingInterface* le_advertising_interface_; 330 std::map<AdvertiserId, Advertiser> advertising_sets_; 331 332 std::mutex id_mutex_; 333 size_t num_instances_; 334 std::vector<hci::EnabledSet> enabled_sets_; 335 336 AdvertisingApiType advertising_api_type_{0}; 337 338 template <class View> 339 static void check_status(CommandCompleteView view) { 340 ASSERT(view.IsValid()); 341 auto status_view = View::Create(view); 342 ASSERT(status_view.IsValid()); 343 if (status_view.GetStatus() != ErrorCode::SUCCESS) { 344 LOG_INFO("SetEnable returned status %s", ErrorCodeText(status_view.GetStatus()).c_str()); 345 } 346 } 347 }; 348 349 LeAdvertisingManager::LeAdvertisingManager() { 350 pimpl_ = std::make_unique<impl>(this); 351 } 352 353 void LeAdvertisingManager::ListDependencies(ModuleList* list) { 354 list->add<hci::HciLayer>(); 355 list->add<hci::Controller>(); 356 } 357 358 void LeAdvertisingManager::Start() { 359 pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>()); 360 } 361 362 void LeAdvertisingManager::Stop() { 363 pimpl_.reset(); 364 } 365 366 std::string LeAdvertisingManager::ToString() const { 367 return "Le Advertising Manager"; 368 } 369 370 size_t LeAdvertisingManager::GetNumberOfAdvertisingInstances() const { 371 return pimpl_->GetNumberOfAdvertisingInstances(); 372 } 373 374 AdvertiserId LeAdvertisingManager::CreateAdvertiser( 375 const AdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback, 376 const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) { 377 if (config.peer_address == Address::kEmpty) { 378 if (config.address_type == hci::AddressType::PUBLIC_IDENTITY_ADDRESS || 379 config.address_type == hci::AddressType::RANDOM_IDENTITY_ADDRESS) { 380 LOG_WARN("Peer address can not be empty"); 381 return kInvalidId; 382 } 383 if (config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND || 384 config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND_LOW) { 385 LOG_WARN("Peer address can not be empty for directed advertising"); 386 return kInvalidId; 387 } 388 } 389 AdvertiserId id = pimpl_->allocate_advertiser(); 390 if (id == kInvalidId) { 391 return id; 392 } 393 GetHandler()->Post(common::BindOnce(&impl::create_advertiser, common::Unretained(pimpl_.get()), id, config, 394 scan_callback, set_terminated_callback, handler)); 395 return id; 396 } 397 398 AdvertiserId LeAdvertisingManager::ExtendedCreateAdvertiser( 399 const ExtendedAdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback, 400 const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) { 401 if (config.directed) { 402 if (config.peer_address == Address::kEmpty) { 403 LOG_INFO("Peer address can not be empty for directed advertising"); 404 return kInvalidId; 405 } 406 } 407 if (config.channel_map == 0) { 408 LOG_INFO("At least one channel must be set in the map"); 409 return kInvalidId; 410 } 411 if (!config.legacy_pdus) { 412 if (config.connectable && config.scannable) { 413 LOG_INFO("Extended advertising PDUs can not be connectable and scannable"); 414 return kInvalidId; 415 } 416 if (config.high_duty_directed_connectable) { 417 LOG_INFO("Extended advertising PDUs can not be high duty cycle"); 418 return kInvalidId; 419 } 420 } 421 if (config.interval_min > config.interval_max) { 422 LOG_INFO("Advertising interval: min (%hu) > max (%hu)", config.interval_min, config.interval_max); 423 return kInvalidId; 424 } 425 AdvertiserId id = pimpl_->allocate_advertiser(); 426 if (id == kInvalidId) { 427 return id; 428 } 429 GetHandler()->Post(common::BindOnce(&impl::create_extended_advertiser, common::Unretained(pimpl_.get()), id, config, 430 scan_callback, set_terminated_callback, handler)); 431 return id; 432 } 433 434 void LeAdvertisingManager::RemoveAdvertiser(AdvertiserId id) { 435 GetHandler()->Post(common::BindOnce(&impl::remove_advertiser, common::Unretained(pimpl_.get()), id)); 436 } 437 438 } // namespace hci 439 } // namespace bluetooth 440