1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <statslog.h>
18
19 #include "btif_bqr.h"
20 #include "btif_dm.h"
21 #include "common/leaky_bonded_queue.h"
22 #include "osi/include/properties.h"
23 #include "stack/btm/btm_int.h"
24
25 namespace bluetooth {
26 namespace bqr {
27
28 using bluetooth::common::LeakyBondedQueue;
29 using std::chrono::system_clock;
30
31 // The instance of BQR event queue
32 static std::unique_ptr<LeakyBondedQueue<BqrVseSubEvt>> kpBqrEventQueue(
33 new LeakyBondedQueue<BqrVseSubEvt>(kBqrEventQueueSize));
34
ParseBqrEvt(uint8_t length,uint8_t * p_param_buf)35 bool BqrVseSubEvt::ParseBqrEvt(uint8_t length, uint8_t* p_param_buf) {
36 if (length < kBqrParamTotalLen) {
37 LOG(FATAL) << __func__
38 << ": Parameter total length: " << std::to_string(length)
39 << " is abnormal. It shall be not shorter than: "
40 << std::to_string(kBqrParamTotalLen);
41 return false;
42 }
43
44 STREAM_TO_UINT8(quality_report_id_, p_param_buf);
45 STREAM_TO_UINT8(packet_types_, p_param_buf);
46 STREAM_TO_UINT16(connection_handle_, p_param_buf);
47 STREAM_TO_UINT8(connection_role_, p_param_buf);
48 STREAM_TO_UINT8(tx_power_level_, p_param_buf);
49 STREAM_TO_INT8(rssi_, p_param_buf);
50 STREAM_TO_UINT8(snr_, p_param_buf);
51 STREAM_TO_UINT8(unused_afh_channel_count_, p_param_buf);
52 STREAM_TO_UINT8(afh_select_unideal_channel_count_, p_param_buf);
53 STREAM_TO_UINT16(lsto_, p_param_buf);
54 STREAM_TO_UINT32(connection_piconet_clock_, p_param_buf);
55 STREAM_TO_UINT32(retransmission_count_, p_param_buf);
56 STREAM_TO_UINT32(no_rx_count_, p_param_buf);
57 STREAM_TO_UINT32(nak_count_, p_param_buf);
58 STREAM_TO_UINT32(last_tx_ack_timestamp_, p_param_buf);
59 STREAM_TO_UINT32(flow_off_count_, p_param_buf);
60 STREAM_TO_UINT32(last_flow_on_timestamp_, p_param_buf);
61 STREAM_TO_UINT32(buffer_overflow_bytes_, p_param_buf);
62 STREAM_TO_UINT32(buffer_underflow_bytes_, p_param_buf);
63
64 const auto now = system_clock::to_time_t(system_clock::now());
65 localtime_r(&now, &tm_timestamp_);
66
67 return true;
68 }
69
ToString() const70 std::string BqrVseSubEvt::ToString() const {
71 std::stringstream ss_return_string;
72 ss_return_string << QualityReportIdToString(quality_report_id_)
73 << ", Handle: " << loghex(connection_handle_) << ", "
74 << PacketTypeToString(packet_types_) << ", "
75 << ((connection_role_ == 0) ? "Master" : "Slave ")
76 << ", PwLv: " << loghex(tx_power_level_)
77 << ", RSSI: " << std::to_string(rssi_)
78 << ", SNR: " << std::to_string(snr_) << ", UnusedCh: "
79 << std::to_string(unused_afh_channel_count_)
80 << ", UnidealCh: "
81 << std::to_string(afh_select_unideal_channel_count_)
82 << ", ReTx: " << std::to_string(retransmission_count_)
83 << ", NoRX: " << std::to_string(no_rx_count_)
84 << ", NAK: " << std::to_string(nak_count_)
85 << ", FlowOff: " << std::to_string(flow_off_count_)
86 << ", OverFlow: " << std::to_string(buffer_overflow_bytes_)
87 << ", UndFlow: " << std::to_string(buffer_underflow_bytes_);
88 return ss_return_string.str();
89 }
90
QualityReportIdToString(uint8_t quality_report_id)91 std::string QualityReportIdToString(uint8_t quality_report_id) {
92 switch (quality_report_id) {
93 case QUALITY_REPORT_ID_MONITOR_MODE:
94 return "Monitoring ";
95 case QUALITY_REPORT_ID_APPROACH_LSTO:
96 return "Appro LSTO ";
97 case QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY:
98 return "A2DP Choppy";
99 case QUALITY_REPORT_ID_SCO_VOICE_CHOPPY:
100 return "SCO Choppy ";
101 default:
102 return "Invalid ";
103 }
104 }
105
PacketTypeToString(uint8_t packet_type)106 std::string PacketTypeToString(uint8_t packet_type) {
107 switch (packet_type) {
108 case PACKET_TYPE_ID:
109 return "ID";
110 case PACKET_TYPE_NULL:
111 return "NULL";
112 case PACKET_TYPE_POLL:
113 return "POLL";
114 case PACKET_TYPE_FHS:
115 return "FHS";
116 case PACKET_TYPE_HV1:
117 return "HV1";
118 case PACKET_TYPE_HV2:
119 return "HV2";
120 case PACKET_TYPE_HV3:
121 return "HV3";
122 case PACKET_TYPE_DV:
123 return "DV";
124 case PACKET_TYPE_EV3:
125 return "EV3";
126 case PACKET_TYPE_EV4:
127 return "EV4";
128 case PACKET_TYPE_EV5:
129 return "EV5";
130 case PACKET_TYPE_2EV3:
131 return "2EV3";
132 case PACKET_TYPE_2EV5:
133 return "2EV5";
134 case PACKET_TYPE_3EV3:
135 return "3EV3";
136 case PACKET_TYPE_3EV5:
137 return "3EV5";
138 case PACKET_TYPE_DM1:
139 return "DM1";
140 case PACKET_TYPE_DH1:
141 return "DH1";
142 case PACKET_TYPE_DM3:
143 return "DM3";
144 case PACKET_TYPE_DH3:
145 return "DH3";
146 case PACKET_TYPE_DM5:
147 return "DM5";
148 case PACKET_TYPE_DH5:
149 return "DH5";
150 case PACKET_TYPE_AUX1:
151 return "AUX1";
152 case PACKET_TYPE_2DH1:
153 return "2DH1";
154 case PACKET_TYPE_2DH3:
155 return "2DH3";
156 case PACKET_TYPE_2DH5:
157 return "2DH5";
158 case PACKET_TYPE_3DH1:
159 return "3DH1";
160 case PACKET_TYPE_3DH3:
161 return "3DH3";
162 case PACKET_TYPE_3DH5:
163 return "3DH5";
164 default:
165 return "UnKnown ";
166 }
167 }
168
AddBqrEventToQueue(uint8_t length,uint8_t * p_stream)169 void AddBqrEventToQueue(uint8_t length, uint8_t* p_stream) {
170 std::unique_ptr<BqrVseSubEvt> p_bqr_event = std::make_unique<BqrVseSubEvt>();
171 if (!p_bqr_event->ParseBqrEvt(length, p_stream)) {
172 LOG(WARNING) << __func__ << ": Fail to parse BQR sub event.";
173 return;
174 }
175
176 LOG(WARNING) << *p_bqr_event;
177 int ret = android::util::stats_write(
178 android::util::BLUETOOTH_QUALITY_REPORT_REPORTED,
179 p_bqr_event->quality_report_id_, p_bqr_event->packet_types_,
180 p_bqr_event->connection_handle_, p_bqr_event->connection_role_,
181 p_bqr_event->tx_power_level_, p_bqr_event->rssi_, p_bqr_event->snr_,
182 p_bqr_event->unused_afh_channel_count_,
183 p_bqr_event->afh_select_unideal_channel_count_, p_bqr_event->lsto_,
184 p_bqr_event->connection_piconet_clock_,
185 p_bqr_event->retransmission_count_, p_bqr_event->no_rx_count_,
186 p_bqr_event->nak_count_, p_bqr_event->last_tx_ack_timestamp_,
187 p_bqr_event->flow_off_count_, p_bqr_event->last_flow_on_timestamp_,
188 p_bqr_event->buffer_overflow_bytes_,
189 p_bqr_event->buffer_underflow_bytes_);
190 if (ret < 0) {
191 LOG(WARNING) << __func__ << ": failed to log BQR event to statsd, error "
192 << ret;
193 }
194 kpBqrEventQueue->Enqueue(p_bqr_event.release());
195 }
196
ConfigureBqrCmpl(uint32_t current_evt_mask)197 void ConfigureBqrCmpl(uint32_t current_evt_mask) {
198 LOG(INFO) << __func__ << ": current_evt_mask: " << loghex(current_evt_mask);
199 // (Un)Register for VSE of Bluetooth Quality Report sub event
200 tBTM_STATUS btm_status = BTM_BT_Quality_Report_VSE_Register(
201 current_evt_mask > kQualityEventMaskAllOff, AddBqrEventToQueue);
202
203 if (btm_status != BTM_SUCCESS) {
204 LOG(ERROR) << __func__ << ": Fail to (un)register VSE of BQR sub event."
205 << " status: " << btm_status;
206 }
207 }
208
EnableBtQualityReport(bool is_enable)209 void EnableBtQualityReport(bool is_enable) {
210 LOG(INFO) << __func__ << ": is_enable: " << logbool(is_enable);
211
212 char bqr_prop_evtmask[PROPERTY_VALUE_MAX] = {0};
213 char bqr_prop_interval_ms[PROPERTY_VALUE_MAX] = {0};
214 osi_property_get(kpPropertyEventMask, bqr_prop_evtmask, "");
215 osi_property_get(kpPropertyMinReportIntervalMs, bqr_prop_interval_ms, "");
216
217 if (strlen(bqr_prop_evtmask) == 0 || strlen(bqr_prop_interval_ms) == 0) {
218 LOG(WARNING) << __func__ << ": Bluetooth Quality Report is disabled."
219 << " bqr_prop_evtmask: " << bqr_prop_evtmask
220 << ", bqr_prop_interval_ms: " << bqr_prop_interval_ms;
221 return;
222 }
223
224 BqrConfiguration bqr_config = {};
225
226 if (is_enable) {
227 bqr_config.report_action = REPORT_ACTION_ADD;
228 bqr_config.quality_event_mask =
229 static_cast<uint32_t>(atoi(bqr_prop_evtmask));
230 bqr_config.minimum_report_interval_ms =
231 static_cast<uint16_t>(atoi(bqr_prop_interval_ms));
232 } else {
233 bqr_config.report_action = REPORT_ACTION_CLEAR;
234 bqr_config.quality_event_mask = kQualityEventMaskAllOff;
235 bqr_config.minimum_report_interval_ms = kMinReportIntervalNoLimit;
236 }
237
238 LOG(INFO) << __func__
239 << ": Event Mask: " << loghex(bqr_config.quality_event_mask)
240 << ", Interval: " << bqr_config.minimum_report_interval_ms;
241 ConfigureBqr(bqr_config);
242 }
243
BqrVscCompleteCallback(tBTM_VSC_CMPL * p_vsc_cmpl_params)244 void BqrVscCompleteCallback(tBTM_VSC_CMPL* p_vsc_cmpl_params) {
245 if (p_vsc_cmpl_params->param_len < 1) {
246 LOG(ERROR) << __func__ << ": The length of returned parameters is less than 1";
247 return;
248 }
249
250 uint8_t* p_event_param_buf = p_vsc_cmpl_params->p_param_buf;
251 uint8_t status = 0xff;
252 // [Return Parameter] | [Size] | [Purpose]
253 // Status | 1 octet | Command complete status
254 // Current_Quality_Event_Mask | 4 octets | Indicates current bit mask setting
255 STREAM_TO_UINT8(status, p_event_param_buf);
256 if (status != HCI_SUCCESS) {
257 LOG(ERROR) << __func__ << ": Fail to configure BQR. status: " << loghex(status);
258 return;
259 }
260
261 if (p_vsc_cmpl_params->param_len != 5) {
262 LOG(FATAL) << __func__
263 << ": The length of returned parameters is not equal to 5: "
264 << std::to_string(p_vsc_cmpl_params->param_len);
265 return;
266 }
267
268 uint32_t current_quality_event_mask = kQualityEventMaskAllOff;
269 STREAM_TO_UINT32(current_quality_event_mask, p_event_param_buf);
270
271 LOG(INFO) << __func__
272 << ", current event mask: " << loghex(current_quality_event_mask);
273 ConfigureBqrCmpl(current_quality_event_mask);
274 }
275
ConfigureBqr(const BqrConfiguration & bqr_config)276 void ConfigureBqr(const BqrConfiguration& bqr_config) {
277 if (bqr_config.report_action > REPORT_ACTION_CLEAR ||
278 bqr_config.quality_event_mask > kQualityEventMaskAll ||
279 bqr_config.minimum_report_interval_ms > kMinReportIntervalMaxMs) {
280 LOG(FATAL) << __func__ << ": Invalid Parameter"
281 << ", Action: " << bqr_config.report_action
282 << ", Mask: " << loghex(bqr_config.quality_event_mask)
283 << ", Interval: " << bqr_config.minimum_report_interval_ms;
284 return;
285 }
286
287 LOG(INFO) << __func__ << ": Action: " << bqr_config.report_action
288 << ", Mask: " << loghex(bqr_config.quality_event_mask)
289 << ", Interval: " << bqr_config.minimum_report_interval_ms;
290
291 uint8_t param[sizeof(BqrConfiguration)];
292 uint8_t* p_param = param;
293 UINT8_TO_STREAM(p_param, bqr_config.report_action);
294 UINT32_TO_STREAM(p_param, bqr_config.quality_event_mask);
295 UINT16_TO_STREAM(p_param, bqr_config.minimum_report_interval_ms);
296
297 BTM_VendorSpecificCommand(HCI_CONTROLLER_BQR_OPCODE_OCF, p_param - param,
298 param, BqrVscCompleteCallback);
299 }
300
DebugDump(int fd)301 void DebugDump(int fd) {
302 dprintf(fd, "\nBT Quality Report Events: \n");
303
304 if (kpBqrEventQueue->Empty()) {
305 dprintf(fd, "Event queue is empty.\n");
306 return;
307 }
308
309 while (!kpBqrEventQueue->Empty()) {
310 std::unique_ptr<BqrVseSubEvt> p_event(kpBqrEventQueue->Dequeue());
311
312 bool warning = (p_event->rssi_ < kCriWarnRssi ||
313 p_event->unused_afh_channel_count_ > kCriWarnUnusedCh);
314
315 std::stringstream ss_timestamp;
316 ss_timestamp << std::put_time(&p_event->tm_timestamp_, "%m-%d %H:%M:%S");
317
318 dprintf(fd, "%c %s %s\n", warning ? '*' : ' ', ss_timestamp.str().c_str(),
319 p_event->ToString().c_str());
320 }
321
322 dprintf(fd, "\n");
323 }
324
325 } // namespace bqr
326 } // namespace bluetooth
327