• Home
  • History
  • Annotate
  • 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