• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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