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