/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include "common/bind.h" #include "common/init_flags.h" #include "crypto_toolbox/crypto_toolbox.h" #include "hci/acl_manager/assembler.h" #include "hci/acl_manager/le_connection_management_callbacks.h" #include "hci/acl_manager/round_robin_scheduler.h" #include "hci/controller.h" #include "hci/hci_layer.h" #include "hci/hci_packets.h" #include "hci/le_address_manager.h" #include "os/alarm.h" #include "os/handler.h" #include "os/metrics.h" #include "os/system_properties.h" #include "packet/packet_view.h" using bluetooth::crypto_toolbox::Octet16; #define PRIVATE_ADDRESS_WITH_TYPE(addr) addr.ToString().substr(12U).c_str() namespace bluetooth { namespace hci { namespace acl_manager { using common::BindOnce; constexpr uint16_t kScanIntervalFast = 0x0060; /* 30 ~ 60 ms (use 60) = 96 *0.625 */ constexpr uint16_t kScanWindowFast = 0x0030; /* 30 ms = 48 *0.625 */ constexpr uint16_t kScanWindow2mFast = 0x0018; /* 15 ms = 24 *0.625 */ constexpr uint16_t kScanWindowCodedFast = 0x0018; /* 15 ms = 24 *0.625 */ constexpr uint16_t kScanIntervalSlow = 0x0800; /* 1.28 s = 2048 *0.625 */ constexpr uint16_t kScanWindowSlow = 0x0030; /* 30 ms = 48 *0.625 */ constexpr std::chrono::milliseconds kCreateConnectionTimeoutMs = std::chrono::milliseconds(30 * 1000); constexpr uint8_t PHY_LE_NO_PACKET = 0x00; constexpr uint8_t PHY_LE_1M = 0x01; constexpr uint8_t PHY_LE_2M = 0x02; constexpr uint8_t PHY_LE_CODED = 0x04; enum class ConnectabilityState { DISARMED = 0, ARMING = 1, ARMED = 2, DISARMING = 3, }; #define CASE_RETURN_TEXT(code) \ case code: \ return #code inline std::string connectability_state_machine_text(const ConnectabilityState& state) { switch (state) { CASE_RETURN_TEXT(ConnectabilityState::DISARMED); CASE_RETURN_TEXT(ConnectabilityState::ARMING); CASE_RETURN_TEXT(ConnectabilityState::ARMED); CASE_RETURN_TEXT(ConnectabilityState::DISARMING); default: return base::StringPrintf("UNKNOWN[%d]", state); } } #undef CASE_RETURN_TEXT struct le_acl_connection { le_acl_connection(AddressWithType remote_address, AclConnection::QueueDownEnd* queue_down_end, os::Handler* handler) : remote_address_(remote_address), assembler_(new acl_manager::assembler(remote_address, queue_down_end, handler)) {} ~le_acl_connection() { delete assembler_; } AddressWithType remote_address_; acl_manager::assembler* assembler_; LeConnectionManagementCallbacks* le_connection_management_callbacks_ = nullptr; }; struct le_impl : public bluetooth::hci::LeAddressManagerCallback { le_impl( HciLayer* hci_layer, Controller* controller, os::Handler* handler, RoundRobinScheduler* round_robin_scheduler, bool crash_on_unknown_handle) : hci_layer_(hci_layer), controller_(controller), round_robin_scheduler_(round_robin_scheduler) { hci_layer_ = hci_layer; controller_ = controller; handler_ = handler; connections.crash_on_unknown_handle_ = crash_on_unknown_handle; le_acl_connection_interface_ = hci_layer_->GetLeAclConnectionInterface( handler_->BindOn(this, &le_impl::on_le_event), handler_->BindOn(this, &le_impl::on_le_disconnect), handler_->BindOn(this, &le_impl::on_le_read_remote_version_information)); le_address_manager_ = new LeAddressManager( common::Bind(&le_impl::enqueue_command, common::Unretained(this)), handler_, controller->GetMacAddress(), controller->GetLeFilterAcceptListSize(), controller->GetLeResolvingListSize()); } ~le_impl() { if (address_manager_registered) { le_address_manager_->UnregisterSync(this); } delete le_address_manager_; hci_layer_->PutLeAclConnectionInterface(); connections.reset(); } void on_le_event(LeMetaEventView event_packet) { SubeventCode code = event_packet.GetSubeventCode(); switch (code) { case SubeventCode::CONNECTION_COMPLETE: on_le_connection_complete(event_packet); break; case SubeventCode::ENHANCED_CONNECTION_COMPLETE: on_le_enhanced_connection_complete(event_packet); break; case SubeventCode::CONNECTION_UPDATE_COMPLETE: on_le_connection_update_complete(event_packet); break; case SubeventCode::PHY_UPDATE_COMPLETE: on_le_phy_update_complete(event_packet); break; case SubeventCode::DATA_LENGTH_CHANGE: on_data_length_change(event_packet); break; case SubeventCode::REMOTE_CONNECTION_PARAMETER_REQUEST: on_remote_connection_parameter_request(event_packet); break; default: LOG_ALWAYS_FATAL("Unhandled event code %s", SubeventCodeText(code).c_str()); } } private: static constexpr uint16_t kIllegalConnectionHandle = 0xffff; struct { private: std::map le_acl_connections_; mutable std::mutex le_acl_connections_guard_; LeConnectionManagementCallbacks* find_callbacks(uint16_t handle) { auto connection = le_acl_connections_.find(handle); if (connection == le_acl_connections_.end()) return nullptr; return connection->second.le_connection_management_callbacks_; } void remove(uint16_t handle) { auto connection = le_acl_connections_.find(handle); if (connection != le_acl_connections_.end()) { connection->second.le_connection_management_callbacks_ = nullptr; le_acl_connections_.erase(handle); } } public: bool crash_on_unknown_handle_ = false; bool is_empty() const { std::unique_lock lock(le_acl_connections_guard_); return le_acl_connections_.empty(); } void reset() { std::unique_lock lock(le_acl_connections_guard_); le_acl_connections_.clear(); } void invalidate(uint16_t handle) { std::unique_lock lock(le_acl_connections_guard_); remove(handle); } void execute( uint16_t handle, std::function execute, bool remove_afterwards = false) { std::unique_lock lock(le_acl_connections_guard_); auto callbacks = find_callbacks(handle); if (callbacks != nullptr) execute(callbacks); else ASSERT_LOG(!crash_on_unknown_handle_, "Received command for unknown handle:0x%x", handle); if (remove_afterwards) remove(handle); } bool send_packet_upward(uint16_t handle, std::function cb) { std::unique_lock lock(le_acl_connections_guard_); auto connection = le_acl_connections_.find(handle); if (connection != le_acl_connections_.end()) cb(connection->second.assembler_); return connection != le_acl_connections_.end(); } void add( uint16_t handle, const AddressWithType& remote_address, AclConnection::QueueDownEnd* queue_end, os::Handler* handler, LeConnectionManagementCallbacks* le_connection_management_callbacks) { std::unique_lock lock(le_acl_connections_guard_); auto emplace_pair = le_acl_connections_.emplace( std::piecewise_construct, std::forward_as_tuple(handle), std::forward_as_tuple(remote_address, queue_end, handler)); ASSERT(emplace_pair.second); // Make sure the connection is unique emplace_pair.first->second.le_connection_management_callbacks_ = le_connection_management_callbacks; } uint16_t HACK_get_handle(Address address) const { std::unique_lock lock(le_acl_connections_guard_); for (auto it = le_acl_connections_.begin(); it != le_acl_connections_.end(); it++) { if (it->second.remote_address_.GetAddress() == address) { return it->first; } } return kIllegalConnectionHandle; } AddressWithType getAddressWithType(uint16_t handle) { std::unique_lock lock(le_acl_connections_guard_); auto it = le_acl_connections_.find(handle); if (it != le_acl_connections_.end()) { return it->second.remote_address_; } AddressWithType empty(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS); return empty; } bool alreadyConnected(AddressWithType address_with_type) { for (auto it = le_acl_connections_.begin(); it != le_acl_connections_.end(); it++) { if (it->second.remote_address_ == address_with_type) { return true; } } return false; } } connections; public: void enqueue_command(std::unique_ptr command_packet) { hci_layer_->EnqueueCommand( std::move(command_packet), handler_->BindOnce(&LeAddressManager::OnCommandComplete, common::Unretained(le_address_manager_))); } bool send_packet_upward(uint16_t handle, std::function cb) { return connections.send_packet_upward(handle, cb); } // connection canceled by LeAddressManager.OnPause(), will auto reconnect by LeAddressManager.OnResume() void on_le_connection_canceled_on_pause() { ASSERT_LOG(pause_connection, "Connection must be paused to ack the le address manager"); arm_on_resume_ = true; connectability_state_ = ConnectabilityState::DISARMED; le_address_manager_->AckPause(this); } void on_common_le_connection_complete(AddressWithType address_with_type) { auto connecting_addr_with_type = connecting_le_.find(address_with_type); if (connecting_addr_with_type == connecting_le_.end()) { LOG_WARN("No prior connection request for %s", address_with_type.ToString().c_str()); } connecting_le_.clear(); if (create_connection_timeout_alarms_.find(address_with_type) != create_connection_timeout_alarms_.end()) { create_connection_timeout_alarms_.at(address_with_type).Cancel(); create_connection_timeout_alarms_.erase(address_with_type); } } void on_le_connection_complete(LeMetaEventView packet) { LeConnectionCompleteView connection_complete = LeConnectionCompleteView::Create(packet); ASSERT(connection_complete.IsValid()); auto status = connection_complete.GetStatus(); auto address = connection_complete.GetPeerAddress(); auto peer_address_type = connection_complete.GetPeerAddressType(); auto role = connection_complete.GetRole(); AddressWithType remote_address(address, peer_address_type); AddressWithType local_address = le_address_manager_->GetCurrentAddress(); const bool in_filter_accept_list = is_device_in_connect_list(remote_address); auto argument_list = std::vector>(); argument_list.push_back( std::make_pair(os::ArgumentType::ACL_STATUS_CODE, static_cast(status))); bluetooth::os::LogMetricBluetoothLEConnectionMetricEvent( address, android::bluetooth::le::LeConnectionOriginType::ORIGIN_NATIVE, android::bluetooth::le::LeConnectionType::CONNECTION_TYPE_LE_ACL, android::bluetooth::le::LeConnectionState::STATE_LE_ACL_END, argument_list); if (role == hci::Role::CENTRAL) { connectability_state_ = ConnectabilityState::DISARMED; if (status == ErrorCode::UNKNOWN_CONNECTION && pause_connection) { on_le_connection_canceled_on_pause(); return; } on_common_le_connection_complete(remote_address); if (status == ErrorCode::UNKNOWN_CONNECTION) { if (remote_address.GetAddress() != Address::kEmpty) { LOG_INFO("Controller send non-empty address field:%s", remote_address.GetAddress().ToString().c_str()); } // direct connect canceled due to connection timeout, start background connect create_le_connection(remote_address, false, false); return; } arm_on_resume_ = false; ready_to_unregister = true; remove_device_from_connect_list(remote_address); if (!connect_list.empty()) { AddressWithType empty(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS); handler_->Post(common::BindOnce(&le_impl::create_le_connection, common::Unretained(this), empty, false, false)); } if (le_client_handler_ == nullptr) { LOG_ERROR("No callbacks to call"); return; } if (status != ErrorCode::SUCCESS) { le_client_handler_->Post(common::BindOnce( &LeConnectionCallbacks::OnLeConnectFail, common::Unretained(le_client_callbacks_), remote_address, status)); return; } } else { LOG_INFO("Received connection complete with Peripheral role"); if (le_client_handler_ == nullptr) { LOG_ERROR("No callbacks to call"); return; } if (status != ErrorCode::SUCCESS) { std::string error_code = ErrorCodeText(status); LOG_WARN("Received on_le_connection_complete with error code %s", error_code.c_str()); return; } if (in_filter_accept_list) { LOG_INFO( "Received incoming connection of device in filter accept_list, %s", PRIVATE_ADDRESS_WITH_TYPE(remote_address)); remove_device_from_connect_list(remote_address); if (create_connection_timeout_alarms_.find(remote_address) != create_connection_timeout_alarms_.end()) { create_connection_timeout_alarms_.at(remote_address).Cancel(); create_connection_timeout_alarms_.erase(remote_address); } } } uint16_t conn_interval = connection_complete.GetConnInterval(); uint16_t conn_latency = connection_complete.GetConnLatency(); uint16_t supervision_timeout = connection_complete.GetSupervisionTimeout(); if (!check_connection_parameters(conn_interval, conn_interval, conn_latency, supervision_timeout)) { LOG_ERROR("Receive connection complete with invalid connection parameters"); return; } uint16_t handle = connection_complete.GetConnectionHandle(); auto queue = std::make_shared(10); auto queue_down_end = queue->GetDownEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, handle, queue); std::unique_ptr connection(new LeAclConnection( std::move(queue), le_acl_connection_interface_, handle, local_address, remote_address, role)); connection->peer_address_with_type_ = AddressWithType(address, peer_address_type); connection->interval_ = conn_interval; connection->latency_ = conn_latency; connection->supervision_timeout_ = supervision_timeout; connection->in_filter_accept_list_ = in_filter_accept_list; connections.add( handle, remote_address, queue_down_end, handler_, connection->GetEventCallbacks([this](uint16_t handle) { this->connections.invalidate(handle); })); le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectSuccess, common::Unretained(le_client_callbacks_), remote_address, std::move(connection))); } void on_le_enhanced_connection_complete(LeMetaEventView packet) { LeEnhancedConnectionCompleteView connection_complete = LeEnhancedConnectionCompleteView::Create(packet); ASSERT(connection_complete.IsValid()); auto status = connection_complete.GetStatus(); auto address = connection_complete.GetPeerAddress(); auto peer_address_type = connection_complete.GetPeerAddressType(); auto peer_resolvable_address = connection_complete.GetPeerResolvablePrivateAddress(); auto role = connection_complete.GetRole(); AddressType remote_address_type; switch (peer_address_type) { case AddressType::PUBLIC_DEVICE_ADDRESS: case AddressType::PUBLIC_IDENTITY_ADDRESS: remote_address_type = AddressType::PUBLIC_DEVICE_ADDRESS; break; case AddressType::RANDOM_DEVICE_ADDRESS: case AddressType::RANDOM_IDENTITY_ADDRESS: remote_address_type = AddressType::RANDOM_DEVICE_ADDRESS; break; } AddressWithType remote_address(address, remote_address_type); const bool in_filter_accept_list = is_device_in_connect_list(remote_address); auto argument_list = std::vector>(); argument_list.push_back( std::make_pair(os::ArgumentType::ACL_STATUS_CODE, static_cast(status))); bluetooth::os::LogMetricBluetoothLEConnectionMetricEvent( address, android::bluetooth::le::LeConnectionOriginType::ORIGIN_NATIVE, android::bluetooth::le::LeConnectionType::CONNECTION_TYPE_LE_ACL, android::bluetooth::le::LeConnectionState::STATE_LE_ACL_END, argument_list); if (role == hci::Role::CENTRAL) { connectability_state_ = ConnectabilityState::DISARMED; if (status == ErrorCode::UNKNOWN_CONNECTION && pause_connection) { on_le_connection_canceled_on_pause(); return; } on_common_le_connection_complete(remote_address); if (status == ErrorCode::UNKNOWN_CONNECTION) { if (remote_address.GetAddress() != Address::kEmpty) { LOG_INFO("Controller send non-empty address field:%s", remote_address.GetAddress().ToString().c_str()); } // direct connect canceled due to connection timeout, start background connect create_le_connection(remote_address, false, false); return; } arm_on_resume_ = false; ready_to_unregister = true; remove_device_from_connect_list(remote_address); if (!connect_list.empty()) { AddressWithType empty(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS); handler_->Post(common::BindOnce(&le_impl::create_le_connection, common::Unretained(this), empty, false, false)); } if (le_client_handler_ == nullptr) { LOG_ERROR("No callbacks to call"); return; } if (status != ErrorCode::SUCCESS) { le_client_handler_->Post(common::BindOnce( &LeConnectionCallbacks::OnLeConnectFail, common::Unretained(le_client_callbacks_), remote_address, status)); return; } } else { LOG_INFO("Received connection complete with Peripheral role"); if (le_client_handler_ == nullptr) { LOG_ERROR("No callbacks to call"); return; } if (status != ErrorCode::SUCCESS) { std::string error_code = ErrorCodeText(status); LOG_WARN("Received on_le_enhanced_connection_complete with error code %s", error_code.c_str()); return; } if (in_filter_accept_list) { LOG_INFO( "Received incoming connection of device in filter accept_list, %s", PRIVATE_ADDRESS_WITH_TYPE(remote_address)); remove_device_from_connect_list(remote_address); if (create_connection_timeout_alarms_.find(remote_address) != create_connection_timeout_alarms_.end()) { create_connection_timeout_alarms_.at(remote_address).Cancel(); create_connection_timeout_alarms_.erase(remote_address); } } } AddressWithType local_address; if (role == hci::Role::CENTRAL) { local_address = le_address_manager_->GetCurrentAddress(); } else { // when accepting connection, we must obtain the address from the advertiser. // When we receive "set terminated event", we associate connection handle with advertiser address local_address = AddressWithType{}; } uint16_t conn_interval = connection_complete.GetConnInterval(); uint16_t conn_latency = connection_complete.GetConnLatency(); uint16_t supervision_timeout = connection_complete.GetSupervisionTimeout(); if (!check_connection_parameters(conn_interval, conn_interval, conn_latency, supervision_timeout)) { LOG_ERROR("Receive enhenced connection complete with invalid connection parameters"); return; } uint16_t handle = connection_complete.GetConnectionHandle(); auto queue = std::make_shared(10); auto queue_down_end = queue->GetDownEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, handle, queue); std::unique_ptr connection(new LeAclConnection( std::move(queue), le_acl_connection_interface_, handle, local_address, remote_address, role)); connection->peer_address_with_type_ = AddressWithType(address, peer_address_type); connection->interval_ = conn_interval; connection->latency_ = conn_latency; connection->supervision_timeout_ = supervision_timeout; connection->local_resolvable_private_address_ = connection_complete.GetLocalResolvablePrivateAddress(); connection->peer_resolvable_private_address_ = connection_complete.GetPeerResolvablePrivateAddress(); connection->in_filter_accept_list_ = in_filter_accept_list; connections.add( handle, remote_address, queue_down_end, handler_, connection->GetEventCallbacks([this](uint16_t handle) { this->connections.invalidate(handle); })); le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectSuccess, common::Unretained(le_client_callbacks_), remote_address, std::move(connection))); } static constexpr bool kRemoveConnectionAfterwards = true; void on_le_disconnect(uint16_t handle, ErrorCode reason) { AddressWithType remote_address = connections.getAddressWithType(handle); bool event_also_routes_to_other_receivers = connections.crash_on_unknown_handle_; connections.crash_on_unknown_handle_ = false; connections.execute( handle, [=](LeConnectionManagementCallbacks* callbacks) { round_robin_scheduler_->Unregister(handle); callbacks->OnDisconnection(reason); }, kRemoveConnectionAfterwards); connections.crash_on_unknown_handle_ = event_also_routes_to_other_receivers; if (background_connections_.count(remote_address) == 1) { LOG_INFO("re-add device to connect list"); arm_on_resume_ = true; add_device_to_connect_list(remote_address); } } void on_le_connection_update_complete(LeMetaEventView view) { auto complete_view = LeConnectionUpdateCompleteView::Create(view); if (!complete_view.IsValid()) { LOG_ERROR("Received on_le_connection_update_complete with invalid packet"); return; } auto handle = complete_view.GetConnectionHandle(); connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { callbacks->OnConnectionUpdate( complete_view.GetStatus(), complete_view.GetConnInterval(), complete_view.GetConnLatency(), complete_view.GetSupervisionTimeout()); }); } void on_le_phy_update_complete(LeMetaEventView view) { auto complete_view = LePhyUpdateCompleteView::Create(view); if (!complete_view.IsValid()) { LOG_ERROR("Received on_le_phy_update_complete with invalid packet"); return; } auto handle = complete_view.GetConnectionHandle(); connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { callbacks->OnPhyUpdate(complete_view.GetStatus(), complete_view.GetTxPhy(), complete_view.GetRxPhy()); }); } void on_le_read_remote_version_information( hci::ErrorCode hci_status, uint16_t handle, uint8_t version, uint16_t manufacturer_name, uint16_t sub_version) { connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { callbacks->OnReadRemoteVersionInformationComplete(hci_status, version, manufacturer_name, sub_version); }); } void on_data_length_change(LeMetaEventView view) { auto data_length_view = LeDataLengthChangeView::Create(view); if (!data_length_view.IsValid()) { LOG_ERROR("Invalid packet"); return; } auto handle = data_length_view.GetConnectionHandle(); connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { callbacks->OnDataLengthChange( data_length_view.GetMaxTxOctets(), data_length_view.GetMaxTxTime(), data_length_view.GetMaxRxOctets(), data_length_view.GetMaxRxTime()); }); } void on_remote_connection_parameter_request(LeMetaEventView view) { auto request_view = LeRemoteConnectionParameterRequestView::Create(view); if (!request_view.IsValid()) { LOG_ERROR("Invalid packet"); return; } auto handle = request_view.GetConnectionHandle(); connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { // TODO: this is blindly accepting any parameters, just so we don't hang connection // have proper parameter negotiation le_acl_connection_interface_->EnqueueCommand( LeRemoteConnectionParameterRequestReplyBuilder::Create( handle, request_view.GetIntervalMin(), request_view.GetIntervalMax(), request_view.GetLatency(), request_view.GetTimeout(), 0, 0), handler_->BindOnce([](CommandCompleteView status) {})); }); } uint16_t HACK_get_handle(Address address) { return connections.HACK_get_handle(address); } void UpdateLocalAddress(uint16_t handle, hci::AddressWithType address_with_type) { connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { callbacks->OnLocalAddressUpdate(address_with_type); }); } void add_device_to_connect_list(AddressWithType address_with_type) { if (connections.alreadyConnected(address_with_type)) { LOG_INFO("Device already connected, return"); return; } if (connect_list.find(address_with_type) != connect_list.end()) { LOG_WARN( "Device already exists in acceptlist and cannot be added:%s", PRIVATE_ADDRESS_WITH_TYPE(address_with_type)); return; } connect_list.insert(address_with_type); register_with_address_manager(); le_address_manager_->AddDeviceToFilterAcceptList( address_with_type.ToFilterAcceptListAddressType(), address_with_type.GetAddress()); } bool is_device_in_connect_list(AddressWithType address_with_type) { return (connect_list.find(address_with_type) != connect_list.end()); } void remove_device_from_connect_list(AddressWithType address_with_type) { if (connect_list.find(address_with_type) == connect_list.end()) { LOG_WARN("Device not in acceptlist and cannot be removed:%s", PRIVATE_ADDRESS_WITH_TYPE(address_with_type)); return; } connect_list.erase(address_with_type); connecting_le_.erase(address_with_type); direct_connections_.erase(address_with_type); register_with_address_manager(); le_address_manager_->RemoveDeviceFromFilterAcceptList( address_with_type.ToFilterAcceptListAddressType(), address_with_type.GetAddress()); } void clear_connect_list() { connect_list.clear(); register_with_address_manager(); le_address_manager_->ClearFilterAcceptList(); } void add_device_to_resolving_list( AddressWithType address_with_type, const std::array& peer_irk, const std::array& local_irk) { register_with_address_manager(); le_address_manager_->AddDeviceToResolvingList( address_with_type.ToPeerAddressType(), address_with_type.GetAddress(), peer_irk, local_irk); } void remove_device_from_resolving_list(AddressWithType address_with_type) { register_with_address_manager(); le_address_manager_->RemoveDeviceFromResolvingList( address_with_type.ToPeerAddressType(), address_with_type.GetAddress()); } void update_connectability_state_after_armed(const ErrorCode& status) { switch (connectability_state_) { case ConnectabilityState::DISARMED: case ConnectabilityState::ARMED: case ConnectabilityState::DISARMING: LOG_ERROR( "Received connectability arm notification for unexpected state:%s status:%s", connectability_state_machine_text(connectability_state_).c_str(), ErrorCodeText(status).c_str()); break; case ConnectabilityState::ARMING: if (status != ErrorCode::SUCCESS) { LOG_ERROR("Le connection state machine armed failed status:%s", ErrorCodeText(status).c_str()); } connectability_state_ = (status == ErrorCode::SUCCESS) ? ConnectabilityState::ARMED : ConnectabilityState::DISARMED; LOG_INFO( "Le connection state machine armed state:%s status:%s", connectability_state_machine_text(connectability_state_).c_str(), ErrorCodeText(status).c_str()); if (disarmed_while_arming_) { disarmed_while_arming_ = false; disarm_connectability(); } } } void on_extended_create_connection(CommandStatusView status) { ASSERT(status.IsValid()); ASSERT(status.GetCommandOpCode() == OpCode::LE_EXTENDED_CREATE_CONNECTION); update_connectability_state_after_armed(status.GetStatus()); } void on_create_connection(CommandStatusView status) { ASSERT(status.IsValid()); ASSERT(status.GetCommandOpCode() == OpCode::LE_CREATE_CONNECTION); update_connectability_state_after_armed(status.GetStatus()); } void arm_connectability() { if (connectability_state_ != ConnectabilityState::DISARMED) { LOG_ERROR( "Attempting to re-arm le connection state machine in unexpected state:%s", connectability_state_machine_text(connectability_state_).c_str()); return; } if (connect_list.empty()) { LOG_INFO("Ignored request to re-arm le connection state machine when filter accept list is empty"); return; } AddressWithType empty(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS); connectability_state_ = ConnectabilityState::ARMING; connecting_le_ = connect_list; uint16_t le_scan_interval = kScanIntervalSlow; uint16_t le_scan_window = kScanWindowSlow; uint16_t le_scan_window_2m = kScanWindowSlow; uint16_t le_scan_window_coded = kScanWindowSlow; // If there is any direct connection in the connection list, use the fast parameter if (!direct_connections_.empty()) { le_scan_interval = kScanIntervalFast; le_scan_window = kScanWindowFast; le_scan_window_2m = kScanWindow2mFast; le_scan_window_coded = kScanWindowCodedFast; } InitiatorFilterPolicy initiator_filter_policy = InitiatorFilterPolicy::USE_FILTER_ACCEPT_LIST; OwnAddressType own_address_type = static_cast(le_address_manager_->GetCurrentAddress().GetAddressType()); uint16_t conn_interval_min = 0x0018; uint16_t conn_interval_max = 0x0028; uint16_t conn_latency = 0x0000; uint16_t supervision_timeout = 0x001f4; ASSERT(check_connection_parameters(conn_interval_min, conn_interval_max, conn_latency, supervision_timeout)); AddressWithType address_with_type = connection_peer_address_with_type_; if (initiator_filter_policy == InitiatorFilterPolicy::USE_FILTER_ACCEPT_LIST) { address_with_type = AddressWithType(); } if (controller_->IsSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION)) { uint8_t initiating_phys = PHY_LE_1M; std::vector parameters = {}; LeCreateConnPhyScanParameters scan_parameters; scan_parameters.scan_interval_ = le_scan_interval; scan_parameters.scan_window_ = le_scan_window; scan_parameters.conn_interval_min_ = conn_interval_min; scan_parameters.conn_interval_max_ = conn_interval_max; scan_parameters.conn_latency_ = conn_latency; scan_parameters.supervision_timeout_ = supervision_timeout; scan_parameters.min_ce_length_ = 0x00; scan_parameters.max_ce_length_ = 0x00; parameters.push_back(scan_parameters); if (controller_->SupportsBle2mPhy()) { LeCreateConnPhyScanParameters scan_parameters_2m; scan_parameters_2m.scan_interval_ = le_scan_interval; scan_parameters_2m.scan_window_ = le_scan_window_2m; scan_parameters_2m.conn_interval_min_ = conn_interval_min; scan_parameters_2m.conn_interval_max_ = conn_interval_max; scan_parameters_2m.conn_latency_ = conn_latency; scan_parameters_2m.supervision_timeout_ = supervision_timeout; scan_parameters_2m.min_ce_length_ = 0x00; scan_parameters_2m.max_ce_length_ = 0x00; parameters.push_back(scan_parameters_2m); initiating_phys |= PHY_LE_2M; } if (controller_->SupportsBleCodedPhy()) { LeCreateConnPhyScanParameters scan_parameters_coded; scan_parameters_coded.scan_interval_ = le_scan_interval; scan_parameters_coded.scan_window_ = le_scan_window_coded; scan_parameters_coded.conn_interval_min_ = conn_interval_min; scan_parameters_coded.conn_interval_max_ = conn_interval_max; scan_parameters_coded.conn_latency_ = conn_latency; scan_parameters_coded.supervision_timeout_ = supervision_timeout; scan_parameters_coded.min_ce_length_ = 0x00; scan_parameters_coded.max_ce_length_ = 0x00; parameters.push_back(scan_parameters_coded); initiating_phys |= PHY_LE_CODED; } le_acl_connection_interface_->EnqueueCommand( LeExtendedCreateConnectionBuilder::Create( initiator_filter_policy, own_address_type, address_with_type.GetAddressType(), address_with_type.GetAddress(), initiating_phys, parameters), handler_->BindOnce(&le_impl::on_extended_create_connection, common::Unretained(this))); } else { le_acl_connection_interface_->EnqueueCommand( LeCreateConnectionBuilder::Create( le_scan_interval, le_scan_window, initiator_filter_policy, address_with_type.GetAddressType(), address_with_type.GetAddress(), own_address_type, conn_interval_min, conn_interval_max, conn_latency, supervision_timeout, 0x00, 0x00), handler_->BindOnce(&le_impl::on_create_connection, common::Unretained(this))); } } void disarm_connectability() { auto argument_list = std::vector>(); bluetooth::os::LogMetricBluetoothLEConnectionMetricEvent( Address::kEmpty, os::LeConnectionOriginType::ORIGIN_UNSPECIFIED, os::LeConnectionType::CONNECTION_TYPE_LE_ACL, os::LeConnectionState::STATE_LE_ACL_CANCEL, argument_list); switch (connectability_state_) { case ConnectabilityState::ARMED: LOG_INFO("Disarming LE connection state machine with create connection cancel"); connectability_state_ = ConnectabilityState::DISARMING; le_acl_connection_interface_->EnqueueCommand( LeCreateConnectionCancelBuilder::Create(), handler_->BindOnce(&le_impl::on_create_connection_cancel_complete, common::Unretained(this))); break; case ConnectabilityState::ARMING: LOG_INFO("Queueing cancel connect until after connection state machine is armed"); disarmed_while_arming_ = true; break; case ConnectabilityState::DISARMING: case ConnectabilityState::DISARMED: LOG_ERROR( "Attempting to disarm le connection state machine in unexpected state:%s", connectability_state_machine_text(connectability_state_).c_str()); break; } } void create_le_connection(AddressWithType address_with_type, bool add_to_connect_list, bool is_direct) { if (le_client_callbacks_ == nullptr) { LOG_ERROR("No callbacks to call"); return; } if (connections.alreadyConnected(address_with_type)) { LOG_INFO("Device already connected, return"); return; } // TODO: Configure default LE connection parameters? if (add_to_connect_list) { add_device_to_connect_list(address_with_type); if (is_direct) { direct_connections_.insert(address_with_type); if (create_connection_timeout_alarms_.find(address_with_type) == create_connection_timeout_alarms_.end()) { create_connection_timeout_alarms_.emplace( std::piecewise_construct, std::forward_as_tuple(address_with_type.GetAddress(), address_with_type.GetAddressType()), std::forward_as_tuple(handler_)); create_connection_timeout_alarms_.at(address_with_type) .Schedule( common::BindOnce(&le_impl::on_create_connection_timeout, common::Unretained(this), address_with_type), kCreateConnectionTimeoutMs); } } } if (!address_manager_registered) { auto policy = le_address_manager_->Register(this); address_manager_registered = true; // Pause connection, wait for set random address complete if (policy == LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS || policy == LeAddressManager::AddressPolicy::USE_NON_RESOLVABLE_ADDRESS) { pause_connection = true; } } if (pause_connection) { arm_on_resume_ = true; return; } switch (connectability_state_) { case ConnectabilityState::ARMED: case ConnectabilityState::ARMING: // Ignored, if we add new device to the filter accept list, create connection command will be sent by OnResume. LOG_DEBUG( "Deferred until filter accept list updated create connection state %s", connectability_state_machine_text(connectability_state_).c_str()); break; default: // If we added to filter accept list then the arming of the le state machine // must wait until the filter accept list command as completed if (add_to_connect_list) { arm_on_resume_ = true; LOG_DEBUG("Deferred until filter accept list has completed"); } else { handler_->CallOn(this, &le_impl::arm_connectability); } break; } } void on_create_connection_timeout(AddressWithType address_with_type) { LOG_INFO("on_create_connection_timeout, address: %s", address_with_type.ToString().c_str()); if (create_connection_timeout_alarms_.find(address_with_type) != create_connection_timeout_alarms_.end()) { create_connection_timeout_alarms_.at(address_with_type).Cancel(); create_connection_timeout_alarms_.erase(address_with_type); auto argument_list = std::vector>(); argument_list.push_back(std::make_pair( os::ArgumentType::ACL_STATUS_CODE, static_cast(android::bluetooth::hci::StatusEnum::STATUS_CONNECTION_TOUT))); bluetooth::os::LogMetricBluetoothLEConnectionMetricEvent( address_with_type.GetAddress(), android::bluetooth::le::LeConnectionOriginType::ORIGIN_NATIVE, android::bluetooth::le::LeConnectionType::CONNECTION_TYPE_LE_ACL, android::bluetooth::le::LeConnectionState::STATE_LE_ACL_TIMEOUT, argument_list); if (background_connections_.find(address_with_type) != background_connections_.end()) { direct_connections_.erase(address_with_type); disarm_connectability(); } else { cancel_connect(address_with_type); } le_client_handler_->Post(common::BindOnce( &LeConnectionCallbacks::OnLeConnectFail, common::Unretained(le_client_callbacks_), address_with_type, ErrorCode::CONNECTION_ACCEPT_TIMEOUT)); } } void cancel_connect(AddressWithType address_with_type) { // Remove any alarms for this peer, if any if (create_connection_timeout_alarms_.find(address_with_type) != create_connection_timeout_alarms_.end()) { create_connection_timeout_alarms_.at(address_with_type).Cancel(); create_connection_timeout_alarms_.erase(address_with_type); } // the connection will be canceled by LeAddressManager.OnPause() remove_device_from_connect_list(address_with_type); } void set_le_suggested_default_data_parameters(uint16_t length, uint16_t time) { auto packet = LeWriteSuggestedDefaultDataLengthBuilder::Create(length, time); le_acl_connection_interface_->EnqueueCommand( std::move(packet), handler_->BindOnce([](CommandCompleteView complete) {})); } void clear_resolving_list() { le_address_manager_->ClearResolvingList(); } void set_privacy_policy_for_initiator_address( LeAddressManager::AddressPolicy address_policy, AddressWithType fixed_address, crypto_toolbox::Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { le_address_manager_->SetPrivacyPolicyForInitiatorAddress( address_policy, fixed_address, rotation_irk, controller_->SupportsBlePrivacy(), minimum_rotation_time, maximum_rotation_time); } // TODO(jpawlowski): remove once we have config file abstraction in cert tests void set_privacy_policy_for_initiator_address_for_test( LeAddressManager::AddressPolicy address_policy, AddressWithType fixed_address, crypto_toolbox::Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { le_address_manager_->SetPrivacyPolicyForInitiatorAddressForTest( address_policy, fixed_address, rotation_irk, minimum_rotation_time, maximum_rotation_time); } void handle_register_le_callbacks(LeConnectionCallbacks* callbacks, os::Handler* handler) { ASSERT(le_client_callbacks_ == nullptr); ASSERT(le_client_handler_ == nullptr); le_client_callbacks_ = callbacks; le_client_handler_ = handler; } void handle_unregister_le_callbacks(LeConnectionCallbacks* callbacks, std::promise promise) { ASSERT_LOG(le_client_callbacks_ == callbacks, "Registered le callback entity is different then unregister request"); le_client_callbacks_ = nullptr; le_client_handler_ = nullptr; promise.set_value(); } bool check_connection_parameters( uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout) { if (conn_interval_min < 0x0006 || conn_interval_min > 0x0C80 || conn_interval_max < 0x0006 || conn_interval_max > 0x0C80 || conn_latency > 0x01F3 || supervision_timeout < 0x000A || supervision_timeout > 0x0C80) { LOG_ERROR("Invalid parameter"); return false; } // The Maximum interval in milliseconds will be conn_interval_max * 1.25 ms // The Timeout in milliseconds will be expected_supervision_timeout * 10 ms // The Timeout in milliseconds shall be larger than (1 + Latency) * Interval_Max * 2, where Interval_Max is given in // milliseconds. uint32_t supervision_timeout_min = (uint32_t)(1 + conn_latency) * conn_interval_max * 2 + 1; if (supervision_timeout * 8 < supervision_timeout_min || conn_interval_max < conn_interval_min) { LOG_ERROR("Invalid parameter"); return false; } return true; } void add_device_to_background_connection_list(AddressWithType address_with_type) { background_connections_.insert(address_with_type); } void remove_device_from_background_connection_list(AddressWithType address_with_type) { background_connections_.erase(address_with_type); } void is_on_background_connection_list(AddressWithType address_with_type, std::promise promise) { promise.set_value(background_connections_.find(address_with_type) != background_connections_.end()); } void cancel_connection_and_remove_device_from_background_connection_list(AddressWithType address_with_type) { remove_device_from_background_connection_list(address_with_type); cancel_connect(address_with_type); } void OnPause() override { // bluetooth::hci::LeAddressManagerCallback if (!address_manager_registered) { LOG_WARN("Unregistered!"); return; } pause_connection = true; if (connectability_state_ == ConnectabilityState::DISARMED) { le_address_manager_->AckPause(this); return; } arm_on_resume_ = !connecting_le_.empty(); disarm_connectability(); } void OnResume() override { // bluetooth::hci::LeAddressManagerCallback if (!address_manager_registered) { LOG_WARN("Unregistered!"); return; } pause_connection = false; if (arm_on_resume_) { arm_connectability(); } arm_on_resume_ = false; le_address_manager_->AckResume(this); check_for_unregister(); } void on_create_connection_cancel_complete(CommandCompleteView view) { auto complete_view = LeCreateConnectionCancelCompleteView::Create(view); ASSERT(complete_view.IsValid()); if (complete_view.GetStatus() != ErrorCode::SUCCESS) { auto status = complete_view.GetStatus(); std::string error_code = ErrorCodeText(status); LOG_WARN("Received on_create_connection_cancel_complete with error code %s", error_code.c_str()); if (pause_connection) { LOG_WARN("AckPause"); le_address_manager_->AckPause(this); return; } } if (connectability_state_ != ConnectabilityState::DISARMING) { LOG_ERROR( "Attempting to disarm le connection state machine in unexpected state:%s", connectability_state_machine_text(connectability_state_).c_str()); } } void register_with_address_manager() { if (!address_manager_registered) { le_address_manager_->Register(this); address_manager_registered = true; pause_connection = true; } } void check_for_unregister() { if (connections.is_empty() && connecting_le_.empty() && address_manager_registered && ready_to_unregister) { le_address_manager_->Unregister(this); address_manager_registered = false; pause_connection = false; ready_to_unregister = false; } } HciLayer* hci_layer_ = nullptr; Controller* controller_ = nullptr; os::Handler* handler_ = nullptr; RoundRobinScheduler* round_robin_scheduler_ = nullptr; LeAddressManager* le_address_manager_ = nullptr; LeAclConnectionInterface* le_acl_connection_interface_ = nullptr; LeConnectionCallbacks* le_client_callbacks_ = nullptr; os::Handler* le_client_handler_ = nullptr; std::unordered_set connecting_le_; bool arm_on_resume_; std::unordered_set direct_connections_; // Set of devices that will not be removed from connect list after direct connect timeout std::unordered_set background_connections_; std::unordered_set connect_list; AddressWithType connection_peer_address_with_type_; // Direct peer address UNSUPPORTEDD bool address_manager_registered = false; bool ready_to_unregister = false; bool pause_connection = false; bool disarmed_while_arming_ = false; ConnectabilityState connectability_state_{ConnectabilityState::DISARMED}; std::map create_connection_timeout_alarms_; }; #undef PRIVATE_ADDRESS_WITH_TYPE } // namespace acl_manager } // namespace hci } // namespace bluetooth