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#pragma once
20
21#include <stdint.h>
22#include <memory>
23#include <string>
24
25namespace system_bt_osi {
26
27// Typedefs to hide protobuf definition to the rest of stack
28
29typedef enum {
30  DEVICE_TYPE_UNKNOWN,
31  DEVICE_TYPE_BREDR,
32  DEVICE_TYPE_LE,
33  DEVICE_TYPE_DUMO,
34} device_type_t;
35
36typedef enum {
37  WAKE_EVENT_UNKNOWN,
38  WAKE_EVENT_ACQUIRED,
39  WAKE_EVENT_RELEASED,
40} wake_event_type_t;
41
42typedef enum {
43  SCAN_TYPE_UNKNOWN,
44  SCAN_TECH_TYPE_LE,
45  SCAN_TECH_TYPE_BREDR,
46  SCAN_TECH_TYPE_BOTH,
47} scan_tech_t;
48
49typedef enum {
50  CONNECTION_TECHNOLOGY_TYPE_UNKNOWN,
51  CONNECTION_TECHNOLOGY_TYPE_LE,
52  CONNECTION_TECHNOLOGY_TYPE_BREDR,
53} connection_tech_t;
54
55typedef enum {
56  DISCONNECT_REASON_UNKNOWN,
57  DISCONNECT_REASON_METRICS_DUMP,
58  DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS,
59} disconnect_reason_t;
60
61/* Values of A2DP metrics that we care about
62 *
63 *    audio_duration_ms : sum of audio duration (in milliseconds).
64 *    device_class: device class of the paired device.
65 *    media_timer_min_ms : minimum scheduled time (in milliseconds)
66 *                         of the media timer.
67 *    media_timer_max_ms: maximum scheduled time (in milliseconds)
68 *                        of the media timer.
69 *    media_timer_avg_ms: average scheduled time (in milliseconds)
70 *                        of the media timer.
71 *    buffer_overruns_max_count: TODO - not clear what this is.
72 *    buffer_overruns_total : number of times the media buffer with
73 *                            audio data has overrun
74 *    buffer_underruns_average: TODO - not clear what this is.
75 *    buffer_underruns_count: number of times there was no enough
76 *                            audio data to add to the media buffer.
77 * NOTE: Negative values are invalid
78*/
79class A2dpSessionMetrics {
80 public:
81  A2dpSessionMetrics() {}
82
83  /*
84   * Update the metrics value in the current metrics object using the metrics
85   * objects supplied
86   */
87  void Update(const A2dpSessionMetrics& metrics);
88
89  /*
90   * Compare whether two metrics objects are equal
91   */
92  bool operator==(const A2dpSessionMetrics& rhs) const;
93
94  /*
95   * Initialize all values to -1 which is invalid in order to make a distinction
96   * between 0 and invalid values
97   */
98  int64_t audio_duration_ms = -1;
99  int32_t media_timer_min_ms = -1;
100  int32_t media_timer_max_ms = -1;
101  int32_t media_timer_avg_ms = -1;
102  int64_t total_scheduling_count = -1;
103  int32_t buffer_overruns_max_count = -1;
104  int32_t buffer_overruns_total = -1;
105  float buffer_underruns_average = -1;
106  int32_t buffer_underruns_count = -1;
107};
108
109class BluetoothMetricsLogger {
110 public:
111  static BluetoothMetricsLogger* GetInstance() {
112    static BluetoothMetricsLogger* instance = new BluetoothMetricsLogger();
113    return instance;
114  }
115
116  /*
117   * Record a pairing event
118   *
119   * Parameters:
120   *    timestamp_ms: Unix epoch time in milliseconds
121   *    device_class: class of remote device
122   *    device_type: type of remote device
123   *    disconnect_reason: HCI reason for pairing disconnection.
124   *                       See: stack/include/hcidefs.h
125   */
126  void LogPairEvent(uint32_t disconnect_reason, uint64_t timestamp_ms,
127                    uint32_t device_class, device_type_t device_type);
128
129  /*
130   * Record a wake event
131   *
132   * Parameters:
133   *    timestamp_ms: Unix epoch time in milliseconds
134   *    type: whether it was acquired or released
135   *    requestor: if provided is the service requesting the wake lock
136   *    name: the name of the wake lock held
137   */
138  void LogWakeEvent(wake_event_type_t type, const std::string& requestor,
139                    const std::string& name, uint64_t timestamp_ms);
140
141  /*
142   * Record a scan event
143   *
144   * Parameters
145   *    timestamp_ms : Unix epoch time in milliseconds
146   *    start : true if this is the beginning of the scan
147   *    initiator: a unique ID identifying the app starting the scan
148   *    type: whether the scan reports BR/EDR, LE, or both.
149   *    results: number of results to be reported.
150   */
151  void LogScanEvent(bool start, const std::string& initator, scan_tech_t type,
152                    uint32_t results, uint64_t timestamp_ms);
153
154  /*
155   * Start logging a Bluetooth session
156   *
157   * A Bluetooth session is defined a a connection between this device and
158   * another remote device which may include multiple profiles and protocols
159   *
160   * Only one Bluetooth session can exist at one time. Calling this method twice
161   * without LogBluetoothSessionEnd will result in logging a premature end of
162   * current Bluetooth session
163   *
164   * Parameters:
165   *    connection_tech_type : type of connection technology
166   *    timestamp_ms : the timestamp for session start, 0 means now
167   *
168   */
169  void LogBluetoothSessionStart(connection_tech_t connection_tech_type,
170                                uint64_t timestamp_ms);
171
172  /*
173   * Stop logging a Bluetooth session and pushes it to the log queue
174   *
175   * If no Bluetooth session exist, this method exits immediately
176   *
177   * Parameters:
178   *    disconnect_reason : A string representation of disconnect reason
179   *    timestamp_ms : the timestamp of session end, 0 means now
180   *
181   */
182  void LogBluetoothSessionEnd(disconnect_reason_t disconnect_reason,
183                              uint64_t timestamp_ms);
184
185  /*
186   * Log information about remote device in a current Bluetooth session
187   *
188   * If a Bluetooth session does not exist, create one with default parameter
189   * and timestamp now
190   *
191   * Parameters:
192   *    device_class : device_class defined in btm_api_types.h
193   *    device_type : type of remote device
194   */
195  void LogBluetoothSessionDeviceInfo(uint32_t device_class,
196                                     device_type_t device_type);
197
198  /*
199   * Log A2DP Audio Session Information
200   *
201   * - Repeated calls to this method will override previous metrics if in the
202   *   same Bluetooth connection
203   * - If a Bluetooth session does not exist, create one with default parameter
204   *   and timestamp now
205   *
206   * Parameters:
207   *    a2dp_session_metrics - pointer to struct holding a2dp stats
208   *
209   */
210  void LogA2dpSession(const A2dpSessionMetrics& a2dp_session_metrics);
211
212  /*
213   * Writes the metrics, in base64 protobuf format, into the descriptor FD
214   * If CLEAR is true, metrics events are cleared afterwards.
215   */
216  void WriteBase64(int fd, bool clear);
217  void WriteBase64String(std::string* serialized, bool clear);
218  void WriteString(std::string* serialized, bool clear);
219
220  /*
221   * Reset the metrics logger by cleaning up its staging queues and existing
222   * protobuf objects.
223   */
224  void Reset();
225
226  /*
227   * Maximum number of log entries for each session or event
228   */
229  static const size_t kMaxNumBluetoothSession = 50;
230  static const size_t kMaxNumPairEvent = 50;
231  static const size_t kMaxNumWakeEvent = 1000;
232  static const size_t kMaxNumScanEvent = 50;
233
234 private:
235  BluetoothMetricsLogger();
236
237  /*
238   * When a Bluetooth session is on and the user initiates a metrics dump, we
239   * need to be able to upload whatever we have first. This method breaks the
240   * ongoing Bluetooth session into two sessions with the previous one labeled
241   * as "METRICS_DUMP" for the disconnect reason.
242   */
243  void CutoffSession();
244
245  /*
246   * Build the internal metrics object using information gathered
247   */
248  void Build();
249
250  /*
251   * Reset objects related to current Bluetooth session
252   */
253  void ResetSession();
254
255  /*
256   * Reset the underlining BluetoothLog object
257   */
258  void ResetLog();
259
260  /*
261   * PIMPL style implementation to hide internal dependencies
262   */
263  struct impl;
264  std::unique_ptr<impl> const pimpl_;
265};
266}
267