• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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