diff options
author | 2024-11-04 20:10:53 +0900 | |
---|---|---|
committer | 2024-12-21 11:01:06 +0900 | |
commit | 9afa02435692ca52952fe7158fcc162e05cff0fc (patch) | |
tree | 26b05edda86e059ba91fbec23eb4b0eb1ba290d3 | |
parent | 28ef7557cd927ed8e3d1133a5809c8d9ced0a66c (diff) |
Use aggressive initial connection params
This CL makes the stack use aggressive initial connection
parameters when there are less than 2 ongoing ACL connections.
Bug: 308483803
Bug: 378595485
Flag: com.android.bluetooth.flags.initial_conn_params_p1
Test: atest LeImplTest
Test: atest GattClientTest
Test: Manual, checked aggressive params are used for first connection,
and relaxed params are used from the third connection.
Test: Manual, checked that paramters are relaxed after service
discovery. Also for the case when the service discovery is
skipped.
Test: Manual, made GATT connection while music is playing via A2DP/ASHA.
The music was continously playing while service discovery.
Test: Manual, had a Wifi traffic and phone call with HFP/ASHA.
The phone call has no noticable sound errors.
Change-Id: Idd8cac01f67e4dd797487fad87781fddb5ce73d3
-rw-r--r-- | framework/tests/bumble/src/android/bluetooth/GattClientTest.java | 31 | ||||
-rw-r--r-- | system/common/Android.bp | 1 | ||||
-rw-r--r-- | system/common/BUILD.gn | 1 | ||||
-rw-r--r-- | system/common/le_conn_params.cc | 142 | ||||
-rw-r--r-- | system/common/le_conn_params.h | 51 | ||||
-rw-r--r-- | system/gd/hci/acl_manager.cc | 2 | ||||
-rw-r--r-- | system/gd/hci/acl_manager/classic_impl.h | 6 | ||||
-rw-r--r-- | system/gd/hci/acl_manager/le_impl.h | 79 | ||||
-rw-r--r-- | system/gd/hci/acl_manager/le_impl_test.cc | 138 | ||||
-rw-r--r-- | system/stack/Android.bp | 1 | ||||
-rw-r--r-- | system/stack/fuzzers/l2cap_fuzzer.cc | 3 | ||||
-rw-r--r-- | system/stack/l2cap/l2c_ble.cc | 20 | ||||
-rw-r--r-- | system/stack/l2cap/l2c_ble_conn_params.cc | 72 | ||||
-rw-r--r-- | system/stack/l2cap/l2c_int.h | 2 |
14 files changed, 536 insertions, 13 deletions
diff --git a/framework/tests/bumble/src/android/bluetooth/GattClientTest.java b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java index 38671a28e9..b4b2762ed7 100644 --- a/framework/tests/bumble/src/android/bluetooth/GattClientTest.java +++ b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java @@ -33,6 +33,7 @@ import static org.mockito.Mockito.verify; import android.bluetooth.test_utils.EnableBluetoothRule; import android.content.Context; +import android.os.SystemProperties; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; @@ -93,6 +94,11 @@ public class GattClientTest { private static final UUID TEST_CHARACTERISTIC_UUID = UUID.fromString("00010001-0000-0000-0000-000000000000"); + private static final int MIN_CONN_INTERVAL_RELAXED = + SystemProperties.getInt("bluetooth.core.le.min_connection_interval_relaxed", 0x0018); + private static final int MAX_CONN_INTERVAL_RELAXED = + SystemProperties.getInt("bluetooth.core.le.max_connection_interval_relaxed", 0x0028); + @Rule(order = 0) public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @@ -172,6 +178,31 @@ public class GattClientTest { disconnectAndWaitDisconnection(gatt, gattCallback); } + @RequiresFlagsEnabled(Flags.FLAG_INITIAL_CONN_PARAMS_P1) + @Test + public void onConnectionUpdatedIsCalledOnlyOnceForRelaxingConnectionParameters_noGattCache() { + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + ArgumentCaptor<Integer> connectionIntervalCaptor = ArgumentCaptor.forClass(Integer.class); + + BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback, false); + + // Wait until service discovery is done and parameters are relaxed. + verify(gattCallback, timeout(10_000).times(1)) + .onConnectionUpdated( + any(), connectionIntervalCaptor.capture(), anyInt(), anyInt(), anyInt()); + + List<Integer> capturedConnectionIntervals = connectionIntervalCaptor.getAllValues(); + assertThat(capturedConnectionIntervals).hasSize(1); + + // Since aggressive parameters are used in the initial connection, + // there should be only one connection parameters update event for relaxing them. + int relaxedConnIntervalAfterServiceDiscovery = capturedConnectionIntervals.get(0); + assertThat(relaxedConnIntervalAfterServiceDiscovery).isAtLeast(MIN_CONN_INTERVAL_RELAXED); + assertThat(relaxedConnIntervalAfterServiceDiscovery).isAtMost(MAX_CONN_INTERVAL_RELAXED); + + disconnectAndWaitDisconnection(gatt, gattCallback); + } + @Test public void reconnectExistingClient() throws Exception { advertiseWithBumble(); diff --git a/system/common/Android.bp b/system/common/Android.bp index 4bc0bebf2d..f3f2a619ca 100644 --- a/system/common/Android.bp +++ b/system/common/Android.bp @@ -20,6 +20,7 @@ cc_library_static { ], srcs: [ "address_obfuscator.cc", + "le_conn_params.cc", "message_loop_thread.cc", "metric_id_allocator.cc", "os_utils.cc", diff --git a/system/common/BUILD.gn b/system/common/BUILD.gn index 8352d2bcc4..a1884973dd 100644 --- a/system/common/BUILD.gn +++ b/system/common/BUILD.gn @@ -17,6 +17,7 @@ static_library("common") { sources = [ "address_obfuscator.cc", + "le_conn_params.cc", "message_loop_thread.cc", "metric_id_allocator.cc", "metrics_linux.cc", diff --git a/system/common/le_conn_params.cc b/system/common/le_conn_params.cc new file mode 100644 index 0000000000..0cfc3675a0 --- /dev/null +++ b/system/common/le_conn_params.cc @@ -0,0 +1,142 @@ +/* + * Copyright 2024 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. + */ + +#define LOG_TAG "le_conn_params" + +#include "common/le_conn_params.h" + +#include <bluetooth/log.h> + +#include <cstdint> + +#include "os/system_properties.h" +#include "stack/include/btm_ble_api_types.h" + +using namespace bluetooth; + +const std::string LeConnectionParameters::kPropertyAggressiveConnThreshold = + "bluetooth.core.le.aggressive_connection_threshold"; +const std::string LeConnectionParameters::kPropertyMinConnIntervalAggressive = + "bluetooth.core.le.min_connection_interval_aggressive"; +const std::string LeConnectionParameters::kPropertyMaxConnIntervalAggressive = + "bluetooth.core.le.max_connection_interval_aggressive"; +const std::string LeConnectionParameters::kPropertyMinConnIntervalRelaxed = + "bluetooth.core.le.min_connection_interval_relaxed"; +const std::string LeConnectionParameters::kPropertyMaxConnIntervalRelaxed = + "bluetooth.core.le.max_connection_interval_relaxed"; + +bool LeConnectionParameters::initialized = false; +uint32_t LeConnectionParameters::aggressive_conn_threshold = kAggressiveConnThreshold; +uint32_t LeConnectionParameters::min_conn_interval_aggressive = kMinConnIntervalAggressive; +uint32_t LeConnectionParameters::max_conn_interval_aggressive = kMaxConnIntervalAggressive; +uint32_t LeConnectionParameters::min_conn_interval_relaxed = kMinConnIntervalRelaxed; +uint32_t LeConnectionParameters::max_conn_interval_relaxed = kMaxConnIntervalRelaxed; + +void LeConnectionParameters::InitConnParamsWithSystemProperties() { + aggressive_conn_threshold = + os::GetSystemPropertyUint32(kPropertyAggressiveConnThreshold, kAggressiveConnThreshold); + min_conn_interval_aggressive = os::GetSystemPropertyUint32(kPropertyMinConnIntervalAggressive, + kMinConnIntervalAggressive); + max_conn_interval_aggressive = os::GetSystemPropertyUint32(kPropertyMaxConnIntervalAggressive, + kMaxConnIntervalAggressive); + min_conn_interval_relaxed = + os::GetSystemPropertyUint32(kPropertyMinConnIntervalRelaxed, kMinConnIntervalRelaxed); + max_conn_interval_relaxed = + os::GetSystemPropertyUint32(kPropertyMaxConnIntervalRelaxed, kMaxConnIntervalRelaxed); + + log::debug("Before checking validity: threshold={}, aggressive={}/{}, relaxed={}/{}", + aggressive_conn_threshold, min_conn_interval_aggressive, max_conn_interval_aggressive, + min_conn_interval_relaxed, max_conn_interval_relaxed); + + // Check validity of each values + if (aggressive_conn_threshold < 0) { + log::warn("Invalid aggressive connection threshold. Using default value.", + aggressive_conn_threshold); + aggressive_conn_threshold = kAggressiveConnThreshold; + } + + if (min_conn_interval_aggressive < BTM_BLE_CONN_INT_MIN || + min_conn_interval_aggressive > BTM_BLE_CONN_INT_MAX || + max_conn_interval_aggressive < BTM_BLE_CONN_INT_MIN || + max_conn_interval_aggressive > BTM_BLE_CONN_INT_MAX || + max_conn_interval_aggressive < min_conn_interval_aggressive) { + log::warn("Invalid aggressive connection intervals. Using default values."); + min_conn_interval_aggressive = kMinConnIntervalAggressive; + max_conn_interval_aggressive = kMaxConnIntervalAggressive; + } + + if (min_conn_interval_relaxed < BTM_BLE_CONN_INT_MIN || + min_conn_interval_relaxed > BTM_BLE_CONN_INT_MAX || + max_conn_interval_relaxed < BTM_BLE_CONN_INT_MIN || + max_conn_interval_relaxed > BTM_BLE_CONN_INT_MAX || + max_conn_interval_relaxed < min_conn_interval_relaxed) { + log::warn("Invalid relaxed connection intervals. Using default values."); + min_conn_interval_relaxed = kMinConnIntervalRelaxed; + max_conn_interval_relaxed = kMaxConnIntervalRelaxed; + } + + if ((min_conn_interval_aggressive > min_conn_interval_relaxed) && + (max_conn_interval_aggressive > max_conn_interval_relaxed)) { + log::warn( + "Relaxed connection intervals are more aggressive than aggressive ones." + " Setting all intervals to default values."); + min_conn_interval_aggressive = kMinConnIntervalAggressive; + max_conn_interval_aggressive = kMaxConnIntervalAggressive; + min_conn_interval_relaxed = kMinConnIntervalRelaxed; + max_conn_interval_relaxed = kMaxConnIntervalRelaxed; + } + + log::debug("After checking validity: threshold={}, aggressive={}/{}, relaxed={}/{}", + aggressive_conn_threshold, min_conn_interval_aggressive, max_conn_interval_aggressive, + min_conn_interval_relaxed, max_conn_interval_relaxed); + + initialized = true; +} + +uint32_t LeConnectionParameters::GetAggressiveConnThreshold() { + if (!initialized) { + InitConnParamsWithSystemProperties(); + } + return aggressive_conn_threshold; +} + +uint32_t LeConnectionParameters::GetMinConnIntervalAggressive() { + if (!initialized) { + InitConnParamsWithSystemProperties(); + } + return min_conn_interval_aggressive; +} + +uint32_t LeConnectionParameters::GetMaxConnIntervalAggressive() { + if (!initialized) { + InitConnParamsWithSystemProperties(); + } + return max_conn_interval_aggressive; +} + +uint32_t LeConnectionParameters::GetMinConnIntervalRelaxed() { + if (!initialized) { + InitConnParamsWithSystemProperties(); + } + return min_conn_interval_relaxed; +} + +uint32_t LeConnectionParameters::GetMaxConnIntervalRelaxed() { + if (!initialized) { + InitConnParamsWithSystemProperties(); + } + return max_conn_interval_relaxed; +} diff --git a/system/common/le_conn_params.h b/system/common/le_conn_params.h new file mode 100644 index 0000000000..2365742ac2 --- /dev/null +++ b/system/common/le_conn_params.h @@ -0,0 +1,51 @@ +/* + * Copyright 2024 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 <bluetooth/log.h> + +#include <cstdint> + +class LeConnectionParameters { +public: + static constexpr uint16_t kAggressiveConnThreshold = 2; + static constexpr uint16_t kMinConnIntervalAggressive = 0x0008; // 8, *1.25 becomes 10ms + static constexpr uint16_t kMaxConnIntervalAggressive = 0x0010; // 16, *1.25 becomes 20ms + static constexpr uint16_t kMinConnIntervalRelaxed = 0x0018; // 24, *1.25 becomes 30ms + static constexpr uint16_t kMaxConnIntervalRelaxed = 0x0028; // 40, *1.25 becomes 50ms + + static const std::string kPropertyAggressiveConnThreshold; + static const std::string kPropertyMinConnIntervalAggressive; + static const std::string kPropertyMaxConnIntervalAggressive; + static const std::string kPropertyMinConnIntervalRelaxed; + static const std::string kPropertyMaxConnIntervalRelaxed; + + static void InitConnParamsWithSystemProperties(); + static uint32_t GetAggressiveConnThreshold(); + static uint32_t GetMinConnIntervalAggressive(); + static uint32_t GetMaxConnIntervalAggressive(); + static uint32_t GetMinConnIntervalRelaxed(); + static uint32_t GetMaxConnIntervalRelaxed(); + +private: + static bool initialized; + static uint32_t aggressive_conn_threshold; + static uint32_t min_conn_interval_aggressive; + static uint32_t max_conn_interval_aggressive; + static uint32_t min_conn_interval_relaxed; + static uint32_t max_conn_interval_relaxed; +}; diff --git a/system/gd/hci/acl_manager.cc b/system/gd/hci/acl_manager.cc index a8edc9ea39..869865e2c2 100644 --- a/system/gd/hci/acl_manager.cc +++ b/system/gd/hci/acl_manager.cc @@ -84,7 +84,7 @@ struct AclManager::impl { crash_on_unknown_handle, acl_scheduler_, remote_name_request_module_); le_impl_ = new le_impl(hci_layer_, controller_, handler_, round_robin_scheduler_, - crash_on_unknown_handle); + crash_on_unknown_handle, classic_impl_); } hci_queue_end_ = hci_layer_->GetAclQueueEnd(); diff --git a/system/gd/hci/acl_manager/classic_impl.h b/system/gd/hci/acl_manager/classic_impl.h index 08cdcbd231..ecef1f9414 100644 --- a/system/gd/hci/acl_manager/classic_impl.h +++ b/system/gd/hci/acl_manager/classic_impl.h @@ -159,6 +159,10 @@ private: public: bool crash_on_unknown_handle_ = false; + size_t size() const { + std::unique_lock<std::mutex> lock(acl_connections_guard_); + return acl_connections_.size(); + } bool is_empty() const { std::unique_lock<std::mutex> lock(acl_connections_guard_); return acl_connections_.empty(); @@ -278,6 +282,8 @@ public: return connections.is_classic_link_already_connected(address); } + size_t get_connection_count() { return connections.size(); } + void create_connection(Address address) { // TODO: Configure default connection parameters? uint16_t packet_type = 0x4408 /* DM 1,3,5 */ | 0x8810 /*DH 1,3,5 */; diff --git a/system/gd/hci/acl_manager/le_impl.h b/system/gd/hci/acl_manager/le_impl.h index 00af9b70ac..f1929adb73 100644 --- a/system/gd/hci/acl_manager/le_impl.h +++ b/system/gd/hci/acl_manager/le_impl.h @@ -27,7 +27,9 @@ #include <vector> #include "common/bind.h" +#include "common/le_conn_params.h" #include "hci/acl_manager/assembler.h" +#include "hci/acl_manager/classic_impl.h" #include "hci/acl_manager/le_acceptlist_callbacks.h" #include "hci/acl_manager/le_acl_connection.h" #include "hci/acl_manager/le_connection_callbacks.h" @@ -41,6 +43,7 @@ #include "os/alarm.h" #include "os/handler.h" #include "os/system_properties.h" +#include "stack/include/btm_ble_api_types.h" #include "stack/include/stack_metrics_logging.h" namespace bluetooth { @@ -102,6 +105,8 @@ enum class ConnectabilityState { DISARMING = 3, }; +enum class ConnectionMode { RELAXED = 0, AGGRESSIVE = 1 }; + inline std::string connectability_state_machine_text(const ConnectabilityState& state) { switch (state) { CASE_RETURN_TEXT(ConnectabilityState::DISARMED); @@ -127,7 +132,8 @@ struct le_acl_connection { 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) + RoundRobinScheduler* round_robin_scheduler, bool crash_on_unknown_handle, + classic_impl* classic_impl) : hci_layer_(hci_layer), controller_(controller), round_robin_scheduler_(round_robin_scheduler) { @@ -135,6 +141,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { controller_ = controller; handler_ = handler; connections.crash_on_unknown_handle_ = crash_on_unknown_handle; + classic_impl_ = classic_impl; le_acl_connection_interface_ = hci_layer_->GetLeAclConnectionInterface( handler_->BindOn(this, &le_impl::on_le_event), handler_->BindOn(this, &le_impl::on_le_disconnect), @@ -204,6 +211,10 @@ private: public: bool crash_on_unknown_handle_ = false; + size_t size() const { + std::unique_lock<std::mutex> lock(le_acl_connections_guard_); + return le_acl_connections_.size(); + } bool is_empty() const { std::unique_lock<std::mutex> lock(le_acl_connections_guard_); return le_acl_connections_.empty(); @@ -301,6 +312,17 @@ private: } } connections; + std::string connection_mode_to_string(ConnectionMode connection_mode) { + switch (connection_mode) { + case ConnectionMode::RELAXED: + return "RELAXED"; + case ConnectionMode::AGGRESSIVE: + return "AGGRESSIVE"; + default: + return "UNKNOWN"; + } + } + public: void enqueue_command(std::unique_ptr<CommandBuilder> command_packet) { hci_layer_->EnqueueCommand(std::move(command_packet), @@ -490,6 +512,8 @@ public: connection->in_filter_accept_list_ = in_filter_accept_list; connection->locally_initiated_ = (role == hci::Role::CENTRAL); + log::info("addr={}, conn_interval={}", remote_address, conn_interval); + if (packet.GetSubeventCode() == SubeventCode::ENHANCED_CONNECTION_COMPLETE) { LeEnhancedConnectionCompleteView connection_complete = LeEnhancedConnectionCompleteView::Create(packet); @@ -845,10 +869,24 @@ public: InitiatorFilterPolicy initiator_filter_policy = InitiatorFilterPolicy::USE_FILTER_ACCEPT_LIST; OwnAddressType own_address_type = static_cast<OwnAddressType>( le_address_manager_->GetInitiatorAddress().GetAddressType()); - uint16_t conn_interval_min = - os::GetSystemPropertyUint32(kPropertyMinConnInterval, kConnIntervalMin); - uint16_t conn_interval_max = - os::GetSystemPropertyUint32(kPropertyMaxConnInterval, kConnIntervalMax); + + uint16_t conn_interval_min; + uint16_t conn_interval_max; + + if (com::android::bluetooth::flags::initial_conn_params_p1()) { + size_t num_classic_acl_connections = classic_impl_->get_connection_count(); + size_t num_acl_connections = connections.size(); + + log::debug("ACL connection count: Classic={}, LE={}", num_classic_acl_connections, + num_acl_connections); + + choose_connection_mode(num_classic_acl_connections + num_acl_connections, &conn_interval_min, + &conn_interval_max); + } else { + conn_interval_min = os::GetSystemPropertyUint32(kPropertyMinConnInterval, kConnIntervalMin); + conn_interval_max = os::GetSystemPropertyUint32(kPropertyMaxConnInterval, kConnIntervalMax); + } + uint16_t conn_latency = os::GetSystemPropertyUint32(kPropertyConnLatency, kConnLatency); uint16_t supervision_timeout = os::GetSystemPropertyUint32(kPropertyConnSupervisionTimeout, kSupervisionTimeout); @@ -930,6 +968,36 @@ public: } } + // Choose which connection mode should be used based on the number of ongoing ACL connections. + // According to the connection mode, connection interval min/max values are set. + void choose_connection_mode(size_t num_acl_connections, uint16_t* conn_interval_min, + uint16_t* conn_interval_max) { + ConnectionMode connection_mode = ConnectionMode::RELAXED; + + uint32_t aggressive_connection_threshold = LeConnectionParameters::GetAggressiveConnThreshold(); + log::debug("num_acl_connections={}, aggressive_connection_threshold={}", num_acl_connections, + aggressive_connection_threshold); + + if (num_acl_connections < aggressive_connection_threshold) { + connection_mode = ConnectionMode::AGGRESSIVE; + } + + switch (connection_mode) { + case ConnectionMode::AGGRESSIVE: + *conn_interval_min = LeConnectionParameters::GetMinConnIntervalAggressive(); + *conn_interval_max = LeConnectionParameters::GetMaxConnIntervalAggressive(); + break; + case ConnectionMode::RELAXED: + default: + *conn_interval_min = LeConnectionParameters::GetMinConnIntervalRelaxed(); + *conn_interval_max = LeConnectionParameters::GetMaxConnIntervalRelaxed(); + break; + } + log::info("Connection mode: {}", connection_mode_to_string(connection_mode)); + log::debug("conn_interval_min={}, conn_interval_max={}", *conn_interval_min, + *conn_interval_max); + } + void disarm_connectability() { switch (connectability_state_) { case ConnectabilityState::ARMED: @@ -1237,6 +1305,7 @@ public: RoundRobinScheduler* round_robin_scheduler_ = nullptr; LeAddressManager* le_address_manager_ = nullptr; LeAclConnectionInterface* le_acl_connection_interface_ = nullptr; + classic_impl* classic_impl_ = nullptr; LeConnectionCallbacks* le_client_callbacks_ = nullptr; os::Handler* le_client_handler_ = nullptr; LeAcceptlistCallbacks* le_acceptlist_callbacks_ = nullptr; diff --git a/system/gd/hci/acl_manager/le_impl_test.cc b/system/gd/hci/acl_manager/le_impl_test.cc index 5a5f15676c..d43d2faca1 100644 --- a/system/gd/hci/acl_manager/le_impl_test.cc +++ b/system/gd/hci/acl_manager/le_impl_test.cc @@ -26,6 +26,7 @@ #include <future> #include "common/bidi_queue.h" +#include "common/le_conn_params.h" #include "hci/acl_manager/le_connection_callbacks.h" #include "hci/acl_manager/le_connection_management_callbacks_mock.h" #include "hci/address_with_type.h" @@ -36,6 +37,7 @@ #include "os/handler.h" #include "packet/bit_inserter.h" #include "packet/raw_builder.h" +#include "stack/l2cap/l2c_api.h" using namespace bluetooth; using namespace std::chrono_literals; @@ -248,8 +250,11 @@ protected: round_robin_scheduler_ = new RoundRobinScheduler(handler_, controller_, hci_queue_.GetUpEnd()); hci_queue_.GetDownEnd()->RegisterDequeue( handler_, common::Bind(&LeImplTest::HciDownEndDequeue, common::Unretained(this))); + + classic_impl_ = new classic_impl(hci_layer_, controller_, handler_, round_robin_scheduler_, + false, nullptr, nullptr); le_impl_ = new le_impl(hci_layer_, controller_, handler_, round_robin_scheduler_, - kCrashOnUnknownHandle); + kCrashOnUnknownHandle, classic_impl_); le_impl_->handle_register_le_callbacks(&mock_le_connection_callbacks_, handler_); Address address; @@ -437,6 +442,69 @@ protected: ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_); } + // Need to store the LeAclConnection so it is not immediately dropped => disconnected + std::unique_ptr<LeAclConnection> create_enhanced_connection(std::string remote_address_string, + int handle) { + std::unique_ptr<LeAclConnection> connection; + + hci::Address remote_address; + Address::FromString(remote_address_string, remote_address); + hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS); + le_impl_->create_le_connection(address_with_type, true, false); + sync_handler(); + + hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST); + hci_layer_->IncomingEvent( + LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + hci_layer_->GetCommand(OpCode::LE_EXTENDED_CREATE_CONNECTION); + hci_layer_->IncomingEvent( + LeExtendedCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); + sync_handler(); + + // Check state is ARMED + EXPECT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_); + + // we need to capture the LeAclConnection so it is not immediately dropped => disconnected + EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, _)) + .WillOnce([&](AddressWithType, std::unique_ptr<LeAclConnection> conn) { + connection = std::move(conn); + connection->RegisterCallbacks(&connection_management_callbacks_, handler_); + }); + + hci_layer_->IncomingLeMetaEvent(LeEnhancedConnectionCompleteBuilder::Create( + ErrorCode::SUCCESS, handle, Role::CENTRAL, AddressType::PUBLIC_DEVICE_ADDRESS, + remote_address, Address::kEmpty, Address::kEmpty, 0x0024, 0x0000, 0x0011, + ClockAccuracy::PPM_30)); + sync_handler(); + + hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST); + hci_layer_->IncomingEvent( + LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + hci_layer_->AssertNoQueuedCommand(); + sync_handler(); + EXPECT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_); + + return connection; + } + + LeExtendedCreateConnectionView get_view_from_creating_connection( + std::string remote_address_string) { + hci::Address remote_address; + Address::FromString(remote_address_string, remote_address); + hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS); + + // Create connection + le_impl_->create_le_connection(address_with_type, true, false); + + hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST); + hci_layer_->IncomingEvent( + LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + sync_handler(); + + return CreateLeConnectionManagementCommandView<LeExtendedCreateConnectionView>( + hci_layer_->GetCommand(OpCode::LE_EXTENDED_CREATE_CONNECTION)); + } + void TearDown() override { com::android::bluetooth::flags::provider_->reset_flags(); @@ -450,6 +518,7 @@ protected: sync_handler(); delete le_impl_; + delete classic_impl_; hci_queue_.GetDownEnd()->UnregisterDequeue(); @@ -511,6 +580,7 @@ protected: Thread* thread_; Handler* handler_; HciLayerFake* hci_layer_{nullptr}; + classic_impl* classic_impl_; TestController* controller_; RoundRobinScheduler* round_robin_scheduler_{nullptr}; @@ -746,6 +816,72 @@ TEST_F(LeImplTest, enhanced_connection_complete_with_central_role) { ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_); } +TEST_F(LeImplTest, aggressive_connection_mode_selected_when_no_ongoing_le_connections_exist) { + if (LeConnectionParameters::GetAggressiveConnThreshold() == 0) { + GTEST_SKIP() << "Skipping test because the threshold is zero"; + } + + com::android::bluetooth::flags::provider_->initial_conn_params_p1(true); + set_random_device_address_policy(); + controller_->AddSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION); + + LeExtendedCreateConnectionView view = get_view_from_creating_connection("FF:EE:DD:CC:BB:AA"); + + ASSERT_TRUE(view.IsValid()); + ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_min_, + LeConnectionParameters::GetMinConnIntervalAggressive()); + ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_max_, + LeConnectionParameters::GetMaxConnIntervalAggressive()); +} + +TEST_F(LeImplTest, aggressive_connection_mode_selected_when_few_le_connections_exist) { + if (LeConnectionParameters::GetAggressiveConnThreshold() == 0) { + GTEST_SKIP() << "Skipping test because the threshold is zero"; + } + + com::android::bluetooth::flags::provider_->initial_conn_params_p1(true); + set_random_device_address_policy(); + controller_->AddSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION); + + std::vector<std::unique_ptr<LeAclConnection>> connections; + for (uint32_t i = 0; i < LeConnectionParameters::GetAggressiveConnThreshold() - 1; i++) { + std::stringstream addr_string_stream; + addr_string_stream << "A0:05:04:03:02:" << std::hex << std::setw(2) << std::setfill('0') << i; + + connections.push_back(create_enhanced_connection(addr_string_stream.str(), i /* handle */)); + } + + LeExtendedCreateConnectionView view = get_view_from_creating_connection("FF:EE:DD:CC:BB:AA"); + + ASSERT_TRUE(view.IsValid()); + ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_min_, + LeConnectionParameters::GetMinConnIntervalAggressive()); + ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_max_, + LeConnectionParameters::GetMaxConnIntervalAggressive()); +} + +TEST_F(LeImplTest, relaxed_connection_mode_selected_when_enough_le_connections_exist) { + com::android::bluetooth::flags::provider_->initial_conn_params_p1(true); + set_random_device_address_policy(); + controller_->AddSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION); + + std::vector<std::unique_ptr<LeAclConnection>> connections; + for (uint32_t i = 0; i < LeConnectionParameters::GetAggressiveConnThreshold(); i++) { + std::stringstream addr_string_stream; + addr_string_stream << "A0:05:04:03:02:" << std::hex << std::setw(2) << std::setfill('0') << i; + + connections.push_back(create_enhanced_connection(addr_string_stream.str(), i /* handle */)); + } + + LeExtendedCreateConnectionView view = get_view_from_creating_connection("FF:EE:DD:CC:BB:AA"); + + ASSERT_TRUE(view.IsValid()); + ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_min_, + LeConnectionParameters::GetMinConnIntervalRelaxed()); + ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_max_, + LeConnectionParameters::GetMaxConnIntervalRelaxed()); +} + // b/260917913 TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyNotSet) { std::promise<void> promise; diff --git a/system/stack/Android.bp b/system/stack/Android.bp index fd805893b7..749a9a7509 100644 --- a/system/stack/Android.bp +++ b/system/stack/Android.bp @@ -718,6 +718,7 @@ cc_fuzz { "libbluetooth_l2cap_pdl", "libbluetooth_log", "libbluetooth_smp_pdl", + "libbt-common", "libbt-platform-protos-lite", ], shared_libs: [ diff --git a/system/stack/fuzzers/l2cap_fuzzer.cc b/system/stack/fuzzers/l2cap_fuzzer.cc index 1963983aef..aa637025cc 100644 --- a/system/stack/fuzzers/l2cap_fuzzer.cc +++ b/system/stack/fuzzers/l2cap_fuzzer.cc @@ -78,6 +78,9 @@ uint32_t GetSystemPropertyUint32Base(const std::string& /*property*/, uint32_t d int /*base*/) { return default_value; } +uint32_t GetSystemPropertyUint32(const std::string& /*property*/, uint32_t default_value) { + return default_value; +} } // namespace os namespace hal { diff --git a/system/stack/l2cap/l2c_ble.cc b/system/stack/l2cap/l2c_ble.cc index 2fdb63f12b..a5b8c08edc 100644 --- a/system/stack/l2cap/l2c_ble.cc +++ b/system/stack/l2cap/l2c_ble.cc @@ -34,6 +34,7 @@ #include "btif/include/core_callbacks.h" #include "btif/include/stack_manager_t.h" +#include "common/le_conn_params.h" #include "hci/controller_interface.h" #include "hci/hci_interface.h" #include "internal_include/bt_target.h" @@ -177,6 +178,22 @@ bool l2cble_conn_comp(uint16_t handle, tHCI_ROLE role, const RawAddress& bda, p_lcb->timeout = conn_timeout; p_lcb->latency = conn_latency; p_lcb->conn_update_mask = L2C_BLE_NOT_DEFAULT_PARAM; + if (com::android::bluetooth::flags::initial_conn_params_p1()) { + uint16_t min_conn_interval_aggressive = LeConnectionParameters::GetMinConnIntervalAggressive(); + uint16_t max_conn_interval_aggressive = LeConnectionParameters::GetMaxConnIntervalAggressive(); + + stack::l2cap::get_interface().L2CA_AdjustConnectionIntervals( + &min_conn_interval_aggressive, &max_conn_interval_aggressive, BTM_BLE_CONN_INT_MIN); + + bool is_aggressive_initial_param = conn_interval <= max_conn_interval_aggressive; + log::info("conn_interval={}, max_conn_interval_aggressive={}, is_aggressive_initial_param={}", + conn_interval, max_conn_interval_aggressive, is_aggressive_initial_param); + + if (is_aggressive_initial_param) { + p_lcb->conn_update_mask |= L2C_BLE_AGGRESSIVE_INITIAL_PARAM; + } + } + p_lcb->conn_update_blocked_by_profile_connection = false; p_lcb->conn_update_blocked_by_service_discovery = false; @@ -328,6 +345,9 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { p_lcb->latency = latency; p_lcb->timeout = timeout; p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM; + if (com::android::bluetooth::flags::initial_conn_params_p1()) { + p_lcb->conn_update_mask &= ~L2C_BLE_AGGRESSIVE_INITIAL_PARAM; + } l2cble_start_conn_update(p_lcb); } diff --git a/system/stack/l2cap/l2c_ble_conn_params.cc b/system/stack/l2cap/l2c_ble_conn_params.cc index 1e9d4ba7ab..f6b5e6f749 100644 --- a/system/stack/l2cap/l2c_ble_conn_params.cc +++ b/system/stack/l2cap/l2c_ble_conn_params.cc @@ -26,7 +26,9 @@ #define LOG_TAG "l2c_ble_conn_params" #include <bluetooth/log.h> +#include <com_android_bluetooth_flags.h> +#include "common/le_conn_params.h" #include "hci/controller_interface.h" #include "hci/event_checkers.h" #include "hci/hci_interface.h" @@ -34,6 +36,7 @@ #include "internal_include/stack_config.h" #include "main/shim/acl_api.h" #include "main/shim/entry.h" +#include "osi/include/properties.h" #include "stack/btm/btm_dev.h" #include "stack/include/acl_api.h" #include "stack/include/btm_ble_api_types.h" @@ -85,6 +88,10 @@ bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int, uint1 p_lcb->latency = latency; p_lcb->timeout = timeout; p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM; + if (com::android::bluetooth::flags::initial_conn_params_p1()) { + p_lcb->conn_update_mask &= ~L2C_BLE_AGGRESSIVE_INITIAL_PARAM; + } + p_lcb->min_ce_len = min_ce_len; p_lcb->max_ce_len = max_ce_len; @@ -117,7 +124,15 @@ void L2CA_LockBleConnParamsForServiceDiscovery(const RawAddress& rem_bda, bool l if (lock == p_lcb->conn_update_blocked_by_service_discovery) { log::warn("{} service discovery already locked/unlocked conn params: {}", rem_bda, lock); - return; + + if (!lock && com::android::bluetooth::flags::initial_conn_params_p1() && + (p_lcb->conn_update_mask & L2C_BLE_AGGRESSIVE_INITIAL_PARAM)) { + p_lcb->conn_update_mask &= ~L2C_BLE_NOT_DEFAULT_PARAM; + p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM; + log::info("Service discovery is skipped. Relaxing connection parameters."); + } else { + return; + } } p_lcb->conn_update_blocked_by_service_discovery = lock; @@ -217,11 +232,41 @@ void l2cble_start_conn_update(tL2C_LCB* p_lcb) { /* application requests to disable parameters update. If parameters are already updated, lets set them up to what has been requested during connection establishement */ - if (p_lcb->conn_update_mask & L2C_BLE_NOT_DEFAULT_PARAM && - /* current connection interval is greater than default min */ - p_lcb->min_interval > BTM_BLE_CONN_INT_MIN) { - /* use 7.5 ms as fast connection parameter, 0 peripheral latency */ - min_conn_int = max_conn_int = BTM_BLE_CONN_INT_MIN; + if (p_lcb->conn_update_mask & L2C_BLE_NOT_DEFAULT_PARAM) { + if (com::android::bluetooth::flags::initial_conn_params_p1()) { + min_conn_int = LeConnectionParameters::GetMinConnIntervalAggressive(); + max_conn_int = LeConnectionParameters::GetMaxConnIntervalAggressive(); + log::info("min_conn_int={}, max_conn_int={}", min_conn_int, max_conn_int); + + if (p_lcb->conn_update_mask & L2C_BLE_AGGRESSIVE_INITIAL_PARAM) { + // Usually, we can use the same aggressive connection parameters for service discovery. + // However when hearing aid is being used, the connection intervals may need to be + // adjusted. + uint16_t adjusted_min_conn_int = min_conn_int; + uint16_t adjusted_max_conn_int = max_conn_int; + + stack::l2cap::get_interface().L2CA_AdjustConnectionIntervals( + &adjusted_min_conn_int, &adjusted_max_conn_int, BTM_BLE_CONN_INT_MIN); + + log::info("adjusted_min_conn_int={}, adjusted_max_conn_int={}", adjusted_min_conn_int, + adjusted_max_conn_int); + + if ((adjusted_min_conn_int == min_conn_int) && (adjusted_max_conn_int == max_conn_int)) { + log::info("No need to update connection parameters."); + p_lcb->conn_update_mask &= ~L2C_BLE_NOT_DEFAULT_PARAM; + p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM; + return; + } + } + } else { + if (p_lcb->min_interval <= BTM_BLE_CONN_INT_MIN) { + // Skip updating connection parameters for service discovery if we are already + // using default minimum interval. + return; + } + /* use 7.5 ms as fast connection parameter, 0 peripheral latency */ + min_conn_int = max_conn_int = BTM_BLE_CONN_INT_MIN; + } stack::l2cap::get_interface().L2CA_AdjustConnectionIntervals(&min_conn_int, &max_conn_int, BTM_BLE_CONN_INT_MIN); @@ -250,6 +295,15 @@ void l2cble_start_conn_update(tL2C_LCB* p_lcb) { if (p_lcb->IsLinkRoleCentral() || (bluetooth::shim::GetController()->SupportsBleConnectionParametersRequest() && acl_peer_supports_ble_connection_parameters_request(p_lcb->remote_bd_addr))) { + if (com::android::bluetooth::flags::initial_conn_params_p1() && + (p_lcb->conn_update_mask & L2C_BLE_AGGRESSIVE_INITIAL_PARAM)) { + log::info("Relaxing aggressive initial connection parameters. addr={}", + p_lcb->remote_bd_addr); + p_lcb->min_interval = LeConnectionParameters::GetMinConnIntervalRelaxed(); + p_lcb->max_interval = LeConnectionParameters::GetMaxConnIntervalRelaxed(); + p_lcb->conn_update_mask &= ~L2C_BLE_AGGRESSIVE_INITIAL_PARAM; + } + acl_ble_connection_parameters_request(p_lcb->Handle(), p_lcb->min_interval, p_lcb->max_interval, p_lcb->latency, p_lcb->timeout, p_lcb->min_ce_len, p_lcb->max_ce_len); @@ -321,6 +375,9 @@ void l2cble_process_rc_param_request_evt(uint16_t handle, uint16_t int_min, uint p_lcb->max_interval = int_max; p_lcb->latency = latency; p_lcb->timeout = timeout; + if (com::android::bluetooth::flags::initial_conn_params_p1()) { + p_lcb->conn_update_mask &= ~L2C_BLE_AGGRESSIVE_INITIAL_PARAM; + } /* if update is enabled, always accept connection parameter update */ if ((p_lcb->conn_update_mask & L2C_BLE_CONN_UPDATE_DISABLE) == 0) { @@ -370,6 +427,9 @@ void l2cble_use_preferred_conn_params(const RawAddress& bda) { p_lcb->max_interval = p_dev_rec->conn_params.max_conn_int; p_lcb->timeout = p_dev_rec->conn_params.supervision_tout; p_lcb->latency = p_dev_rec->conn_params.peripheral_latency; + if (com::android::bluetooth::flags::initial_conn_params_p1()) { + p_lcb->conn_update_mask &= ~L2C_BLE_AGGRESSIVE_INITIAL_PARAM; + } acl_ble_connection_parameters_request(p_lcb->Handle(), p_dev_rec->conn_params.min_conn_int, p_dev_rec->conn_params.max_conn_int, diff --git a/system/stack/l2cap/l2c_int.h b/system/stack/l2cap/l2c_int.h index 0077cab5bf..c7ca28bae6 100644 --- a/system/stack/l2cap/l2c_int.h +++ b/system/stack/l2cap/l2c_int.h @@ -395,6 +395,8 @@ enum tCONN_UPDATE_MASK : uint8_t { L2C_BLE_UPDATE_PENDING = (1u << 2), /* not using default connection parameters */ L2C_BLE_NOT_DEFAULT_PARAM = (1u << 3), + /* Aggressive initial connection parameters are used */ + L2C_BLE_AGGRESSIVE_INITIAL_PARAM = (1u << 4), }; /* Define a link control block. There is one link control block between |