summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hyundo Moon <hdmoon@google.com> 2024-11-04 20:10:53 +0900
committer Hyundo Moon <hdmoon@google.com> 2024-12-21 11:01:06 +0900
commit9afa02435692ca52952fe7158fcc162e05cff0fc (patch)
tree26b05edda86e059ba91fbec23eb4b0eb1ba290d3
parent28ef7557cd927ed8e3d1133a5809c8d9ced0a66c (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.java31
-rw-r--r--system/common/Android.bp1
-rw-r--r--system/common/BUILD.gn1
-rw-r--r--system/common/le_conn_params.cc142
-rw-r--r--system/common/le_conn_params.h51
-rw-r--r--system/gd/hci/acl_manager.cc2
-rw-r--r--system/gd/hci/acl_manager/classic_impl.h6
-rw-r--r--system/gd/hci/acl_manager/le_impl.h79
-rw-r--r--system/gd/hci/acl_manager/le_impl_test.cc138
-rw-r--r--system/stack/Android.bp1
-rw-r--r--system/stack/fuzzers/l2cap_fuzzer.cc3
-rw-r--r--system/stack/l2cap/l2c_ble.cc20
-rw-r--r--system/stack/l2cap/l2c_ble_conn_params.cc72
-rw-r--r--system/stack/l2cap/l2c_int.h2
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