aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TEST_MAPPING2
-rw-r--r--binder/android/bluetooth/IBluetoothManager.aidl2
-rw-r--r--binder/android/bluetooth/IBluetoothPan.aidl2
-rw-r--r--bta/av/bta_av_aact.cc3
-rw-r--r--bta/av/bta_av_main.cc6
-rw-r--r--bta/av/bta_av_ssm.cc2
-rw-r--r--bta/hearing_aid/hearing_aid.cc81
-rw-r--r--bta/hearing_aid/hearing_aid_audio_source.cc100
-rw-r--r--bta/hf_client/bta_hf_client_rfc.cc5
-rw-r--r--bta/include/bta_hearing_aid_api.h19
-rw-r--r--bta/jv/bta_jv_act.cc4
-rw-r--r--btif/Android.bp33
-rw-r--r--btif/include/btif_api.h4
-rw-r--r--btif/include/btif_bqr.h8
-rw-r--r--btif/include/btif_keystore.h4
-rw-r--r--btif/src/bluetooth.cc12
-rw-r--r--btif/src/btif_a2dp_sink.cc1
-rw-r--r--btif/src/btif_config.cc135
-rw-r--r--btif/src/btif_keystore.cc115
-rw-r--r--btif/src/btif_profile_queue.cc9
-rw-r--r--btif/src/btif_rc.cc33
-rw-r--r--btif/src/btif_sock_l2cap.cc9
-rw-r--r--btif/test/btif_profile_queue_test.cc43
-rw-r--r--btif/test/btif_rc_test.cc131
-rw-r--r--hci/Android.bp1
-rw-r--r--hci/src/hci_layer.cc98
-rw-r--r--hci/src/hci_layer_android.cc3
-rw-r--r--include/hardware/bluetooth.h5
-rw-r--r--internal_include/bt_target.h2
-rw-r--r--profile/avrcp/connection_handler.cc2
-rw-r--r--profile/avrcp/device.cc23
-rw-r--r--stack/Android.bp34
-rw-r--r--stack/BUILD.gn1
-rw-r--r--stack/a2dp/a2dp_vendor_ldac_decoder.cc9
-rw-r--r--stack/avdt/avdt_msg.cc30
-rw-r--r--stack/avrc/avrc_pars_ct.cc2
-rw-r--r--stack/avrc/avrc_pars_tg.cc52
-rw-r--r--stack/btm/btm_acl.cc3
-rw-r--r--stack/btm/btm_ble_batchscan.cc2
-rw-r--r--stack/btm/btm_ble_bgconn.cc19
-rw-r--r--stack/btm/btm_ble_connection_establishment.cc1
-rw-r--r--stack/btm/btm_ble_gap.cc1
-rw-r--r--stack/btm/btm_ble_multi_adv.cc15
-rw-r--r--stack/btm/btm_inq.cc52
-rw-r--r--stack/btm/btm_int.h5
-rw-r--r--stack/btm/btm_sec.cc13
-rw-r--r--stack/btu/btu_hcif.cc54
-rw-r--r--stack/gatt/gatt_main.cc3
-rw-r--r--stack/include/hci_evt_length.h278
-rw-r--r--stack/include/ldacBT_bco_for_fluoride.h152
-rw-r--r--stack/l2cap/l2c_int.h2
-rw-r--r--stack/l2cap/l2c_link.cc22
-rw-r--r--stack/l2cap/l2c_main.cc5
-rw-r--r--stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc68
-rw-r--r--stack/test/a2dp/misc_fake.cc28
-rw-r--r--stack/test/stack_avrcp_test.cc112
56 files changed, 1302 insertions, 558 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING
index d29c2f7d0..8b050569b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -78,7 +78,7 @@
"host" : true
},
{
- "name" : "net_test_stack_a2dp_native",
+ "name" : "net_test_btif_rc",
"host" : true
}
]
diff --git a/binder/android/bluetooth/IBluetoothManager.aidl b/binder/android/bluetooth/IBluetoothManager.aidl
index 2e1270048..8a80d4991 100644
--- a/binder/android/bluetooth/IBluetoothManager.aidl
+++ b/binder/android/bluetooth/IBluetoothManager.aidl
@@ -46,6 +46,8 @@ interface IBluetoothManager
String getAddress();
String getName();
+ boolean onFactoryReset();
+
boolean isBleScanAlwaysAvailable();
int updateBleAppCount(IBinder b, boolean enable, String packageName);
boolean isBleAppPresent();
diff --git a/binder/android/bluetooth/IBluetoothPan.aidl b/binder/android/bluetooth/IBluetoothPan.aidl
index 16b6ddff8..4052aa4a1 100644
--- a/binder/android/bluetooth/IBluetoothPan.aidl
+++ b/binder/android/bluetooth/IBluetoothPan.aidl
@@ -26,7 +26,7 @@ import android.bluetooth.BluetoothDevice;
interface IBluetoothPan {
// Public API
boolean isTetheringOn();
- void setBluetoothTethering(boolean value);
+ void setBluetoothTethering(boolean value, String pkgName);
boolean connect(in BluetoothDevice device);
boolean disconnect(in BluetoothDevice device);
List<BluetoothDevice> getConnectedDevices();
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index b022b43af..7cd70561c 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -1246,7 +1246,6 @@ void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
open.chnl = p_scb->chnl;
open.hndl = p_scb->hndl;
open.status = BTA_AV_SUCCESS;
- open.starting = bta_av_chk_start(p_scb);
open.edr = 0;
p = BTM_ReadRemoteFeatures(p_scb->PeerAddress());
if (p != NULL) {
@@ -1262,8 +1261,10 @@ void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr, p_scb->hdi);
#endif
if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC) {
+ open.starting = false;
open.sep = AVDT_TSEP_SNK;
} else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK) {
+ open.starting = bta_av_chk_start(p_scb);
open.sep = AVDT_TSEP_SRC;
}
diff --git a/bta/av/bta_av_main.cc b/bta/av/bta_av_main.cc
index 34516fcdd..bdd8a70fa 100644
--- a/bta/av/bta_av_main.cc
+++ b/bta/av/bta_av_main.cc
@@ -1108,8 +1108,10 @@ bool bta_av_link_role_ok(tBTA_AV_SCB* p_scb, uint8_t bits) {
"%s: peer %s BTM_SwitchRole(BTM_ROLE_MASTER) error: %d",
__func__, p_scb->PeerAddress().ToString().c_str(), status);
}
- is_ok = false;
- p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START;
+ if (status != BTM_DEV_BLACKLISTED) {
+ is_ok = false;
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START;
+ }
}
}
diff --git a/bta/av/bta_av_ssm.cc b/bta/av/bta_av_ssm.cc
index a1a94b0e3..80effa372 100644
--- a/bta/av/bta_av_ssm.cc
+++ b/bta/av/bta_av_ssm.cc
@@ -329,7 +329,7 @@ static const uint8_t bta_av_sst_open[][BTA_AV_NUM_COLS] = {
/* STR_RECONFIG_CFM_EVT */
{BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVRC_TIMER_EVT */
- {BTA_AV_OPEN_RC, BTA_AV_CHK_2ND_START, BTA_AV_OPEN_SST},
+ {BTA_AV_OPEN_RC, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVDT_DISCONNECT_EVT */
{BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
diff --git a/bta/hearing_aid/hearing_aid.cc b/bta/hearing_aid/hearing_aid.cc
index fb7cab71a..867c6282b 100644
--- a/bta/hearing_aid/hearing_aid.cc
+++ b/bta/hearing_aid/hearing_aid.cc
@@ -390,6 +390,13 @@ class HearingAidImpl : public HearingAid {
hearingDevice->connection_update_status = AWAITING;
}
+ tACL_CONN* p_acl = btm_bda_to_acl(address, BT_TRANSPORT_LE);
+ if (p_acl != nullptr && controller_get_interface()->supports_ble_2m_phy() &&
+ HCI_LE_2M_PHY_SUPPORTED(p_acl->peer_le_features)) {
+ LOG(INFO) << address << " set preferred PHY to 2M";
+ BTM_BleSetPhy(address, PHY_LE_2M, PHY_LE_2M, 0);
+ }
+
// Set data length
// TODO(jpawlowski: for 16khz only 87 is required, optimize
BTM_SetBleDataLength(address, 167);
@@ -1005,13 +1012,16 @@ class HearingAidImpl : public HearingAid {
}
}
- void OnAudioSuspend() {
+ void OnAudioSuspend(const std::function<void()>& stop_audio_ticks) {
+ CHECK(stop_audio_ticks) << "stop_audio_ticks is empty";
+
if (!audio_running) {
LOG(WARNING) << __func__ << ": Unexpected audio suspend";
} else {
LOG(INFO) << __func__ << ": audio_running=" << audio_running;
}
audio_running = false;
+ stop_audio_ticks();
std::vector<uint8_t> stop({CONTROL_POINT_OP_STOP});
for (auto& device : hearingDevices.devices) {
@@ -1032,23 +1042,33 @@ class HearingAidImpl : public HearingAid {
}
}
- void OnAudioResume() {
+ void OnAudioResume(const std::function<void()>& start_audio_ticks) {
+ CHECK(start_audio_ticks) << "start_audio_ticks is empty";
+
if (audio_running) {
LOG(ERROR) << __func__ << ": Unexpected Audio Resume";
} else {
LOG(INFO) << __func__ << ": audio_running=" << audio_running;
}
- audio_running = true;
+
+ for (auto& device : hearingDevices.devices) {
+ if (!device.accepting_audio) continue;
+ audio_running = true;
+ SendStart(&device);
+ }
+
+ if (!audio_running) {
+ LOG(INFO) << __func__ << ": No device (0/" << GetDeviceCount()
+ << ") ready to start";
+ return;
+ }
// TODO: shall we also reset the encoder ?
encoder_state_release();
encoder_state_init();
seq_counter = 0;
- for (auto& device : hearingDevices.devices) {
- if (!device.accepting_audio) continue;
- SendStart(&device);
- }
+ start_audio_ticks();
}
uint8_t GetOtherSideStreamStatus(HearingDevice* this_side_device) {
@@ -1140,10 +1160,9 @@ class HearingAidImpl : public HearingAid {
}
if (left == nullptr && right == nullptr) {
- HearingAidAudioSource::Stop();
- audio_running = false;
- encoder_state_release();
- current_volume = VOLUME_UNKNOWN;
+ LOG(WARNING) << __func__ << ": No more (0/" << GetDeviceCount()
+ << ") devices ready";
+ DoDisconnectAudioStop();
return;
}
@@ -1456,8 +1475,17 @@ class HearingAidImpl : public HearingAid {
hearingDevices.Remove(address);
- if (connected)
- callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
+ if (!connected) {
+ return;
+ }
+
+ callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
+ for (const auto& device : hearingDevices.devices) {
+ if (device.accepting_audio) return;
+ }
+ LOG(INFO) << __func__ << ": No more (0/" << GetDeviceCount()
+ << ") devices ready";
+ DoDisconnectAudioStop();
}
void OnGattDisconnected(tGATT_STATUS status, uint16_t conn_id,
@@ -1479,7 +1507,16 @@ class HearingAidImpl : public HearingAid {
DoDisconnectCleanUp(hearingDevice);
+ // Keep this hearing aid in the list, and allow to reconnect back.
+
callbacks->OnConnectionState(ConnectionState::DISCONNECTED, remote_bda);
+
+ for (const auto& device : hearingDevices.devices) {
+ if (device.accepting_audio) return;
+ }
+ LOG(INFO) << __func__ << ": No more (0/" << GetDeviceCount()
+ << ") devices ready";
+ DoDisconnectAudioStop();
}
void DoDisconnectCleanUp(HearingDevice* hearingDevice) {
@@ -1512,6 +1549,13 @@ class HearingAidImpl : public HearingAid {
hearingDevice->command_acked = false;
}
+ void DoDisconnectAudioStop() {
+ HearingAidAudioSource::Stop();
+ audio_running = false;
+ encoder_state_release();
+ current_volume = VOLUME_UNKNOWN;
+ }
+
void SetVolume(int8_t volume) override {
VLOG(2) << __func__ << ": " << +volume;
current_volume = volume;
@@ -1723,14 +1767,11 @@ class HearingAidAudioReceiverImpl : public HearingAidAudioReceiver {
void OnAudioDataReady(const std::vector<uint8_t>& data) override {
if (instance) instance->OnAudioDataReady(data);
}
- void OnAudioSuspend(std::promise<void> do_suspend_promise) override {
- if (instance) instance->OnAudioSuspend();
- do_suspend_promise.set_value();
+ void OnAudioSuspend(const std::function<void()>& stop_audio_ticks) override {
+ if (instance) instance->OnAudioSuspend(stop_audio_ticks);
}
-
- void OnAudioResume(std::promise<void> do_resume_promise) override {
- if (instance) instance->OnAudioResume();
- do_resume_promise.set_value();
+ void OnAudioResume(const std::function<void()>& start_audio_ticks) override {
+ if (instance) instance->OnAudioResume(start_audio_ticks);
}
};
diff --git a/bta/hearing_aid/hearing_aid_audio_source.cc b/bta/hearing_aid/hearing_aid_audio_source.cc
index 3b92d41a8..0896e2bb3 100644
--- a/bta/hearing_aid/hearing_aid_audio_source.cc
+++ b/bta/hearing_aid/hearing_aid_audio_source.cc
@@ -97,12 +97,20 @@ void hearing_aid_send_ack(tHEARING_AID_CTRL_ACK status) {
}
void start_audio_ticks() {
+ if (data_interval_ms != HA_INTERVAL_10_MS &&
+ data_interval_ms != HA_INTERVAL_20_MS) {
+ LOG(FATAL) << " Unsupported data interval: " << data_interval_ms;
+ }
+
wakelock_acquire();
- audio_timer.SchedulePeriodic(get_main_thread()->GetWeakPtr(), FROM_HERE, base::Bind(&send_audio_data),
- base::TimeDelta::FromMilliseconds(data_interval_ms));
+ audio_timer.SchedulePeriodic(
+ get_main_thread()->GetWeakPtr(), FROM_HERE, base::Bind(&send_audio_data),
+ base::TimeDelta::FromMilliseconds(data_interval_ms));
+ LOG(INFO) << __func__ << ": running with data interval: " << data_interval_ms;
}
void stop_audio_ticks() {
+ LOG(INFO) << __func__ << ": stopped";
audio_timer.CancelAndWait();
wakelock_release();
}
@@ -121,17 +129,12 @@ void hearing_aid_data_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
UIPC_Ioctl(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
reinterpret_cast<void*>(0));
- if (data_interval_ms != HA_INTERVAL_10_MS &&
- data_interval_ms != HA_INTERVAL_20_MS) {
- LOG(FATAL) << " Unsupported data interval: " << data_interval_ms;
- }
-
- start_audio_ticks();
+ do_in_main_thread(FROM_HERE, base::BindOnce(start_audio_ticks));
break;
case UIPC_CLOSE_EVT:
LOG(INFO) << __func__ << ": UIPC_CLOSE_EVT";
hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
- stop_audio_ticks();
+ do_in_main_thread(FROM_HERE, base::BindOnce(stop_audio_ticks));
break;
default:
LOG(ERROR) << "Hearing Aid audio data event not recognized:" << event;
@@ -306,65 +309,52 @@ void hearing_aid_ctrl_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
}
bool hearing_aid_on_resume_req(bool start_media_task) {
- // hearing_aid_recv_ctrl_data(HEARING_AID_CTRL_CMD_START)
- if (localAudioReceiver != nullptr) {
- // Call OnAudioResume and block till it returns.
- std::promise<void> do_resume_promise;
- std::future<void> do_resume_future = do_resume_promise.get_future();
- bt_status_t status = do_in_main_thread(
- FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
- base::Unretained(localAudioReceiver),
- std::move(do_resume_promise)));
- if (status == BT_STATUS_SUCCESS) {
- do_resume_future.wait();
- } else {
- LOG(ERROR) << __func__
- << ": HEARING_AID_CTRL_CMD_START: do_in_main_thread err="
- << status;
- return false;
- }
- } else {
+ if (localAudioReceiver == nullptr) {
LOG(ERROR) << __func__
<< ": HEARING_AID_CTRL_CMD_START: audio receiver not started";
return false;
}
-
- // hearing_aid_data_cb(UIPC_OPEN_EVT): start_media_task
+ bt_status_t status;
if (start_media_task) {
- if (data_interval_ms != HA_INTERVAL_10_MS &&
- data_interval_ms != HA_INTERVAL_20_MS) {
- LOG(FATAL) << " Unsupported data interval: " << data_interval_ms;
- data_interval_ms = HA_INTERVAL_10_MS;
- }
- start_audio_ticks();
+ status = do_in_main_thread(
+ FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
+ base::Unretained(localAudioReceiver),
+ start_audio_ticks));
+ } else {
+ auto start_dummy_ticks = []() {
+ LOG(INFO) << "start_audio_ticks: waiting for data path opened";
+ };
+ status = do_in_main_thread(
+ FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
+ base::Unretained(localAudioReceiver),
+ start_dummy_ticks));
+ }
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << __func__
+ << ": HEARING_AID_CTRL_CMD_START: do_in_main_thread err="
+ << status;
+ return false;
}
return true;
}
bool hearing_aid_on_suspend_req() {
- // hearing_aid_recv_ctrl_data(HEARING_AID_CTRL_CMD_SUSPEND): stop_media_task
- stop_audio_ticks();
- if (localAudioReceiver != nullptr) {
- // Call OnAudioSuspend and block till it returns.
- std::promise<void> do_suspend_promise;
- std::future<void> do_suspend_future = do_suspend_promise.get_future();
- bt_status_t status = do_in_main_thread(
- FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioSuspend,
- base::Unretained(localAudioReceiver),
- std::move(do_suspend_promise)));
- if (status == BT_STATUS_SUCCESS) {
- do_suspend_future.wait();
- return true;
- } else {
- LOG(ERROR) << __func__
- << ": HEARING_AID_CTRL_CMD_SUSPEND: do_in_main_thread err="
- << status;
- }
- } else {
+ if (localAudioReceiver == nullptr) {
LOG(ERROR) << __func__
<< ": HEARING_AID_CTRL_CMD_SUSPEND: audio receiver not started";
+ return false;
}
- return false;
+ bt_status_t status = do_in_main_thread(
+ FROM_HERE,
+ base::BindOnce(&HearingAidAudioReceiver::OnAudioSuspend,
+ base::Unretained(localAudioReceiver), stop_audio_ticks));
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << __func__
+ << ": HEARING_AID_CTRL_CMD_SUSPEND: do_in_main_thread err="
+ << status;
+ return false;
+ }
+ return true;
}
} // namespace
diff --git a/bta/hf_client/bta_hf_client_rfc.cc b/bta/hf_client/bta_hf_client_rfc.cc
index f3e0947eb..535371f6b 100644
--- a/bta/hf_client/bta_hf_client_rfc.cc
+++ b/bta/hf_client/bta_hf_client_rfc.cc
@@ -127,6 +127,7 @@ static void bta_hf_client_mgmt_cback(uint32_t code, uint16_t port_handle) {
} else {
APPL_TRACE_ERROR("%s: PORT_SUCCESS, ignoring handle = %d", __func__,
port_handle);
+ osi_free(p_buf);
return;
}
} else if (client_cb != NULL &&
@@ -136,6 +137,10 @@ static void bta_hf_client_mgmt_cback(uint32_t code, uint16_t port_handle) {
RFCOMM_RemoveServer(port_handle);
p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
+ } else if (client_cb == NULL) {
+ // client_cb is already cleaned due to hfp client disabled.
+ // Assigned a valid event value to header and send this message anyway.
+ p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
}
p_buf->hdr.layer_specific = client_cb != NULL ? client_cb->handle : 0;
diff --git a/bta/include/bta_hearing_aid_api.h b/bta/include/bta_hearing_aid_api.h
index 902626221..6c4954b09 100644
--- a/bta/include/bta_hearing_aid_api.h
+++ b/bta/include/bta_hearing_aid_api.h
@@ -21,7 +21,6 @@
#include <base/callback_forward.h>
#include <hardware/bt_hearing_aid.h>
#include <deque>
-#include <future>
#include <vector>
constexpr uint16_t HEARINGAID_MAX_NUM_UUIDS = 1;
@@ -39,8 +38,22 @@ class HearingAidAudioReceiver {
public:
virtual ~HearingAidAudioReceiver() = default;
virtual void OnAudioDataReady(const std::vector<uint8_t>& data) = 0;
- virtual void OnAudioSuspend(std::promise<void> do_suspend_promise) = 0;
- virtual void OnAudioResume(std::promise<void> do_resume_promise) = 0;
+
+ // API to stop our feeding timer, and notify hearing aid devices that the
+ // streaming would stop, too.
+ //
+ // @param stop_audio_ticks a callable function calls out to stop the media
+ // timer for reading data.
+ virtual void OnAudioSuspend(
+ const std::function<void()>& stop_audio_ticks) = 0;
+
+ // To notify hearing aid devices to be ready for streaming, and start the
+ // media timer to feed the audio data.
+ //
+ // @param start_audio_ticks a callable function calls out to start a periodic
+ // timer for feeding data from the audio HAL.
+ virtual void OnAudioResume(
+ const std::function<void()>& start_audio_ticks) = 0;
};
// Number of rssi reads to attempt when requested
diff --git a/bta/jv/bta_jv_act.cc b/bta/jv/bta_jv_act.cc
index 462ee9d6b..2ede5c948 100644
--- a/bta/jv/bta_jv_act.cc
+++ b/bta/jv/bta_jv_act.cc
@@ -362,6 +362,8 @@ tBTA_JV_STATUS bta_jv_free_l2c_cb(tBTA_JV_L2C_CB* p_cb) {
p_cb->cong = false;
bta_jv_free_sec_id(&p_cb->sec_id);
p_cb->p_cback = NULL;
+ p_cb->handle = 0;
+ p_cb->l2cap_socket_id = 0;
return status;
}
@@ -1121,7 +1123,7 @@ void bta_jv_l2cap_start_server(int32_t type, tBTA_SEC sec_mask,
/* stops an L2CAP server */
void bta_jv_l2cap_stop_server(uint16_t local_psm, uint32_t l2cap_socket_id) {
for (int i = 0; i < BTA_JV_MAX_L2C_CONN; i++) {
- if (bta_jv_cb.l2c_cb[i].psm == local_psm) {
+ if (bta_jv_cb.l2c_cb[i].l2cap_socket_id == l2cap_socket_id) {
tBTA_JV_L2C_CB* p_cb = &bta_jv_cb.l2c_cb[i];
tBTA_JV_L2CAP_CBACK* p_cback = p_cb->p_cback;
tBTA_JV_L2CAP_CLOSE evt_data;
diff --git a/btif/Android.bp b/btif/Android.bp
index f33d174cf..0ecf20792 100644
--- a/btif/Android.bp
+++ b/btif/Android.bp
@@ -208,3 +208,36 @@ cc_test {
],
cflags: ["-DBUILDCFG"],
}
+
+// btif rc unit tests for target
+// ========================================================
+cc_test {
+ name: "net_test_btif_rc",
+ defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
+ host_supported: true,
+ include_dirs: btifCommonIncludes,
+ srcs: [
+ "test/btif_rc_test.cc",
+ ],
+ header_libs: ["libbluetooth_headers"],
+ shared_libs: [
+ "libcrypto",
+ "libcutils",
+ "liblog",
+ "libprotobuf-cpp-lite",
+ ],
+ static_libs: [
+ "libbluetooth-types",
+ "libbt-common",
+ "libbt-protos-lite",
+ "libosi",
+ "libosi-AllocationTestHarness",
+ ],
+ cflags: ["-DBUILDCFG"],
+ sanitize: {
+ address: true,
+ cfi: true,
+ misc_undefined: ["bounds"],
+ },
+}
diff --git a/btif/include/btif_api.h b/btif/include/btif_api.h
index 71acd2836..50d833f30 100644
--- a/btif/include/btif_api.h
+++ b/btif/include/btif_api.h
@@ -105,7 +105,7 @@ bool is_restricted_mode(void);
/*******************************************************************************
*
- * Function is_single_user_mode_
+ * Function is_niap_mode
*
* Description Checks if BT was enabled in single user mode. In this
* mode, use of keystore for key attestation of LTK is limitee
@@ -114,7 +114,7 @@ bool is_restricted_mode(void);
* Returns bool
*
******************************************************************************/
-bool is_single_user_mode(void);
+bool is_niap_mode(void);
/*******************************************************************************
*
diff --git a/btif/include/btif_bqr.h b/btif/include/btif_bqr.h
index 4407b0d03..ecf69f187 100644
--- a/btif/include/btif_bqr.h
+++ b/btif/include/btif_bqr.h
@@ -67,6 +67,11 @@ static constexpr int8_t kCriWarnRssi = -80;
static constexpr uint8_t kCriWarnUnusedCh = 55;
// The queue size of recording the BQR events.
static constexpr uint8_t kBqrEventQueueSize = 25;
+// The minimum size of the ROOT_INFLAMMATION event
+// HCI_VENDOR_SPECIFIC_EVT(1) + BQR sub event(1) + BQR report ID(1) +
+// error code(1) + vendor error code(1) = 5
+static constexpr uint8_t kRootInflammationPacketMinSize = 5;
+
// The Property of BQR event mask configuration.
static constexpr const char* kpPropertyEventMask =
"persist.bluetooth.bqr.event_mask";
@@ -90,7 +95,8 @@ enum BqrQualityReportId : uint8_t {
QUALITY_REPORT_ID_MONITOR_MODE = 0x01,
QUALITY_REPORT_ID_APPROACH_LSTO = 0x02,
QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY = 0x03,
- QUALITY_REPORT_ID_SCO_VOICE_CHOPPY = 0x04
+ QUALITY_REPORT_ID_SCO_VOICE_CHOPPY = 0x04,
+ QUALITY_REPORT_ID_ROOT_INFLAMMATION = 0x05
};
// Packet Type definition
diff --git a/btif/include/btif_keystore.h b/btif/include/btif_keystore.h
index cc06a9826..1b3663d03 100644
--- a/btif/include/btif_keystore.h
+++ b/btif/include/btif_keystore.h
@@ -70,9 +70,7 @@ class BtifKeystore {
private:
std::unique_ptr<keystore::KeystoreClient> keystore_client_;
std::mutex api_mutex_;
- keystore::KeyStoreNativeReturnCode GenerateKey(const std::string& name,
- int32_t flags,
- bool auth_bound);
+ bool GenerateKey(const std::string& name, int32_t flags);
};
} // namespace bluetooth
diff --git a/btif/src/bluetooth.cc b/btif/src/bluetooth.cc
index f55bcf9ba..158a739ca 100644
--- a/btif/src/bluetooth.cc
+++ b/btif/src/bluetooth.cc
@@ -81,7 +81,7 @@ using bluetooth::hearing_aid::HearingAidInterface;
bt_callbacks_t* bt_hal_cbacks = NULL;
bool restricted_mode = false;
-bool single_user_mode = false;
+bool niap_mode = false;
bool is_local_device_atv = false;
/*******************************************************************************
@@ -135,9 +135,9 @@ static bool is_profile(const char* p1, const char* p2) {
****************************************************************************/
static int init(bt_callbacks_t* callbacks, bool start_restricted,
- bool is_single_user_mode, bool is_atv) {
- LOG_INFO(LOG_TAG, "%s: start restricted = %d ; single user = %d", __func__,
- start_restricted, is_single_user_mode);
+ bool is_niap_mode, bool is_atv) {
+ LOG_INFO(LOG_TAG, "%s: start restricted = %d ; niap = %d", __func__,
+ start_restricted, is_niap_mode);
if (interface_ready()) return BT_STATUS_DONE;
@@ -147,7 +147,7 @@ static int init(bt_callbacks_t* callbacks, bool start_restricted,
bt_hal_cbacks = callbacks;
restricted_mode = start_restricted;
- single_user_mode = is_single_user_mode;
+ niap_mode = is_niap_mode;
is_local_device_atv = is_atv;
stack_manager_get_interface()->init_stack();
btif_debug_init();
@@ -171,7 +171,7 @@ static int disable(void) {
static void cleanup(void) { stack_manager_get_interface()->clean_up_stack(); }
bool is_restricted_mode() { return restricted_mode; }
-bool is_single_user_mode() { return single_user_mode; }
+bool is_niap_mode() { return niap_mode; }
bool is_atv_device() { return is_local_device_atv; }
diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc
index bb1bc49c0..aa75d21d4 100644
--- a/btif/src/btif_a2dp_sink.cc
+++ b/btif/src/btif_a2dp_sink.cc
@@ -667,7 +667,6 @@ static void btif_a2dp_sink_set_focus_state_event(
LOG_INFO(LOG_TAG, "%s: state=%d", __func__, state);
LockGuard lock(g_mutex);
- if (!btif_av_is_connected()) return;
APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state);
btif_a2dp_sink_cb.rx_focus_state = state;
if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) {
diff --git a/btif/src/btif_config.cc b/btif/src/btif_config.cc
index ed24d7dde..277671ca0 100644
--- a/btif/src/btif_config.cc
+++ b/btif/src/btif_config.cc
@@ -20,6 +20,7 @@
#include "btif_config.h"
+#include <base/base64.h>
#include <base/logging.h>
#include <ctype.h>
#include <openssl/rand.h>
@@ -60,8 +61,8 @@ static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S";
constexpr int kBufferSize = 400 * 10; // initial file is ~400B
-static bool use_key_attestation() {
- return getuid() == AID_BLUETOOTH && is_single_user_mode();
+static bool btif_is_niap_mode() {
+ return getuid() == AID_BLUETOOTH && is_niap_mode();
}
#define BT_CONFIG_METRICS_SECTION "Metrics"
@@ -93,10 +94,22 @@ static void btif_config_remove_restricted(config_t* config);
static std::unique_ptr<config_t> btif_config_open(const char* filename, const char* checksum_filename);
// Key attestation
+static std::string btif_convert_to_encrypt_key(
+ const std::string& unencrypt_str);
+static std::string btif_convert_to_unencrypt_key(
+ const std::string& encrypt_str);
+static bool btif_in_encrypt_key_name_list(std::string key);
+static bool btif_is_key_encrypted(int key_from_config_size,
+ std::string key_type_string);
static std::string hash_file(const char* filename);
static std::string read_checksum_file(const char* filename);
static void write_checksum_file(const char* filename, const std::string& hash);
+static const int ENCRYPT_KEY_NAME_LIST_SIZE = 7;
+static const std::string encrypt_key_name_list[] = {
+ "LinkKey", "LE_KEY_PENC", "LE_KEY_PID", "LE_KEY_LID",
+ "LE_KEY_PCSRK", "LE_KEY_LENC", "LE_KEY_LCSRK"};
+
static enum ConfigSource {
NOT_LOADED,
ORIGINAL,
@@ -183,9 +196,7 @@ static BtifKeystore btif_keystore(new keystore::KeystoreClientImpl);
static future_t* init(void) {
std::unique_lock<std::recursive_mutex> lock(config_lock);
- if (is_factory_reset() ||
- (use_key_attestation() && !btif_keystore.DoesKeyExist()))
- delete_config_files();
+ if (is_factory_reset()) delete_config_files();
std::string file_source;
@@ -271,7 +282,8 @@ static std::unique_ptr<config_t> btif_config_open(const char* filename, const ch
std::string stored_hash = read_checksum_file(checksum_filename);
if (stored_hash.empty()) {
LOG(ERROR) << __func__ << ": stored_hash=<empty>";
- if (!current_hash.empty()) {
+ // Will encrypt once since the bt_config never encrypt.
+ if (!btif_keystore.DoesKeyExist() && !current_hash.empty()) {
write_checksum_file(checksum_filename, current_hash);
stored_hash = read_checksum_file(checksum_filename);
}
@@ -408,14 +420,29 @@ bool btif_config_get_bin(const std::string& section, const std::string& key,
CHECK(length != NULL);
std::unique_lock<std::recursive_mutex> lock(config_lock);
- const std::string* value_str = config_get_string(*config, section, key, NULL);
+ const std::string* value_str;
+ const std::string* value_str_from_config =
+ config_get_string(*config, section, key, NULL);
- if (!value_str) {
+ if (!value_str_from_config) {
VLOG(1) << __func__ << ": cannot find string for section " << section
<< ", key " << key;
return false;
}
+ bool in_encrypt_key_name_list = btif_in_encrypt_key_name_list(key);
+ bool is_key_encrypted =
+ btif_is_key_encrypted(value_str_from_config->size(), key);
+
+ if (in_encrypt_key_name_list && is_key_encrypted) {
+ VLOG(2) << __func__ << " decrypt section: " << section << " key:" << key;
+ std::string tmp_value_str =
+ btif_convert_to_unencrypt_key(*value_str_from_config);
+ value_str = &tmp_value_str;
+ } else {
+ value_str = value_str_from_config;
+ }
+
size_t value_len = value_str->length();
if ((value_len % 2) != 0 || *length < (value_len / 2)) {
LOG(WARNING) << ": value size not divisible by 2, size is " << value_len;
@@ -429,12 +456,72 @@ bool btif_config_get_bin(const std::string& section, const std::string& key,
}
const char* ptr = value_str->c_str();
- for (*length = 0; *ptr; ptr += 2, *length += 1)
+ for (*length = 0; *ptr; ptr += 2, *length += 1) {
sscanf(ptr, "%02hhx", &value[*length]);
+ }
+
+ if (btif_is_niap_mode()) {
+ if (in_encrypt_key_name_list && !is_key_encrypted) {
+ VLOG(2) << __func__ << " encrypt section: " << section << " key:" << key;
+ std::string encrypt_str =
+ btif_convert_to_encrypt_key(*value_str_from_config);
+ config_set_string(config.get(), section, key, encrypt_str);
+ }
+ } else {
+ if (in_encrypt_key_name_list && is_key_encrypted) {
+ config_set_string(config.get(), section, key, value_str->c_str());
+ }
+ }
return true;
}
+static bool btif_in_encrypt_key_name_list(std::string key) {
+ return std::find(encrypt_key_name_list,
+ encrypt_key_name_list + ENCRYPT_KEY_NAME_LIST_SIZE,
+ key) != (encrypt_key_name_list + ENCRYPT_KEY_NAME_LIST_SIZE);
+}
+
+static bool btif_is_key_encrypted(int key_from_config_size,
+ std::string key_type_string) {
+ if (key_type_string.compare("LinkKey") == 0) {
+ return sizeof(LinkKey) * 2 != key_from_config_size;
+ } else if (key_type_string.compare("LE_KEY_PENC") == 0) {
+ return sizeof(tBTM_LE_PENC_KEYS) * 2 != key_from_config_size;
+ } else if (key_type_string.compare("LE_KEY_PID") == 0) {
+ return sizeof(tBTM_LE_PID_KEYS) * 2 != key_from_config_size;
+ } else if (key_type_string.compare("LE_KEY_LID") == 0) {
+ return sizeof(tBTM_LE_PID_KEYS) * 2 != key_from_config_size;
+ } else if (key_type_string.compare("LE_KEY_PCSRK") == 0) {
+ return sizeof(tBTM_LE_PCSRK_KEYS) * 2 != key_from_config_size;
+ } else if (key_type_string.compare("LE_KEY_LENC") == 0) {
+ return sizeof(tBTM_LE_LENC_KEYS) * 2 != key_from_config_size;
+ } else if (key_type_string.compare("LE_KEY_LCSRK") == 0) {
+ return sizeof(tBTM_LE_LCSRK_KEYS) * 2 != key_from_config_size;
+ } else {
+ VLOG(2) << __func__ << ": " << key_type_string
+ << " Key type is unknown, return false first";
+ return false;
+ }
+}
+
+static std::string btif_convert_to_unencrypt_key(
+ const std::string& encrypt_str) {
+ if (!encrypt_str.empty()) {
+ std::string tmp_encrypt_str("");
+ if (base::Base64Decode(encrypt_str, &tmp_encrypt_str)) {
+ std::string unencrypt_str = btif_keystore.Decrypt(tmp_encrypt_str);
+ if (!unencrypt_str.empty()) {
+ return unencrypt_str;
+ }
+ } else {
+ LOG(WARNING) << __func__
+ << ": base64string decode fail, will return empty string";
+ }
+ }
+ return "";
+}
+
size_t btif_config_get_bin_length(const std::string& section,
const std::string& key) {
CHECK(config != NULL);
@@ -468,15 +555,37 @@ bool btif_config_set_bin(const std::string& section, const std::string& key,
str[(i * 2) + 1] = lookup[value[i] & 0x0F];
}
+ std::string value_str;
+ if (btif_is_niap_mode() && btif_in_encrypt_key_name_list(key)) {
+ VLOG(2) << __func__ << " encrypt section: " << section << " key:" << key;
+ value_str = btif_convert_to_encrypt_key(str);
+ } else {
+ value_str = str;
+ }
+
{
std::unique_lock<std::recursive_mutex> lock(config_lock);
- config_set_string(config.get(), section, key, str);
+ config_set_string(config.get(), section, key, value_str);
}
osi_free(str);
return true;
}
+static std::string btif_convert_to_encrypt_key(
+ const std::string& unencrypt_str) {
+ if (!unencrypt_str.empty()) {
+ std::string encrypt_str = btif_keystore.Encrypt(unencrypt_str, 0);
+ if (!encrypt_str.empty()) {
+ base::Base64Encode(encrypt_str, &encrypt_str);
+ return encrypt_str;
+ } else {
+ LOG(ERROR) << __func__ << ": Encrypt fail, will return empty str.";
+ }
+ }
+ return "";
+}
+
std::list<section_t>& btif_config_sections() { return config->sections; }
bool btif_config_remove(const std::string& section, const std::string& key) {
@@ -643,7 +752,7 @@ static void delete_config_files(void) {
}
static std::string hash_file(const char* filename) {
- if (!use_key_attestation()) {
+ if (!btif_is_niap_mode()) {
LOG(INFO) << __func__ << ": Disabled for multi-user";
return DISABLED;
}
@@ -671,7 +780,7 @@ static std::string hash_file(const char* filename) {
}
static std::string read_checksum_file(const char* checksum_filename) {
- if (!use_key_attestation()) {
+ if (!btif_is_niap_mode()) {
LOG(INFO) << __func__ << ": Disabled for multi-user";
return DISABLED;
}
@@ -685,7 +794,7 @@ static std::string read_checksum_file(const char* checksum_filename) {
static void write_checksum_file(const char* checksum_filename,
const std::string& hash) {
- if (!use_key_attestation()) {
+ if (!btif_is_niap_mode()) {
LOG(INFO) << __func__
<< ": Disabled for multi-user, since config changed removing "
"checksums.";
diff --git a/btif/src/btif_keystore.cc b/btif/src/btif_keystore.cc
index 0af03e11b..1bf2c0ff1 100644
--- a/btif/src/btif_keystore.cc
+++ b/btif/src/btif_keystore.cc
@@ -17,6 +17,8 @@
******************************************************************************/
#include "btif_keystore.h"
+#include "keystore_client.pb.h"
+#include "string.h"
#include <base/files/file_util.h>
#include <base/logging.h>
@@ -29,7 +31,9 @@
using namespace keystore;
using namespace bluetooth;
-constexpr char kKeyStore[] = "AndroidKeystore";
+const std::string kKeyStore = "bluetooth-key-encrypted";
+constexpr uint32_t kAESKeySize = 256; // bits
+constexpr uint32_t kMACOutputSize = 128; // bits
namespace bluetooth {
@@ -43,19 +47,45 @@ std::string BtifKeystore::Encrypt(const std::string& data, int32_t flags) {
LOG(ERROR) << __func__ << ": empty data";
return output;
}
- if (!keystore_client_->doesKeyExist(kKeyStore)) {
- auto gen_result = GenerateKey(kKeyStore, 0, false);
- if (!gen_result.isOk()) {
- LOG(FATAL) << "EncryptWithAuthentication Failed: generateKey response="
- << gen_result;
- return output;
- }
+ if (!GenerateKey(kKeyStore, flags)) {
+ return output;
}
- if (!keystore_client_->encryptWithAuthentication(kKeyStore, data, flags,
- &output)) {
- LOG(FATAL) << "EncryptWithAuthentication failed.";
+
+ AuthorizationSetBuilder encrypt_params;
+ encrypt_params.Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+ .Authorization(TAG_MAC_LENGTH, kMACOutputSize)
+ .Padding(PaddingMode::NONE);
+ AuthorizationSet output_params;
+ std::string raw_encrypted_data;
+ if (!keystore_client_->oneShotOperation(
+ KeyPurpose::ENCRYPT, kKeyStore, encrypt_params, data,
+ std::string() /* signature_to_verify */, &output_params,
+ &raw_encrypted_data)) {
+ LOG(ERROR) << __func__ << ": AES operation failed.";
return output;
}
+ auto init_vector_blob = output_params.GetTagValue(TAG_NONCE);
+ if (!init_vector_blob.isOk()) {
+ LOG(ERROR) << __func__ << ": Missing initialization vector.";
+ return output;
+ }
+
+ const hidl_vec<uint8_t>& value = init_vector_blob.value();
+ std::string init_vector =
+ std::string(reinterpret_cast<const std::string::value_type*>(&value[0]),
+ value.size());
+
+ if (memcmp(&init_vector_blob, &init_vector, init_vector.length()) == 0) {
+ LOG(ERROR) << __func__
+ << ": Protobuf nonce data doesn't match the actual nonce.";
+ }
+
+ EncryptedData protobuf;
+ protobuf.set_init_vector(init_vector);
+ protobuf.set_encrypted_data(raw_encrypted_data);
+ if (!protobuf.SerializeToString(&output)) {
+ LOG(ERROR) << __func__ << ": Failed to serialize EncryptedData protobuf.";
+ }
return output;
}
@@ -66,36 +96,49 @@ std::string BtifKeystore::Decrypt(const std::string& input) {
return "";
}
std::string output;
- if (!keystore_client_->decryptWithAuthentication(kKeyStore, input, &output)) {
- LOG(FATAL) << "DecryptWithAuthentication failed.\n";
+ EncryptedData protobuf;
+ if (!protobuf.ParseFromString(input)) {
+ LOG(ERROR) << __func__ << ": Failed to parse EncryptedData protobuf.";
+ return output;
+ }
+ AuthorizationSetBuilder encrypt_params;
+ encrypt_params.Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+ .Authorization(TAG_MAC_LENGTH, kMACOutputSize)
+ .Authorization(TAG_NONCE, protobuf.init_vector().data(),
+ protobuf.init_vector().size())
+ .Padding(PaddingMode::NONE);
+ AuthorizationSet output_params;
+ if (!keystore_client_->oneShotOperation(
+ KeyPurpose::DECRYPT, kKeyStore, encrypt_params,
+ protobuf.encrypted_data(), std::string() /* signature_to_verify */,
+ &output_params, &output)) {
+ LOG(ERROR) << __func__ << ": AES operation failed.";
}
return output;
}
-// Note: auth_bound keys created with this tool will not be usable.
-KeyStoreNativeReturnCode BtifKeystore::GenerateKey(const std::string& name,
- int32_t flags,
- bool auth_bound) {
- AuthorizationSetBuilder params;
- params.RsaSigningKey(2048, 65537)
- .Digest(Digest::SHA_2_224)
- .Digest(Digest::SHA_2_256)
- .Digest(Digest::SHA_2_384)
- .Digest(Digest::SHA_2_512)
- .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
- .Padding(PaddingMode::RSA_PSS);
- if (auth_bound) {
- // Gatekeeper normally generates the secure user id.
- // Using zero allows the key to be created, but it will not be usuable.
- params.Authorization(TAG_USER_SECURE_ID, 0);
- } else {
- params.Authorization(TAG_NO_AUTH_REQUIRED);
+bool BtifKeystore::GenerateKey(const std::string& name, int32_t flags) {
+ if (!DoesKeyExist()) {
+ AuthorizationSetBuilder params;
+ params.AesEncryptionKey(kAESKeySize)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+ .Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT)
+ .Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, kMACOutputSize);
+ AuthorizationSet hardware_enforced_characteristics;
+ AuthorizationSet software_enforced_characteristics;
+ auto result = keystore_client_->generateKey(
+ name, params, flags, &hardware_enforced_characteristics,
+ &software_enforced_characteristics);
+ if (!result.isOk()) {
+ LOG(FATAL) << __func__ << "Failed to generate key: name: " << name
+ << ", error code: " << result.getErrorCode();
+ return false;
+ }
}
- AuthorizationSet hardware_enforced_characteristics;
- AuthorizationSet software_enforced_characteristics;
- return keystore_client_->generateKey(name, params, flags,
- &hardware_enforced_characteristics,
- &software_enforced_characteristics);
+ return true;
}
bool BtifKeystore::DoesKeyExist() {
diff --git a/btif/src/btif_profile_queue.cc b/btif/src/btif_profile_queue.cc
index 41275f127..900a6af52 100644
--- a/btif/src/btif_profile_queue.cc
+++ b/btif/src/btif_profile_queue.cc
@@ -195,7 +195,14 @@ bt_status_t btif_queue_connect_next(void) {
LOG_INFO(LOG_TAG, "%s: executing connection request: %s", __func__,
head.ToString().c_str());
- return head.connect();
+ bt_status_t b_status = head.connect();
+ if (b_status != BT_STATUS_SUCCESS) {
+ LOG_INFO(LOG_TAG,
+ "%s: connect %s failed, advance to next scheduled connection.",
+ __func__, head.ToString().c_str());
+ btif_queue_advance();
+ }
+ return b_status;
}
/*******************************************************************************
diff --git a/btif/src/btif_rc.cc b/btif/src/btif_rc.cc
index 9919a7b42..575d83e37 100644
--- a/btif/src/btif_rc.cc
+++ b/btif/src/btif_rc.cc
@@ -1836,6 +1836,12 @@ static bt_status_t get_element_attr_rsp(const RawAddress& bd_addr,
BTIF_TRACE_DEBUG("%s", __func__);
CHECK_RC_CONNECTED(p_dev);
+ if (num_attr > BTRC_MAX_ELEM_ATTR_SIZE) {
+ LOG(WARNING) << __func__
+ << " Exceeded number attributes:" << static_cast<int>(num_attr)
+ << " max:" << BTRC_MAX_ELEM_ATTR_SIZE;
+ num_attr = BTRC_MAX_ELEM_ATTR_SIZE;
+ }
memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
if (num_attr == 0) {
@@ -1844,7 +1850,8 @@ static bt_status_t get_element_attr_rsp(const RawAddress& bd_addr,
for (i = 0; i < num_attr; i++) {
element_attrs[i].attr_id = p_attrs[i].attr_id;
element_attrs[i].name.charset_id = AVRC_CHARSET_ID_UTF8;
- element_attrs[i].name.str_len = (uint16_t)strlen((char*)p_attrs[i].text);
+ element_attrs[i].name.str_len =
+ (uint16_t)strnlen((char*)p_attrs[i].text, BTRC_MAX_ATTR_STR_LEN);
element_attrs[i].name.p_str = p_attrs[i].text;
BTIF_TRACE_DEBUG(
"%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s", __func__,
@@ -2939,11 +2946,12 @@ static void register_for_event_notification(btif_rc_supported_event_t* p_event,
return;
}
// interval is only valid for AVRC_EVT_PLAY_POS_CHANGED
- uint32_t interval = 0;
+ uint32_t interval_in_seconds = 0;
if (p_event->event_id == AVRC_EVT_PLAY_POS_CHANGED) {
- interval = 2000;
+ interval_in_seconds = 2;
}
- status = register_notification_cmd(p_transaction->lbl, p_event->event_id, interval, p_dev);
+ status = register_notification_cmd(p_transaction->lbl, p_event->event_id,
+ interval_in_seconds, p_dev);
if (status != BT_STATUS_SUCCESS) {
BTIF_TRACE_ERROR("%s: Error in Notification registration: %d", __func__,
status);
@@ -3152,11 +3160,10 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg,
break;
} else {
uint8_t* p_data = p_rsp->param.track;
- /* Update the UID for current track
- * Attributes will be fetched after the AVRCP procedure
- */
BE_STREAM_TO_UINT64(p_dev->rc_playing_uid, p_data);
get_play_status_cmd(p_dev);
+ get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list,
+ p_dev);
}
break;
@@ -3336,6 +3343,8 @@ static void handle_app_attr_response(tBTA_AV_META_MSG* pmeta_msg,
rc_ctrl_procedure_complete(p_dev);
return;
}
+ p_dev->rc_app_settings.num_attrs = 0;
+ p_dev->rc_app_settings.num_ext_attrs = 0;
for (xx = 0; xx < p_rsp->num_attr; xx++) {
uint8_t st_index;
@@ -3809,6 +3818,10 @@ static void handle_get_playstatus_response(tBTA_AV_META_MSG* pmeta_msg,
if (p_rsp->status == AVRC_STS_NO_ERROR) {
do_in_jni_thread(
FROM_HERE,
+ base::Bind(bt_rc_ctrl_callbacks->play_status_changed_cb, p_dev->rc_addr,
+ (btrc_play_status_t)p_rsp->play_status));
+ do_in_jni_thread(
+ FROM_HERE,
base::Bind(bt_rc_ctrl_callbacks->play_position_changed_cb,
p_dev->rc_addr, p_rsp->song_len, p_rsp->song_pos));
} else {
@@ -3907,6 +3920,12 @@ static void handle_get_folder_items_response(tBTA_AV_META_MSG* pmeta_msg,
/* We want to make the ownership explicit in native */
btrc_items, item_count));
+ if (item_count > 0) {
+ if (btrc_items[0].item_type == AVRC_ITEM_PLAYER &&
+ (p_dev->rc_features & BTA_AV_FEAT_APP_SETTING)) {
+ list_player_app_setting_attrib_cmd(p_dev);
+ }
+ }
/* Release the memory block for items and attributes allocated here.
* Since the executor for do_in_jni_thread is a Single Thread Task Runner it
* is okay to queue up the cleanup of btrc_items */
diff --git a/btif/src/btif_sock_l2cap.cc b/btif/src/btif_sock_l2cap.cc
index 1f85c732b..105d5a1cc 100644
--- a/btif/src/btif_sock_l2cap.cc
+++ b/btif/src/btif_sock_l2cap.cc
@@ -97,6 +97,7 @@ static void btsock_l2cap_server_listen(l2cap_socket* sock);
static std::mutex state_lock;
l2cap_socket* socks = NULL;
+static uint32_t last_sock_id = 0;
static uid_set_t* uid_set = NULL;
static int pth = -1;
@@ -254,6 +255,11 @@ static void btsock_l2cap_free_l(l2cap_socket* sock) {
}
if ((sock->channel >= 0) && (sock->server)) {
BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP_LE);
+ if (!sock->fixed_chan) {
+ VLOG(2) << __func__ << ": stopping L2CAP LE COC server channel "
+ << sock->channel;
+ BTA_JvL2capStopServer(sock->channel, sock->id);
+ }
}
} else {
// Only call if we are non server connections
@@ -322,7 +328,7 @@ static l2cap_socket* btsock_l2cap_alloc_l(const char* name,
sock->next = socks;
sock->prev = NULL;
if (socks) socks->prev = sock;
- sock->id = (socks ? socks->id : 0) + 1;
+ sock->id = last_sock_id + 1;
sock->tx_bytes = 0;
sock->rx_bytes = 0;
socks = sock;
@@ -340,6 +346,7 @@ static l2cap_socket* btsock_l2cap_alloc_l(const char* name,
if (!++sock->id) /* no zero IDs allowed */
sock->id++;
}
+ last_sock_id = sock->id;
DVLOG(2) << __func__ << " SOCK_LIST: alloc id:" << sock->id;
return sock;
diff --git a/btif/test/btif_profile_queue_test.cc b/btif/test/btif_profile_queue_test.cc
index 486959b56..af0255b19 100644
--- a/btif/test/btif_profile_queue_test.cc
+++ b/btif/test/btif_profile_queue_test.cc
@@ -97,6 +97,49 @@ TEST_F(BtifProfileQueueTest, test_connect) {
EXPECT_EQ(sResult, UUID1_ADDR1);
}
+static bt_status_t test_connect_cb_fail(RawAddress* bda, uint16_t uuid) {
+ sResult = UNKNOWN;
+ if (*bda == BtifProfileQueueTest::kTestAddr1) {
+ if (uuid == BtifProfileQueueTest::kTestUuid1) {
+ sResult = UUID1_ADDR1;
+ } else if (uuid == BtifProfileQueueTest::kTestUuid2) {
+ sResult = UUID2_ADDR1;
+ }
+ } else if (*bda == BtifProfileQueueTest::kTestAddr2) {
+ if (uuid == BtifProfileQueueTest::kTestUuid1) {
+ sResult = UUID1_ADDR2;
+ } else if (uuid == BtifProfileQueueTest::kTestUuid2) {
+ sResult = UUID2_ADDR2;
+ }
+ }
+ return BT_STATUS_BUSY;
+}
+
+TEST_F(BtifProfileQueueTest, test_connect_fail_still_can_advance_the_queue) {
+ sResult = NOT_SET;
+ // First connect-message for UUID1-ADDR1 is executed, but does not be removed
+ // from connect-queue yet.
+ btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, UUID1_ADDR1);
+ sResult = NOT_SET;
+ // Second connect-message for UUID2-ADDR1 be pushed into connect-queue, but is
+ // not executed
+ btif_queue_connect(kTestUuid2, &kTestAddr1, test_connect_cb_fail);
+ EXPECT_EQ(sResult, NOT_SET);
+ // Third connect-message for UUID1-ADDR2 be pushed into connect-queue, but is
+ // not executed
+ btif_queue_connect(kTestUuid1, &kTestAddr2, test_connect_cb_fail);
+ EXPECT_EQ(sResult, NOT_SET);
+ // Fourth connect-message for UUID2-ADDR2 be pushed into connect-queue, but is
+ // not executed
+ btif_queue_connect(kTestUuid2, &kTestAddr2, test_connect_cb_fail);
+ EXPECT_EQ(sResult, NOT_SET);
+ // removed First connect-message from connect-queue, check it can advance to
+ // subsequent connect-message.
+ btif_queue_advance();
+ EXPECT_EQ(sResult, UUID2_ADDR2);
+}
+
TEST_F(BtifProfileQueueTest, test_connect_same_uuid_do_not_repeat) {
sResult = NOT_SET;
btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
diff --git a/btif/test/btif_rc_test.cc b/btif/test/btif_rc_test.cc
new file mode 100644
index 000000000..6271881c9
--- /dev/null
+++ b/btif/test/btif_rc_test.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <base/logging.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <cstdint>
+
+#include "bta/include/bta_av_api.h"
+#include "btif/include/btif_common.h"
+#include "device/include/interop.h"
+#include "include/hardware/bt_rc.h"
+#include "osi/test/AllocationTestHarness.h"
+#include "stack/include/btm_api_types.h"
+#include "types/raw_address.h"
+#undef LOG_TAG
+#include "btif/src/btif_rc.cc"
+
+extern void allocation_tracker_uninit(void);
+
+namespace {
+int AVRC_BldResponse_ = 0;
+} // namespace
+
+uint8_t appl_trace_level = BT_TRACE_LEVEL_WARNING;
+uint8_t btif_trace_level = BT_TRACE_LEVEL_WARNING;
+
+tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) { return 0; }
+tAVRC_STS AVRC_BldResponse(uint8_t handle, tAVRC_RESPONSE* p_rsp,
+ BT_HDR** pp_pkt) {
+ AVRC_BldResponse_++;
+ return 0;
+}
+tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) {
+ return 0;
+}
+tAVRC_STS AVRC_Ctrl_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result,
+ uint8_t* p_buf, uint16_t* buf_len) {
+ return 0;
+}
+tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result,
+ uint8_t* p_buf, uint16_t buf_len) {
+ return 0;
+}
+tAVRC_STS AVRC_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result,
+ UNUSED_ATTR uint8_t* p_buf,
+ UNUSED_ATTR uint16_t buf_len) {
+ return 0;
+}
+void BTA_AvCloseRc(uint8_t rc_handle) {}
+void BTA_AvMetaCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CMD cmd_code,
+ BT_HDR* p_pkt) {}
+void BTA_AvMetaRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+ BT_HDR* p_pkt) {}
+void BTA_AvRemoteCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_RC rc_id,
+ tBTA_AV_STATE key_state) {}
+void BTA_AvRemoteVendorUniqueCmd(uint8_t rc_handle, uint8_t label,
+ tBTA_AV_STATE key_state, uint8_t* p_msg,
+ uint8_t buf_len) {}
+void BTA_AvVendorCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code,
+ uint8_t* p_data, uint16_t len) {}
+void BTA_AvVendorRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+ uint8_t* p_data, uint16_t len, uint32_t company_id) {}
+void btif_av_clear_remote_suspend_flag(void) {}
+bool btif_av_is_connected(void) { return false; }
+bool btif_av_is_sink_enabled(void) { return false; }
+RawAddress btif_av_sink_active_peer(void) { return RawAddress(); }
+RawAddress btif_av_source_active_peer(void) { return RawAddress(); }
+bool btif_av_stream_started_ready(void) { return false; }
+bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
+ char* p_params, int param_len,
+ tBTIF_COPY_CBACK* p_copy_cback) {
+ return BT_STATUS_SUCCESS;
+}
+const char* dump_rc_event(uint8_t event) { return nullptr; }
+const char* dump_rc_notification_event_id(uint8_t event_id) { return nullptr; }
+const char* dump_rc_pdu(uint8_t pdu) { return nullptr; }
+bt_status_t do_in_jni_thread(const base::Location& from_here,
+ base::OnceClosure task) {
+ return BT_STATUS_SUCCESS;
+}
+base::MessageLoop* get_main_message_loop() { return nullptr; }
+bool interop_match_addr(const interop_feature_t feature,
+ const RawAddress* addr) {
+ return false;
+}
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}
+
+/**
+ * Test class to test selected functionality in hci/src/hci_layer.cc
+ */
+class BtifRcTest : public AllocationTestHarness {
+ protected:
+ void SetUp() override {
+ AllocationTestHarness::SetUp();
+ // Disable our allocation tracker to allow ASAN full range
+ allocation_tracker_uninit();
+ }
+
+ void TearDown() override { AllocationTestHarness::TearDown(); }
+};
+
+TEST_F(BtifRcTest, get_element_attr_rsp) {
+ RawAddress bd_addr;
+
+ btif_rc_cb.rc_multi_cb[0].rc_addr = bd_addr;
+ btif_rc_cb.rc_multi_cb[0].rc_connected = true;
+ btif_rc_cb.rc_multi_cb[0]
+ .rc_pdu_info[IDX_GET_ELEMENT_ATTR_RSP]
+ .is_rsp_pending = true;
+ btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
+
+ btrc_element_attr_val_t p_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ uint8_t num_attr = BTRC_MAX_ELEM_ATTR_SIZE + 1;
+
+ CHECK(get_element_attr_rsp(bd_addr, num_attr, p_attrs) == BT_STATUS_SUCCESS);
+ CHECK(AVRC_BldResponse_ == 1);
+}
diff --git a/hci/Android.bp b/hci/Android.bp
index 635d939e3..57021770c 100644
--- a/hci/Android.bp
+++ b/hci/Android.bp
@@ -36,6 +36,7 @@ cc_library_static {
"system/bt/stack/include",
"system/bt/utils/include",
"system/bt/bta/include",
+ "system/bt/btif/include",
"system/libhwbinder/include",
],
}
diff --git a/hci/src/hci_layer.cc b/hci/src/hci_layer.cc
index ed2908cdd..80f63deee 100644
--- a/hci/src/hci_layer.cc
+++ b/hci/src/hci_layer.cc
@@ -36,10 +36,12 @@
#include <mutex>
#include "btcore/include/module.h"
+#include "btif/include/btif_bqr.h"
#include "btsnoop.h"
#include "buffer_allocator.h"
#include "common/message_loop_thread.h"
#include "common/metrics.h"
+#include "common/once_timer.h"
#include "hci_inject.h"
#include "hci_internals.h"
#include "hcidefs.h"
@@ -54,6 +56,7 @@
#define BT_HCI_TIMEOUT_TAG_NUM 1010000
using bluetooth::common::MessageLoopThread;
+using bluetooth::common::OnceTimer;
extern void hci_initialize();
extern void hci_transmit(BT_HDR* packet);
@@ -110,7 +113,7 @@ static std::queue<base::Closure> command_queue;
static alarm_t* command_response_timer;
static list_t* commands_pending_response;
static std::recursive_timed_mutex commands_pending_response_mutex;
-static alarm_t* hci_timeout_abort_timer;
+static OnceTimer abort_timer;
// The hand-off point for data going to a higher layer, set by the higher layer
static base::Callback<void(const base::Location&, BT_HDR*)> send_data_upwards;
@@ -160,6 +163,14 @@ void sco_data_received(BT_HDR* packet) {
packet_fragmenter->reassemble_and_dispatch(packet);
}
+void hal_service_died() {
+ if (abort_timer.IsScheduled()) {
+ LOG(ERROR) << "abort_timer is scheduled, wait for timeout";
+ return;
+ }
+ abort();
+}
+
// Module lifecycle functions
static future_t* hci_module_shut_down();
@@ -258,12 +269,6 @@ static future_t* hci_module_shut_down() {
packet_fragmenter->cleanup();
- // Clean up abort timer, if it exists.
- if (hci_timeout_abort_timer != NULL) {
- alarm_free(hci_timeout_abort_timer);
- hci_timeout_abort_timer = NULL;
- }
-
if (hci_firmware_log_fd != INVALID_FD) {
hci_close_firmware_log_file(hci_firmware_log_fd);
hci_firmware_log_fd = INVALID_FD;
@@ -436,7 +441,7 @@ static void fragmenter_transmit_finished(BT_HDR* packet,
}
// Abort. The chip has had time to write any debugging information.
-static void hci_timeout_abort(void* unused_data) {
+static void hci_timeout_abort(void) {
LOG_ERROR(LOG_TAG, "%s restarting the Bluetooth process.", __func__);
hci_close_firmware_log_file(hci_firmware_log_fd);
@@ -445,6 +450,12 @@ static void hci_timeout_abort(void* unused_data) {
abort();
}
+static void hci_root_inflamed_abort(uint8_t error_code,
+ uint8_t vendor_error_code) {
+ LOG(FATAL) << __func__ << ": error_code = " << std::to_string(error_code)
+ << ", vendor_error_code = " << std::to_string(vendor_error_code);
+}
+
static void command_timed_out_log_info(void* original_wait_entry) {
LOG_ERROR(LOG_TAG, "%s: %d commands pending response", __func__,
get_num_waiting_commands());
@@ -494,7 +505,7 @@ static void command_timed_out(void* original_wait_entry) {
}
// Don't request a firmware dump for multiple hci timeouts
- if (hci_timeout_abort_timer != NULL || hci_firmware_log_fd != INVALID_FD) {
+ if (hci_firmware_log_fd != INVALID_FD) {
return;
}
@@ -521,13 +532,13 @@ static void command_timed_out(void* original_wait_entry) {
osi_free(bt_hdr);
LOG_ERROR(LOG_TAG, "%s: Setting a timer to restart.", __func__);
- hci_timeout_abort_timer = alarm_new("hci.hci_timeout_aborter");
- if (!hci_timeout_abort_timer) {
+ // alarm_default_callbacks thread post to hci_thread.
+ if (!abort_timer.Schedule(
+ hci_thread.GetWeakPtr(), FROM_HERE, base::Bind(hci_timeout_abort),
+ base::TimeDelta::FromMilliseconds(COMMAND_TIMEOUT_RESTART_MS))) {
LOG_ERROR(LOG_TAG, "%s unable to create an abort timer.", __func__);
abort();
}
- alarm_set(hci_timeout_abort_timer, COMMAND_TIMEOUT_RESTART_MS,
- hci_timeout_abort, nullptr);
}
// Event/packet receiving functions
@@ -614,15 +625,62 @@ static bool filter_incoming_event(BT_HDR* packet) {
}
goto intercepted;
- } else if (event_code == HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT) {
- if (hci_firmware_log_fd == INVALID_FD)
- hci_firmware_log_fd = hci_open_firmware_log_file();
+ } else if (event_code == HCI_VENDOR_SPECIFIC_EVT) {
+ uint8_t sub_event_code;
+ STREAM_TO_UINT8(sub_event_code, stream);
- if (hci_firmware_log_fd != INVALID_FD)
- hci_log_firmware_debug_packet(hci_firmware_log_fd, packet);
+ if (sub_event_code == HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT) {
+ if (hci_firmware_log_fd == INVALID_FD)
+ hci_firmware_log_fd = hci_open_firmware_log_file();
- buffer_allocator->free(packet);
- return true;
+ if (hci_firmware_log_fd != INVALID_FD)
+ hci_log_firmware_debug_packet(hci_firmware_log_fd, packet);
+
+ buffer_allocator->free(packet);
+ return true;
+ } else if (sub_event_code == HCI_VSE_SUBCODE_BQR_SUB_EVT) {
+ uint8_t bqr_report_id;
+ STREAM_TO_UINT8(bqr_report_id, stream);
+
+ if (bqr_report_id ==
+ bluetooth::bqr::QUALITY_REPORT_ID_ROOT_INFLAMMATION &&
+ packet->len >= bluetooth::bqr::kRootInflammationPacketMinSize) {
+ uint8_t error_code;
+ uint8_t vendor_error_code;
+ STREAM_TO_UINT8(error_code, stream);
+ STREAM_TO_UINT8(vendor_error_code, stream);
+ // TODO(ugoyu) Report to bluetooth metrics here
+
+ LOG(ERROR) << __func__
+ << ": Root inflammation event! setting timer to restart.";
+ {
+ // Try to stop hci command and startup timers
+ std::unique_lock<std::recursive_timed_mutex> lock(
+ commands_pending_response_mutex, std::defer_lock);
+ if (lock.try_lock_for(std::chrono::milliseconds(
+ COMMAND_PENDING_MUTEX_ACQUIRE_TIMEOUT_MS))) {
+ if (alarm_is_scheduled(startup_timer)) {
+ alarm_cancel(startup_timer);
+ }
+ if (alarm_is_scheduled(command_response_timer)) {
+ alarm_cancel(command_response_timer);
+ }
+ } else {
+ LOG(ERROR) << __func__ << ": Failed to obtain mutex";
+ }
+ }
+
+ // HwBinder thread post to hci_thread
+ if (!abort_timer.Schedule(hci_thread.GetWeakPtr(), FROM_HERE,
+ base::Bind(hci_root_inflamed_abort,
+ error_code, vendor_error_code),
+ base::TimeDelta::FromMilliseconds(
+ COMMAND_TIMEOUT_RESTART_MS))) {
+ LOG(ERROR) << "Failed to schedule abort_timer!";
+ hci_root_inflamed_abort(error_code, vendor_error_code);
+ }
+ }
+ }
}
return false;
diff --git a/hci/src/hci_layer_android.cc b/hci/src/hci_layer_android.cc
index 92be0df59..a9fde50ee 100644
--- a/hci/src/hci_layer_android.cc
+++ b/hci/src/hci_layer_android.cc
@@ -51,6 +51,7 @@ extern void initialization_complete();
extern void hci_event_received(const base::Location& from_here, BT_HDR* packet);
extern void acl_event_received(BT_HDR* packet);
extern void sco_data_received(BT_HDR* packet);
+extern void hal_service_died();
android::sp<IBluetoothHci> btHci;
@@ -58,7 +59,7 @@ class BluetoothHciDeathRecipient : public hidl_death_recipient {
public:
virtual void serviceDied(uint64_t /*cookie*/, const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
LOG_ERROR(LOG_TAG, "Bluetooth HAL service died!");
- abort();
+ hal_service_died();
}
};
android::sp<BluetoothHciDeathRecipient> bluetoothHciDeathRecipient = new BluetoothHciDeathRecipient();
diff --git a/include/hardware/bluetooth.h b/include/hardware/bluetooth.h
index 4c88de8d8..ae58ac22e 100644
--- a/include/hardware/bluetooth.h
+++ b/include/hardware/bluetooth.h
@@ -469,11 +469,10 @@ typedef struct {
* The |start_restricted| flag inits the adapter in restricted mode. In
* restricted mode, bonds that are created are marked as restricted in the
* config file. These devices are deleted upon leaving restricted mode.
- * The |is_single_user_mode| flag inits the adapter in NIAP mode.
+ * The |is_niap_mode| flag inits the adapter in NIAP mode.
* The |is_atv| flag indicates whether the local device is an Android TV
*/
- int (*init)(bt_callbacks_t* callbacks, bool guest_mode,
- bool is_single_user_mode, bool is_atv);
+ int (*init)(bt_callbacks_t* callbacks, bool guest_mode, bool is_niap_mode, bool is_atv);
/** Enable Bluetooth. */
int (*enable)();
diff --git a/internal_include/bt_target.h b/internal_include/bt_target.h
index 67a67c56d..d12223425 100644
--- a/internal_include/bt_target.h
+++ b/internal_include/bt_target.h
@@ -108,7 +108,7 @@
#endif
#ifndef BTA_DM_SDP_DB_SIZE
-#define BTA_DM_SDP_DB_SIZE 8000
+#define BTA_DM_SDP_DB_SIZE 20000
#endif
#ifndef HL_INCLUDED
diff --git a/profile/avrcp/connection_handler.cc b/profile/avrcp/connection_handler.cc
index 3177506a1..686f89be6 100644
--- a/profile/avrcp/connection_handler.cc
+++ b/profile/avrcp/connection_handler.cc
@@ -138,9 +138,7 @@ bool ConnectionHandler::ConnectDevice(const RawAddress& bdaddr) {
bool ConnectionHandler::DisconnectDevice(const RawAddress& bdaddr) {
for (auto it = device_map_.begin(); it != device_map_.end(); it++) {
if (bdaddr == it->second->GetAddress()) {
- it->second->DeviceDisconnected();
uint8_t handle = it->first;
- device_map_.erase(handle);
return avrc_->Close(handle) == AVRC_SUCCESS;
}
}
diff --git a/profile/avrcp/device.cc b/profile/avrcp/device.cc
index 4ca624b81..264eaf04c 100644
--- a/profile/avrcp/device.cc
+++ b/profile/avrcp/device.cc
@@ -98,6 +98,19 @@ void Device::VendorPacketHandler(uint8_t label,
case CommandPdu::REGISTER_NOTIFICATION: {
auto register_notification =
Packet::Specialize<RegisterNotificationResponse>(pkt);
+
+ if (!register_notification->IsValid()) {
+ DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+ auto response =
+ RejectBuilder::MakeBuilder(pkt->GetCommandPdu(),
+ Status::INVALID_PARAMETER);
+ send_message(label, false, std::move(response));
+ active_labels_.erase(label);
+ volume_interface_ = nullptr;
+ volume_ = VOL_REGISTRATION_FAILED;
+ return;
+ }
+
if (register_notification->GetEvent() != Event::VOLUME_CHANGED) {
DEVICE_LOG(WARNING)
<< __func__ << ": Unhandled register notification received: "
@@ -336,16 +349,6 @@ void Device::HandleVolumeChanged(
uint8_t label, const std::shared_ptr<RegisterNotificationResponse>& pkt) {
DEVICE_VLOG(1) << __func__ << ": interim=" << pkt->IsInterim();
- if (!pkt->IsValid()) {
- DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
- auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
- send_message(label, false, std::move(response));
- active_labels_.erase(label);
- volume_interface_ = nullptr;
- volume_ = VOL_REGISTRATION_FAILED;
- return;
- }
-
if (volume_interface_ == nullptr) return;
if (pkt->GetCType() == CType::REJECTED) {
diff --git a/stack/Android.bp b/stack/Android.bp
index 4863afbce..f9d11e21d 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -200,6 +200,7 @@ cc_test {
],
srcs: [
"test/stack_a2dp_test.cc",
+ "test/stack_avrcp_test.cc",
],
shared_libs: [
"libcrypto",
@@ -446,36 +447,3 @@ cc_test {
cfi: false,
},
}
-
-cc_test {
- name: "net_test_stack_a2dp_native",
- defaults: ["fluoride_defaults"],
- test_suites: ["device-tests"],
- host_supported: true,
- include_dirs: [
- "external/libldac/inc",
- "system/bt",
- "system/bt/stack/include",
- ],
- srcs: [
- "test/a2dp/a2dp_vendor_ldac_decoder_test.cc",
- "test/a2dp/misc_fake.cc",
- ],
- shared_libs: [
- "libcrypto",
- "libcutils",
- "libprotobuf-cpp-lite",
- ],
- static_libs: [
- "libbt-common",
- "libbt-protos-lite",
- "liblog",
- "libosi",
- "libosi-AllocationTestHarness",
- ],
- sanitize: {
- address: true,
- cfi: true,
- misc_undefined: ["bounds"],
- },
-}
diff --git a/stack/BUILD.gn b/stack/BUILD.gn
index 00680c85e..87dc72639 100644
--- a/stack/BUILD.gn
+++ b/stack/BUILD.gn
@@ -202,6 +202,7 @@ executable("stack_unittests") {
testonly = true
sources = [
"test/stack_a2dp_test.cc",
+ "test/stack_avrcp_test.cc",
]
include_dirs = [
diff --git a/stack/a2dp/a2dp_vendor_ldac_decoder.cc b/stack/a2dp/a2dp_vendor_ldac_decoder.cc
index d49337a98..444af3426 100644
--- a/stack/a2dp/a2dp_vendor_ldac_decoder.cc
+++ b/stack/a2dp/a2dp_vendor_ldac_decoder.cc
@@ -217,20 +217,11 @@ void a2dp_vendor_ldac_decoder_cleanup(void) {
}
bool a2dp_vendor_ldac_decoder_decode_packet(BT_HDR* p_buf) {
- if (p_buf == nullptr) {
- LOG_ERROR(LOG_TAG, "%s Dropping packet with nullptr", __func__);
- return false;
- }
unsigned char* pBuffer =
reinterpret_cast<unsigned char*>(p_buf->data + p_buf->offset);
// unsigned int bufferSize = p_buf->len;
unsigned int bytesValid = p_buf->len;
int err;
- if (bytesValid == 0) {
- LOG_WARN(LOG_TAG, "%s Dropping packet with zero length", __func__);
- return false;
- }
-
LDACBT_SMPL_FMT_T fmt;
int bs_bytes, used_bytes, wrote_bytes, frame_number;
diff --git a/stack/avdt/avdt_msg.cc b/stack/avdt/avdt_msg.cc
index 853f36985..33fbfa744 100644
--- a/stack/avdt/avdt_msg.cc
+++ b/stack/avdt/avdt_msg.cc
@@ -985,18 +985,30 @@ static uint8_t avdt_msg_prs_security_rsp(tAVDT_MSG* p_msg, uint8_t* p,
* Returns Error code or zero if no error.
*
******************************************************************************/
-static uint8_t avdt_msg_prs_rej(tAVDT_MSG* p_msg, uint8_t* p, uint8_t sig) {
- if ((sig == AVDT_SIG_SETCONFIG) || (sig == AVDT_SIG_RECONFIG)) {
- p_msg->hdr.err_param = *p++;
- p_msg->hdr.err_code = *p;
- } else if ((sig == AVDT_SIG_START) || (sig == AVDT_SIG_SUSPEND)) {
- AVDT_MSG_PRS_SEID(p, p_msg->hdr.err_param);
- p_msg->hdr.err_code = *p;
+static uint8_t avdt_msg_prs_rej(tAVDT_MSG* p_msg, uint8_t* p, uint16_t len,
+ uint8_t sig) {
+ uint8_t error = 0;
+
+ if (len > 0) {
+ if ((sig == AVDT_SIG_SETCONFIG) || (sig == AVDT_SIG_RECONFIG)) {
+ p_msg->hdr.err_param = *p++;
+ len--;
+ } else if ((sig == AVDT_SIG_START) || (sig == AVDT_SIG_SUSPEND)) {
+ AVDT_MSG_PRS_SEID(p, p_msg->hdr.err_param);
+ len--;
+ }
+ }
+
+ if (len < 1) {
+ char error_info[] = "AVDT rejected response length mismatch";
+ android_errorWriteWithInfoLog(0x534e4554, "79702484", -1, error_info,
+ strlen(error_info));
+ error = AVDT_ERR_LENGTH;
} else {
p_msg->hdr.err_code = *p;
}
- return 0;
+ return error;
}
/*******************************************************************************
@@ -1604,7 +1616,7 @@ void avdt_msg_ind(AvdtpCcb* p_ccb, BT_HDR* p_buf) {
evt = avdt_msg_rsp_2_evt[sig - 1];
} else /* msg_type == AVDT_MSG_TYPE_REJ */
{
- err = avdt_msg_prs_rej(&msg, p, sig);
+ err = avdt_msg_prs_rej(&msg, p, p_buf->len, sig);
evt = avdt_msg_rej_2_evt[sig - 1];
}
diff --git a/stack/avrc/avrc_pars_ct.cc b/stack/avrc/avrc_pars_ct.cc
index 80dc882da..39ed921d9 100644
--- a/stack/avrc/avrc_pars_ct.cc
+++ b/stack/avrc/avrc_pars_ct.cc
@@ -806,7 +806,7 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg,
if (len < min_len) goto length_error;
BE_STREAM_TO_UINT32(p_result->get_play_status.song_len, p);
BE_STREAM_TO_UINT32(p_result->get_play_status.song_pos, p);
- BE_STREAM_TO_UINT8(p_result->get_play_status.status, p);
+ BE_STREAM_TO_UINT8(p_result->get_play_status.play_status, p);
break;
case AVRC_PDU_SET_ADDRESSED_PLAYER:
diff --git a/stack/avrc/avrc_pars_tg.cc b/stack/avrc/avrc_pars_tg.cc
index 22471bda5..fe1db3dbc 100644
--- a/stack/avrc/avrc_pars_tg.cc
+++ b/stack/avrc/avrc_pars_tg.cc
@@ -363,7 +363,7 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg,
*
* Description This function is used to parse cmds received for CTRL
* Currently it is for SetAbsVolume and Volume Change
- * Notification..
+ * Notification.
*
* Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
* successfully.
@@ -390,6 +390,12 @@ tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) {
return status;
}
+#define RETURN_STATUS_IF_FALSE(_status_, _b_, _msg_, ...) \
+ if (!(_b_)) { \
+ AVRC_TRACE_DEBUG(_msg_, ##__VA_ARGS__); \
+ return _status_; \
+ }
+
/*******************************************************************************
*
* Function avrc_pars_browsing_cmd
@@ -409,6 +415,10 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
uint8_t* p = p_msg->p_browse_data;
int count;
+ uint16_t min_len = 3;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
p_result->pdu = *p++;
AVRC_TRACE_DEBUG("avrc_pars_browsing_cmd() pdu:0x%x", p_result->pdu);
/* skip over len */
@@ -416,11 +426,20 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
switch (p_result->pdu) {
case AVRC_PDU_SET_BROWSED_PLAYER: /* 0x70 */
+ min_len += 2;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
// For current implementation all players are browsable.
BE_STREAM_TO_UINT16(p_result->br_player.player_id, p);
break;
case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */
+
+ min_len += 10;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
STREAM_TO_UINT8(p_result->get_items.scope, p);
// To be modified later here (Scope) when all browsing commands are
// supported
@@ -441,12 +460,21 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
if (buf_len < (count << 2))
p_result->get_items.attr_count = count = (buf_len >> 2);
for (int idx = 0; idx < count; idx++) {
+ min_len += 4;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD,
+ (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT32(p_result->get_items.p_attr_list[idx], p);
}
}
break;
case AVRC_PDU_CHANGE_PATH: /* 0x72 */
+ min_len += 11;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT16(p_result->chg_path.uid_counter, p);
BE_STREAM_TO_UINT8(p_result->chg_path.direction, p);
if (p_result->chg_path.direction != AVRC_DIR_UP &&
@@ -457,7 +485,12 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
break;
case AVRC_PDU_GET_ITEM_ATTRIBUTES: /* 0x73 */
+ min_len += 12;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT8(p_result->get_attrs.scope, p);
+
if (p_result->get_attrs.scope > AVRC_SCOPE_NOW_PLAYING) {
status = AVRC_STS_BAD_SCOPE;
break;
@@ -473,6 +506,11 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
p_result->get_attrs.attr_count = count = (buf_len >> 2);
for (int idx = 0, count = 0; idx < p_result->get_attrs.attr_count;
idx++) {
+ min_len += 4;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD,
+ (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT32(p_result->get_attrs.p_attr_list[count], p);
if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(
p_result->get_attrs.p_attr_list[count])) {
@@ -488,6 +526,10 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
break;
case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS: /* 0x75 */
+ ++min_len;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT8(p_result->get_num_of_items.scope, p);
if (p_result->get_num_of_items.scope > AVRC_SCOPE_NOW_PLAYING) {
status = AVRC_STS_BAD_SCOPE;
@@ -495,6 +537,10 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
break;
case AVRC_PDU_SEARCH: /* 0x80 */
+ min_len += 4;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT16(p_result->search.string.charset_id, p);
BE_STREAM_TO_UINT16(p_result->search.string.str_len, p);
p_result->search.string.p_str = p_buf;
@@ -504,6 +550,10 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
} else {
android_errorWriteLog(0x534e4554, "63146237");
}
+ min_len += p_result->search.string.str_len;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_ARRAY(p, p_buf, p_result->search.string.str_len);
} else {
status = AVRC_STS_INTERNAL_ERR;
diff --git a/stack/btm/btm_acl.cc b/stack/btm/btm_acl.cc
index 694577d0e..6daf2d23c 100644
--- a/stack/btm/btm_acl.cc
+++ b/stack/btm/btm_acl.cc
@@ -825,7 +825,8 @@ void btm_use_preferred_conn_params(const RawAddress& bda) {
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
/* If there are any preferred connection parameters, set them now */
- if ((p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN) &&
+ if ((p_lcb != NULL) && (p_dev_rec != NULL) &&
+ (p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN) &&
(p_dev_rec->conn_params.min_conn_int <= BTM_BLE_CONN_INT_MAX) &&
(p_dev_rec->conn_params.max_conn_int >= BTM_BLE_CONN_INT_MIN) &&
(p_dev_rec->conn_params.max_conn_int <= BTM_BLE_CONN_INT_MAX) &&
diff --git a/stack/btm/btm_ble_batchscan.cc b/stack/btm/btm_ble_batchscan.cc
index 89b3e6c55..db8282995 100644
--- a/stack/btm/btm_ble_batchscan.cc
+++ b/stack/btm/btm_ble_batchscan.cc
@@ -63,6 +63,7 @@ void btm_ble_batchscan_filter_track_adv_vse_cback(uint8_t len, uint8_t* p) {
uint8_t sub_event = 0;
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+ if (len == 0) return;
STREAM_TO_UINT8(sub_event, p);
BTM_TRACE_EVENT(
@@ -90,6 +91,7 @@ void btm_ble_batchscan_filter_track_adv_vse_cback(uint8_t len, uint8_t* p) {
/* Extract the adv info details */
if (ADV_INFO_PRESENT == adv_data.advertiser_info_present) {
+ if (len < 15) return;
STREAM_TO_UINT8(adv_data.tx_power, p);
STREAM_TO_UINT8(adv_data.rssi_value, p);
STREAM_TO_UINT16(adv_data.time_stamp, p);
diff --git a/stack/btm/btm_ble_bgconn.cc b/stack/btm/btm_ble_bgconn.cc
index 73256c883..209f49fe5 100644
--- a/stack/btm/btm_ble_bgconn.cc
+++ b/stack/btm/btm_ble_bgconn.cc
@@ -39,6 +39,7 @@ extern void btm_send_hci_create_connection(
uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len,
uint8_t phy);
extern void btm_ble_create_conn_cancel();
+void wl_remove_complete(uint8_t* p_data, uint16_t /* evt_len */);
// Unfortunately (for now?) we have to maintain a copy of the device whitelist
// on the host to determine if a device is pending to be connected or not. This
@@ -72,7 +73,14 @@ static void background_connection_add(uint8_t addr_type,
BackgroundConnection{address, addr_type, false, 0, false};
} else {
BackgroundConnection* connection = &map_iter->second;
- connection->addr_type = addr_type;
+ if (addr_type != connection->addr_type) {
+ LOG(INFO) << __func__ << " Addr type mismatch " << address;
+ btsnd_hcic_ble_remove_from_white_list(
+ connection->addr_type_in_wl, connection->address,
+ base::Bind(&wl_remove_complete));
+ connection->addr_type = addr_type;
+ connection->in_controller_wl = false;
+ }
connection->pending_removal = false;
}
}
@@ -170,8 +178,7 @@ bool BTM_BackgroundConnectAddressKnown(const RawAddress& address) {
return true;
// bonded device with identity address known
- if (p_dev_rec->ble.identity_addr != address &&
- !p_dev_rec->ble.identity_addr.IsEmpty()) {
+ if (!p_dev_rec->ble.identity_addr.IsEmpty()) {
return true;
}
@@ -197,8 +204,7 @@ bool btm_add_dev_to_controller(bool to_add, const RawAddress& bd_addr) {
if (p_dev_rec != NULL && p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) {
if (to_add) {
- if (p_dev_rec->ble.identity_addr != bd_addr &&
- !p_dev_rec->ble.identity_addr.IsEmpty()) {
+ if (!p_dev_rec->ble.identity_addr.IsEmpty()) {
background_connection_add(p_dev_rec->ble.identity_addr_type,
p_dev_rec->ble.identity_addr);
} else {
@@ -212,8 +218,7 @@ bool btm_add_dev_to_controller(bool to_add, const RawAddress& bd_addr) {
p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
} else {
- if (!p_dev_rec->ble.identity_addr.IsEmpty() &&
- p_dev_rec->ble.identity_addr != bd_addr) {
+ if (!p_dev_rec->ble.identity_addr.IsEmpty()) {
background_connection_remove(p_dev_rec->ble.identity_addr);
} else {
background_connection_remove(bd_addr);
diff --git a/stack/btm/btm_ble_connection_establishment.cc b/stack/btm/btm_ble_connection_establishment.cc
index c0d77911e..77bc00f0e 100644
--- a/stack/btm/btm_ble_connection_establishment.cc
+++ b/stack/btm/btm_ble_connection_establishment.cc
@@ -159,6 +159,7 @@ void btm_ble_conn_complete(uint8_t* p, UNUSED_ATTR uint16_t evt_len,
if (!btm_ble_init_pseudo_addr(match_rec, bda)) {
/* assign the original address to be the current report address */
bda = match_rec->ble.pseudo_addr;
+ bda_type = match_rec->ble.ble_addr_type;
} else {
bda = match_rec->bd_addr;
}
diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc
index c46acf0d3..05cac15b4 100644
--- a/stack/btm/btm_ble_gap.cc
+++ b/stack/btm/btm_ble_gap.cc
@@ -1755,6 +1755,7 @@ void btm_ble_process_adv_addr(RawAddress& bda, uint8_t* addr_type) {
} else {
// Assign the original address to be the current report address
bda = match_rec->ble.pseudo_addr;
+ *addr_type = match_rec->ble.ble_addr_type;
}
}
}
diff --git a/stack/btm/btm_ble_multi_adv.cc b/stack/btm/btm_ble_multi_adv.cc
index 22d2e176a..b425c0927 100644
--- a/stack/btm/btm_ble_multi_adv.cc
+++ b/stack/btm/btm_ble_multi_adv.cc
@@ -728,16 +728,13 @@ class BleAdvertisingManagerImpl
data.insert(data.begin(), flags.begin(), flags.end());
}
- // Find and fill TX Power with the correct value
- if (data.size()) {
- size_t i = 0;
- while (i < data.size()) {
- uint8_t type = data[i + 1];
- if (type == HCI_EIR_TX_POWER_LEVEL_TYPE) {
- data[i + 2] = adv_inst[inst_id].tx_power;
- }
- i += data[i] + 1;
+ // Find and fill TX Power with the correct value.
+ // The TX Power section is a 3 byte section.
+ for (size_t i = 0; (i + 2) < data.size();) {
+ if (data[i + 1] == HCI_EIR_TX_POWER_LEVEL_TYPE) {
+ data[i + 2] = adv_inst[inst_id].tx_power;
}
+ i += data[i] + 1;
}
VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size());
diff --git a/stack/btm/btm_inq.cc b/stack/btm/btm_inq.cc
index 1a5d7f526..f56369b4b 100644
--- a/stack/btm/btm_inq.cc
+++ b/stack/btm/btm_inq.cc
@@ -25,6 +25,7 @@
*
******************************************************************************/
+#include <log/log.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -914,10 +915,9 @@ tBTM_STATUS BTM_CancelRemoteDeviceName(void) {
/* Make sure there is not already one in progress */
if (p_inq->remname_active) {
if (BTM_UseLeLink(p_inq->remname_bda)) {
- if (btm_ble_cancel_remote_name(p_inq->remname_bda))
- return (BTM_CMD_STARTED);
- else
- return (BTM_UNKNOWN_ADDR);
+ /* Cancel remote name request for LE device, and process remote name
+ * callback. */
+ btm_inq_rmt_name_failed_cancelled();
} else
btsnd_hcic_rmt_name_req_cancel(p_inq->remname_bda);
return (BTM_CMD_STARTED);
@@ -1602,7 +1602,8 @@ static void btm_initiate_inquiry(tBTM_INQUIRY_VAR_ST* p_inq) {
* Returns void
*
******************************************************************************/
-void btm_process_inq_results(uint8_t* p, uint8_t inq_res_mode) {
+void btm_process_inq_results(uint8_t* p, uint8_t hci_evt_len,
+ uint8_t inq_res_mode) {
uint8_t num_resp, xx;
RawAddress bda;
tINQ_DB_ENT* p_i;
@@ -1631,10 +1632,29 @@ void btm_process_inq_results(uint8_t* p, uint8_t inq_res_mode) {
STREAM_TO_UINT8(num_resp, p);
- if (inq_res_mode == BTM_INQ_RESULT_EXTENDED && (num_resp > 1)) {
- BTM_TRACE_ERROR("btm_process_inq_results() extended results (%d) > 1",
- num_resp);
- return;
+ if (inq_res_mode == BTM_INQ_RESULT_EXTENDED) {
+ if (num_resp > 1) {
+ BTM_TRACE_ERROR("btm_process_inq_results() extended results (%d) > 1",
+ num_resp);
+ return;
+ }
+
+ constexpr uint16_t extended_inquiry_result_size = 254;
+ if (hci_evt_len - 1 != extended_inquiry_result_size) {
+ android_errorWriteLog(0x534e4554, "141620271");
+ BTM_TRACE_ERROR("%s: can't fit %d results in %d bytes", __func__,
+ num_resp, hci_evt_len);
+ return;
+ }
+ } else if (inq_res_mode == BTM_INQ_RESULT_STANDARD ||
+ inq_res_mode == BTM_INQ_RESULT_WITH_RSSI) {
+ constexpr uint16_t inquiry_result_size = 14;
+ if (hci_evt_len < num_resp * inquiry_result_size) {
+ android_errorWriteLog(0x534e4554, "141620271");
+ BTM_TRACE_ERROR("%s: can't fit %d results in %d bytes", __func__,
+ num_resp, hci_evt_len);
+ return;
+ }
}
for (xx = 0; xx < num_resp; xx++) {
@@ -2070,22 +2090,22 @@ void btm_process_remote_name(const RawAddress* bda, BD_NAME bdn,
}
void btm_inq_remote_name_timer_timeout(UNUSED_ATTR void* data) {
- btm_inq_rmt_name_failed();
+ btm_inq_rmt_name_failed_cancelled();
}
/*******************************************************************************
*
- * Function btm_inq_rmt_name_failed
+ * Function btm_inq_rmt_name_failed_cancelled
*
- * Description This function is if timeout expires while getting remote
- * name. This is done for devices that incorrectly do not
- * report operation failure
+ * Description This function is if timeout expires or request is cancelled
+ * while getting remote name. This is done for devices that
+ * incorrectly do not report operation failure
*
* Returns void
*
******************************************************************************/
-void btm_inq_rmt_name_failed(void) {
- BTM_TRACE_ERROR("btm_inq_rmt_name_failed() remname_active=%d",
+void btm_inq_rmt_name_failed_cancelled(void) {
+ BTM_TRACE_ERROR("btm_inq_rmt_name_failed_cancelled() remname_active=%d",
btm_cb.btm_inq_vars.remname_active);
if (btm_cb.btm_inq_vars.remname_active)
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
index ee1d6554a..05180db5e 100644
--- a/stack/btm/btm_int.h
+++ b/stack/btm/btm_int.h
@@ -59,13 +59,14 @@ extern tBTM_STATUS btm_initiate_rem_name(const RawAddress& remote_bda,
extern void btm_process_remote_name(const RawAddress* bda, BD_NAME name,
uint16_t evt_len, uint8_t hci_status);
-extern void btm_inq_rmt_name_failed(void);
+extern void btm_inq_rmt_name_failed_cancelled(void);
extern void btm_inq_remote_name_timer_timeout(void* data);
/* Inquiry related functions */
extern void btm_clr_inq_db(const RawAddress* p_bda);
extern void btm_inq_db_init(void);
-extern void btm_process_inq_results(uint8_t* p, uint8_t inq_res_mode);
+extern void btm_process_inq_results(uint8_t* p, uint8_t hci_evt_len,
+ uint8_t inq_res_mode);
extern void btm_process_inq_complete(uint8_t status, uint8_t mode);
extern void btm_process_cancel_complete(uint8_t status, uint8_t mode);
extern void btm_event_filter_complete(uint8_t* p);
diff --git a/stack/btm/btm_sec.cc b/stack/btm/btm_sec.cc
index ad3763f92..32e4b4e82 100644
--- a/stack/btm/btm_sec.cc
+++ b/stack/btm/btm_sec.cc
@@ -4313,12 +4313,15 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, uint8_t status,
}
}
- if (!addr_matched) {
- /* Don't callback unless this Connection-Complete-failure event has the
- * same mac address as the bonding device */
+ /* p_auth_complete_callback might have freed the p_dev_rec, ensure it exists
+ * before accessing */
+ p_dev_rec = btm_find_dev(bda);
+ if (!p_dev_rec) {
+ /* Don't callback when device security record was removed */
VLOG(1) << __func__
- << ": Different mac addresses: pairing_bda=" << btm_cb.pairing_bda
- << ", bda=" << bda << ", do not callback";
+ << ": device security record associated with this bda has been "
+ "removed! bda="
+ << bda << ", do not callback!";
return;
}
diff --git a/stack/btu/btu_hcif.cc b/stack/btu/btu_hcif.cc
index c70448e81..52d5d60f8 100644
--- a/stack/btu/btu_hcif.cc
+++ b/stack/btu/btu_hcif.cc
@@ -48,6 +48,7 @@
#include "btu.h"
#include "common/metrics.h"
#include "device/include/controller.h"
+#include "hci_evt_length.h"
#include "hci_layer.h"
#include "hcimsgs.h"
#include "l2c_int.h"
@@ -64,11 +65,12 @@ extern void smp_cancel_start_encryption_attempt();
/* L O C A L F U N C T I O N P R O T O T Y P E S */
/******************************************************************************/
static void btu_hcif_inquiry_comp_evt(uint8_t* p);
-static void btu_hcif_inquiry_result_evt(uint8_t* p);
-static void btu_hcif_inquiry_rssi_result_evt(uint8_t* p);
-static void btu_hcif_extended_inquiry_result_evt(uint8_t* p);
+static void btu_hcif_inquiry_result_evt(uint8_t* p, uint8_t hci_evt_len);
+static void btu_hcif_inquiry_rssi_result_evt(uint8_t* p, uint8_t hci_evt_len);
+static void btu_hcif_extended_inquiry_result_evt(uint8_t* p,
+ uint8_t hci_evt_len);
-static void btu_hcif_connection_comp_evt(uint8_t* p);
+static void btu_hcif_connection_comp_evt(uint8_t* p, uint8_t evt_len);
static void btu_hcif_connection_request_evt(uint8_t* p);
static void btu_hcif_disconnection_comp_evt(uint8_t* p);
static void btu_hcif_authentication_comp_evt(uint8_t* p);
@@ -85,7 +87,7 @@ static void btu_hcif_command_status_evt(uint8_t status, BT_HDR* command,
static void btu_hcif_hardware_error_evt(uint8_t* p);
static void btu_hcif_flush_occured_evt(void);
static void btu_hcif_role_change_evt(uint8_t* p);
-static void btu_hcif_num_compl_data_pkts_evt(uint8_t* p);
+static void btu_hcif_num_compl_data_pkts_evt(uint8_t* p, uint8_t evt_len);
static void btu_hcif_mode_change_evt(uint8_t* p);
static void btu_hcif_pin_code_request_evt(uint8_t* p);
static void btu_hcif_link_key_request_evt(uint8_t* p);
@@ -256,6 +258,13 @@ void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_msg) {
STREAM_TO_UINT8(hci_evt_code, p);
STREAM_TO_UINT8(hci_evt_len, p);
+ // validate event size
+ if (hci_evt_len < hci_event_parameters_minimum_length[hci_evt_code]) {
+ HCI_TRACE_WARNING("%s: evt:0x%2X, malformed event of size %hhd", __func__,
+ hci_evt_code, hci_evt_len);
+ return;
+ }
+
btu_hcif_log_event_metrics(hci_evt_code, p);
switch (hci_evt_code) {
@@ -263,16 +272,16 @@ void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_msg) {
btu_hcif_inquiry_comp_evt(p);
break;
case HCI_INQUIRY_RESULT_EVT:
- btu_hcif_inquiry_result_evt(p);
+ btu_hcif_inquiry_result_evt(p, hci_evt_len);
break;
case HCI_INQUIRY_RSSI_RESULT_EVT:
- btu_hcif_inquiry_rssi_result_evt(p);
+ btu_hcif_inquiry_rssi_result_evt(p, hci_evt_len);
break;
case HCI_EXTENDED_INQUIRY_RESULT_EVT:
- btu_hcif_extended_inquiry_result_evt(p);
+ btu_hcif_extended_inquiry_result_evt(p, hci_evt_len);
break;
case HCI_CONNECTION_COMP_EVT:
- btu_hcif_connection_comp_evt(p);
+ btu_hcif_connection_comp_evt(p, hci_evt_len);
break;
case HCI_CONNECTION_REQUEST_EVT:
btu_hcif_connection_request_evt(p);
@@ -326,7 +335,7 @@ void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_msg) {
btu_hcif_role_change_evt(p);
break;
case HCI_NUM_COMPL_DATA_PKTS_EVT:
- btu_hcif_num_compl_data_pkts_evt(p);
+ btu_hcif_num_compl_data_pkts_evt(p, hci_evt_len);
break;
case HCI_MODE_CHANGE_EVT:
btu_hcif_mode_change_evt(p);
@@ -948,9 +957,9 @@ static void btu_hcif_inquiry_comp_evt(uint8_t* p) {
* Returns void
*
******************************************************************************/
-static void btu_hcif_inquiry_result_evt(uint8_t* p) {
+static void btu_hcif_inquiry_result_evt(uint8_t* p, uint8_t hci_evt_len) {
/* Store results in the cache */
- btm_process_inq_results(p, BTM_INQ_RESULT_STANDARD);
+ btm_process_inq_results(p, hci_evt_len, BTM_INQ_RESULT_STANDARD);
}
/*******************************************************************************
@@ -962,9 +971,9 @@ static void btu_hcif_inquiry_result_evt(uint8_t* p) {
* Returns void
*
******************************************************************************/
-static void btu_hcif_inquiry_rssi_result_evt(uint8_t* p) {
+static void btu_hcif_inquiry_rssi_result_evt(uint8_t* p, uint8_t hci_evt_len) {
/* Store results in the cache */
- btm_process_inq_results(p, BTM_INQ_RESULT_WITH_RSSI);
+ btm_process_inq_results(p, hci_evt_len, BTM_INQ_RESULT_WITH_RSSI);
}
/*******************************************************************************
@@ -976,9 +985,10 @@ static void btu_hcif_inquiry_rssi_result_evt(uint8_t* p) {
* Returns void
*
******************************************************************************/
-static void btu_hcif_extended_inquiry_result_evt(uint8_t* p) {
+static void btu_hcif_extended_inquiry_result_evt(uint8_t* p,
+ uint8_t hci_evt_len) {
/* Store results in the cache */
- btm_process_inq_results(p, BTM_INQ_RESULT_EXTENDED);
+ btm_process_inq_results(p, hci_evt_len, BTM_INQ_RESULT_EXTENDED);
}
/*******************************************************************************
@@ -990,7 +1000,7 @@ static void btu_hcif_extended_inquiry_result_evt(uint8_t* p) {
* Returns void
*
******************************************************************************/
-static void btu_hcif_connection_comp_evt(uint8_t* p) {
+static void btu_hcif_connection_comp_evt(uint8_t* p, uint8_t evt_len) {
uint8_t status;
uint16_t handle;
RawAddress bda;
@@ -998,6 +1008,12 @@ static void btu_hcif_connection_comp_evt(uint8_t* p) {
uint8_t enc_mode;
tBTM_ESCO_DATA esco_data;
+ if (evt_len < 11) {
+ android_errorWriteLog(0x534e4554, "141619686");
+ HCI_TRACE_WARNING("%s: malformed event of size %hhd", __func__, evt_len);
+ return;
+ }
+
STREAM_TO_UINT8(status, p);
STREAM_TO_UINT16(handle, p);
STREAM_TO_BDADDR(bda, p);
@@ -1699,9 +1715,9 @@ static void btu_hcif_role_change_evt(uint8_t* p) {
* Returns void
*
******************************************************************************/
-static void btu_hcif_num_compl_data_pkts_evt(uint8_t* p) {
+static void btu_hcif_num_compl_data_pkts_evt(uint8_t* p, uint8_t evt_len) {
/* Process for L2CAP and SCO */
- l2c_link_process_num_completed_pkts(p);
+ l2c_link_process_num_completed_pkts(p, evt_len);
/* Send on to SCO */
/*?? No SCO for now */
diff --git a/stack/gatt/gatt_main.cc b/stack/gatt/gatt_main.cc
index 87f9c87f7..ed8d3fd11 100644
--- a/stack/gatt/gatt_main.cc
+++ b/stack/gatt/gatt_main.cc
@@ -823,6 +823,9 @@ static void gatt_send_conn_cback(tGATT_TCB* p_tcb) {
}
}
+ /* Remove the direct connection */
+ connection_manager::on_connection_complete(p_tcb->peer_bda);
+
if (!p_tcb->app_hold_link.empty() && p_tcb->att_lcid == L2CAP_ATT_CID) {
/* disable idle timeout if one or more clients are holding the link disable
* the idle timer */
diff --git a/stack/include/hci_evt_length.h b/stack/include/hci_evt_length.h
new file mode 100644
index 000000000..ea8dfdff1
--- /dev/null
+++ b/stack/include/hci_evt_length.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Definitions for HCI Event Parameter Minimum Length
+ */
+static const uint8_t hci_event_parameters_minimum_length[] = {
+ 0, // 0x00 - N/A
+ 1, // 0x01 - HCI_Inquiry_Complete Event
+ 15, // 0x02 - HCI_Inquiry_Result Event (Num_Responses = 1)
+ 11, // 0x03 - HCI_Connection_Complete Event
+ 10, // 0x04 - HCI_Connection_Request Event
+ 4, // 0x05 - HCI_Disconnection_Complete Event
+ 3, // 0x06 - HCI_Authentication_Complete Event
+ 255, // 0x07 - HCI_Remote_Name_Request_Complete Event
+ 4, // 0x08 - HCI_Encryption_Change Event
+ 3, // 0x09 - HCI_Change_Connection_Link_Key_Complete Event
+ 4, // 0x0A - HCI_Master_Link_Key_Complete Event
+ 11, // 0x0B - HCI_Read_Remote_Supported_Features_Complete Event
+ 8, // 0x0C - HCI_Read_Remote_Version_Information_Complete Event
+ 21, // 0x0D - HCI_QoS_Setup_Complete Event
+ 3, // 0x0E - HCI_Command_Complete Event (Depends on command)
+ 4, // 0x0F - HCI_Command_Status Event
+ 1, // 0x10 - HCI_Hardware_Error Event
+ 2, // 0x11 - HCI_Flush_Occurred Event
+ 8, // 0x12 - HCI_Role_Change Event
+ 5, // 0x13 - HCI_Number_Of_Completed_Packets Event (Num_Handles = 1)
+ 6, // 0x14 - HCI_Mode_Change Event
+ 23, // 0x15 - HCI_Return_Link_Keys Event (Num_Keys = 1)
+ 6, // 0x16 - HCI_PIN_Code_Request Event
+ 6, // 0x17 - HCI_Link_Key_Request Event
+ 23, // 0x18 - HCI_Link_Key_Notification Event
+ 3, // 0x19 - HCI_Loopback_Command Event (Depends on command)
+ 1, // 0x1A - HCI_Data_Buffer_Overflow Event
+ 3, // 0x1B - HCI_Max_Slots_Change Event
+ 5, // 0x1C - HCI_Read_Clock_Offset_Complete Event
+ 5, // 0x1D - HCI_Connection_Packet_Type_Changed Event
+ 2, // 0x1E - HCI_QoS_Violation Event
+ 7, // 0x1F - HCI_Page_Scan_Mode_Change Event (Deprecated)
+ 7, // 0x20 - HCI_Page_Scan_Repetition_Mode_Change Event
+ 22, // 0x21 - HCI_Flow_Specification_Complet Event
+ 15, // 0x22 - HCI_Inquiry_Result_with_RSSI Event (Num_Responses = 1)
+ 13, // 0x23 - HCI_Read_Remote_Extended_Features_Complete Event
+ 0, // 0x24 - N/A
+ 0, // 0x25 - N/A
+ 0, // 0x26 - N/A
+ 0, // 0x27 - N/A
+ 0, // 0x28 - N/A
+ 0, // 0x29 - N/A
+ 0, // 0x2A - N/A
+ 0, // 0x2B - N/A
+ 17, // 0x2C - HCI_Synchronous_Connection_Complete Event
+ 9, // 0x2D - HCI_Synchronous_Connection_Changed Event
+ 11, // 0x2E - HCI_Sniff_Subrating Event
+ 255, // 0x2F - HCI_Extended_Inquiry_Result Event
+ 3, // 0x30 - HCI_Encryption_Key_Refresh_Complete Event
+ 6, // 0x31 - HCI_IO_Capability_Request Event
+ 9, // 0x32 - HCI_IO_Capability_Response Event
+ 10, // 0x33 - HCI_User_Confirmation_Request Event
+ 6, // 0x34 - HCI_User_Passkey_Request Event
+ 6, // 0x35 - HCI_Remote_OOB_Data_Request Event
+ 7, // 0x36 - HCI_Simple_Pairing_Complete Event
+ 0, // 0x37 - N/A
+ 4, // 0x38 - HCI_Link_Supervision_Timeout_Changed Event
+ 2, // 0x39 - HCI_Enhanced_Flush_Complete Event
+ 0, // 0x3A - N/A
+ 10, // 0x3B - HCI_User_Passkey_Notification Event
+ 7, // 0x3C - HCI_Keypress_Notification Event
+ 14, // 0x3D - HCI_Remote_Host_Supported_Features_Notification Event
+ 0, // 0x3E - LE Meta event
+ 0, // 0x3F - N/A
+ 2, // 0x40 - HCI_Physical_Link_Complete Event
+ 1, // 0x41 - HCI_Channel_Selected Event
+ 3, // 0x42 - HCI_Disconnection_Physical_Link_Complete Event
+ 2, // 0x43 - HCI_Physical_Link_Loss_Early_Warning Event
+ 1, // 0x44 - HCI_Physical_Link_Recovery Event
+ 5, // 0x45 - HCI_Logical_Link_Complete Event
+ 4, // 0x46 - HCI_Disconnection_Logical_Link_Complete Event
+ 3, // 0x47 - HCI_Flow_Spec_Modify_Complete Event
+ 9, // 0x48 - HCI_Number_Of_Completed_Data_Blocks Event (Num_Handles = 1)
+ 2, // 0x49 - HCI_AMP_Start_Test Event
+ 2, // 0x4A - HCI_AMP_Test_End Event
+ 18, // 0x4B - HCI_AMP_Receiver_Report Event
+ 3, // 0x4C - HCI_Short_Range_Mode_Change_Complete Event
+ 2, // 0x4D - HCI_AMP_Status_Change Event
+ 9, // 0x4E - HCI_Triggered_Clock_Capture Event
+ 1, // 0x4F - HCI_Synchronization_Train_Complete Event
+ 29, // 0x50 - HCI_Synchronization_Train_Received Event
+ 18, // 0x51 - HCI_Connectionless_Slave_Broadcast_Receive Event
+ // (Data_Length = 0)
+ 7, // 0x52 - HCI_Connectionless_Slave_Broadcast_Timeout Event
+ 7, // 0x53 - HCI_Truncated_Page_Complete Event
+ 0, // 0x54 - HCI_Slave_Page_Response_Timeout Event
+ 10, // 0x55 - HCI_Connectionless_Slave_Broadcast_Channel_Map_Change Event
+ 4, // 0x56 - HCI_Inquiry_Response_Notification Event
+ 2, // 0x57 - HCI_Authenticated_Payload_Timeout_Expired Event
+ 8, // 0x58 - HCI_SAM_Status_Change Event
+ 0, // 0x59 - N/A
+ 0, // 0x5A - N/A
+ 0, // 0x5B - N/A
+ 0, // 0x5C - N/A
+ 0, // 0x5D - N/A
+ 0, // 0x5E - N/A
+ 0, // 0x5F - N/A
+ 0, // 0x60 - N/A
+ 0, // 0x61 - N/A
+ 0, // 0x62 - N/A
+ 0, // 0x63 - N/A
+ 0, // 0x64 - N/A
+ 0, // 0x65 - N/A
+ 0, // 0x66 - N/A
+ 0, // 0x67 - N/A
+ 0, // 0x68 - N/A
+ 0, // 0x69 - N/A
+ 0, // 0x6A - N/A
+ 0, // 0x6B - N/A
+ 0, // 0x6C - N/A
+ 0, // 0x6D - N/A
+ 0, // 0x6E - N/A
+ 0, // 0x6F - N/A
+ 0, // 0x70 - N/A
+ 0, // 0x71 - N/A
+ 0, // 0x72 - N/A
+ 0, // 0x73 - N/A
+ 0, // 0x74 - N/A
+ 0, // 0x75 - N/A
+ 0, // 0x76 - N/A
+ 0, // 0x77 - N/A
+ 0, // 0x78 - N/A
+ 0, // 0x79 - N/A
+ 0, // 0x7A - N/A
+ 0, // 0x7B - N/A
+ 0, // 0x7C - N/A
+ 0, // 0x7D - N/A
+ 0, // 0x7E - N/A
+ 0, // 0x7F - N/A
+ 0, // 0x80 - N/A
+ 0, // 0x81 - N/A
+ 0, // 0x82 - N/A
+ 0, // 0x83 - N/A
+ 0, // 0x84 - N/A
+ 0, // 0x85 - N/A
+ 0, // 0x86 - N/A
+ 0, // 0x87 - N/A
+ 0, // 0x88 - N/A
+ 0, // 0x89 - N/A
+ 0, // 0x8A - N/A
+ 0, // 0x8B - N/A
+ 0, // 0x8C - N/A
+ 0, // 0x8D - N/A
+ 0, // 0x8E - N/A
+ 0, // 0x8F - N/A
+ 0, // 0x90 - N/A
+ 0, // 0x91 - N/A
+ 0, // 0x92 - N/A
+ 0, // 0x93 - N/A
+ 0, // 0x94 - N/A
+ 0, // 0x95 - N/A
+ 0, // 0x96 - N/A
+ 0, // 0x97 - N/A
+ 0, // 0x98 - N/A
+ 0, // 0x99 - N/A
+ 0, // 0x9A - N/A
+ 0, // 0x9B - N/A
+ 0, // 0x9C - N/A
+ 0, // 0x9D - N/A
+ 0, // 0x9E - N/A
+ 0, // 0x9F - N/A
+ 0, // 0xA0 - N/A
+ 0, // 0xA1 - N/A
+ 0, // 0xA2 - N/A
+ 0, // 0xA3 - N/A
+ 0, // 0xA4 - N/A
+ 0, // 0xA5 - N/A
+ 0, // 0xA6 - N/A
+ 0, // 0xA7 - N/A
+ 0, // 0xA8 - N/A
+ 0, // 0xA9 - N/A
+ 0, // 0xAA - N/A
+ 0, // 0xAB - N/A
+ 0, // 0xAC - N/A
+ 0, // 0xAD - N/A
+ 0, // 0xAE - N/A
+ 0, // 0xAF - N/A
+ 0, // 0xB0 - N/A
+ 0, // 0xB1 - N/A
+ 0, // 0xB2 - N/A
+ 0, // 0xB3 - N/A
+ 0, // 0xB4 - N/A
+ 0, // 0xB5 - N/A
+ 0, // 0xB6 - N/A
+ 0, // 0xB7 - N/A
+ 0, // 0xB8 - N/A
+ 0, // 0xB9 - N/A
+ 0, // 0xBA - N/A
+ 0, // 0xBB - N/A
+ 0, // 0xBC - N/A
+ 0, // 0xBD - N/A
+ 0, // 0xBE - N/A
+ 0, // 0xBF - N/A
+ 0, // 0xC0 - N/A
+ 0, // 0xC1 - N/A
+ 0, // 0xC2 - N/A
+ 0, // 0xC3 - N/A
+ 0, // 0xC4 - N/A
+ 0, // 0xC5 - N/A
+ 0, // 0xC6 - N/A
+ 0, // 0xC7 - N/A
+ 0, // 0xC8 - N/A
+ 0, // 0xC9 - N/A
+ 0, // 0xCA - N/A
+ 0, // 0xCB - N/A
+ 0, // 0xCC - N/A
+ 0, // 0xCD - N/A
+ 0, // 0xCE - N/A
+ 0, // 0xCF - N/A
+ 0, // 0xD0 - N/A
+ 0, // 0xD1 - N/A
+ 0, // 0xD2 - N/A
+ 0, // 0xD3 - N/A
+ 0, // 0xD4 - N/A
+ 0, // 0xD5 - N/A
+ 0, // 0xD6 - N/A
+ 0, // 0xD7 - N/A
+ 0, // 0xD8 - N/A
+ 0, // 0xD9 - N/A
+ 0, // 0xDA - N/A
+ 0, // 0xDB - N/A
+ 0, // 0xDC - N/A
+ 0, // 0xDD - N/A
+ 0, // 0xDE - N/A
+ 0, // 0xDF - N/A
+ 0, // 0xE0 - N/A
+ 0, // 0xE1 - N/A
+ 0, // 0xE2 - N/A
+ 0, // 0xE3 - N/A
+ 0, // 0xE4 - N/A
+ 0, // 0xE5 - N/A
+ 0, // 0xE6 - N/A
+ 0, // 0xE7 - N/A
+ 0, // 0xE8 - N/A
+ 0, // 0xE9 - N/A
+ 0, // 0xEA - N/A
+ 0, // 0xEB - N/A
+ 0, // 0xEC - N/A
+ 0, // 0xED - N/A
+ 0, // 0xEE - N/A
+ 0, // 0xEF - N/A
+ 0, // 0xF0 - N/A
+ 0, // 0xF1 - N/A
+ 0, // 0xF2 - N/A
+ 0, // 0xF3 - N/A
+ 0, // 0xF4 - N/A
+ 0, // 0xF5 - N/A
+ 0, // 0xF6 - N/A
+ 0, // 0xF7 - N/A
+ 0, // 0xF8 - N/A
+ 0, // 0xF9 - N/A
+ 0, // 0xFA - N/A
+ 0, // 0xFB - N/A
+ 0, // 0xFC - N/A
+ 0, // 0xFD - N/A
+ 0, // 0xFE - N/A
+ 0, // 0xFF - HCI_Vendor_Specific Event
+};
diff --git a/stack/include/ldacBT_bco_for_fluoride.h b/stack/include/ldacBT_bco_for_fluoride.h
deleted file mode 100644
index 9666a7c9d..000000000
--- a/stack/include/ldacBT_bco_for_fluoride.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2016 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 LDACBT_BCO_FOR_FLUORIDE_H__
-#define LDACBT_BCO_FOR_FLUORIDE_H__
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#ifndef LDAC_BCO_API
-#define LDAC_BCO_API
-#endif /* LDAC_BCO_API */
-
-/* This file contains the definitions, declarations and macros for an
- * implementation of LDAC buffer control operation.
- */
-
-#define LDAC_BCO_ERR_NONE 0
-#define LDAC_BCO_ERR_FATAL (-1)
-
-/* LDAC BCO handle type */
-typedef struct _ldacbt_bco_handle* HANDLE_LDAC_BCO;
-
-typedef void (*decoded_data_callback_t)(uint8_t* buf, uint32_t len);
-
-/* Prepare to use LDAC BCO.
- * - Register a callback function for passing decoded data.
- * - Allocation of LDAC BCO handle.
- * Format
- * HANDLE_LDAC_BCO ldac_BCO_init(decoded_data_callback_t decode_callback);
- * Arguments
- * decoded_data_callback_t decode_callback
- * Callback function that outputs PCM data after decoding.
- * (See also a2dp_codec_api.h)
- * Return value
- * HANDLE_LDAC_BCO for success, NULL for failure.
- */
-LDAC_BCO_API HANDLE_LDAC_BCO
-ldac_BCO_init(decoded_data_callback_t decode_callback);
-
-/* End LDAC BCO.
- * - Release of LDAC BCO handle.
- * Format
- * int32_t ldac_BCO_cleanup(HANDLE_LDAC_BCO hLdacBco);
- * Arguments
- * HANDLE_LDAC_BCO hLdacBco LDAC BCO handle.
- * Return value
- * int32_t : Processing result.
- * LDAC_BCO_ERR_NONE:Successful completion
- * LDAC_BCO_ERR_FATAL:Error
- * Note
- * The function ldac_BCO_init() shall be called before calling this
- * function.
- */
-LDAC_BCO_API int32_t ldac_BCO_cleanup(HANDLE_LDAC_BCO hLdacBco);
-
-/* Decode LDAC packets.
- * - Perform buffer control and decode processing.
- * Format
- * int32_t ldac_BCO_decode_packet(HANDLE_LDAC_BCO hLdacBco, void *data,
- * int32_t length);
- * Arguments
- * HANDLE_LDAC_BCO hLdacBco LDAC BCO handle.
- * void *data LDAC packet.
- * int32_t length LDAC packet size.
- * Return value
- * int32_t : Processing result.
- * LDAC_BCO_ERR_NONE:Successful completion
- * LDAC_BCO_ERR_FATAL:Error
- * Note
- * The function ldac_BCO_init() shall be called before calling this
- * function.
- */
-LDAC_BCO_API int32_t ldac_BCO_decode_packet(HANDLE_LDAC_BCO hLdacBco,
- void* data, int32_t length);
-
-/* Start decoding process.
- * - Start or resume decoder thread.
- * Format
- * int32_t ldac_BCO_start(HANDLE_LDAC_BCO hLdacBco);
- * Arguments
- * HANDLE_LDAC_BCO hLdacBco LDAC BCO handle.
- * Return value
- * int32_t : Processing result.
- * LDAC_BCO_ERR_NONE:Successful completion
- * LDAC_BCO_ERR_FATAL:Error
- * Note
- * The function ldac_BCO_init() shall be called before calling this
- * function.
- */
-LDAC_BCO_API int32_t ldac_BCO_start(HANDLE_LDAC_BCO hLdacBco);
-
-/* Suspend decoding process.
- * - Suspend the decoder thread.
- * Format
- * int32_t ldac_BCO_suspend(HANDLE_LDAC_BCO hLdacBco);
- * Arguments
- * HANDLE_LDAC_BCO hLdacBco LDAC BCO handle.
- * Return value
- * int32_t : Processing result.
- * LDAC_BCO_ERR_NONE:Successful completion
- * LDAC_BCO_ERR_FATAL:Error
- * Note
- * The function ldac_BCO_init() shall be called before calling this
- * function.
- */
-LDAC_BCO_API int32_t ldac_BCO_suspend(HANDLE_LDAC_BCO hLdacBco);
-
-/* Configure codec information.
- * - Set sample rate, bits/sample and channel mode.
- * Format
- * int32_t ldac_BCO_configure(HANDLE_LDAC_BCO hLdacBco,
- * int32_t sample_rate, int32_t bits_per_sample,
- * int32_t channel_mode);
- * Arguments
- * HANDLE_LDAC_BCO hLdacBco LDAC BCO handle.
- * int32_t sample_rate sample rate.
- * int32_t bits_per_sample bits/sample.
- * int32_t channel_mode channel mode.
- * Return value
- * int32_t : Processing result.
- * LDAC_BCO_ERR_NONE:Successful completion
- * LDAC_BCO_ERR_FATAL:Error
- * Note
- * The function ldac_BCO_init() shall be called before calling this
- * function.
- */
-LDAC_BCO_API int32_t ldac_BCO_configure(HANDLE_LDAC_BCO hLdacBco,
- int32_t sample_rate,
- int32_t bits_per_sample,
- int32_t channel_mode);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* LDACBT_BCO_FOR_FLUORIDE_H__ */
diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h
index 53b6f3239..e58efaf16 100644
--- a/stack/l2cap/l2c_int.h
+++ b/stack/l2cap/l2c_int.h
@@ -713,7 +713,7 @@ extern void l2c_info_resp_timer_timeout(void* data);
extern void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, tL2C_CCB* p_ccb,
BT_HDR* p_buf);
extern void l2c_link_adjust_allocation(void);
-extern void l2c_link_process_num_completed_pkts(uint8_t* p);
+extern void l2c_link_process_num_completed_pkts(uint8_t* p, uint8_t evt_len);
extern void l2c_link_process_num_completed_blocks(uint8_t controller_id,
uint8_t* p, uint16_t evt_len);
extern void l2c_link_processs_num_bufs(uint16_t num_lm_acl_bufs);
diff --git a/stack/l2cap/l2c_link.cc b/stack/l2cap/l2c_link.cc
index 8e04c6e98..958425d20 100644
--- a/stack/l2cap/l2c_link.cc
+++ b/stack/l2cap/l2c_link.cc
@@ -40,6 +40,7 @@
#include "l2c_api.h"
#include "l2c_int.h"
#include "l2cdefs.h"
+#include "log/log.h"
#include "osi/include/osi.h"
static bool l2c_link_send_to_lower(tL2C_LCB* p_lcb, BT_HDR* p_buf,
@@ -675,6 +676,8 @@ void l2c_link_adjust_allocation(void) {
uint16_t num_hipri_links = 0;
uint16_t controller_xmit_quota = l2cb.num_lm_acl_bufs;
uint16_t high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A;
+ bool is_share_buffer =
+ (l2cb.num_lm_ble_bufs == L2C_DEF_NUM_BLE_BUF_SHARED) ? true : false;
/* If no links active, reset buffer quotas and controller buffers */
if (l2cb.num_links_active == 0) {
@@ -685,7 +688,8 @@ void l2c_link_adjust_allocation(void) {
/* First, count the links */
for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) {
- if (p_lcb->in_use) {
+ if (p_lcb->in_use &&
+ (is_share_buffer || p_lcb->transport != BT_TRANSPORT_LE)) {
if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
num_hipri_links++;
else
@@ -732,7 +736,8 @@ void l2c_link_adjust_allocation(void) {
/* Now, assign the quotas to each link */
for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) {
- if (p_lcb->in_use) {
+ if (p_lcb->in_use &&
+ (is_share_buffer || p_lcb->transport != BT_TRANSPORT_LE)) {
if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) {
p_lcb->link_xmit_quota = high_pri_link_quota;
} else {
@@ -1210,13 +1215,22 @@ static bool l2c_link_send_to_lower(tL2C_LCB* p_lcb, BT_HDR* p_buf,
* Returns void
*
******************************************************************************/
-void l2c_link_process_num_completed_pkts(uint8_t* p) {
+void l2c_link_process_num_completed_pkts(uint8_t* p, uint8_t evt_len) {
uint8_t num_handles, xx;
uint16_t handle;
uint16_t num_sent;
tL2C_LCB* p_lcb;
- STREAM_TO_UINT8(num_handles, p);
+ if (evt_len > 0) {
+ STREAM_TO_UINT8(num_handles, p);
+ } else {
+ num_handles = 0;
+ }
+
+ if (num_handles > evt_len / (2 * sizeof(uint16_t))) {
+ android_errorWriteLog(0x534e4554, "141617601");
+ num_handles = evt_len / (2 * sizeof(uint16_t));
+ }
for (xx = 0; xx < num_handles; xx++) {
STREAM_TO_UINT16(handle, p);
diff --git a/stack/l2cap/l2c_main.cc b/stack/l2cap/l2c_main.cc
index 128f60e97..52d77c5b2 100644
--- a/stack/l2cap/l2c_main.cc
+++ b/stack/l2cap/l2c_main.cc
@@ -97,6 +97,11 @@ void l2c_rcv_acl_data(BT_HDR* p_msg) {
/* There is a slight possibility (specifically with USB) that we get an */
/* L2CAP connection request before we get the HCI connection complete. */
/* So for these types of messages, hold them for up to 2 seconds. */
+ if (l2cap_len == 0) {
+ L2CAP_TRACE_WARNING("received empty L2CAP packet");
+ osi_free(p_msg);
+ return;
+ }
uint8_t cmd_code;
STREAM_TO_UINT8(cmd_code, p);
diff --git a/stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc b/stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc
deleted file mode 100644
index ac8c2609c..000000000
--- a/stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <base/logging.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-#include <cstdint>
-
-#include "stack/include/ldacBT_bco_for_fluoride.h"
-
-#include "osi/test/AllocationTestHarness.h"
-#undef LOG_TAG
-#include "stack/a2dp/a2dp_vendor_ldac_decoder.cc"
-
-extern void allocation_tracker_uninit(void);
-namespace {
-
-uint8_t* Data(BT_HDR* packet) { return packet->data + packet->offset; }
-
-} // namespace
-
-/**
- * Test class to test selected functionality in stack/a2dp
- */
-class A2dpStackTest : public AllocationTestHarness {
- protected:
- void SetUp() override {
- AllocationTestHarness::SetUp();
- // Disable our allocation tracker to allow ASAN full range
- allocation_tracker_uninit();
- }
-
- void TearDown() override { AllocationTestHarness::TearDown(); }
-
- BT_HDR* AllocateL2capPacket(const std::vector<uint8_t> data) const {
- auto packet = AllocatePacket(data.size());
- std::copy(data.cbegin(), data.cend(), Data(packet));
- return packet;
- }
-
- private:
- BT_HDR* AllocatePacket(size_t packet_length) const {
- BT_HDR* packet =
- static_cast<BT_HDR*>(osi_calloc(sizeof(BT_HDR) + packet_length));
- packet->len = packet_length;
- return packet;
- }
-};
-
-TEST_F(A2dpStackTest, DecodePacket_ZeroLength) {
- const std::vector<uint8_t> data;
- BT_HDR* p_buf = AllocateL2capPacket(data);
- CHECK(!a2dp_vendor_ldac_decoder_decode_packet(p_buf));
- osi_free(p_buf);
-}
diff --git a/stack/test/a2dp/misc_fake.cc b/stack/test/a2dp/misc_fake.cc
deleted file mode 100644
index 6f06218fb..000000000
--- a/stack/test/a2dp/misc_fake.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "service/common/bluetooth/a2dp_codec_config.h"
-#include "stack/include/a2dp_vendor_ldac.h"
-
-bluetooth::A2dpCodecConfig* bta_av_get_a2dp_current_codec(void) {
- return nullptr;
-}
-
-int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* p_codec_info) { return 0; }
-int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* p_codec_info) {
- return 0;
-}
-int A2DP_VendorGetChannelModeCodeLdac(const uint8_t* p_codec_info) { return 0; }
diff --git a/stack/test/stack_avrcp_test.cc b/stack/test/stack_avrcp_test.cc
new file mode 100644
index 000000000..ad1cc9e72
--- /dev/null
+++ b/stack/test/stack_avrcp_test.cc
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dlfcn.h>
+#include <gtest/gtest.h>
+
+#include "stack/include/avrc_api.h"
+
+class StackAvrcpTest : public ::testing::Test {
+ protected:
+ StackAvrcpTest() = default;
+
+ virtual ~StackAvrcpTest() = default;
+};
+
+TEST_F(StackAvrcpTest, test_avrcp_parse_browse_cmd) {
+ uint8_t scratch_buf[512]{};
+ tAVRC_MSG msg{};
+ tAVRC_COMMAND result{};
+ uint8_t browse_cmd_buf[512]{};
+
+ msg.hdr.opcode = AVRC_OP_BROWSE;
+ msg.browse.p_browse_data = browse_cmd_buf;
+ msg.browse.browse_len = 2;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_SET_BROWSED_PLAYER;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ msg.browse.browse_len = 5;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_GET_FOLDER_ITEMS;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ msg.browse.browse_len = 13;
+ uint8_t* p = &browse_cmd_buf[3];
+ UINT8_TO_STREAM(p, AVRC_SCOPE_NOW_PLAYING); // scope
+ UINT32_TO_STREAM(p, 0x00000001); // start_item
+ UINT32_TO_STREAM(p, 0x00000002); // end_item
+ browse_cmd_buf[12] = 0; // attr_count
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_CHANGE_PATH;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ msg.browse.browse_len = 14;
+ p = &browse_cmd_buf[3];
+ UINT16_TO_STREAM(p, 0x1234); // uid_counter
+ UINT8_TO_STREAM(p, AVRC_DIR_UP); // direction
+ UINT8_TO_STREAM(p, 0); // attr_count
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_GET_ITEM_ATTRIBUTES;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ msg.browse.browse_len = 15;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ msg.browse.browse_len = 4;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_SEARCH;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ p = &browse_cmd_buf[3];
+ UINT16_TO_STREAM(p, 0x0000); // charset_id
+ UINT16_TO_STREAM(p, 0x0000); // str_len
+ msg.browse.browse_len = 7;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+}