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 <base/logging.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #ifdef OS_ANDROID
21 #include <statslog.h>
22 #endif
23 #include <stdio.h>
24 #include <sys/stat.h>
25
26 #include "btif_bqr.h"
27 #include "btif_common.h"
28 #include "btm_api.h"
29 #include "common/leaky_bonded_queue.h"
30 #include "common/time_util.h"
31 #include "osi/include/properties.h"
32
33 namespace bluetooth {
34 namespace bqr {
35
36 using bluetooth::common::LeakyBondedQueue;
37 using std::chrono::system_clock;
38
39 // The instance of BQR event queue
40 static std::unique_ptr<LeakyBondedQueue<BqrVseSubEvt>> kpBqrEventQueue(
41 new LeakyBondedQueue<BqrVseSubEvt>(kBqrEventQueueSize));
42
ParseBqrLinkQualityEvt(uint8_t length,uint8_t * p_param_buf)43 void BqrVseSubEvt::ParseBqrLinkQualityEvt(uint8_t length,
44 uint8_t* p_param_buf) {
45 if (length < kLinkQualityParamTotalLen) {
46 LOG(FATAL) << __func__
47 << ": Parameter total length: " << std::to_string(length)
48 << " is abnormal. It shall be not shorter than: "
49 << std::to_string(kLinkQualityParamTotalLen);
50 return;
51 }
52
53 STREAM_TO_UINT8(bqr_link_quality_event_.quality_report_id, p_param_buf);
54 STREAM_TO_UINT8(bqr_link_quality_event_.packet_types, p_param_buf);
55 STREAM_TO_UINT16(bqr_link_quality_event_.connection_handle, p_param_buf);
56 STREAM_TO_UINT8(bqr_link_quality_event_.connection_role, p_param_buf);
57 STREAM_TO_INT8(bqr_link_quality_event_.tx_power_level, p_param_buf);
58 STREAM_TO_INT8(bqr_link_quality_event_.rssi, p_param_buf);
59 STREAM_TO_UINT8(bqr_link_quality_event_.snr, p_param_buf);
60 STREAM_TO_UINT8(bqr_link_quality_event_.unused_afh_channel_count,
61 p_param_buf);
62 STREAM_TO_UINT8(bqr_link_quality_event_.afh_select_unideal_channel_count,
63 p_param_buf);
64 STREAM_TO_UINT16(bqr_link_quality_event_.lsto, p_param_buf);
65 STREAM_TO_UINT32(bqr_link_quality_event_.connection_piconet_clock,
66 p_param_buf);
67 STREAM_TO_UINT32(bqr_link_quality_event_.retransmission_count, p_param_buf);
68 STREAM_TO_UINT32(bqr_link_quality_event_.no_rx_count, p_param_buf);
69 STREAM_TO_UINT32(bqr_link_quality_event_.nak_count, p_param_buf);
70 STREAM_TO_UINT32(bqr_link_quality_event_.last_tx_ack_timestamp, p_param_buf);
71 STREAM_TO_UINT32(bqr_link_quality_event_.flow_off_count, p_param_buf);
72 STREAM_TO_UINT32(bqr_link_quality_event_.last_flow_on_timestamp, p_param_buf);
73 STREAM_TO_UINT32(bqr_link_quality_event_.buffer_overflow_bytes, p_param_buf);
74 STREAM_TO_UINT32(bqr_link_quality_event_.buffer_underflow_bytes, p_param_buf);
75
76 const auto now = system_clock::to_time_t(system_clock::now());
77 localtime_r(&now, &tm_timestamp_);
78 }
79
WriteLmpLlTraceLogFile(int fd,uint8_t length,uint8_t * p_param_buf)80 void BqrVseSubEvt::WriteLmpLlTraceLogFile(int fd, uint8_t length,
81 uint8_t* p_param_buf) {
82 const auto now = system_clock::to_time_t(system_clock::now());
83 localtime_r(&now, &tm_timestamp_);
84
85 STREAM_TO_UINT8(bqr_log_dump_event_.quality_report_id, p_param_buf);
86 STREAM_TO_UINT16(bqr_log_dump_event_.connection_handle, p_param_buf);
87 length -= kLogDumpParamTotalLen;
88 bqr_log_dump_event_.vendor_specific_parameter = p_param_buf;
89
90 std::stringstream ss_log;
91 ss_log << "\n"
92 << std::put_time(&tm_timestamp_, "%m-%d %H:%M:%S ")
93 << "Handle: " << loghex(bqr_log_dump_event_.connection_handle)
94 << " VSP: ";
95
96 TEMP_FAILURE_RETRY(write(fd, ss_log.str().c_str(), ss_log.str().size()));
97 TEMP_FAILURE_RETRY(
98 write(fd, bqr_log_dump_event_.vendor_specific_parameter, length));
99 LmpLlMessageTraceCounter++;
100 }
101
WriteBtSchedulingTraceLogFile(int fd,uint8_t length,uint8_t * p_param_buf)102 void BqrVseSubEvt::WriteBtSchedulingTraceLogFile(int fd, uint8_t length,
103 uint8_t* p_param_buf) {
104 const auto now = system_clock::to_time_t(system_clock::now());
105 localtime_r(&now, &tm_timestamp_);
106
107 STREAM_TO_UINT8(bqr_log_dump_event_.quality_report_id, p_param_buf);
108 STREAM_TO_UINT16(bqr_log_dump_event_.connection_handle, p_param_buf);
109 length -= kLogDumpParamTotalLen;
110 bqr_log_dump_event_.vendor_specific_parameter = p_param_buf;
111
112 std::stringstream ss_log;
113 ss_log << "\n"
114 << std::put_time(&tm_timestamp_, "%m-%d %H:%M:%S ")
115 << "Handle: " << loghex(bqr_log_dump_event_.connection_handle)
116 << " VSP: ";
117
118 TEMP_FAILURE_RETRY(write(fd, ss_log.str().c_str(), ss_log.str().size()));
119 TEMP_FAILURE_RETRY(
120 write(fd, bqr_log_dump_event_.vendor_specific_parameter, length));
121 BtSchedulingTraceCounter++;
122 }
123
ToString() const124 std::string BqrVseSubEvt::ToString() const {
125 std::stringstream ss;
126 ss << QualityReportIdToString(bqr_link_quality_event_.quality_report_id)
127 << ", Handle: " << loghex(bqr_link_quality_event_.connection_handle)
128 << ", " << PacketTypeToString(bqr_link_quality_event_.packet_types) << ", "
129 << ((bqr_link_quality_event_.connection_role == 0) ? "Central"
130 : "Peripheral ")
131 << ", PwLv: " << std::to_string(bqr_link_quality_event_.tx_power_level)
132 << ", RSSI: " << std::to_string(bqr_link_quality_event_.rssi)
133 << ", SNR: " << std::to_string(bqr_link_quality_event_.snr)
134 << ", UnusedCh: "
135 << std::to_string(bqr_link_quality_event_.unused_afh_channel_count)
136 << ", UnidealCh: "
137 << std::to_string(bqr_link_quality_event_.afh_select_unideal_channel_count)
138 << ", ReTx: "
139 << std::to_string(bqr_link_quality_event_.retransmission_count)
140 << ", NoRX: " << std::to_string(bqr_link_quality_event_.no_rx_count)
141 << ", NAK: " << std::to_string(bqr_link_quality_event_.nak_count)
142 << ", FlowOff: " << std::to_string(bqr_link_quality_event_.flow_off_count)
143 << ", OverFlow: "
144 << std::to_string(bqr_link_quality_event_.buffer_overflow_bytes)
145 << ", UndFlow: "
146 << std::to_string(bqr_link_quality_event_.buffer_underflow_bytes);
147 return ss.str();
148 }
149
QualityReportIdToString(uint8_t quality_report_id)150 std::string QualityReportIdToString(uint8_t quality_report_id) {
151 switch (quality_report_id) {
152 case QUALITY_REPORT_ID_MONITOR_MODE:
153 return "Monitoring ";
154 case QUALITY_REPORT_ID_APPROACH_LSTO:
155 return "Appro LSTO ";
156 case QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY:
157 return "A2DP Choppy";
158 case QUALITY_REPORT_ID_SCO_VOICE_CHOPPY:
159 return "SCO Choppy ";
160 default:
161 return "Invalid ";
162 }
163 }
164
PacketTypeToString(uint8_t packet_type)165 std::string PacketTypeToString(uint8_t packet_type) {
166 switch (packet_type) {
167 case PACKET_TYPE_ID:
168 return "ID";
169 case PACKET_TYPE_NULL:
170 return "NULL";
171 case PACKET_TYPE_POLL:
172 return "POLL";
173 case PACKET_TYPE_FHS:
174 return "FHS";
175 case PACKET_TYPE_HV1:
176 return "HV1";
177 case PACKET_TYPE_HV2:
178 return "HV2";
179 case PACKET_TYPE_HV3:
180 return "HV3";
181 case PACKET_TYPE_DV:
182 return "DV";
183 case PACKET_TYPE_EV3:
184 return "EV3";
185 case PACKET_TYPE_EV4:
186 return "EV4";
187 case PACKET_TYPE_EV5:
188 return "EV5";
189 case PACKET_TYPE_2EV3:
190 return "2EV3";
191 case PACKET_TYPE_2EV5:
192 return "2EV5";
193 case PACKET_TYPE_3EV3:
194 return "3EV3";
195 case PACKET_TYPE_3EV5:
196 return "3EV5";
197 case PACKET_TYPE_DM1:
198 return "DM1";
199 case PACKET_TYPE_DH1:
200 return "DH1";
201 case PACKET_TYPE_DM3:
202 return "DM3";
203 case PACKET_TYPE_DH3:
204 return "DH3";
205 case PACKET_TYPE_DM5:
206 return "DM5";
207 case PACKET_TYPE_DH5:
208 return "DH5";
209 case PACKET_TYPE_AUX1:
210 return "AUX1";
211 case PACKET_TYPE_2DH1:
212 return "2DH1";
213 case PACKET_TYPE_2DH3:
214 return "2DH3";
215 case PACKET_TYPE_2DH5:
216 return "2DH5";
217 case PACKET_TYPE_3DH1:
218 return "3DH1";
219 case PACKET_TYPE_3DH3:
220 return "3DH3";
221 case PACKET_TYPE_3DH5:
222 return "3DH5";
223 default:
224 return "UnKnown ";
225 }
226 }
227
EnableBtQualityReport(bool is_enable)228 void EnableBtQualityReport(bool is_enable) {
229 LOG(INFO) << __func__ << ": is_enable: " << logbool(is_enable);
230
231 char bqr_prop_evtmask[PROPERTY_VALUE_MAX] = {0};
232 char bqr_prop_interval_ms[PROPERTY_VALUE_MAX] = {0};
233 osi_property_get(kpPropertyEventMask, bqr_prop_evtmask, "");
234 osi_property_get(kpPropertyMinReportIntervalMs, bqr_prop_interval_ms, "");
235
236 if (strlen(bqr_prop_evtmask) == 0 || strlen(bqr_prop_interval_ms) == 0) {
237 LOG(WARNING) << __func__ << ": Bluetooth Quality Report is disabled."
238 << " bqr_prop_evtmask: " << bqr_prop_evtmask
239 << ", bqr_prop_interval_ms: " << bqr_prop_interval_ms;
240 return;
241 }
242
243 BqrConfiguration bqr_config = {};
244
245 if (is_enable) {
246 bqr_config.report_action = REPORT_ACTION_ADD;
247 bqr_config.quality_event_mask =
248 static_cast<uint32_t>(atoi(bqr_prop_evtmask));
249 bqr_config.minimum_report_interval_ms =
250 static_cast<uint16_t>(atoi(bqr_prop_interval_ms));
251 } else {
252 bqr_config.report_action = REPORT_ACTION_CLEAR;
253 bqr_config.quality_event_mask = kQualityEventMaskAllOff;
254 bqr_config.minimum_report_interval_ms = kMinReportIntervalNoLimit;
255 }
256
257 LOG(INFO) << __func__
258 << ": Event Mask: " << loghex(bqr_config.quality_event_mask)
259 << ", Interval: " << bqr_config.minimum_report_interval_ms;
260 ConfigureBqr(bqr_config);
261 }
262
ConfigureBqr(const BqrConfiguration & bqr_config)263 void ConfigureBqr(const BqrConfiguration& bqr_config) {
264 if (bqr_config.report_action > REPORT_ACTION_CLEAR ||
265 bqr_config.quality_event_mask > kQualityEventMaskAll ||
266 bqr_config.minimum_report_interval_ms > kMinReportIntervalMaxMs) {
267 LOG(FATAL) << __func__ << ": Invalid Parameter"
268 << ", Action: " << bqr_config.report_action
269 << ", Mask: " << loghex(bqr_config.quality_event_mask)
270 << ", Interval: " << bqr_config.minimum_report_interval_ms;
271 return;
272 }
273
274 LOG(INFO) << __func__ << ": Action: "
275 << loghex(static_cast<uint8_t>(bqr_config.report_action))
276 << ", Mask: " << loghex(bqr_config.quality_event_mask)
277 << ", Interval: " << bqr_config.minimum_report_interval_ms;
278
279 uint8_t param[sizeof(BqrConfiguration)];
280 uint8_t* p_param = param;
281 UINT8_TO_STREAM(p_param, bqr_config.report_action);
282 UINT32_TO_STREAM(p_param, bqr_config.quality_event_mask);
283 UINT16_TO_STREAM(p_param, bqr_config.minimum_report_interval_ms);
284
285 BTM_VendorSpecificCommand(HCI_CONTROLLER_BQR, p_param - param, param,
286 BqrVscCompleteCallback);
287 }
288
BqrVscCompleteCallback(tBTM_VSC_CMPL * p_vsc_cmpl_params)289 void BqrVscCompleteCallback(tBTM_VSC_CMPL* p_vsc_cmpl_params) {
290 if (p_vsc_cmpl_params->param_len < 1) {
291 LOG(ERROR) << __func__ << ": The length of returned parameters is less than 1";
292 return;
293 }
294
295 uint8_t* p_event_param_buf = p_vsc_cmpl_params->p_param_buf;
296 uint8_t status = 0xff;
297 // [Return Parameter] | [Size] | [Purpose]
298 // Status | 1 octet | Command complete status
299 // Current_Quality_Event_Mask | 4 octets | Indicates current bit mask setting
300 STREAM_TO_UINT8(status, p_event_param_buf);
301 if (status != HCI_SUCCESS) {
302 LOG(ERROR) << __func__ << ": Fail to configure BQR. status: " << loghex(status);
303 return;
304 }
305
306 if (p_vsc_cmpl_params->param_len != 5) {
307 LOG(FATAL) << __func__
308 << ": The length of returned parameters is not equal to 5: "
309 << std::to_string(p_vsc_cmpl_params->param_len);
310 return;
311 }
312
313 uint32_t current_quality_event_mask = kQualityEventMaskAllOff;
314 STREAM_TO_UINT32(current_quality_event_mask, p_event_param_buf);
315
316 LOG(INFO) << __func__
317 << ", current event mask: " << loghex(current_quality_event_mask);
318 ConfigureBqrCmpl(current_quality_event_mask);
319 }
320
ConfigureBqrCmpl(uint32_t current_evt_mask)321 void ConfigureBqrCmpl(uint32_t current_evt_mask) {
322 LOG(INFO) << __func__ << ": current_evt_mask: " << loghex(current_evt_mask);
323 // (Un)Register for VSE of Bluetooth Quality Report sub event
324 tBTM_STATUS btm_status = BTM_BT_Quality_Report_VSE_Register(
325 current_evt_mask > kQualityEventMaskAllOff, CategorizeBqrEvent);
326
327 if (btm_status != BTM_SUCCESS) {
328 LOG(ERROR) << __func__ << ": Fail to (un)register VSE of BQR sub event."
329 << " status: " << btm_status;
330 return;
331 }
332
333 if (LmpLlMessageTraceLogFd != INVALID_FD &&
334 (current_evt_mask & kQualityEventMaskLmpMessageTrace) == 0) {
335 LOG(INFO) << __func__ << ": Closing LMP/LL log file.";
336 close(LmpLlMessageTraceLogFd);
337 LmpLlMessageTraceLogFd = INVALID_FD;
338 }
339 if (BtSchedulingTraceLogFd != INVALID_FD &&
340 (current_evt_mask & kQualityEventMaskBtSchedulingTrace) == 0) {
341 LOG(INFO) << __func__ << ": Closing Scheduling log file.";
342 close(BtSchedulingTraceLogFd);
343 BtSchedulingTraceLogFd = INVALID_FD;
344 }
345 }
346
CategorizeBqrEvent(uint8_t length,uint8_t * p_bqr_event)347 void CategorizeBqrEvent(uint8_t length, uint8_t* p_bqr_event) {
348 if (length == 0) {
349 LOG(WARNING) << __func__ << ": Lengths of all of the parameters are zero.";
350 return;
351 }
352
353 uint8_t quality_report_id = p_bqr_event[0];
354 switch (quality_report_id) {
355 case QUALITY_REPORT_ID_MONITOR_MODE:
356 case QUALITY_REPORT_ID_APPROACH_LSTO:
357 case QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY:
358 case QUALITY_REPORT_ID_SCO_VOICE_CHOPPY:
359 if (length < kLinkQualityParamTotalLen) {
360 LOG(FATAL) << __func__
361 << ": Parameter total length: " << std::to_string(length)
362 << " is abnormal. It shall be not shorter than: "
363 << std::to_string(kLinkQualityParamTotalLen);
364 return;
365 }
366
367 AddLinkQualityEventToQueue(length, p_bqr_event);
368 break;
369
370 // The Root Inflammation and Log Dump related event should be handled and
371 // intercepted already.
372 case QUALITY_REPORT_ID_ROOT_INFLAMMATION:
373 case QUALITY_REPORT_ID_LMP_LL_MESSAGE_TRACE:
374 case QUALITY_REPORT_ID_BT_SCHEDULING_TRACE:
375 case QUALITY_REPORT_ID_CONTROLLER_DBG_INFO:
376 LOG(WARNING) << __func__
377 << ": Unexpected ID: " << loghex(quality_report_id);
378 break;
379
380 default:
381 LOG(WARNING) << __func__ << ": Unknown ID: " << loghex(quality_report_id);
382 break;
383 }
384 }
385
AddLinkQualityEventToQueue(uint8_t length,uint8_t * p_link_quality_event)386 void AddLinkQualityEventToQueue(uint8_t length, uint8_t* p_link_quality_event) {
387 std::unique_ptr<BqrVseSubEvt> p_bqr_event = std::make_unique<BqrVseSubEvt>();
388 p_bqr_event->ParseBqrLinkQualityEvt(length, p_link_quality_event);
389
390 LOG(WARNING) << *p_bqr_event;
391 invoke_link_quality_report_cb(
392 bluetooth::common::time_get_os_boottime_ms(),
393 p_bqr_event->bqr_link_quality_event_.quality_report_id,
394 p_bqr_event->bqr_link_quality_event_.rssi,
395 p_bqr_event->bqr_link_quality_event_.snr,
396 p_bqr_event->bqr_link_quality_event_.retransmission_count,
397 p_bqr_event->bqr_link_quality_event_.no_rx_count,
398 p_bqr_event->bqr_link_quality_event_.nak_count);
399
400 #ifdef OS_ANDROID
401 int ret = android::util::stats_write(
402 android::util::BLUETOOTH_QUALITY_REPORT_REPORTED,
403 p_bqr_event->bqr_link_quality_event_.quality_report_id,
404 p_bqr_event->bqr_link_quality_event_.packet_types,
405 p_bqr_event->bqr_link_quality_event_.connection_handle,
406 p_bqr_event->bqr_link_quality_event_.connection_role,
407 p_bqr_event->bqr_link_quality_event_.tx_power_level,
408 p_bqr_event->bqr_link_quality_event_.rssi,
409 p_bqr_event->bqr_link_quality_event_.snr,
410 p_bqr_event->bqr_link_quality_event_.unused_afh_channel_count,
411 p_bqr_event->bqr_link_quality_event_.afh_select_unideal_channel_count,
412 p_bqr_event->bqr_link_quality_event_.lsto,
413 p_bqr_event->bqr_link_quality_event_.connection_piconet_clock,
414 p_bqr_event->bqr_link_quality_event_.retransmission_count,
415 p_bqr_event->bqr_link_quality_event_.no_rx_count,
416 p_bqr_event->bqr_link_quality_event_.nak_count,
417 p_bqr_event->bqr_link_quality_event_.last_tx_ack_timestamp,
418 p_bqr_event->bqr_link_quality_event_.flow_off_count,
419 p_bqr_event->bqr_link_quality_event_.last_flow_on_timestamp,
420 p_bqr_event->bqr_link_quality_event_.buffer_overflow_bytes,
421 p_bqr_event->bqr_link_quality_event_.buffer_underflow_bytes);
422 if (ret < 0) {
423 LOG(WARNING) << __func__ << ": failed to log BQR event to statsd, error "
424 << ret;
425 }
426 #else
427 // TODO(abps) Metrics for non-Android build
428 #endif
429 kpBqrEventQueue->Enqueue(p_bqr_event.release());
430 }
431
DumpLmpLlMessage(uint8_t length,uint8_t * p_lmp_ll_message_event)432 void DumpLmpLlMessage(uint8_t length, uint8_t* p_lmp_ll_message_event) {
433 std::unique_ptr<BqrVseSubEvt> p_bqr_event = std::make_unique<BqrVseSubEvt>();
434
435 if (LmpLlMessageTraceLogFd == INVALID_FD ||
436 LmpLlMessageTraceCounter >= kLogDumpEventPerFile) {
437 LmpLlMessageTraceLogFd = OpenLmpLlTraceLogFile();
438 }
439 if (LmpLlMessageTraceLogFd != INVALID_FD) {
440 p_bqr_event->WriteLmpLlTraceLogFile(LmpLlMessageTraceLogFd, length,
441 p_lmp_ll_message_event);
442 }
443 }
444
OpenLmpLlTraceLogFile()445 int OpenLmpLlTraceLogFile() {
446 if (rename(kpLmpLlMessageTraceLogPath, kpLmpLlMessageTraceLastLogPath) != 0 &&
447 errno != ENOENT) {
448 LOG(ERROR) << __func__ << ": Unable to rename '"
449 << kpLmpLlMessageTraceLogPath << "' to '"
450 << kpLmpLlMessageTraceLastLogPath << "' : " << strerror(errno);
451 }
452
453 mode_t prevmask = umask(0);
454 int logfile_fd =
455 open(kpLmpLlMessageTraceLogPath, O_WRONLY | O_CREAT | O_TRUNC,
456 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
457 umask(prevmask);
458 if (logfile_fd == INVALID_FD) {
459 LOG(ERROR) << __func__ << ": Unable to open '" << kpLmpLlMessageTraceLogPath
460 << "' : " << strerror(errno);
461 } else {
462 LmpLlMessageTraceCounter = 0;
463 }
464 return logfile_fd;
465 }
466
DumpBtScheduling(uint8_t length,uint8_t * p_bt_scheduling_event)467 void DumpBtScheduling(uint8_t length, uint8_t* p_bt_scheduling_event) {
468 std::unique_ptr<BqrVseSubEvt> p_bqr_event = std::make_unique<BqrVseSubEvt>();
469
470 if (BtSchedulingTraceLogFd == INVALID_FD ||
471 BtSchedulingTraceCounter == kLogDumpEventPerFile) {
472 BtSchedulingTraceLogFd = OpenBtSchedulingTraceLogFile();
473 }
474 if (BtSchedulingTraceLogFd != INVALID_FD) {
475 p_bqr_event->WriteBtSchedulingTraceLogFile(BtSchedulingTraceLogFd, length,
476 p_bt_scheduling_event);
477 }
478 }
479
OpenBtSchedulingTraceLogFile()480 int OpenBtSchedulingTraceLogFile() {
481 if (rename(kpBtSchedulingTraceLogPath, kpBtSchedulingTraceLastLogPath) != 0 &&
482 errno != ENOENT) {
483 LOG(ERROR) << __func__ << ": Unable to rename '"
484 << kpBtSchedulingTraceLogPath << "' to '"
485 << kpBtSchedulingTraceLastLogPath << "' : " << strerror(errno);
486 }
487
488 mode_t prevmask = umask(0);
489 int logfile_fd =
490 open(kpBtSchedulingTraceLogPath, O_WRONLY | O_CREAT | O_TRUNC,
491 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
492 umask(prevmask);
493 if (logfile_fd == INVALID_FD) {
494 LOG(ERROR) << __func__ << ": Unable to open '" << kpBtSchedulingTraceLogPath
495 << "' : " << strerror(errno);
496 } else {
497 BtSchedulingTraceCounter = 0;
498 }
499 return logfile_fd;
500 }
501
DebugDump(int fd)502 void DebugDump(int fd) {
503 dprintf(fd, "\nBT Quality Report Events: \n");
504
505 if (kpBqrEventQueue->Empty()) {
506 dprintf(fd, "Event queue is empty.\n");
507 return;
508 }
509
510 while (!kpBqrEventQueue->Empty()) {
511 std::unique_ptr<BqrVseSubEvt> p_event(kpBqrEventQueue->Dequeue());
512
513 bool warning = (p_event->bqr_link_quality_event_.rssi < kCriWarnRssi ||
514 p_event->bqr_link_quality_event_.unused_afh_channel_count >
515 kCriWarnUnusedCh);
516
517 std::stringstream ss_timestamp;
518 ss_timestamp << std::put_time(&p_event->tm_timestamp_, "%m-%d %H:%M:%S");
519
520 dprintf(fd, "%c %s %s\n", warning ? '*' : ' ', ss_timestamp.str().c_str(),
521 p_event->ToString().c_str());
522 }
523
524 dprintf(fd, "\n");
525 }
526
527 } // namespace bqr
528 } // namespace bluetooth
529