Merge "Pass the written value for gatt characteristic and descriptor write callbacks to the java layer"
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index 585c552..2ef03fd 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -852,7 +852,6 @@
/* if de-registering shut everything down */
msg.hdr.layer_specific = p_scb->hndl;
p_scb->started = false;
- p_scb->offload_started = false;
p_scb->use_rtp_header_marker_bit = false;
p_scb->cong = false;
p_scb->role = role;
@@ -875,8 +874,6 @@
}
*/
- p_scb->offload_start_pending = false;
-
if (p_scb->deregistering) {
/* remove stream */
for (int i = 0; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
@@ -1171,7 +1168,6 @@
bta_av_conn_chg((tBTA_AV_DATA*)&msg);
/* set the congestion flag, so AV would not send media packets by accident */
p_scb->cong = true;
- p_scb->offload_start_pending = false;
// Don't use AVDTP SUSPEND for restrict listed devices
btif_storage_get_stored_remote_name(p_scb->PeerAddress(), remote_name);
if (interop_match_name(INTEROP_DISABLE_AVDTP_SUSPEND, remote_name) ||
@@ -1895,9 +1891,15 @@
BTM_unblock_role_switch_and_sniff_mode_for(p_scb->PeerAddress());
if (p_scb->co_started) {
- if (p_scb->offload_started) {
+ uint16_t handle = get_btm_client_interface().lifecycle.BTM_GetHCIConnHandle(
+ p_scb->PeerAddress(), BT_TRANSPORT_BR_EDR);
+ if (bta_av_cb.offload_started_acl_hdl == handle) {
bta_av_vendor_offload_stop();
- p_scb->offload_started = false;
+ bta_av_cb.offload_started_acl_hdl = HCI_INVALID_HANDLE;
+ } else if (bta_av_cb.offload_start_pending_acl_hdl == handle) {
+ APPL_TRACE_WARNING("%s: Stop pending offload start command", __func__);
+ bta_av_vendor_offload_stop();
+ bta_av_cb.offload_start_pending_acl_hdl = HCI_INVALID_HANDLE;
}
bta_av_stream_chg(p_scb, false);
@@ -2519,9 +2521,15 @@
/* in case that we received suspend_ind, we may need to call co_stop here */
if (p_scb->co_started) {
- if (p_scb->offload_started) {
+ uint16_t handle = get_btm_client_interface().lifecycle.BTM_GetHCIConnHandle(
+ p_scb->PeerAddress(), BT_TRANSPORT_BR_EDR);
+ if (bta_av_cb.offload_started_acl_hdl == handle) {
bta_av_vendor_offload_stop();
- p_scb->offload_started = false;
+ bta_av_cb.offload_started_acl_hdl = HCI_INVALID_HANDLE;
+ } else if (bta_av_cb.offload_start_pending_acl_hdl == handle) {
+ APPL_TRACE_WARNING("%s: Stop pending offload start command", __func__);
+ bta_av_vendor_offload_stop();
+ bta_av_cb.offload_start_pending_acl_hdl = HCI_INVALID_HANDLE;
}
bta_av_stream_chg(p_scb, false);
@@ -3012,6 +3020,13 @@
APPL_TRACE_DEBUG("%s: VS_HCI_STOP_A2DP_MEDIA successful", __func__);
break;
case VS_HCI_A2DP_OFFLOAD_START:
+ if (bta_av_cb.offload_start_pending_acl_hdl != HCI_INVALID_HANDLE) {
+ bta_av_cb.offload_started_acl_hdl =
+ bta_av_cb.offload_start_pending_acl_hdl;
+ bta_av_cb.offload_start_pending_acl_hdl = HCI_INVALID_HANDLE;
+ } else {
+ LOG_INFO("%s: No pending start command due to AVDTP suspend immediately", __func__);
+ }
(*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &value);
break;
default:
@@ -3020,8 +3035,10 @@
} else {
APPL_TRACE_DEBUG("%s: Offload failed for subopcode= %d", __func__,
sub_opcode);
- if (param->opcode != VS_HCI_A2DP_OFFLOAD_STOP)
+ if (param->opcode != VS_HCI_A2DP_OFFLOAD_STOP) {
+ bta_av_cb.offload_start_pending_acl_hdl = HCI_INVALID_HANDLE;
(*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &value);
+ }
}
}
@@ -3046,7 +3063,7 @@
UINT16_TO_STREAM(p_param, offload_start->mtu);
ARRAY_TO_STREAM(p_param, offload_start->codec_info,
(int8_t)sizeof(offload_start->codec_info));
- p_scb->offload_started = true;
+ bta_av_cb.offload_start_pending_acl_hdl = offload_start->acl_hdl;
LOG_INFO(
"codec: %#x, sample rate: %#x, bit depth: %#x, channel: %#x, bitrate: "
"%#x, ACL: %#x, L2CAP: %#x, MTU: %#x",
@@ -3086,6 +3103,10 @@
/* Support offload if only one audio source stream is open. */
if (p_scb->started != true) {
status = BTA_AV_FAIL_STREAM;
+ } else if (bta_av_cb.offload_start_pending_acl_hdl != HCI_INVALID_HANDLE ||
+ bta_av_cb.offload_started_acl_hdl != HCI_INVALID_HANDLE) {
+ APPL_TRACE_WARNING("%s: offload already started, ignore request", __func__);
+ return;
} else {
bta_av_offload_codec_builder(p_scb, &offload_start);
bta_av_vendor_offload_start(p_scb, &offload_start);
@@ -3155,7 +3176,7 @@
status = BTA_AV_FAIL_STREAM;
}
- p_scb->offload_start_pending = false;
+ bta_av_cb.offload_start_pending_acl_hdl = HCI_INVALID_HANDLE;
tBTA_AV bta_av_data;
bta_av_data.status = status;
(*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
diff --git a/bta/av/bta_av_int.h b/bta/av/bta_av_int.h
index e97a24b..9a65ec5 100644
--- a/bta/av/bta_av_int.h
+++ b/bta/av/bta_av_int.h
@@ -539,8 +539,6 @@
uint8_t q_tag; /* identify the associated q_info union member */
bool no_rtp_header; /* true if add no RTP header */
uint16_t uuid_int; /*intended UUID of Initiator to connect to */
- bool offload_start_pending;
- bool offload_started;
/**
* Called to setup the state when connected to a peer.
@@ -639,6 +637,8 @@
uint8_t rc_acp_idx; /* (index + 1) to RCB */
uint8_t rs_idx; /* (index + 1) to SCB for the one waiting for RS on open */
bool sco_occupied; /* true if SCO is being used or call is in progress */
+ uint16_t offload_start_pending_acl_hdl;
+ uint16_t offload_started_acl_hdl;
} tBTA_AV_CB;
// total attempts are half seconds
diff --git a/bta/av/bta_av_main.cc b/bta/av/bta_av_main.cc
index 83f802c..257770c 100644
--- a/bta/av/bta_av_main.cc
+++ b/bta/av/bta_av_main.cc
@@ -40,6 +40,7 @@
#include "osi/include/properties.h"
#include "stack/include/acl_api.h"
#include "stack/include/bt_hdr.h"
+#include "stack/include/btm_api.h"
#include "types/hci_role.h"
#include "types/raw_address.h"
@@ -165,6 +166,8 @@
/* store parameters */
bta_av_cb.p_cback = p_data->api_enable.p_cback;
bta_av_cb.features = p_data->api_enable.features;
+ bta_av_cb.offload_start_pending_acl_hdl = HCI_INVALID_HANDLE;
+ bta_av_cb.offload_started_acl_hdl = HCI_INVALID_HANDLE;
tBTA_AV_ENABLE enable;
enable.features = bta_av_cb.features;
@@ -337,6 +340,16 @@
evt = BTA_AV_SIG_CHG_EVT;
if (event == AVDT_DISCONNECT_IND_EVT) {
p_scb = bta_av_addr_to_scb(bd_addr);
+ if (p_scb) {
+ uint16_t handle =
+ BTM_GetHCIConnHandle(p_scb->PeerAddress(), BT_TRANSPORT_BR_EDR);
+ if (bta_av_cb.offload_started_acl_hdl == handle ||
+ bta_av_cb.offload_start_pending_acl_hdl == handle) {
+ LOG_INFO("%s: Cleanup offload related flag", __func__);
+ bta_av_cb.offload_started_acl_hdl = HCI_INVALID_HANDLE;
+ bta_av_cb.offload_start_pending_acl_hdl = HCI_INVALID_HANDLE;
+ }
+ }
} else if (event == AVDT_CONNECT_IND_EVT) {
APPL_TRACE_DEBUG("%s: CONN_IND is ACP:%d", __func__,
p_data->hdr.err_param);
@@ -1406,6 +1419,10 @@
dprintf(fd, " Connected audio channels mask: 0x%x\n", bta_av_cb.conn_audio);
dprintf(fd, " Registered audio channels mask: 0x%x\n", bta_av_cb.reg_audio);
dprintf(fd, " Connected LCBs mask: 0x%x\n", bta_av_cb.conn_lcb);
+ dprintf(fd, " Offload start pending handle: %d\n",
+ bta_av_cb.offload_start_pending_acl_hdl);
+ dprintf(fd, " Offload started handle: %d\n",
+ bta_av_cb.offload_started_acl_hdl);
for (size_t i = 0; i < sizeof(bta_av_cb.lcb) / sizeof(bta_av_cb.lcb[0]);
i++) {
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index 38f1f0e..42fcdc7 100644
--- a/bta/dm/bta_dm_act.cc
+++ b/bta/dm/bta_dm_act.cc
@@ -2909,8 +2909,8 @@
num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / Uuid::kNumBytes16;
#else // BTA_EIR_CANNED_UUID_LIST
max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes16;
- data_type = BTM_GetEirSupportedServices(bta_dm_cb.eir_uuid, &p,
- max_num_uuid, &num_uuid);
+ data_type = get_btm_client_interface().eir.BTM_GetEirSupportedServices(
+ bta_dm_cb.eir_uuid, &p, max_num_uuid, &num_uuid);
p = (uint8_t*)p_buf + BTM_HCI_EIR_OFFSET; /* reset p */
#endif // BTA_EIR_CANNED_UUID_LIST
@@ -2967,8 +2967,8 @@
num_uuid = 0;
max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes16;
- data_type = BTM_GetEirSupportedServices(bta_dm_cb.eir_uuid, &p,
- max_num_uuid, &num_uuid);
+ data_type = get_btm_client_interface().eir.BTM_GetEirSupportedServices(
+ bta_dm_cb.eir_uuid, &p, max_num_uuid, &num_uuid);
if (data_type == HCI_EIR_MORE_16BITS_UUID_TYPE) {
APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated");
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index 7335609..8ac2635 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -65,7 +65,11 @@
#define BTA_BIP_SERVICE_ID 13 /* Basic Imaging profile */
#define BTA_A2DP_SINK_SERVICE_ID 18 /* A2DP Sink */
#define BTA_HID_SERVICE_ID 20 /* HID */
+#define BTA_PBAP_SERVICE_ID 22 /* PhoneBook Access Server*/
#define BTA_HFP_HS_SERVICE_ID 24 /* HSP HS role */
+#define BTA_MAP_SERVICE_ID 25 /* Message Access Profile */
+#define BTA_MN_SERVICE_ID 26 /* Message Notification Service */
+#define BTA_PCE_SERVICE_ID 28 /* PhoneBook Access Client */
#define BTA_SDP_SERVICE_ID 29 /* SDP Search */
#define BTA_HIDD_SERVICE_ID 30 /* HID Device */
diff --git a/bta/le_audio/client.cc b/bta/le_audio/client.cc
index dd15408..8dc6e3f 100644
--- a/bta/le_audio/client.cc
+++ b/bta/le_audio/client.cc
@@ -414,6 +414,12 @@
group_id);
}
+ void remove_group_if_possible(LeAudioDeviceGroup* group) {
+ if (group && group->IsEmpty() && !group->cig_created_) {
+ aseGroups_.Remove(group->group_id_);
+ }
+ }
+
void group_remove_node(LeAudioDeviceGroup* group, const RawAddress& address,
bool update_group_module = false) {
int group_id = group->group_id_;
@@ -431,8 +437,7 @@
/* Remove group if this was the last leAudioDevice in this group */
if (group->IsEmpty()) {
- aseGroups_.Remove(group_id);
-
+ remove_group_if_possible(group);
return;
}
@@ -657,6 +662,12 @@
return;
}
+ if (leAudioDevice->conn_id_ != GATT_INVALID_CONN_ID) {
+ Disconnect(address);
+ leAudioDevice->removing_device_ = true;
+ return;
+ }
+
/* Remove the group assignment if not yet removed. It might happen that the
* group module has already called the appropriate callback and we have
* already removed the group assignment.
@@ -666,12 +677,6 @@
group_remove_node(group, address, true);
}
- if (leAudioDevice->conn_id_ != GATT_INVALID_CONN_ID) {
- Disconnect(address);
- leAudioDevice->removing_device_ = true;
- return;
- }
-
leAudioDevices_.Remove(address);
}
@@ -1181,7 +1186,13 @@
leAudioDevice->conn_id_ = GATT_INVALID_CONN_ID;
leAudioDevice->encrypted_ = false;
- if (leAudioDevice->removing_device_) leAudioDevices_.Remove(address);
+ if (leAudioDevice->removing_device_) {
+ if (leAudioDevice->group_id_ != bluetooth::groups::kGroupUnknown) {
+ auto group = aseGroups_.FindById(leAudioDevice->group_id_);
+ group_remove_node(group, address, true);
+ }
+ leAudioDevices_.Remove(address);
+ }
}
bool subscribe_for_indications(uint16_t conn_id, const RawAddress& address,
@@ -2525,6 +2536,7 @@
auto* evt = static_cast<cig_remove_cmpl_evt*>(data);
LeAudioDeviceGroup* group = aseGroups_.FindById(evt->cig_id);
groupStateMachine_->ProcessHciNotifOnCigRemove(evt->status, group);
+ remove_group_if_possible(group);
} break;
default:
LOG(ERROR) << __func__ << " Invalid event " << int{event_type};
diff --git a/bta/le_audio/hal_verifier.cc b/bta/le_audio/hal_verifier.cc
index 6fd2c66..9210714 100644
--- a/bta/le_audio/hal_verifier.cc
+++ b/bta/le_audio/hal_verifier.cc
@@ -18,6 +18,6 @@
#include "bta_le_audio_api.h"
bool LeAudioHalVerifier::SupportsLeAudio() {
- return bluetooth::audio::HalVersionManager::GetHalVersion() ==
+ return bluetooth::audio::HalVersionManager::GetHalVersion() >=
bluetooth::audio::BluetoothAudioHalVersion::VERSION_2_1;
}
diff --git a/bta/le_audio/le_audio_client_test.cc b/bta/le_audio/le_audio_client_test.cc
index 3af1ed1..13fe4c8 100644
--- a/bta/le_audio/le_audio_client_test.cc
+++ b/bta/le_audio/le_audio_client_test.cc
@@ -531,6 +531,10 @@
state_machine_callbacks_->StatusReportCb(
group->group_id_, GroupStreamStatus::STREAMING);
streaming_groups[group->group_id_] = group;
+
+ /* Assume CIG is created */
+ group->cig_created_ = true;
+
return true;
});
@@ -557,8 +561,8 @@
});
ON_CALL(mock_state_machine_, ProcessHciNotifAclDisconnected(_, _))
- .WillByDefault([](LeAudioDeviceGroup* group,
- LeAudioDevice* leAudioDevice) {
+ .WillByDefault([this](LeAudioDeviceGroup* group,
+ LeAudioDevice* leAudioDevice) {
if (!group) return;
auto* stream_conf = &group->stream_conf;
if (stream_conf->valid) {
@@ -587,6 +591,11 @@
stream_conf->valid = false;
}
}
+
+ if (group->IsEmpty()) {
+ group->cig_created_ = false;
+ InjectCigRemoved(group->group_id_);
+ }
});
ON_CALL(mock_state_machine_, ProcessHciNotifCisDisconnected(_, _, _))
@@ -1551,6 +1560,16 @@
bluetooth::hci::iso_manager::kIsoEventCisDisconnected, &cis_evt);
}
+ void InjectCigRemoved(uint8_t cig_id) {
+ bluetooth::hci::iso_manager::cig_remove_cmpl_evt evt;
+ evt.status = 0;
+ evt.cig_id = cig_id;
+
+ ASSERT_NE(cig_callbacks_, nullptr);
+ cig_callbacks_->OnCisEvent(
+ bluetooth::hci::iso_manager::kIsoEventCigOnRemoveCmpl, &evt);
+ }
+
MockLeAudioClientCallbacks mock_client_callbacks_;
MockLeAudioClientAudioSource mock_audio_source_;
MockLeAudioClientAudioSink mock_audio_sink_;
@@ -2230,6 +2249,69 @@
Mock::VerifyAndClearExpectations(&mock_btif_storage_);
}
+TEST_F(UnicastTest, RemoveWhileStreaming) {
+ const RawAddress test_address0 = GetTestAddress(0);
+ int group_id = bluetooth::groups::kGroupUnknown;
+
+ SetSampleDatabaseEarbudsValid(
+ 1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
+ codec_spec_conf::kLeAudioLocationStereo, false /*add_csis*/,
+ true /*add_cas*/, true /*add_pacs*/, true /*add_ascs*/, 1 /*set_size*/,
+ 0 /*rank*/);
+ EXPECT_CALL(mock_client_callbacks_,
+ OnConnectionState(ConnectionState::CONNECTED, test_address0))
+ .Times(1);
+ EXPECT_CALL(mock_client_callbacks_,
+ OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED))
+ .WillOnce(DoAll(SaveArg<1>(&group_id)));
+
+ ConnectLeAudio(test_address0);
+ ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown);
+
+ // Start streaming
+ uint8_t cis_count_out = 1;
+ uint8_t cis_count_in = 0;
+
+ EXPECT_CALL(mock_audio_source_, Start(_, _)).Times(1);
+ LeAudioClient::Get()->GroupSetActive(group_id);
+
+ EXPECT_CALL(mock_state_machine_, StartStream(_, _)).Times(1);
+
+ StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id);
+
+ SyncOnMainLoop();
+ Mock::VerifyAndClearExpectations(&mock_client_callbacks_);
+ Mock::VerifyAndClearExpectations(&mock_audio_source_);
+ Mock::VerifyAndClearExpectations(&mock_state_machine_);
+ SyncOnMainLoop();
+
+ // Verify Data transfer on one audio source cis
+ TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920);
+
+ EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address0, group_id))
+ .Times(1);
+
+ LeAudioDeviceGroup* group = nullptr;
+ EXPECT_CALL(mock_state_machine_, ProcessHciNotifAclDisconnected(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&group)));
+ EXPECT_CALL(
+ mock_client_callbacks_,
+ OnGroupNodeStatus(test_address0, group_id, GroupNodeStatus::REMOVED));
+
+ EXPECT_CALL(mock_client_callbacks_,
+ OnConnectionState(ConnectionState::DISCONNECTED, test_address0))
+ .Times(1);
+
+ LeAudioClient::Get()->RemoveDevice(test_address0);
+
+ SyncOnMainLoop();
+ Mock::VerifyAndClearExpectations(&mock_groups_module_);
+ Mock::VerifyAndClearExpectations(&mock_state_machine_);
+ Mock::VerifyAndClearExpectations(&mock_client_callbacks_);
+
+ ASSERT_NE(group, nullptr);
+}
+
TEST_F(UnicastTest, SpeakerStreaming) {
const RawAddress test_address0 = GetTestAddress(0);
int group_id = bluetooth::groups::kGroupUnknown;
diff --git a/btcore/Android.bp b/btcore/Android.bp
index f96877f..ea71c79 100644
--- a/btcore/Android.bp
+++ b/btcore/Android.bp
@@ -8,8 +8,8 @@
default_applicable_licenses: ["system_bt_license"],
}
-cc_library_static {
- name: "libbtcore",
+cc_defaults {
+ name: "libbtcore_defaults",
defaults: ["fluoride_defaults"],
local_include_dirs: ["include"],
include_dirs: [
@@ -35,6 +35,17 @@
},
}
+cc_library_static {
+ name: "libbtcore",
+ defaults: ["libbtcore_defaults"],
+}
+
+cc_library_static {
+ name: "libbtcore-static",
+ defaults: ["libbtcore_defaults"],
+ cflags: ["-DSTATIC_LIBBLUETOOTH"],
+}
+
cc_library_headers {
name: "libbtcore_headers",
defaults: ["libchrome_support_defaults"],
diff --git a/btif/Android.bp b/btif/Android.bp
index 238f964..bbdcebd 100644
--- a/btif/Android.bp
+++ b/btif/Android.bp
@@ -88,8 +88,8 @@
}
// libbtif static library for target
-cc_library_static {
- name: "libbtif",
+cc_defaults {
+ name: "libbtif_defaults",
defaults: ["fluoride_defaults"],
include_dirs: btifCommonIncludes,
srcs: [
@@ -195,6 +195,17 @@
host_supported: true,
}
+cc_library_static {
+ name: "libbtif",
+ defaults: ["libbtif_defaults"],
+}
+
+cc_library_static {
+ name: "libbtif-static",
+ defaults: ["libbtif_defaults"],
+ cflags: ["-DSTATIC_LIBBLUETOOTH"],
+}
+
// btif unit tests for target
cc_test {
name: "net_test_btif",
diff --git a/btif/BUILD.gn b/btif/BUILD.gn
index 0100bb0..26be562 100644
--- a/btif/BUILD.gn
+++ b/btif/BUILD.gn
@@ -102,6 +102,7 @@
"//bt/device/include",
"//bt/embdrv/sbc/encoder/include",
"//bt/embdrv/sbc/decoder/include",
+ "//bt/gd",
"//bt/hci/include",
"//bt/stack/a2dp",
"//bt/stack/btm",
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index 4f0097f..3fd506c 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -307,6 +307,22 @@
case BTA_HIDD_SERVICE_ID: {
btif_hd_execute_service(b_enable);
} break;
+ case BTA_PBAP_SERVICE_ID:
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
+ case BTA_PCE_SERVICE_ID:
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
+ case BTA_MAP_SERVICE_ID:
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
+ case BTA_MN_SERVICE_ID: {
+ /**
+ * Do nothing; these services were started elsewhere. However, we need to flow through this
+ * codepath in order to properly report back the local UUIDs back to adapter properties in
+ * Java. To achieve this, we need to catch these service IDs in order for {@link
+ * btif_in_execute_service_request} to return {@code BT_STATUS_SUCCESS}, so that in {@link
+ * btif_dm_enable_service} the check passes and the UUIDs are allowed to be passed up into
+ * the Java layer.
+ */
+ } break;
default:
BTIF_TRACE_ERROR("%s: Unknown service %d being %s", __func__, service_id,
(b_enable) ? "enabled" : "disabled");
diff --git a/btif/src/btif_sdp_server.cc b/btif/src/btif_sdp_server.cc
index cab4520..ba166b6 100644
--- a/btif/src/btif_sdp_server.cc
+++ b/btif/src/btif_sdp_server.cc
@@ -288,6 +288,38 @@
bt_status_t remove_sdp_record(int record_id) {
int handle;
+ bluetooth_sdp_record* record;
+ bluetooth_sdp_types sdp_type = SDP_TYPE_RAW;
+ {
+ std::unique_lock<std::recursive_mutex> lock(sdp_lock);
+ record = sdp_slots[record_id].record_data;
+ if (record != NULL) {
+ sdp_type = record->hdr.type;
+ }
+ }
+ tBTA_SERVICE_ID service_id = -1;
+ switch (sdp_type) {
+ case SDP_TYPE_MAP_MAS:
+ service_id = BTA_MAP_SERVICE_ID;
+ break;
+ case SDP_TYPE_MAP_MNS:
+ service_id = BTA_MN_SERVICE_ID;
+ break;
+ case SDP_TYPE_PBAP_PSE:
+ service_id = BTA_PBAP_SERVICE_ID;
+ break;
+ case SDP_TYPE_PBAP_PCE:
+ service_id = BTA_PCE_SERVICE_ID;
+ break;
+ default:
+ /* other enumeration values were not enabled in {@link on_create_record_event} */
+ break;
+ }
+ if (service_id > 0) {
+ // {@link btif_disable_service} sets the mask {@link btif_enabled_services}.
+ btif_disable_service(service_id);
+ }
+
/* Get the Record handle, and free the slot */
handle = free_sdp_slot(record_id);
BTIF_TRACE_DEBUG("Sdp Server %s id=%d to handle=0x%08x", __func__, record_id,
@@ -317,6 +349,7 @@
* */
BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
const sdp_slot_t* sdp_slot = start_create_sdp(id);
+ tBTA_SERVICE_ID service_id = -1;
/* In the case we are shutting down, sdp_slot is NULL */
if (sdp_slot != NULL) {
bluetooth_sdp_record* record = sdp_slot->record_data;
@@ -324,12 +357,15 @@
switch (record->hdr.type) {
case SDP_TYPE_MAP_MAS:
handle = add_maps_sdp(&record->mas);
+ service_id = BTA_MAP_SERVICE_ID;
break;
case SDP_TYPE_MAP_MNS:
handle = add_mapc_sdp(&record->mns);
+ service_id = BTA_MN_SERVICE_ID;
break;
case SDP_TYPE_PBAP_PSE:
handle = add_pbaps_sdp(&record->pse);
+ service_id = BTA_PBAP_SERVICE_ID;
break;
case SDP_TYPE_OPP_SERVER:
handle = add_opps_sdp(&record->ops);
@@ -339,6 +375,7 @@
break;
case SDP_TYPE_PBAP_PCE:
handle = add_pbapc_sdp(&record->pce);
+ service_id = BTA_PCE_SERVICE_ID;
break;
default:
BTIF_TRACE_DEBUG("Record type %d is not supported", record->hdr.type);
@@ -346,6 +383,18 @@
}
if (handle != -1) {
set_sdp_handle(id, handle);
+ if (service_id > 0) {
+ /**
+ * {@link btif_enable_service} calls {@link btif_dm_enable_service}, which calls {@link
+ * btif_in_execute_service_request}.
+ * - {@link btif_enable_service} sets the mask {@link btif_enabled_services}.
+ * - {@link btif_dm_enable_service} invokes the java callback to return uuids based
+ * on the enabled services mask.
+ * - {@link btif_in_execute_service_request} gates the java callback in {@link
+ * btif_dm_enable_service}.
+ */
+ btif_enable_service(service_id);
+ }
}
}
}
diff --git a/btif/src/btif_storage.cc b/btif/src/btif_storage.cc
index 38640e2..af84a22 100644
--- a/btif/src/btif_storage.cc
+++ b/btif/src/btif_storage.cc
@@ -698,11 +698,27 @@
*(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_AUDIO_SINK);
num_uuids++;
} break;
+ case BTA_PBAP_SERVICE_ID: {
+ *(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_PBAP_PSE);
+ num_uuids++;
+ } break;
case BTA_HFP_HS_SERVICE_ID: {
*(p_uuid + num_uuids) =
Uuid::From16Bit(UUID_SERVCLASS_HF_HANDSFREE);
num_uuids++;
} break;
+ case BTA_MAP_SERVICE_ID: {
+ *(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_MESSAGE_ACCESS);
+ num_uuids++;
+ } break;
+ case BTA_MN_SERVICE_ID: {
+ *(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_MESSAGE_NOTIFICATION);
+ num_uuids++;
+ } break;
+ case BTA_PCE_SERVICE_ID: {
+ *(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_PBAP_PCE);
+ num_uuids++;
+ } break;
}
}
}
diff --git a/gd/btaa/android/activity_attribution.cc b/gd/btaa/android/activity_attribution.cc
index 34d4a36..19c0df1 100644
--- a/gd/btaa/android/activity_attribution.cc
+++ b/gd/btaa/android/activity_attribution.cc
@@ -46,41 +46,62 @@
static const std::string kBtWakeupReason("hs_uart_wakeup");
static const size_t kHciAclHeaderSize = 4;
+static std::mutex g_module_mutex;
+static ActivityAttribution* g_module = nullptr;
+static bool is_wakeup_callback_registered = false;
+static bool is_wakelock_callback_registered = false;
+
struct wakelock_callback : public BnWakelockCallback {
- wakelock_callback(ActivityAttribution* module) : module_(module) {}
+ wakelock_callback() {}
Status notifyAcquired() override {
- module_->OnWakelockAcquired();
+ std::lock_guard<std::mutex> guard(g_module_mutex);
+ if (g_module != nullptr) {
+ g_module->OnWakelockAcquired();
+ }
return Status::ok();
}
Status notifyReleased() override {
- module_->OnWakelockReleased();
+ std::lock_guard<std::mutex> guard(g_module_mutex);
+ if (g_module != nullptr) {
+ g_module->OnWakelockReleased();
+ }
return Status::ok();
}
-
- ActivityAttribution* module_;
};
+static std::shared_ptr<wakelock_callback> g_wakelock_callback = nullptr;
+
struct wakeup_callback : public BnSuspendCallback {
- wakeup_callback(ActivityAttribution* module) : module_(module) {}
+ wakeup_callback() {}
Status notifyWakeup(bool success, const std::vector<std::string>& wakeup_reasons) override {
for (auto& wakeup_reason : wakeup_reasons) {
if (wakeup_reason.find(kBtWakeupReason) != std::string::npos) {
- module_->OnWakeup();
+ std::lock_guard<std::mutex> guard(g_module_mutex);
+ if (g_module != nullptr) {
+ g_module->OnWakeup();
+ }
break;
}
}
return Status::ok();
}
-
- ActivityAttribution* module_;
};
+static std::shared_ptr<wakeup_callback> g_wakeup_callback = nullptr;
+
struct ActivityAttribution::impl {
impl(ActivityAttribution* module) {
- bool is_registered = false;
+ std::lock_guard<std::mutex> guard(g_module_mutex);
+ g_module = module;
+ if (is_wakeup_callback_registered && is_wakelock_callback_registered) {
+ LOG_ERROR("Wakeup and wakelock callbacks are already registered");
+ return;
+ }
+ Status register_callback_status;
+ bool is_register_successful = false;
auto control_service =
ISuspendControlService::fromBinder(SpAIBinder(AServiceManager_getService("suspend_control")));
if (!control_service) {
@@ -88,21 +109,33 @@
return;
}
- Status register_callback_status =
- control_service->registerCallback(SharedRefBase::make<wakeup_callback>(module), &is_registered);
- if (!is_registered || !register_callback_status.isOk()) {
- LOG_ERROR("Fail to register wakeup callback");
- return;
+ if (!is_wakeup_callback_registered) {
+ g_wakeup_callback = SharedRefBase::make<wakeup_callback>();
+ register_callback_status = control_service->registerCallback(g_wakeup_callback, &is_register_successful);
+ if (!is_register_successful || !register_callback_status.isOk()) {
+ LOG_ERROR("Fail to register wakeup callback");
+ return;
+ }
+ is_wakeup_callback_registered = true;
}
- register_callback_status = control_service->registerWakelockCallback(
- SharedRefBase::make<wakelock_callback>(module), kBtWakelockName, &is_registered);
- if (!is_registered || !register_callback_status.isOk()) {
- LOG_ERROR("Fail to register wakelock callback");
- return;
+ if (!is_wakelock_callback_registered) {
+ g_wakelock_callback = SharedRefBase::make<wakelock_callback>();
+ register_callback_status =
+ control_service->registerWakelockCallback(g_wakelock_callback, kBtWakelockName, &is_register_successful);
+ if (!is_register_successful || !register_callback_status.isOk()) {
+ LOG_ERROR("Fail to register wakelock callback");
+ return;
+ }
+ is_wakelock_callback_registered = true;
}
}
+ ~impl() {
+ std::lock_guard<std::mutex> guard(g_module_mutex);
+ g_module = nullptr;
+ }
+
void on_hci_packet(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) {
attribution_processor_.OnBtaaPackets(std::move(hci_processor_.OnHciPacket(std::move(packet), type, length)));
}
diff --git a/gd/rust/linux/mgmt/src/bin/btmanagerd/config_util.rs b/gd/rust/linux/mgmt/src/bin/btmanagerd/config_util.rs
index d29e782..26c997b 100644
--- a/gd/rust/linux/mgmt/src/bin/btmanagerd/config_util.rs
+++ b/gd/rust/linux/mgmt/src/bin/btmanagerd/config_util.rs
@@ -5,7 +5,7 @@
pub const HCI_DEVICES_DIR: &str = "/sys/class/bluetooth";
// File to store the Bluetooth daemon to use (bluez or floss)
-const BLUETOOTH_DAEMON_CURRENT: &str = "/var/lib/misc/bluetooth-daemon.current";
+const BLUETOOTH_DAEMON_CURRENT: &str = "/var/lib/bluetooth/bluetooth-daemon.current";
// File to store the config for BluetoothManager
const BTMANAGERD_CONF: &str = "/var/lib/bluetooth/btmanagerd.json";
diff --git a/gd/rust/shim/Android.bp b/gd/rust/shim/Android.bp
index 6db3bfd..b5b6042 100644
--- a/gd/rust/shim/Android.bp
+++ b/gd/rust/shim/Android.bp
@@ -26,8 +26,8 @@
},
}
-rust_ffi_static {
- name: "libbt_shim_ffi",
+rust_defaults {
+ name: "libbt_shim_defaults",
defaults: ["gd_rust_defaults"],
crate_name: "bt_shim",
srcs: ["src/lib.rs"],
@@ -51,8 +51,18 @@
],
}
+rust_library_rlib {
+ name: "libbt_shim",
+ defaults: ["libbt_shim_defaults"],
+}
+
+rust_ffi_static {
+ name: "libbt_shim_ffi",
+ defaults: ["libbt_shim_defaults"],
+}
+
cc_library_static {
- name: "libbluetooth_rust_interop",
+ name: "libbt_shim_bridge",
defaults: ["gd_ffi_defaults"],
generated_headers: [
"libbt_init_flags_bridge_header",
@@ -87,9 +97,16 @@
shared_libs: [
"libchrome",
],
+}
+
+cc_library_static {
+ name: "libbluetooth_rust_interop",
+ defaults: ["gd_ffi_defaults"],
whole_static_libs: [
+ "libbt_shim_bridge",
"libbt_shim_ffi",
],
+ host_supported: true,
}
cc_library_static {
diff --git a/gd/rust/topshim/Android.bp b/gd/rust/topshim/Android.bp
index 95326a6..1e9677e 100644
--- a/gd/rust/topshim/Android.bp
+++ b/gd/rust/topshim/Android.bp
@@ -51,6 +51,7 @@
"btif/btif_shim.cc",
"gatt/gatt_shim.cc",
"hfp/hfp_shim.cc",
+ "controller/controller_shim.cc",
],
generated_headers: ["libbt_topshim_bridge_header", "cxx-bridge-header"],
generated_sources: ["libbt_topshim_bridge_code"],
@@ -76,6 +77,7 @@
"src/profiles/avrcp.rs",
"src/profiles/hfp.rs",
"src/profiles/gatt.rs",
+ "src/controller.rs",
],
output_extension: "rs.h",
export_include_dirs: ["."],
@@ -91,6 +93,7 @@
"src/profiles/avrcp.rs",
"src/profiles/hfp.rs",
"src/profiles/gatt.rs",
+ "src/controller.rs",
],
output_extension: "cc",
export_include_dirs: ["."],
diff --git a/gd/rust/topshim/BUILD.gn b/gd/rust/topshim/BUILD.gn
index d6e2252..bf986cb 100644
--- a/gd/rust/topshim/BUILD.gn
+++ b/gd/rust/topshim/BUILD.gn
@@ -29,6 +29,7 @@
"src/profiles/avrcp.rs",
"src/profiles/hfp.rs",
"src/profiles/gatt.rs",
+ "src/controller.rs",
]
all_dependent_configs = [ ":rust_topshim_config" ]
deps = [":cxxlibheader"]
@@ -41,8 +42,9 @@
"src/profiles/avrcp.rs",
"src/profiles/hfp.rs",
"src/profiles/gatt.rs",
+ "src/controller.rs",
]
- deps = [":btif_bridge_header"]
+ deps = [":btif_bridge_header", "//bt/gd:BluetoothGeneratedPackets_h"]
configs = [ "//bt/gd:gd_defaults" ]
}
@@ -53,9 +55,10 @@
"btav_sink/btav_sink_shim.cc",
"hfp/hfp_shim.cc",
"gatt/gatt_shim.cc",
+ "controller/controller_shim.cc",
]
- deps = [":btif_bridge_header"]
+ deps = [":btif_bridge_header", "//bt/gd:BluetoothGeneratedPackets_h"]
configs += ["//bt/gd:gd_defaults"]
}
diff --git a/gd/rust/topshim/btav_sink/btav_sink_shim.cc b/gd/rust/topshim/btav_sink/btav_sink_shim.cc
index f0816df..53d943a 100644
--- a/gd/rust/topshim/btav_sink/btav_sink_shim.cc
+++ b/gd/rust/topshim/btav_sink/btav_sink_shim.cc
@@ -19,6 +19,8 @@
#include <memory>
#include "include/hardware/bluetooth.h"
+#include "rust/cxx.h"
+#include "src/profiles/a2dp.rs.h"
#include "types/raw_address.h"
namespace bluetooth {
@@ -37,6 +39,12 @@
audio_state_cb,
audio_config_cb,
};
+
+static RawAddress from_rust_address(const RustRawAddress& raddr) {
+ RawAddress addr;
+ addr.FromOctets(raddr.address.data());
+ return addr;
+}
} // namespace internal
A2dpSinkIntf::~A2dpSinkIntf() {
@@ -54,11 +62,23 @@
return a2dp_sink;
}
-int A2dpSinkIntf::init() {
+int A2dpSinkIntf::init() const {
return intf_->init(&internal::g_a2dp_sink_callbacks, 1);
}
-void A2dpSinkIntf::cleanup() {
+int A2dpSinkIntf::connect(RustRawAddress bt_addr) const {
+ return intf_->connect(internal::from_rust_address(bt_addr));
+}
+
+int A2dpSinkIntf::disconnect(RustRawAddress bt_addr) const {
+ return intf_->disconnect(internal::from_rust_address(bt_addr));
+}
+
+int A2dpSinkIntf::set_active_device(RustRawAddress bt_addr) const {
+ return intf_->set_active_device(internal::from_rust_address(bt_addr));
+}
+
+void A2dpSinkIntf::cleanup() const {
// TODO: Implement.
}
diff --git a/gd/rust/topshim/btav_sink/btav_sink_shim.h b/gd/rust/topshim/btav_sink/btav_sink_shim.h
index 2306ee1..785c150 100644
--- a/gd/rust/topshim/btav_sink/btav_sink_shim.h
+++ b/gd/rust/topshim/btav_sink/btav_sink_shim.h
@@ -18,20 +18,28 @@
#include <memory>
+#include "gd/rust/topshim/btav_sink/btav_sink_shim.h"
#include "include/hardware/bt_av.h"
+#include "rust/cxx.h"
+#include "types/raw_address.h"
namespace bluetooth {
namespace topshim {
namespace rust {
+struct RustRawAddress;
+
class A2dpSinkIntf {
public:
A2dpSinkIntf(const btav_sink_interface_t* intf) : intf_(intf){};
~A2dpSinkIntf();
// interface for Settings
- int init();
- void cleanup();
+ int init() const;
+ int connect(RustRawAddress bt_addr) const;
+ int disconnect(RustRawAddress bt_addr) const;
+ int set_active_device(RustRawAddress bt_addr) const;
+ void cleanup() const;
private:
const btav_sink_interface_t* intf_;
diff --git a/gd/rust/topshim/controller/controller_shim.cc b/gd/rust/topshim/controller/controller_shim.cc
new file mode 100644
index 0000000..cd04f4f
--- /dev/null
+++ b/gd/rust/topshim/controller/controller_shim.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#include "gd/rust/topshim/controller/controller_shim.h"
+
+#include <memory>
+
+#include "rust/cxx.h"
+#include "src/controller.rs.h"
+#include "types/raw_address.h"
+
+namespace bluetooth {
+namespace topshim {
+namespace rust {
+namespace internal {
+static ControllerIntf* g_controller_intf;
+
+static RustRawAddress to_rust_address(const RawAddress& address) {
+ RustRawAddress raddr;
+ std::copy(std::begin(address.address), std::end(address.address), std::begin(raddr.address));
+ return raddr;
+}
+} // namespace internal
+
+ControllerIntf::~ControllerIntf() {}
+
+std::unique_ptr<ControllerIntf> GetControllerInterface() {
+ if (internal::g_controller_intf) std::abort();
+ auto controller_intf = std::make_unique<ControllerIntf>();
+ internal::g_controller_intf = controller_intf.get();
+ return controller_intf;
+}
+
+RustRawAddress ControllerIntf::read_local_addr() const {
+ if (!controller_) std::abort();
+ return internal::to_rust_address(*controller_->get_address());
+}
+
+} // namespace rust
+} // namespace topshim
+} // namespace bluetooth
diff --git a/gd/rust/topshim/controller/controller_shim.h b/gd/rust/topshim/controller/controller_shim.h
new file mode 100644
index 0000000..b817ee9
--- /dev/null
+++ b/gd/rust/topshim/controller/controller_shim.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+#ifndef GD_RUST_TOPSHIM_CONTROLLER_SHIM
+#define GD_RUST_TOPSHIM_CONTROLLER_SHIM
+
+#include <memory>
+
+#include "main/shim/controller.h"
+#include "rust/cxx.h"
+#include "types/raw_address.h"
+
+namespace bluetooth {
+namespace topshim {
+namespace rust {
+
+struct RustRawAddress;
+
+class ControllerIntf {
+ public:
+ ControllerIntf() : controller_(controller_get_interface()) {}
+ ~ControllerIntf();
+
+ RustRawAddress read_local_addr() const;
+
+ private:
+ const controller_t* controller_;
+};
+
+// ControllerIntf* GetControllerInterface();
+std::unique_ptr<ControllerIntf> GetControllerInterface();
+
+} // namespace rust
+} // namespace topshim
+} // namespace bluetooth
+
+#endif // GD_RUST_TOPSHIM_CONTROLLER_SHIM
\ No newline at end of file
diff --git a/gd/rust/topshim/facade/Android.bp b/gd/rust/topshim/facade/Android.bp
index f0e185a..a92671b 100644
--- a/gd/rust/topshim/facade/Android.bp
+++ b/gd/rust/topshim/facade/Android.bp
@@ -12,6 +12,7 @@
defaults: ["gd_rust_defaults"],
crate_name: "bt_topshim_facade",
srcs: ["src/main.rs"],
+ ld_flags: ["-fsanitize=undefined", "-fsanitize-minimal-runtime"],
rustlibs: [
"libbluetooth_rs",
"libbt_common",
@@ -25,17 +26,18 @@
"libbt_facade_helpers",
"libbt_topshim",
"libbt_topshim_facade_protobuf",
+ "libbt_shim",
],
static_libs: [
"libbt_topshim_cxx",
"libbt-bta",
"libbt-common",
"libbtdevice",
- "libbtif",
+ "libbtif-static",
"libbt-hci",
"libbt-stack",
"libbt-utils",
- "libbtcore",
+ "libbtcore-static",
"libosi",
"libbt-protos-lite",
"libbte",
@@ -46,18 +48,19 @@
"liblc3codec",
"libudrv-uipc",
"libbluetooth_gd", // Gabeldorsche
- "libbluetooth_rust_interop",
"libbluetooth-dumpsys",
+ "libbluetooth-types",
"libflatbuffers-cpp",
+ "libbt_shim_bridge",
],
shared_libs: [
"libcrypto",
- "libbluetooth",
"libchrome",
+ "liblog",
+ "libcutils",
+ "libgrpc++",
+ "libgrpc_wrap"
],
- sanitize: {
- never: true,
- },
proc_macros: [
"libpaste",
],
diff --git a/gd/rust/topshim/facade/src/main.rs b/gd/rust/topshim/facade/src/main.rs
index 0736933..44d27aa 100644
--- a/gd/rust/topshim/facade/src/main.rs
+++ b/gd/rust/topshim/facade/src/main.rs
@@ -21,6 +21,18 @@
mod adapter_service;
mod media_service;
+// This is needed for linking, libbt_shim_bridge needs symbols defined by
+// bt_shim, however bt_shim depends on rust crates (future, tokio) that
+// we use too, if we build and link them separately we ends with duplicate
+// symbols. To solve that we build bt_shim with bt_topshim_facade so the rust
+// compiler share the transitive dependencies.
+//
+// The `::*` is here to circuvent the single_component_path_imports from
+// clippy that is denied on the rust command line so we can't just allow it.
+// This is fine for now since bt_shim doesn't export anything
+#[allow(unused)]
+use bt_shim::*;
+
fn main() {
let sigint = install_sigint();
bt_common::init_logging();
diff --git a/gd/rust/topshim/facade/src/media_service.rs b/gd/rust/topshim/facade/src/media_service.rs
index a5f37d5..1998af4 100644
--- a/gd/rust/topshim/facade/src/media_service.rs
+++ b/gd/rust/topshim/facade/src/media_service.rs
@@ -1,7 +1,9 @@
//! Media service facade
use bt_topshim::btif::BluetoothInterface;
-use bt_topshim::profiles::a2dp::{A2dp, A2dpCallbacksDispatcher, A2dpSink};
+use bt_topshim::profiles::a2dp::{
+ A2dp, A2dpCallbacksDispatcher, A2dpSink, A2dpSinkCallbacksDispatcher,
+};
use bt_topshim::profiles::avrcp::{Avrcp, AvrcpCallbacksDispatcher};
use bt_topshim_facade_protobuf::facade::{
A2dpSourceConnectRequest, A2dpSourceConnectResponse, StartA2dpRequest, StartA2dpResponse,
@@ -17,6 +19,10 @@
A2dpCallbacksDispatcher { dispatch: Box::new(move |_cb| {}) }
}
+fn get_a2dp_sink_dispatcher() -> A2dpSinkCallbacksDispatcher {
+ A2dpSinkCallbacksDispatcher { dispatch: Box::new(move |_cb| {}) }
+}
+
fn get_avrcp_dispatcher() -> AvrcpCallbacksDispatcher {
AvrcpCallbacksDispatcher { dispatch: Box::new(move |_cb| {}) }
}
@@ -60,7 +66,7 @@
sink.success(StartA2dpResponse::default()).await.unwrap();
})
} else if req.start_a2dp_sink {
- self.btif_a2dp_sink.lock().unwrap().initialize();
+ self.btif_a2dp_sink.lock().unwrap().initialize(get_a2dp_sink_dispatcher());
ctx.spawn(async move {
sink.success(StartA2dpResponse::default()).await.unwrap();
})
diff --git a/gd/rust/topshim/facade/utils.proto b/gd/rust/topshim/facade/utils.proto
new file mode 100644
index 0000000..9f0fd5c
--- /dev/null
+++ b/gd/rust/topshim/facade/utils.proto
@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+package blueberry;
+
+message Empty {}
+
+message BluetoothAddress {
+ bytes address = 1;
+}
+
+service ReadOnlyProperty {
+ rpc ReadLocalAddress(Empty) returns (BluetoothAddress) {}
+}
\ No newline at end of file
diff --git a/gd/rust/topshim/hfp/hfp_shim.h b/gd/rust/topshim/hfp/hfp_shim.h
index e8a9622..3ce8db0 100644
--- a/gd/rust/topshim/hfp/hfp_shim.h
+++ b/gd/rust/topshim/hfp/hfp_shim.h
@@ -16,6 +16,8 @@
#pragma once
+#include <memory>
+
#include "btif/include/btif_hf.h"
#include "include/hardware/bluetooth_headset_callbacks.h"
#include "types/raw_address.h"
diff --git a/gd/rust/topshim/src/controller.rs b/gd/rust/topshim/src/controller.rs
new file mode 100644
index 0000000..1984928
--- /dev/null
+++ b/gd/rust/topshim/src/controller.rs
@@ -0,0 +1,32 @@
+#[cxx::bridge(namespace = bluetooth::topshim::rust)]
+mod ffi {
+ pub struct RustRawAddress {
+ address: [u8; 6],
+ }
+
+ unsafe extern "C++" {
+ include!("controller/controller_shim.h");
+
+ type ControllerIntf;
+
+ fn GetControllerInterface() -> UniquePtr<ControllerIntf>;
+ fn read_local_addr(self: &ControllerIntf) -> RustRawAddress;
+ }
+}
+
+pub struct Controller {
+ internal: cxx::UniquePtr<ffi::ControllerIntf>,
+}
+
+unsafe impl Send for Controller {}
+
+impl Controller {
+ pub fn new() -> Controller {
+ let intf = ffi::GetControllerInterface();
+ Controller { internal: intf }
+ }
+
+ pub fn read_local_addr(&mut self) -> [u8; 6] {
+ self.internal.read_local_addr().address
+ }
+}
diff --git a/gd/rust/topshim/src/lib.rs b/gd/rust/topshim/src/lib.rs
index a28f2aa..c240ba8 100644
--- a/gd/rust/topshim/src/lib.rs
+++ b/gd/rust/topshim/src/lib.rs
@@ -8,5 +8,6 @@
pub mod bindings;
pub mod btif;
+pub mod controller;
pub mod profiles;
pub mod topstack;
diff --git a/gd/rust/topshim/src/profiles/a2dp.rs b/gd/rust/topshim/src/profiles/a2dp.rs
index ec285c4..380ebdd 100644
--- a/gd/rust/topshim/src/profiles/a2dp.rs
+++ b/gd/rust/topshim/src/profiles/a2dp.rs
@@ -182,8 +182,11 @@
unsafe fn GetA2dpSinkProfile(btif: *const u8) -> UniquePtr<A2dpSinkIntf>;
- fn init(self: Pin<&mut A2dpSinkIntf>) -> i32;
- fn cleanup(self: Pin<&mut A2dpSinkIntf>);
+ fn init(self: &A2dpSinkIntf) -> i32;
+ fn connect(self: &A2dpSinkIntf, bt_addr: RustRawAddress) -> i32;
+ fn disconnect(self: &A2dpSinkIntf, bt_addr: RustRawAddress) -> i32;
+ fn set_active_device(self: &A2dpSinkIntf, bt_addr: RustRawAddress) -> i32;
+ fn cleanup(self: &A2dpSinkIntf);
}
extern "Rust" {
fn connection_state_callback(addr: RustRawAddress, state: u32);
@@ -335,6 +338,17 @@
}
}
+#[derive(Debug)]
+pub enum A2dpSinkCallbacks {
+ ConnectionState(RawAddress, BtavConnectionState),
+}
+
+pub struct A2dpSinkCallbacksDispatcher {
+ pub dispatch: Box<dyn Fn(A2dpSinkCallbacks) + Send>,
+}
+
+type A2dpSinkCb = Arc<Mutex<A2dpSinkCallbacksDispatcher>>;
+
pub struct A2dpSink {
internal: cxx::UniquePtr<ffi::A2dpSinkIntf>,
_is_init: bool,
@@ -353,11 +367,26 @@
A2dpSink { internal: a2dp_sink, _is_init: false }
}
- pub fn initialize(&mut self) -> bool {
- self.internal.pin_mut().init();
+ pub fn initialize(&mut self, callbacks: A2dpSinkCallbacksDispatcher) -> bool {
+ if get_dispatchers().lock().unwrap().set::<A2dpSinkCb>(Arc::new(Mutex::new(callbacks))) {
+ panic!("Tried to set dispatcher for A2dp Sink Callbacks while it already exists");
+ }
+ self.internal.init();
true
}
+ pub fn connect(&mut self, bt_addr: RawAddress) {
+ self.internal.connect(bt_addr.into());
+ }
+
+ pub fn disconnect(&mut self, bt_addr: RawAddress) {
+ self.internal.disconnect(bt_addr.into());
+ }
+
+ pub fn set_active_device(&mut self, bt_addr: RawAddress) {
+ self.internal.set_active_device(bt_addr.into());
+ }
+
pub fn cleanup(&mut self) {}
}
diff --git a/main/shim/btm_api.cc b/main/shim/btm_api.cc
index 2e0a338..d26dd6c 100644
--- a/main/shim/btm_api.cc
+++ b/main/shim/btm_api.cc
@@ -924,18 +924,6 @@
CHECK(p_eir_uuid != nullptr);
}
-uint8_t bluetooth::shim::BTM_GetEirSupportedServices(uint32_t* p_eir_uuid,
- uint8_t** p,
- uint8_t max_num_uuid16,
- uint8_t* p_num_uuid16) {
- LOG_INFO("UNIMPLEMENTED %s", __func__);
- CHECK(p_eir_uuid != nullptr);
- CHECK(p != nullptr);
- CHECK(*p != nullptr);
- CHECK(p_num_uuid16 != nullptr);
- return BTM_NO_RESOURCES;
-}
-
void bluetooth::shim::BTM_SecAddBleDevice(const RawAddress& bd_addr,
tBT_DEVICE_TYPE dev_type,
tBLE_ADDR_TYPE addr_type) {
diff --git a/main/shim/btm_api.h b/main/shim/btm_api.h
index 8eb81d9..c276d01 100644
--- a/main/shim/btm_api.h
+++ b/main/shim/btm_api.h
@@ -366,26 +366,6 @@
/*******************************************************************************
*
- * Function BTM_GetEirSupportedServices
- *
- * Description This function is called to get UUID list from bit map UUID
- * list.
- *
- * Parameters p_eir_uuid - bit mask of UUID list for EIR
- * p - reference of current pointer of EIR
- * max_num_uuid16 - max number of UUID can be written in EIR
- * num_uuid16 - number of UUID have been written in EIR
- *
- * Returns HCI_EIR_MORE_16BITS_UUID_TYPE, if it has more than max
- * HCI_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise
- *
- ******************************************************************************/
-uint8_t BTM_GetEirSupportedServices(uint32_t* p_eir_uuid, uint8_t** p,
- uint8_t max_num_uuid16,
- uint8_t* p_num_uuid16);
-
-/*******************************************************************************
- *
* Function BTM_SecAddBleDevice
*
* Description Add/modify device. This function will be normally called
diff --git a/stack/avrc/avrc_bld_tg.cc b/stack/avrc/avrc_bld_tg.cc
index 93ae296..92dbc5e 100644
--- a/stack/avrc/avrc_bld_tg.cc
+++ b/stack/avrc/avrc_bld_tg.cc
@@ -963,27 +963,31 @@
p_item_len = p_data;
p_data += 2;
item_len = 0;
- len_left -= 3; /* item_type(1) + item len(2) */
+ const uint16_t item_header_len = 3; /* item_type(1) + item len(2) */
+ uint16_t item_len_left = len_left - item_header_len;
switch (p_item_list[xx].item_type) {
case AVRC_ITEM_PLAYER:
/* min len required: 2 + 1 + 4 + 1 + 16 + 2 + 2 = 30 + str_len */
p_player = &p_item_list[xx].u.player;
item_len = AVRC_FEATURE_MASK_SIZE + p_player->name.str_len + 12;
- if ((len_left <= item_len) || !AVRC_ITEM_PLAYER_IS_VALID(p_player)) {
+ if ((item_len_left < item_len) ||
+ !AVRC_ITEM_PLAYER_IS_VALID(p_player)) {
+ if (item_len_left < item_len && item_count > 0) {
+ multi_items_add_fail = true;
+ }
p_data = p_item_start;
- } else {
- UINT16_TO_BE_STREAM(p_data, p_player->player_id);
- UINT8_TO_BE_STREAM(p_data, p_player->major_type);
- UINT32_TO_BE_STREAM(p_data, p_player->sub_type);
- UINT8_TO_BE_STREAM(p_data, p_player->play_status);
- ARRAY_TO_BE_STREAM(p_data, p_player->features,
- AVRC_FEATURE_MASK_SIZE);
- UINT16_TO_BE_STREAM(p_data, p_player->name.charset_id);
- UINT16_TO_BE_STREAM(p_data, p_player->name.str_len);
- ARRAY_TO_BE_STREAM(p_data, p_player->name.p_str,
- p_player->name.str_len);
+ break;
}
+ UINT16_TO_BE_STREAM(p_data, p_player->player_id);
+ UINT8_TO_BE_STREAM(p_data, p_player->major_type);
+ UINT32_TO_BE_STREAM(p_data, p_player->sub_type);
+ UINT8_TO_BE_STREAM(p_data, p_player->play_status);
+ ARRAY_TO_BE_STREAM(p_data, p_player->features, AVRC_FEATURE_MASK_SIZE);
+ UINT16_TO_BE_STREAM(p_data, p_player->name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_player->name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_player->name.p_str,
+ p_player->name.str_len);
break;
case AVRC_ITEM_FOLDER:
@@ -991,18 +995,21 @@
p_folder = &p_item_list[xx].u.folder;
item_len = AVRC_UID_SIZE + p_folder->name.str_len + 6;
- if ((len_left > item_len) && p_folder->name.p_str &&
- p_folder->type <= AVRC_FOLDER_TYPE_YEARS) {
- ARRAY_TO_BE_STREAM(p_data, p_folder->uid, AVRC_UID_SIZE);
- UINT8_TO_BE_STREAM(p_data, p_folder->type);
- UINT8_TO_BE_STREAM(p_data, p_folder->playable);
- UINT16_TO_BE_STREAM(p_data, p_folder->name.charset_id);
- UINT16_TO_BE_STREAM(p_data, p_folder->name.str_len);
- ARRAY_TO_BE_STREAM(p_data, p_folder->name.p_str,
- p_folder->name.str_len);
- } else {
+ if ((item_len_left < item_len) || !p_folder->name.p_str ||
+ p_folder->type > AVRC_FOLDER_TYPE_YEARS) {
+ if (item_len_left < item_len && item_count > 0) {
+ multi_items_add_fail = true;
+ }
p_data = p_item_start;
+ break;
}
+ ARRAY_TO_BE_STREAM(p_data, p_folder->uid, AVRC_UID_SIZE);
+ UINT8_TO_BE_STREAM(p_data, p_folder->type);
+ UINT8_TO_BE_STREAM(p_data, p_folder->playable);
+ UINT16_TO_BE_STREAM(p_data, p_folder->name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_folder->name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_folder->name.p_str,
+ p_folder->name.str_len);
break;
case AVRC_ITEM_MEDIA:
@@ -1010,43 +1017,43 @@
p_media = &p_item_list[xx].u.media;
item_len = AVRC_UID_SIZE + p_media->name.str_len + 6;
- if ((len_left >= item_len) && p_media->name.p_str &&
- p_media->type <= AVRC_MEDIA_TYPE_VIDEO) {
- ARRAY_TO_BE_STREAM(p_data, p_media->uid, AVRC_UID_SIZE);
- UINT8_TO_BE_STREAM(p_data, p_media->type);
- UINT16_TO_BE_STREAM(p_data, p_media->name.charset_id);
- UINT16_TO_BE_STREAM(p_data, p_media->name.str_len);
- ARRAY_TO_BE_STREAM(p_data, p_media->name.p_str,
- p_media->name.str_len);
- p_attr_count = p_data++;
- *p_attr_count = 0;
- len_left -= item_len;
- if (p_media->attr_count > 0) {
- p_attr = p_media->p_attr_list;
- for (yy = 0; yy < p_media->attr_count; yy++) {
- if (p_attr[yy].name.p_str &&
- AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_attr[yy].attr_id) &&
- (len_left >= (p_attr[yy].name.str_len + 8))) {
- (*p_attr_count)++;
- UINT32_TO_BE_STREAM(p_data, p_attr[yy].attr_id);
- UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.charset_id);
- UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.str_len);
- ARRAY_TO_BE_STREAM(p_data, p_attr[yy].name.p_str,
- p_attr[yy].name.str_len);
- item_len += (p_attr[yy].name.str_len + 8);
- len_left -= (p_attr[yy].name.str_len + 8);
- } else if ((len_left < (p_attr[yy].name.str_len + 8)) &&
- item_count > 0) {
- p_data = p_item_start;
- multi_items_add_fail = TRUE;
- break;
- }
- }
+ if ((item_len_left < item_len) || !p_media->name.p_str ||
+ p_media->type > AVRC_MEDIA_TYPE_VIDEO) {
+ if (item_len_left < item_len && item_count > 0) {
+ multi_items_add_fail = true;
}
- } else {
- if (len_left < item_len && item_count > 0)
- multi_items_add_fail = TRUE;
p_data = p_item_start;
+ break;
+ }
+ ARRAY_TO_BE_STREAM(p_data, p_media->uid, AVRC_UID_SIZE);
+ UINT8_TO_BE_STREAM(p_data, p_media->type);
+ UINT16_TO_BE_STREAM(p_data, p_media->name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_media->name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_media->name.p_str, p_media->name.str_len);
+ p_attr_count = p_data++;
+ *p_attr_count = 0;
+ uint16_t attribute_len_left = item_len_left - item_len;
+ p_attr = p_media->p_attr_list;
+ for (yy = 0; yy < p_media->attr_count; yy++) {
+ /* len required: 4 + 2 + 2 + str_len */
+ const uint16_t attribute_len = p_attr[yy].name.str_len + 8;
+ if (item_len_left < attribute_len || !p_attr[yy].name.p_str ||
+ AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_attr[yy].attr_id)) {
+ if (attribute_len_left < attribute_len && item_count > 0) {
+ multi_items_add_fail = true;
+ p_data = p_item_start;
+ break;
+ }
+ continue;
+ }
+ (*p_attr_count)++;
+ UINT32_TO_BE_STREAM(p_data, p_attr[yy].attr_id);
+ UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_attr[yy].name.p_str,
+ p_attr[yy].name.str_len);
+ item_len += attribute_len;
+ attribute_len_left -= attribute_len;
}
break;
} /* switch item_type */
@@ -1056,18 +1063,15 @@
item_count++;
/* fill in variable item lenth */
UINT16_TO_BE_STREAM(p_item_len, item_len);
- } else {
- if (!multi_items_add_fail) {
- /* some item is not added properly - set an error status */
- if (len_left < item_len)
- status = AVRC_STS_INTERNAL_ERR;
- else
- status = AVRC_STS_BAD_PARAM;
- }
- }
- if (!multi_items_add_fail) {
- len += item_len;
- len += 3; /* the item_type(1) and item_len(2) */
+ len_left -= item_len + item_header_len;
+ len += item_len + item_header_len;
+ } else if (!multi_items_add_fail) {
+ /* some item is not added properly - set an error status */
+ if (item_len_left < item_len)
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ status = AVRC_STS_BAD_PARAM;
+ break;
}
AVRC_TRACE_DEBUG("len:%d, len_left:%d, num:%d, item_len:%d", len, len_left,
item_count, item_len);
diff --git a/stack/btm/btm_ble.cc b/stack/btm/btm_ble.cc
index 805a1e2..3d0228d 100644
--- a/stack/btm/btm_ble.cc
+++ b/stack/btm/btm_ble.cc
@@ -485,16 +485,21 @@
p_dev_rec->device_type = p_inq_info->results.device_type;
p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type;
}
- if (p_dev_rec->bd_addr == remote_bda && p_dev_rec->device_type != 0) {
+
+ if (p_dev_rec->bd_addr == remote_bda &&
+ p_dev_rec->ble.pseudo_addr == remote_bda) {
*p_dev_type = p_dev_rec->device_type;
*p_addr_type = p_dev_rec->ble.ble_addr_type;
} else if (p_dev_rec->ble.pseudo_addr == remote_bda) {
*p_dev_type = BT_DEVICE_TYPE_BLE;
*p_addr_type = p_dev_rec->ble.ble_addr_type;
- } else /* matching static adddress only */
- {
- LOG(ERROR) << __func__ << " device_type not set; assuming BR/EDR";
- *p_dev_type = BT_DEVICE_TYPE_BREDR;
+ } else /* matching static adddress only */ {
+ if (p_dev_rec->device_type != BT_DEVICE_TYPE_UNKNOWN) {
+ *p_dev_type = p_dev_rec->device_type;
+ } else {
+ LOG_WARN("device_type not set; assuming BR/EDR");
+ *p_dev_type = BT_DEVICE_TYPE_BREDR;
+ }
*p_addr_type = BLE_ADDR_PUBLIC;
}
}
diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc
index 831d031..d8896b3 100644
--- a/stack/gatt/gatt_cl.cc
+++ b/stack/gatt/gatt_cl.cc
@@ -615,6 +615,7 @@
gatt_end_operation(p_clcb, p_clcb->status, &value);
}
}
+
/*******************************************************************************
*
* Function gatt_process_notification
@@ -626,10 +627,10 @@
******************************************************************************/
void gatt_process_notification(tGATT_TCB& tcb, uint16_t cid, uint8_t op_code,
uint16_t len, uint8_t* p_data) {
- tGATT_VALUE value;
+ tGATT_VALUE value = {};
tGATT_REG* p_reg;
uint16_t conn_id;
- tGATT_STATUS encrypt_status;
+ tGATT_STATUS encrypt_status = {};
uint8_t* p = p_data;
uint8_t i;
tGATTC_OPTYPE event = (op_code == GATT_HANDLE_VALUE_IND)
@@ -638,27 +639,16 @@
VLOG(1) << __func__;
+ // Ensure our packet has enough data (2 bytes)
if (len < GATT_NOTIFICATION_MIN_LEN) {
LOG(ERROR) << "illegal notification PDU length, discard";
return;
}
- memset(&value, 0, sizeof(value));
+ // Get 2 byte handle
STREAM_TO_UINT16(value.handle, p);
- if (op_code == GATT_HANDLE_MULTI_VALUE_NOTIF) {
- STREAM_TO_UINT16(value.len, p);
- } else {
- value.len = len - 2;
- }
-
- if (value.len > GATT_MAX_ATTR_LEN) {
- LOG(ERROR) << "value.len larger than GATT_MAX_ATTR_LEN, discard";
- return;
- }
-
- STREAM_TO_ARRAY(value.value, p, value.len);
-
+ // Fail early if the GATT handle is not valid
if (!GATT_HANDLE_IS_VALID(value.handle)) {
/* illegal handle, send ack now */
if (op_code == GATT_HANDLE_VALUE_IND)
@@ -666,6 +656,35 @@
return;
}
+ // Calculate value length based on opcode
+ if (op_code == GATT_HANDLE_MULTI_VALUE_NOTIF) {
+ // Ensure our packet has enough data; MIN + 2 more bytes for len value
+ if (len < GATT_NOTIFICATION_MIN_LEN + 2) {
+ LOG(ERROR) << "illegal notification PDU length, discard";
+ return;
+ }
+
+ // Allow multi value opcode to set value len from the packet
+ STREAM_TO_UINT16(value.len, p);
+
+ if (value.len > len - 4) {
+ LOG(ERROR) << "value.len (" << value.len << ") greater than length ("
+ << (len - 4);
+ return;
+ }
+
+ } else {
+ // For single value, just use the passed in len minus opcode length (2)
+ value.len = len - 2;
+ }
+
+ // Verify the new calculated length
+ if (value.len > GATT_MAX_ATTR_LEN) {
+ LOG(ERROR) << "value.len larger than GATT_MAX_ATTR_LEN, discard";
+ return;
+ }
+
+ // Handle indications differently
if (event == GATTC_OPTYPE_INDICATION) {
if (tcb.ind_count) {
/* this is an error case that receiving an indication but we
@@ -676,34 +695,67 @@
LOG(ERROR) << __func__ << " rcv Ind. but ind_count=" << tcb.ind_count
<< " (will reset ind_count)";
}
+
+ // Zero out the ind_count
tcb.ind_count = 0;
- }
- /* should notify all registered client with the handle value
- notificaion/indication
- Note: need to do the indication count and start timer first then do
- callback
- */
+ // Notify all registered clients with the handle value
+ // notification/indication
+ // Note: need to do the indication count and start timer first then do
+ // callback
+ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
+ if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) tcb.ind_count++;
+ }
- for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
- if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb &&
- (event == GATTC_OPTYPE_INDICATION))
- tcb.ind_count++;
- }
-
- if (event == GATTC_OPTYPE_INDICATION) {
/* start a timer for app confirmation */
- if (tcb.ind_count > 0)
+ if (tcb.ind_count > 0) {
gatt_start_ind_ack_timer(tcb, cid);
- else /* no app to indicate, or invalid handle */
+ } else { /* no app to indicate, or invalid handle */
attp_send_cl_confirmation_msg(tcb, cid);
+ }
}
encrypt_status = gatt_get_link_encrypt_status(tcb);
- uint16_t rem_len = len;
- while (rem_len) {
- tGATT_CL_COMPLETE gatt_cl_complete;
+ STREAM_TO_ARRAY(value.value, p, value.len);
+
+ tGATT_CL_COMPLETE gatt_cl_complete;
+ gatt_cl_complete.att_value = value;
+ gatt_cl_complete.cid = cid;
+
+ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
+ if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) {
+ conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, p_reg->gatt_if);
+ (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status,
+ &gatt_cl_complete);
+ }
+ }
+
+ // If this is single value, then nothing is left to do
+ if (op_code != GATT_HANDLE_MULTI_VALUE_NOTIF) return;
+
+ // Need a signed type to check if the value is below 0
+ // as uint16_t doesn't have negatives so the negatives register as a number
+ // thus anything less than zero won't trigger the conditional and it is not
+ // always 0
+ // when done looping as value.len is arbitrary.
+ int16_t rem_len = (int16_t)len - (4 /* octets */ + value.len);
+
+ // Already streamed the first value and sent it, lets send the rest
+ while (rem_len > 4 /* octets */) {
+ // 2
+ STREAM_TO_UINT16(value.handle, p);
+ // + 2 = 4
+ STREAM_TO_UINT16(value.len, p);
+ // Accounting
+ rem_len -= 4;
+ // Make sure we don't read past the remaining data even if the length says
+ // we can Also need to watch comparing the int16_t with the uint16_t
+ value.len = std::min(rem_len, (int16_t)value.len);
+ STREAM_TO_ARRAY(value.value, p, value.len);
+ // Accounting
+ rem_len -= value.len;
+
gatt_cl_complete.att_value = value;
gatt_cl_complete.cid = cid;
@@ -714,16 +766,6 @@
&gatt_cl_complete);
}
}
-
- if (op_code != GATT_HANDLE_MULTI_VALUE_NOTIF) return;
-
- /* 4 stands for 2 octects for handle and 2 octecs for len */
- rem_len -= (4 + value.len);
- if (rem_len) {
- STREAM_TO_UINT16(value.handle, p);
- STREAM_TO_UINT16(value.len, p);
- STREAM_TO_ARRAY(value.value, p, value.len);
- }
}
}
diff --git a/test/mock/mock_main_shim_btm_api.cc b/test/mock/mock_main_shim_btm_api.cc
index 83aeb03..33f9672 100644
--- a/test/mock/mock_main_shim_btm_api.cc
+++ b/test/mock/mock_main_shim_btm_api.cc
@@ -244,13 +244,6 @@
mock_function_count_map[__func__]++;
return 0;
}
-uint8_t bluetooth::shim::BTM_GetEirSupportedServices(uint32_t* p_eir_uuid,
- uint8_t** p,
- uint8_t max_num_uuid16,
- uint8_t* p_num_uuid16) {
- mock_function_count_map[__func__]++;
- return 0;
-}
void bluetooth::shim::BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16) {
mock_function_count_map[__func__]++;
}
diff --git a/test/mock/mock_stack_btm.cc b/test/mock/mock_stack_btm.cc
index d14af15..0dd5c65 100644
--- a/test/mock/mock_stack_btm.cc
+++ b/test/mock/mock_stack_btm.cc
@@ -18,6 +18,7 @@
* Generated mock file from original source file
*/
+#include "stack/include/btm_api.h"
#include "stack/include/btm_ble_api_types.h"
#include "stack/include/btm_client_interface.h"
#include "types/raw_address.h"
@@ -29,7 +30,12 @@
void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback) {}
uint8_t BTM_GetAcceptlistSize() { return 0; }
-struct btm_client_interface_s btm_client_interface = {};
+struct btm_client_interface_s btm_client_interface = {
+ .eir =
+ {
+ .BTM_GetEirSupportedServices = BTM_GetEirSupportedServices,
+ },
+};
struct btm_client_interface_s& get_btm_client_interface() {
return btm_client_interface;
diff --git a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
index 654aeac..6cd3fc5 100644
--- a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
@@ -1611,12 +1611,16 @@
}
void DualModeController::LeSetAddressResolutionEnable(CommandView command) {
- // NOP
- auto payload =
- std::make_unique<bluetooth::packet::RawBuilder>(std::vector<uint8_t>(
- {static_cast<uint8_t>(bluetooth::hci::ErrorCode::SUCCESS)}));
- send_event_(bluetooth::hci::CommandCompleteBuilder::Create(
- kNumCommandPackets, command.GetOpCode(), std::move(payload)));
+ auto command_view = gd_hci::LeSetAddressResolutionEnableView::Create(
+ gd_hci::LeSecurityCommandView::Create(
+ gd_hci::SecurityCommandView::Create(command)));
+ ASSERT(command_view.IsValid());
+ auto status = link_layer_controller_.LeSetAddressResolutionEnable(
+ command_view.GetAddressResolutionEnable() ==
+ bluetooth::hci::Enable::ENABLED);
+ send_event_(
+ bluetooth::hci::LeSetAddressResolutionEnableCompleteBuilder::Create(
+ kNumCommandPackets, status));
}
void DualModeController::LeSetResovalablePrivateAddressTimeout(CommandView command) {
diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
index dc1ffbb..091b700 100644
--- a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
@@ -1566,8 +1566,6 @@
auto adv_type = scan_response.GetAdvertisementType();
auto address_type =
static_cast<LeAdvertisement::AddressType>(scan_response.GetAddressType());
- LOG_INFO("Scan response with %s",
- bluetooth::hci::OpCodeText(le_scan_enable_).c_str());
if (le_scan_enable_ == bluetooth::hci::OpCode::LE_SET_SCAN_ENABLE) {
if (adv_type != model::packets::AdvertisementType::SCAN_RESPONSE) {
return;
@@ -2878,6 +2876,15 @@
return ErrorCode::SUCCESS;
}
+ErrorCode LinkLayerController::LeSetAddressResolutionEnable(bool enable) {
+ if (ResolvingListBusy()) {
+ return ErrorCode::COMMAND_DISALLOWED;
+ }
+
+ le_resolving_list_enabled_ = enable;
+ return ErrorCode::SUCCESS;
+}
+
ErrorCode LinkLayerController::LeResolvingListClear() {
if (ResolvingListBusy()) {
return ErrorCode::COMMAND_DISALLOWED;
diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
index 8693add..f3ab298 100644
--- a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
+++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
@@ -181,6 +181,7 @@
bool LeConnectListContainsDevice(Address addr, uint8_t addr_type);
bool LeConnectListFull();
bool ResolvingListBusy();
+ ErrorCode LeSetAddressResolutionEnable(bool enable);
ErrorCode LeResolvingListClear();
ErrorCode LeResolvingListAddDevice(Address addr, uint8_t addr_type,
std::array<uint8_t, kIrkSize> peerIrk,
@@ -463,6 +464,7 @@
std::array<uint8_t, kIrkSize> local_irk;
};
std::vector<ResolvingListEntry> le_resolving_list_;
+ bool le_resolving_list_enabled_{false};
std::array<LeAdvertiser, 7> advertisers_;