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
22 extern "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
37 using clearcut::connectivity::A2DPSession;
38 using clearcut::connectivity::BluetoothLog;
39 using clearcut::connectivity::BluetoothSession;
40 using clearcut::connectivity::DeviceInfo;
41 using clearcut::connectivity::DeviceInfo_DeviceType;
42 using clearcut::connectivity::PairEvent;
43 using clearcut::connectivity::ScanEvent;
44 using clearcut::connectivity::ScanEvent_ScanTechnologyType;
45 using clearcut::connectivity::ScanEvent_ScanEventType;
46 using clearcut::connectivity::WakeEvent;
47 using clearcut::connectivity::WakeEvent_WakeEventType;
48
49 BluetoothLog *pending;
50 std::mutex log_lock;
51
lazy_initialize(void)52 static void lazy_initialize(void) {
53 if (pending == nullptr) {
54 pending = BluetoothLog::default_instance().New();
55 }
56 }
57
metrics_pair_event(uint32_t disconnect_reason,uint64_t timestamp_ms,uint32_t device_class,device_type_t device_type)58 void 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
metrics_wake_event(wake_event_type_t type,const char * requestor,const char * name,uint64_t timestamp_ms)85 void 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
metrics_scan_event(bool start,const char * initator,scan_tech_t type,uint32_t results,uint64_t timestamp_ms)110 void 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
metrics_a2dp_session(int64_t session_duration_sec,const char * disconnect_reason,uint32_t device_class,int32_t media_timer_min_ms,int32_t media_timer_max_ms,int32_t media_timer_avg_ms,int32_t buffer_overruns_max_count,int32_t buffer_overruns_total,float buffer_underruns_average,int32_t buffer_underruns_count)141 void 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
metrics_write(int fd,bool clear)180 void 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
metrics_print(int fd,bool clear)207 void 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