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 19 20#define LOG_TAG "bt_osi_metrics" 21 22extern "C" { 23#include "osi/include/metrics.h" 24 25#include <errno.h> 26 27#include "osi/include/log.h" 28#include "osi/include/osi.h" 29} 30 31#include "osi/src/protos/bluetooth.pb.h" 32 33#include <base/base64.h> 34#include <google/protobuf/text_format.h> 35#include <mutex> 36 37using clearcut::connectivity::A2DPSession; 38using clearcut::connectivity::BluetoothLog; 39using clearcut::connectivity::BluetoothSession; 40using clearcut::connectivity::DeviceInfo; 41using clearcut::connectivity::DeviceInfo_DeviceType; 42using clearcut::connectivity::PairEvent; 43using clearcut::connectivity::ScanEvent; 44using clearcut::connectivity::ScanEvent_ScanTechnologyType; 45using clearcut::connectivity::ScanEvent_ScanEventType; 46using clearcut::connectivity::WakeEvent; 47using clearcut::connectivity::WakeEvent_WakeEventType; 48 49BluetoothLog *pending; 50std::mutex log_lock; 51 52static void lazy_initialize(void) { 53 if (pending == nullptr) { 54 pending = BluetoothLog::default_instance().New(); 55 } 56} 57 58void metrics_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms, 59 uint32_t device_class, device_type_t device_type) { 60 std::lock_guard<std::mutex> lock(log_lock); 61 lazy_initialize(); 62 63 PairEvent *event = pending->add_pair_event(); 64 65 DeviceInfo *info = event->mutable_device_paired_with(); 66 67 info->set_device_class(device_class); 68 69 DeviceInfo_DeviceType type = DeviceInfo::DEVICE_TYPE_UNKNOWN; 70 71 if (device_type == DEVICE_TYPE_BREDR) 72 type = DeviceInfo::DEVICE_TYPE_BREDR; 73 if (device_type == DEVICE_TYPE_LE) 74 type = DeviceInfo::DEVICE_TYPE_LE; 75 if (device_type == DEVICE_TYPE_DUMO) 76 type = DeviceInfo::DEVICE_TYPE_DUMO; 77 78 info->set_device_type(type); 79 80 event->set_disconnect_reason(disconnect_reason); 81 82 event->set_event_time_millis(timestamp_ms); 83} 84 85void metrics_wake_event(wake_event_type_t type, const char *requestor, 86 const char *name, uint64_t timestamp_ms) { 87 std::lock_guard<std::mutex> lock(log_lock); 88 lazy_initialize(); 89 90 WakeEvent *event = pending->add_wake_event(); 91 92 WakeEvent_WakeEventType waketype = WakeEvent::UNKNOWN; 93 94 if (type == WAKE_EVENT_ACQUIRED) 95 waketype = WakeEvent::ACQUIRED; 96 if (type == WAKE_EVENT_RELEASED) 97 waketype = WakeEvent::RELEASED; 98 99 event->set_wake_event_type(waketype); 100 101 if (requestor) 102 event->set_requestor(requestor); 103 104 if (name) 105 event->set_name(name); 106 107 event->set_event_time_millis(timestamp_ms); 108} 109 110void metrics_scan_event(bool start, const char *initator, scan_tech_t type, 111 uint32_t results, uint64_t timestamp_ms) { 112 std::lock_guard<std::mutex> lock(log_lock); 113 lazy_initialize(); 114 115 ScanEvent *event = pending->add_scan_event(); 116 117 if (start) 118 event->set_scan_event_type(ScanEvent::SCAN_EVENT_START); 119 else 120 event->set_scan_event_type(ScanEvent::SCAN_EVENT_STOP); 121 122 if (initator) 123 event->set_initiator(initator); 124 125 ScanEvent::ScanTechnologyType scantype = ScanEvent::SCAN_TYPE_UNKNOWN; 126 127 if (type == SCAN_TECH_TYPE_LE) 128 scantype = ScanEvent::SCAN_TECH_TYPE_LE; 129 if (type == SCAN_TECH_TYPE_BREDR) 130 scantype = ScanEvent::SCAN_TECH_TYPE_BREDR; 131 if (type == SCAN_TECH_TYPE_BOTH) 132 scantype = ScanEvent::SCAN_TECH_TYPE_BOTH; 133 134 event->set_scan_technology_type(scantype); 135 136 event->set_number_results(results); 137 138 event->set_event_time_millis(timestamp_ms); 139} 140 141void metrics_a2dp_session(int64_t session_duration_sec, 142 const char *disconnect_reason, 143 uint32_t device_class, 144 int32_t media_timer_min_ms, 145 int32_t media_timer_max_ms, 146 int32_t media_timer_avg_ms, 147 int32_t buffer_overruns_max_count, 148 int32_t buffer_overruns_total, 149 float buffer_underruns_average, 150 int32_t buffer_underruns_count) { 151 std::lock_guard<std::mutex> lock(log_lock); 152 lazy_initialize(); 153 154 BluetoothSession *bt_session = pending->add_session(); 155 156 // Set connection type: for A2DP it is always BR/EDR 157 BluetoothSession::ConnectionTechnologyType conn_type = 158 BluetoothSession::CONNECTION_TECHNOLOGY_TYPE_BREDR; 159 bt_session->set_connection_technology_type(conn_type); 160 161 bt_session->set_session_duration_sec(session_duration_sec); 162 if (disconnect_reason != NULL) 163 bt_session->set_disconnect_reason(disconnect_reason); 164 165 // Set device: class and type are pre-defined 166 DeviceInfo *info = bt_session->mutable_device_connected_to(); 167 info->set_device_class(device_class); 168 info->set_device_type(DeviceInfo::DEVICE_TYPE_BREDR); 169 170 A2DPSession *a2dp_session = bt_session->mutable_a2dp_session(); 171 a2dp_session->set_media_timer_min_millis(media_timer_min_ms); 172 a2dp_session->set_media_timer_max_millis(media_timer_max_ms); 173 a2dp_session->set_media_timer_avg_millis(media_timer_avg_ms); 174 a2dp_session->set_buffer_overruns_max_count(buffer_overruns_max_count); 175 a2dp_session->set_buffer_overruns_total(buffer_overruns_total); 176 a2dp_session->set_buffer_underruns_average(buffer_underruns_average); 177 a2dp_session->set_buffer_underruns_count(buffer_underruns_count); 178} 179 180void metrics_write(int fd, bool clear) { 181 log_lock.lock(); 182 LOG_DEBUG(LOG_TAG, "%s serializing metrics", __func__); 183 lazy_initialize(); 184 185 std::string serialized; 186 if (!pending->SerializeToString(&serialized)) { 187 LOG_ERROR(LOG_TAG, "%s: error serializing metrics", __func__); 188 return; 189 } 190 191 if (clear) { 192 pending->Clear(); 193 } 194 log_lock.unlock(); 195 196 std::string protoBase64; 197 base::Base64Encode(serialized, &protoBase64); 198 199 ssize_t ret; 200 OSI_NO_INTR(ret = write(fd, protoBase64.c_str(), protoBase64.size())); 201 if (ret == -1) { 202 LOG_ERROR(LOG_TAG, "%s: error writing to dumpsys fd: %s (%d)", __func__, 203 strerror(errno), errno); 204 } 205} 206 207void metrics_print(int fd, bool clear) { 208 log_lock.lock(); 209 LOG_DEBUG(LOG_TAG, "%s printing metrics", __func__); 210 lazy_initialize(); 211 212 std::string pretty_output; 213 google::protobuf::TextFormat::PrintToString(*pending, &pretty_output); 214 215 if (clear) { 216 pending->Clear(); 217 } 218 log_lock.unlock(); 219 220 ssize_t ret; 221 OSI_NO_INTR(ret = write(fd, pretty_output.c_str(), pretty_output.size())); 222 if (ret == -1) { 223 LOG_ERROR(LOG_TAG, "%s: error writing to dumpsys fd: %s (%d)", __func__, 224 strerror(errno), errno); 225 } 226} 227