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 
25 namespace system_bt_osi {
26 
27 // Typedefs to hide protobuf definition to the rest of stack
28 
29 typedef enum {
30   DEVICE_TYPE_UNKNOWN,
31   DEVICE_TYPE_BREDR,
32   DEVICE_TYPE_LE,
33   DEVICE_TYPE_DUMO,
34 } device_type_t;
35 
36 typedef enum {
37   WAKE_EVENT_UNKNOWN,
38   WAKE_EVENT_ACQUIRED,
39   WAKE_EVENT_RELEASED,
40 } wake_event_type_t;
41 
42 typedef 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 
49 typedef enum {
50   CONNECTION_TECHNOLOGY_TYPE_UNKNOWN,
51   CONNECTION_TECHNOLOGY_TYPE_LE,
52   CONNECTION_TECHNOLOGY_TYPE_BREDR,
53 } connection_tech_t;
54 
55 typedef 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 */
79 class A2dpSessionMetrics {
80  public:
A2dpSessionMetrics()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 
109 class BluetoothMetricsLogger {
110  public:
GetInstance()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