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