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
37#include "osi/include/metrics.h"
38
39namespace system_bt_osi {
40
41// Maximum number of log entries for each repeated field
42#define MAX_NUM_BLUETOOTH_SESSION 50
43#define MAX_NUM_PAIR_EVENT 50
44#define MAX_NUM_WAKE_EVENT 50
45#define MAX_NUM_SCAN_EVENT 50
46
47static float combine_averages(float avg_a, int64_t ct_a, float avg_b,
48                              int64_t ct_b) {
49  if (ct_a > 0 && ct_b > 0) {
50    return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
51  } else if (ct_b > 0) {
52    return avg_b;
53  } else {
54    return avg_a;
55  }
56}
57
58static int32_t combine_averages(int32_t avg_a, int64_t ct_a, int32_t avg_b,
59                                int64_t ct_b) {
60  if (ct_a > 0 && ct_b > 0) {
61    return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
62  } else if (ct_b > 0) {
63    return avg_b;
64  } else {
65    return avg_a;
66  }
67}
68
69void A2dpSessionMetrics::Update(const A2dpSessionMetrics& metrics) {
70  if (metrics.audio_duration_ms > 0) {
71    audio_duration_ms = std::max(static_cast<int64_t>(0), audio_duration_ms);
72    audio_duration_ms += metrics.audio_duration_ms;
73  }
74  if (metrics.media_timer_min_ms > 0) {
75    if (media_timer_min_ms < 0) {
76      media_timer_min_ms = metrics.media_timer_min_ms;
77    } else {
78      media_timer_min_ms =
79          std::min(media_timer_min_ms, metrics.media_timer_min_ms);
80    }
81  }
82  if (metrics.media_timer_max_ms > 0) {
83    media_timer_max_ms =
84        std::max(media_timer_max_ms, metrics.media_timer_max_ms);
85  }
86  if (metrics.media_timer_avg_ms > 0 && metrics.total_scheduling_count > 0) {
87    if (media_timer_avg_ms < 0 || total_scheduling_count < 0) {
88      media_timer_avg_ms = metrics.media_timer_avg_ms;
89      total_scheduling_count = metrics.total_scheduling_count;
90    } else {
91      media_timer_avg_ms = combine_averages(
92          media_timer_avg_ms, total_scheduling_count,
93          metrics.media_timer_avg_ms, metrics.total_scheduling_count);
94      total_scheduling_count += metrics.total_scheduling_count;
95    }
96  }
97  if (metrics.buffer_overruns_max_count > 0) {
98    buffer_overruns_max_count =
99        std::max(buffer_overruns_max_count, metrics.buffer_overruns_max_count);
100  }
101  if (metrics.buffer_overruns_total > 0) {
102    buffer_overruns_total =
103        std::max(static_cast<int32_t>(0), buffer_overruns_total);
104    buffer_overruns_total += metrics.buffer_overruns_total;
105  }
106  if (metrics.buffer_underruns_average > 0 &&
107      metrics.buffer_underruns_count > 0) {
108    if (buffer_underruns_average < 0 || buffer_underruns_count < 0) {
109      buffer_underruns_average = metrics.buffer_underruns_average;
110      buffer_underruns_count = metrics.buffer_underruns_count;
111    } else {
112      buffer_underruns_average = combine_averages(
113          metrics.buffer_underruns_average, metrics.buffer_underruns_count,
114          buffer_underruns_average, buffer_underruns_count);
115      buffer_underruns_count += metrics.buffer_underruns_count;
116    }
117  }
118}
119
120bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
121  return audio_duration_ms == rhs.audio_duration_ms &&
122         media_timer_min_ms == rhs.media_timer_min_ms &&
123         media_timer_max_ms == rhs.media_timer_max_ms &&
124         media_timer_avg_ms == rhs.media_timer_avg_ms &&
125         total_scheduling_count == rhs.total_scheduling_count &&
126         buffer_overruns_max_count == rhs.buffer_overruns_max_count &&
127         buffer_overruns_total == rhs.buffer_overruns_total &&
128         buffer_underruns_average == rhs.buffer_underruns_average &&
129         buffer_underruns_count == rhs.buffer_underruns_count;
130}
131
132struct BluetoothMetricsLogger::impl {
133  // TODO(siyuanh): Implement for linux
134};
135
136BluetoothMetricsLogger::BluetoothMetricsLogger() : pimpl_(new impl) {}
137
138void BluetoothMetricsLogger::LogPairEvent(uint32_t disconnect_reason,
139                                          uint64_t timestamp_ms,
140                                          uint32_t device_class,
141                                          device_type_t device_type) {
142  // TODO(siyuanh): Implement for linux
143}
144
145void BluetoothMetricsLogger::LogWakeEvent(wake_event_type_t type,
146                                          const std::string& requestor,
147                                          const std::string& name,
148                                          uint64_t timestamp_ms) {
149  // TODO(siyuanh): Implement for linux
150}
151
152void BluetoothMetricsLogger::LogScanEvent(bool start,
153                                          const std::string& initator,
154                                          scan_tech_t type, uint32_t results,
155                                          uint64_t timestamp_ms) {
156  // TODO(siyuanh): Implement for linux
157}
158
159void BluetoothMetricsLogger::LogBluetoothSessionStart(
160    connection_tech_t connection_tech_type, uint64_t timestamp_ms) {
161  // TODO(siyuanh): Implement for linux
162}
163
164void BluetoothMetricsLogger::LogBluetoothSessionEnd(
165    disconnect_reason_t disconnect_reason, uint64_t timestamp_ms) {
166  // TODO(siyuanh): Implement for linux
167}
168
169void BluetoothMetricsLogger::LogBluetoothSessionDeviceInfo(
170    uint32_t device_class, device_type_t device_type) {
171  // TODO(siyuanh): Implement for linux
172}
173
174void BluetoothMetricsLogger::LogA2dpSession(
175    const A2dpSessionMetrics& a2dp_session_metrics) {
176  // TODO(siyuanh): Implement for linux
177}
178
179void BluetoothMetricsLogger::WriteString(std::string* serialized, bool clear) {
180  // TODO(siyuanh): Implement for linux
181}
182
183void BluetoothMetricsLogger::WriteBase64String(std::string* serialized,
184                                               bool clear) {
185  // TODO(siyuanh): Implement for linux
186}
187
188void BluetoothMetricsLogger::WriteBase64(int fd, bool clear) {
189  // TODO(siyuanh): Implement for linux
190}
191
192void BluetoothMetricsLogger::CutoffSession() {
193  // TODO(siyuanh): Implement for linux
194}
195
196void BluetoothMetricsLogger::Build() {
197  // TODO(siyuanh): Implement for linux
198}
199
200void BluetoothMetricsLogger::Reset() {
201  // TODO(siyuanh): Implement for linux
202}
203
204}  // namespace system_bt_osi
205