Home | History | Annotate | Download | only in src
      1 /******************************************************************************
      2  *
      3  *  Copyright 2016 Google, Inc.
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 #define LOG_TAG "bt_osi_metrics"
     19 
     20 #include <unistd.h>
     21 #include <algorithm>
     22 #include <array>
     23 #include <cerrno>
     24 #include <chrono>
     25 #include <cstdint>
     26 #include <cstring>
     27 #include <memory>
     28 #include <mutex>
     29 
     30 #include <base/base64.h>
     31 #include <base/logging.h>
     32 
     33 #include "bluetooth/metrics/bluetooth.pb.h"
     34 #include "osi/include/leaky_bonded_queue.h"
     35 #include "osi/include/log.h"
     36 #include "osi/include/osi.h"
     37 #include "osi/include/time.h"
     38 #include "stack/include/btm_api_types.h"
     39 
     40 #include "osi/include/metrics.h"
     41 
     42 namespace system_bt_osi {
     43 
     44 using bluetooth::metrics::BluetoothMetricsProto::A2DPSession;
     45 using bluetooth::metrics::BluetoothMetricsProto::BluetoothLog;
     46 using bluetooth::metrics::BluetoothMetricsProto::BluetoothSession;
     47 using bluetooth::metrics::BluetoothMetricsProto::
     48     BluetoothSession_ConnectionTechnologyType;
     49 using bluetooth::metrics::BluetoothMetricsProto::
     50     BluetoothSession_DisconnectReasonType;
     51 using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo;
     52 using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo_DeviceType;
     53 using bluetooth::metrics::BluetoothMetricsProto::PairEvent;
     54 using bluetooth::metrics::BluetoothMetricsProto::ScanEvent;
     55 using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanTechnologyType;
     56 using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanEventType;
     57 using bluetooth::metrics::BluetoothMetricsProto::WakeEvent;
     58 using bluetooth::metrics::BluetoothMetricsProto::WakeEvent_WakeEventType;
     59 using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType;
     60 using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_MIN;
     61 using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_MAX;
     62 using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_ARRAYSIZE;
     63 using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_IsValid;
     64 using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileConnectionStats;
     65 /*
     66  * Get current OS boot time in millisecond
     67  */
     68 static int64_t time_get_os_boottime_ms(void) {
     69   return time_get_os_boottime_us() / 1000;
     70 }
     71 
     72 static float combine_averages(float avg_a, int64_t ct_a, float avg_b,
     73                               int64_t ct_b) {
     74   if (ct_a > 0 && ct_b > 0) {
     75     return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
     76   } else if (ct_b > 0) {
     77     return avg_b;
     78   } else {
     79     return avg_a;
     80   }
     81 }
     82 
     83 static int32_t combine_averages(int32_t avg_a, int64_t ct_a, int32_t avg_b,
     84                                 int64_t ct_b) {
     85   if (ct_a > 0 && ct_b > 0) {
     86     return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
     87   } else if (ct_b > 0) {
     88     return avg_b;
     89   } else {
     90     return avg_a;
     91   }
     92 }
     93 
     94 void A2dpSessionMetrics::Update(const A2dpSessionMetrics& metrics) {
     95   if (metrics.audio_duration_ms >= 0) {
     96     audio_duration_ms = std::max(static_cast<int64_t>(0), audio_duration_ms);
     97     audio_duration_ms += metrics.audio_duration_ms;
     98   }
     99   if (metrics.media_timer_min_ms >= 0) {
    100     if (media_timer_min_ms < 0) {
    101       media_timer_min_ms = metrics.media_timer_min_ms;
    102     } else {
    103       media_timer_min_ms =
    104           std::min(media_timer_min_ms, metrics.media_timer_min_ms);
    105     }
    106   }
    107   if (metrics.media_timer_max_ms >= 0) {
    108     media_timer_max_ms =
    109         std::max(media_timer_max_ms, metrics.media_timer_max_ms);
    110   }
    111   if (metrics.media_timer_avg_ms >= 0 && metrics.total_scheduling_count >= 0) {
    112     if (media_timer_avg_ms < 0 || total_scheduling_count < 0) {
    113       media_timer_avg_ms = metrics.media_timer_avg_ms;
    114       total_scheduling_count = metrics.total_scheduling_count;
    115     } else {
    116       media_timer_avg_ms = combine_averages(
    117           media_timer_avg_ms, total_scheduling_count,
    118           metrics.media_timer_avg_ms, metrics.total_scheduling_count);
    119       total_scheduling_count += metrics.total_scheduling_count;
    120     }
    121   }
    122   if (metrics.buffer_overruns_max_count >= 0) {
    123     buffer_overruns_max_count =
    124         std::max(buffer_overruns_max_count, metrics.buffer_overruns_max_count);
    125   }
    126   if (metrics.buffer_overruns_total >= 0) {
    127     buffer_overruns_total =
    128         std::max(static_cast<int32_t>(0), buffer_overruns_total);
    129     buffer_overruns_total += metrics.buffer_overruns_total;
    130   }
    131   if (metrics.buffer_underruns_average >= 0 &&
    132       metrics.buffer_underruns_count >= 0) {
    133     if (buffer_underruns_average < 0 || buffer_underruns_count < 0) {
    134       buffer_underruns_average = metrics.buffer_underruns_average;
    135       buffer_underruns_count = metrics.buffer_underruns_count;
    136     } else {
    137       buffer_underruns_average = combine_averages(
    138           buffer_underruns_average, buffer_underruns_count,
    139           metrics.buffer_underruns_average, metrics.buffer_underruns_count);
    140       buffer_underruns_count += metrics.buffer_underruns_count;
    141     }
    142   }
    143 }
    144 
    145 bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
    146   return audio_duration_ms == rhs.audio_duration_ms &&
    147          media_timer_min_ms == rhs.media_timer_min_ms &&
    148          media_timer_max_ms == rhs.media_timer_max_ms &&
    149          media_timer_avg_ms == rhs.media_timer_avg_ms &&
    150          total_scheduling_count == rhs.total_scheduling_count &&
    151          buffer_overruns_max_count == rhs.buffer_overruns_max_count &&
    152          buffer_overruns_total == rhs.buffer_overruns_total &&
    153          buffer_underruns_average == rhs.buffer_underruns_average &&
    154          buffer_underruns_count == rhs.buffer_underruns_count;
    155 }
    156 
    157 static DeviceInfo_DeviceType get_device_type(device_type_t type) {
    158   switch (type) {
    159     case DEVICE_TYPE_BREDR:
    160       return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR;
    161     case DEVICE_TYPE_LE:
    162       return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_LE;
    163     case DEVICE_TYPE_DUMO:
    164       return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_DUMO;
    165     case DEVICE_TYPE_UNKNOWN:
    166     default:
    167       return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_UNKNOWN;
    168   }
    169 }
    170 
    171 static BluetoothSession_ConnectionTechnologyType get_connection_tech_type(
    172     connection_tech_t type) {
    173   switch (type) {
    174     case CONNECTION_TECHNOLOGY_TYPE_LE:
    175       return BluetoothSession_ConnectionTechnologyType::
    176           BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE;
    177     case CONNECTION_TECHNOLOGY_TYPE_BREDR:
    178       return BluetoothSession_ConnectionTechnologyType::
    179           BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR;
    180     case CONNECTION_TECHNOLOGY_TYPE_UNKNOWN:
    181     default:
    182       return BluetoothSession_ConnectionTechnologyType::
    183           BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_UNKNOWN;
    184   }
    185 }
    186 
    187 static ScanEvent_ScanTechnologyType get_scan_tech_type(scan_tech_t type) {
    188   switch (type) {
    189     case SCAN_TECH_TYPE_LE:
    190       return ScanEvent_ScanTechnologyType::
    191           ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_LE;
    192     case SCAN_TECH_TYPE_BREDR:
    193       return ScanEvent_ScanTechnologyType::
    194           ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BREDR;
    195     case SCAN_TECH_TYPE_BOTH:
    196       return ScanEvent_ScanTechnologyType::
    197           ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BOTH;
    198     case SCAN_TYPE_UNKNOWN:
    199     default:
    200       return ScanEvent_ScanTechnologyType::
    201           ScanEvent_ScanTechnologyType_SCAN_TYPE_UNKNOWN;
    202   }
    203 }
    204 
    205 static WakeEvent_WakeEventType get_wake_event_type(wake_event_type_t type) {
    206   switch (type) {
    207     case WAKE_EVENT_ACQUIRED:
    208       return WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED;
    209     case WAKE_EVENT_RELEASED:
    210       return WakeEvent_WakeEventType::WakeEvent_WakeEventType_RELEASED;
    211     case WAKE_EVENT_UNKNOWN:
    212     default:
    213       return WakeEvent_WakeEventType::WakeEvent_WakeEventType_UNKNOWN;
    214   }
    215 }
    216 
    217 static BluetoothSession_DisconnectReasonType get_disconnect_reason_type(
    218     disconnect_reason_t type) {
    219   switch (type) {
    220     case DISCONNECT_REASON_METRICS_DUMP:
    221       return BluetoothSession_DisconnectReasonType::
    222           BluetoothSession_DisconnectReasonType_METRICS_DUMP;
    223     case DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS:
    224       return BluetoothSession_DisconnectReasonType::
    225           BluetoothSession_DisconnectReasonType_NEXT_START_WITHOUT_END_PREVIOUS;
    226     case DISCONNECT_REASON_UNKNOWN:
    227     default:
    228       return BluetoothSession_DisconnectReasonType::
    229           BluetoothSession_DisconnectReasonType_UNKNOWN;
    230   }
    231 }
    232 
    233 struct BluetoothMetricsLogger::impl {
    234   impl(size_t max_bluetooth_session, size_t max_pair_event,
    235        size_t max_wake_event, size_t max_scan_event)
    236       : bt_session_queue_(
    237             new LeakyBondedQueue<BluetoothSession>(max_bluetooth_session)),
    238         pair_event_queue_(new LeakyBondedQueue<PairEvent>(max_pair_event)),
    239         wake_event_queue_(new LeakyBondedQueue<WakeEvent>(max_wake_event)),
    240         scan_event_queue_(new LeakyBondedQueue<ScanEvent>(max_scan_event)) {
    241     bluetooth_log_ = BluetoothLog::default_instance().New();
    242     headset_profile_connection_counts_.fill(0);
    243     bluetooth_session_ = nullptr;
    244     bluetooth_session_start_time_ms_ = 0;
    245     a2dp_session_metrics_ = A2dpSessionMetrics();
    246   }
    247 
    248   /* Bluetooth log lock protected */
    249   BluetoothLog* bluetooth_log_;
    250   std::array<int, HeadsetProfileType_ARRAYSIZE>
    251       headset_profile_connection_counts_;
    252   std::recursive_mutex bluetooth_log_lock_;
    253   /* End Bluetooth log lock protected */
    254   /* Bluetooth session lock protected */
    255   BluetoothSession* bluetooth_session_;
    256   uint64_t bluetooth_session_start_time_ms_;
    257   A2dpSessionMetrics a2dp_session_metrics_;
    258   std::recursive_mutex bluetooth_session_lock_;
    259   /* End bluetooth session lock protected */
    260   std::unique_ptr<LeakyBondedQueue<BluetoothSession>> bt_session_queue_;
    261   std::unique_ptr<LeakyBondedQueue<PairEvent>> pair_event_queue_;
    262   std::unique_ptr<LeakyBondedQueue<WakeEvent>> wake_event_queue_;
    263   std::unique_ptr<LeakyBondedQueue<ScanEvent>> scan_event_queue_;
    264 };
    265 
    266 BluetoothMetricsLogger::BluetoothMetricsLogger()
    267     : pimpl_(new impl(kMaxNumBluetoothSession, kMaxNumPairEvent,
    268                       kMaxNumWakeEvent, kMaxNumScanEvent)) {}
    269 
    270 void BluetoothMetricsLogger::LogPairEvent(uint32_t disconnect_reason,
    271                                           uint64_t timestamp_ms,
    272                                           uint32_t device_class,
    273                                           device_type_t device_type) {
    274   PairEvent* event = new PairEvent();
    275   DeviceInfo* info = event->mutable_device_paired_with();
    276   info->set_device_class(device_class);
    277   info->set_device_type(get_device_type(device_type));
    278   event->set_disconnect_reason(disconnect_reason);
    279   event->set_event_time_millis(timestamp_ms);
    280   pimpl_->pair_event_queue_->Enqueue(event);
    281   {
    282     std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
    283     pimpl_->bluetooth_log_->set_num_pair_event(
    284         pimpl_->bluetooth_log_->num_pair_event() + 1);
    285   }
    286 }
    287 
    288 void BluetoothMetricsLogger::LogWakeEvent(wake_event_type_t type,
    289                                           const std::string& requestor,
    290                                           const std::string& name,
    291                                           uint64_t timestamp_ms) {
    292   WakeEvent* event = new WakeEvent();
    293   event->set_wake_event_type(get_wake_event_type(type));
    294   event->set_requestor(requestor);
    295   event->set_name(name);
    296   event->set_event_time_millis(timestamp_ms);
    297   pimpl_->wake_event_queue_->Enqueue(event);
    298   {
    299     std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
    300     pimpl_->bluetooth_log_->set_num_wake_event(
    301         pimpl_->bluetooth_log_->num_wake_event() + 1);
    302   }
    303 }
    304 
    305 void BluetoothMetricsLogger::LogScanEvent(bool start,
    306                                           const std::string& initator,
    307                                           scan_tech_t type, uint32_t results,
    308                                           uint64_t timestamp_ms) {
    309   ScanEvent* event = new ScanEvent();
    310   if (start) {
    311     event->set_scan_event_type(ScanEvent::SCAN_EVENT_START);
    312   } else {
    313     event->set_scan_event_type(ScanEvent::SCAN_EVENT_STOP);
    314   }
    315   event->set_initiator(initator);
    316   event->set_scan_technology_type(get_scan_tech_type(type));
    317   event->set_number_results(results);
    318   event->set_event_time_millis(timestamp_ms);
    319   pimpl_->scan_event_queue_->Enqueue(event);
    320   {
    321     std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
    322     pimpl_->bluetooth_log_->set_num_scan_event(
    323         pimpl_->bluetooth_log_->num_scan_event() + 1);
    324   }
    325 }
    326 
    327 void BluetoothMetricsLogger::LogBluetoothSessionStart(
    328     connection_tech_t connection_tech_type, uint64_t timestamp_ms) {
    329   std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
    330   if (pimpl_->bluetooth_session_ != nullptr) {
    331     LogBluetoothSessionEnd(DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS,
    332                            0);
    333   }
    334   if (timestamp_ms == 0) {
    335     timestamp_ms = time_get_os_boottime_ms();
    336   }
    337   pimpl_->bluetooth_session_start_time_ms_ = timestamp_ms;
    338   pimpl_->bluetooth_session_ = new BluetoothSession();
    339   pimpl_->bluetooth_session_->set_connection_technology_type(
    340       get_connection_tech_type(connection_tech_type));
    341 }
    342 
    343 void BluetoothMetricsLogger::LogBluetoothSessionEnd(
    344     disconnect_reason_t disconnect_reason, uint64_t timestamp_ms) {
    345   std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
    346   if (pimpl_->bluetooth_session_ == nullptr) {
    347     return;
    348   }
    349   if (timestamp_ms == 0) {
    350     timestamp_ms = time_get_os_boottime_ms();
    351   }
    352   int64_t session_duration_sec =
    353       (timestamp_ms - pimpl_->bluetooth_session_start_time_ms_) / 1000;
    354   pimpl_->bluetooth_session_->set_session_duration_sec(session_duration_sec);
    355   pimpl_->bluetooth_session_->set_disconnect_reason_type(
    356       get_disconnect_reason_type(disconnect_reason));
    357   pimpl_->bt_session_queue_->Enqueue(pimpl_->bluetooth_session_);
    358   pimpl_->bluetooth_session_ = nullptr;
    359   {
    360     std::lock_guard<std::recursive_mutex> log_lock(pimpl_->bluetooth_log_lock_);
    361     pimpl_->bluetooth_log_->set_num_bluetooth_session(
    362         pimpl_->bluetooth_log_->num_bluetooth_session() + 1);
    363   }
    364 }
    365 
    366 void BluetoothMetricsLogger::LogBluetoothSessionDeviceInfo(
    367     uint32_t device_class, device_type_t device_type) {
    368   std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
    369   if (pimpl_->bluetooth_session_ == nullptr) {
    370     LogBluetoothSessionStart(CONNECTION_TECHNOLOGY_TYPE_UNKNOWN, 0);
    371   }
    372   DeviceInfo* info = pimpl_->bluetooth_session_->mutable_device_connected_to();
    373   info->set_device_class(device_class);
    374   info->set_device_type(DeviceInfo::DEVICE_TYPE_BREDR);
    375 }
    376 
    377 void BluetoothMetricsLogger::LogA2dpSession(
    378     const A2dpSessionMetrics& a2dp_session_metrics) {
    379   std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
    380   if (pimpl_->bluetooth_session_ == nullptr) {
    381     // When no bluetooth session exist, create one on system's behalf
    382     // Set connection type: for A2DP it is always BR/EDR
    383     LogBluetoothSessionStart(CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
    384     LogBluetoothSessionDeviceInfo(BTM_COD_MAJOR_AUDIO, DEVICE_TYPE_BREDR);
    385   }
    386   // Accumulate metrics
    387   pimpl_->a2dp_session_metrics_.Update(a2dp_session_metrics);
    388   // Get or allocate new A2DP session object
    389   A2DPSession* a2dp_session =
    390       pimpl_->bluetooth_session_->mutable_a2dp_session();
    391   a2dp_session->set_audio_duration_millis(
    392       pimpl_->a2dp_session_metrics_.audio_duration_ms);
    393   a2dp_session->set_media_timer_min_millis(
    394       pimpl_->a2dp_session_metrics_.media_timer_min_ms);
    395   a2dp_session->set_media_timer_max_millis(
    396       pimpl_->a2dp_session_metrics_.media_timer_max_ms);
    397   a2dp_session->set_media_timer_avg_millis(
    398       pimpl_->a2dp_session_metrics_.media_timer_avg_ms);
    399   a2dp_session->set_buffer_overruns_max_count(
    400       pimpl_->a2dp_session_metrics_.buffer_overruns_max_count);
    401   a2dp_session->set_buffer_overruns_total(
    402       pimpl_->a2dp_session_metrics_.buffer_overruns_total);
    403   a2dp_session->set_buffer_underruns_average(
    404       pimpl_->a2dp_session_metrics_.buffer_underruns_average);
    405   a2dp_session->set_buffer_underruns_count(
    406       pimpl_->a2dp_session_metrics_.buffer_underruns_count);
    407 }
    408 
    409 void BluetoothMetricsLogger::LogHeadsetProfileRfcConnection(
    410     tBTA_SERVICE_ID service_id) {
    411   std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
    412   switch (service_id) {
    413     case BTA_HSP_SERVICE_ID:
    414       pimpl_->headset_profile_connection_counts_[HeadsetProfileType::HSP]++;
    415       break;
    416     case BTA_HFP_SERVICE_ID:
    417       pimpl_->headset_profile_connection_counts_[HeadsetProfileType::HFP]++;
    418       break;
    419     default:
    420       pimpl_->headset_profile_connection_counts_
    421           [HeadsetProfileType::HEADSET_PROFILE_UNKNOWN]++;
    422       break;
    423   }
    424   return;
    425 }
    426 
    427 void BluetoothMetricsLogger::WriteString(std::string* serialized) {
    428   std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
    429   LOG_DEBUG(LOG_TAG, "%s building metrics", __func__);
    430   Build();
    431   LOG_DEBUG(LOG_TAG, "%s serializing metrics", __func__);
    432   if (!pimpl_->bluetooth_log_->SerializeToString(serialized)) {
    433     LOG_ERROR(LOG_TAG, "%s: error serializing metrics", __func__);
    434   }
    435   // Always clean up log objects
    436   pimpl_->bluetooth_log_->Clear();
    437 }
    438 
    439 void BluetoothMetricsLogger::WriteBase64String(std::string* serialized) {
    440   this->WriteString(serialized);
    441   base::Base64Encode(*serialized, serialized);
    442 }
    443 
    444 void BluetoothMetricsLogger::WriteBase64(int fd) {
    445   std::string protoBase64;
    446   this->WriteBase64String(&protoBase64);
    447   ssize_t ret;
    448   OSI_NO_INTR(ret = write(fd, protoBase64.c_str(), protoBase64.size()));
    449   if (ret == -1) {
    450     LOG_ERROR(LOG_TAG, "%s: error writing to dumpsys fd: %s (%d)", __func__,
    451               strerror(errno), errno);
    452   }
    453 }
    454 
    455 void BluetoothMetricsLogger::CutoffSession() {
    456   std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
    457   if (pimpl_->bluetooth_session_ != nullptr) {
    458     BluetoothSession* new_bt_session =
    459         new BluetoothSession(*pimpl_->bluetooth_session_);
    460     new_bt_session->clear_a2dp_session();
    461     new_bt_session->clear_rfcomm_session();
    462     LogBluetoothSessionEnd(DISCONNECT_REASON_METRICS_DUMP, 0);
    463     pimpl_->bluetooth_session_ = new_bt_session;
    464     pimpl_->bluetooth_session_start_time_ms_ = time_get_os_boottime_ms();
    465     pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
    466   }
    467 }
    468 
    469 void BluetoothMetricsLogger::Build() {
    470   std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
    471   CutoffSession();
    472   BluetoothLog* bluetooth_log = pimpl_->bluetooth_log_;
    473   while (!pimpl_->bt_session_queue_->Empty() &&
    474          static_cast<size_t>(bluetooth_log->session_size()) <=
    475              pimpl_->bt_session_queue_->Capacity()) {
    476     bluetooth_log->mutable_session()->AddAllocated(
    477         pimpl_->bt_session_queue_->Dequeue());
    478   }
    479   while (!pimpl_->pair_event_queue_->Empty() &&
    480          static_cast<size_t>(bluetooth_log->pair_event_size()) <=
    481              pimpl_->pair_event_queue_->Capacity()) {
    482     bluetooth_log->mutable_pair_event()->AddAllocated(
    483         pimpl_->pair_event_queue_->Dequeue());
    484   }
    485   while (!pimpl_->scan_event_queue_->Empty() &&
    486          static_cast<size_t>(bluetooth_log->scan_event_size()) <=
    487              pimpl_->scan_event_queue_->Capacity()) {
    488     bluetooth_log->mutable_scan_event()->AddAllocated(
    489         pimpl_->scan_event_queue_->Dequeue());
    490   }
    491   while (!pimpl_->wake_event_queue_->Empty() &&
    492          static_cast<size_t>(bluetooth_log->wake_event_size()) <=
    493              pimpl_->wake_event_queue_->Capacity()) {
    494     bluetooth_log->mutable_wake_event()->AddAllocated(
    495         pimpl_->wake_event_queue_->Dequeue());
    496   }
    497   while (!pimpl_->bt_session_queue_->Empty() &&
    498          static_cast<size_t>(bluetooth_log->wake_event_size()) <=
    499              pimpl_->wake_event_queue_->Capacity()) {
    500     bluetooth_log->mutable_wake_event()->AddAllocated(
    501         pimpl_->wake_event_queue_->Dequeue());
    502   }
    503   for (size_t i = 0; i < HeadsetProfileType_ARRAYSIZE; ++i) {
    504     int num_times_connected = pimpl_->headset_profile_connection_counts_[i];
    505     if (HeadsetProfileType_IsValid(i) && num_times_connected > 0) {
    506       HeadsetProfileConnectionStats* headset_profile_connection_stats =
    507           bluetooth_log->add_headset_profile_connection_stats();
    508       // Able to static_cast because HeadsetProfileType_IsValid(i) is true
    509       headset_profile_connection_stats->set_headset_profile_type(
    510           static_cast<HeadsetProfileType>(i));
    511       headset_profile_connection_stats->set_num_times_connected(
    512           num_times_connected);
    513     }
    514   }
    515   pimpl_->headset_profile_connection_counts_.fill(0);
    516 }
    517 
    518 void BluetoothMetricsLogger::ResetSession() {
    519   std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
    520   if (pimpl_->bluetooth_session_ != nullptr) {
    521     delete pimpl_->bluetooth_session_;
    522     pimpl_->bluetooth_session_ = nullptr;
    523   }
    524   pimpl_->bluetooth_session_start_time_ms_ = 0;
    525   pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
    526 }
    527 
    528 void BluetoothMetricsLogger::ResetLog() {
    529   std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
    530   pimpl_->bluetooth_log_->Clear();
    531 }
    532 
    533 void BluetoothMetricsLogger::Reset() {
    534   ResetSession();
    535   ResetLog();
    536   pimpl_->bt_session_queue_->Clear();
    537   pimpl_->pair_event_queue_->Clear();
    538   pimpl_->wake_event_queue_->Clear();
    539   pimpl_->scan_event_queue_->Clear();
    540 }
    541 
    542 }  // namespace system_bt_osi
    543