1 /******************************************************************************
2  *
3  *  Copyright 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 <android/bluetooth/hci/enums.pb.h>
22 #include <bta/include/bta_api.h>
23 #include <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
24 #include <stdint.h>
25 #include <memory>
26 #include <string>
27 
28 namespace bluetooth {
29 
30 namespace common {
31 
32 // Typedefs to hide protobuf definition to the rest of stack
33 
34 typedef enum {
35   DEVICE_TYPE_UNKNOWN,
36   DEVICE_TYPE_BREDR,
37   DEVICE_TYPE_LE,
38   DEVICE_TYPE_DUMO,
39 } device_type_t;
40 
41 typedef enum {
42   WAKE_EVENT_UNKNOWN,
43   WAKE_EVENT_ACQUIRED,
44   WAKE_EVENT_RELEASED,
45 } wake_event_type_t;
46 
47 typedef enum {
48   SCAN_TYPE_UNKNOWN,
49   SCAN_TECH_TYPE_LE,
50   SCAN_TECH_TYPE_BREDR,
51   SCAN_TECH_TYPE_BOTH,
52 } scan_tech_t;
53 
54 typedef enum {
55   CONNECTION_TECHNOLOGY_TYPE_UNKNOWN,
56   CONNECTION_TECHNOLOGY_TYPE_LE,
57   CONNECTION_TECHNOLOGY_TYPE_BREDR,
58 } connection_tech_t;
59 
60 typedef enum {
61   DISCONNECT_REASON_UNKNOWN,
62   DISCONNECT_REASON_METRICS_DUMP,
63   DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS,
64 } disconnect_reason_t;
65 
66 /* Values of A2DP metrics that we care about
67  *
68  *    audio_duration_ms : sum of audio duration (in milliseconds).
69  *    device_class: device class of the paired device.
70  *    media_timer_min_ms : minimum scheduled time (in milliseconds)
71  *                         of the media timer.
72  *    media_timer_max_ms: maximum scheduled time (in milliseconds)
73  *                        of the media timer.
74  *    media_timer_avg_ms: average scheduled time (in milliseconds)
75  *                        of the media timer.
76  *    buffer_overruns_max_count: TODO - not clear what this is.
77  *    buffer_overruns_total : number of times the media buffer with
78  *                            audio data has overrun
79  *    buffer_underruns_average: TODO - not clear what this is.
80  *    buffer_underruns_count: number of times there was no enough
81  *                            audio data to add to the media buffer.
82  * NOTE: Negative values are invalid
83  */
84 class A2dpSessionMetrics {
85  public:
A2dpSessionMetrics()86   A2dpSessionMetrics() {}
87 
88   /*
89    * Update the metrics value in the current metrics object using the metrics
90    * objects supplied
91    */
92   void Update(const A2dpSessionMetrics& metrics);
93 
94   /*
95    * Compare whether two metrics objects are equal
96    */
97   bool operator==(const A2dpSessionMetrics& rhs) const;
98 
99   /*
100    * Initialize all values to -1 which is invalid in order to make a distinction
101    * between 0 and invalid values
102    */
103   int64_t audio_duration_ms = -1;
104   int32_t media_timer_min_ms = -1;
105   int32_t media_timer_max_ms = -1;
106   int32_t media_timer_avg_ms = -1;
107   int64_t total_scheduling_count = -1;
108   int32_t buffer_overruns_max_count = -1;
109   int32_t buffer_overruns_total = -1;
110   float buffer_underruns_average = -1;
111   int32_t buffer_underruns_count = -1;
112   int64_t codec_index = -1;
113   bool is_a2dp_offload = false;
114 };
115 
116 class BluetoothMetricsLogger {
117  public:
GetInstance()118   static BluetoothMetricsLogger* GetInstance() {
119     static BluetoothMetricsLogger* instance = new BluetoothMetricsLogger();
120     return instance;
121   }
122 
123   /*
124    * Record a pairing event
125    *
126    * Parameters:
127    *    timestamp_ms: Unix epoch time in milliseconds
128    *    device_class: class of remote device
129    *    device_type: type of remote device
130    *    disconnect_reason: HCI reason for pairing disconnection.
131    *                       See: stack/include/hcidefs.h
132    */
133   void LogPairEvent(uint32_t disconnect_reason, uint64_t timestamp_ms,
134                     uint32_t device_class, device_type_t device_type);
135 
136   /*
137    * Record a wake event
138    *
139    * Parameters:
140    *    timestamp_ms: Unix epoch time in milliseconds
141    *    type: whether it was acquired or released
142    *    requestor: if provided is the service requesting the wake lock
143    *    name: the name of the wake lock held
144    */
145   void LogWakeEvent(wake_event_type_t type, const std::string& requestor,
146                     const std::string& name, uint64_t timestamp_ms);
147 
148   /*
149    * Record a scan event
150    *
151    * Parameters
152    *    timestamp_ms : Unix epoch time in milliseconds
153    *    start : true if this is the beginning of the scan
154    *    initiator: a unique ID identifying the app starting the scan
155    *    type: whether the scan reports BR/EDR, LE, or both.
156    *    results: number of results to be reported.
157    */
158   void LogScanEvent(bool start, const std::string& initator, scan_tech_t type,
159                     uint32_t results, uint64_t timestamp_ms);
160 
161   /*
162    * Start logging a Bluetooth session
163    *
164    * A Bluetooth session is defined a a connection between this device and
165    * another remote device which may include multiple profiles and protocols
166    *
167    * Only one Bluetooth session can exist at one time. Calling this method twice
168    * without LogBluetoothSessionEnd will result in logging a premature end of
169    * current Bluetooth session
170    *
171    * Parameters:
172    *    connection_tech_type : type of connection technology
173    *    timestamp_ms : the timestamp for session start, 0 means now
174    *
175    */
176   void LogBluetoothSessionStart(connection_tech_t connection_tech_type,
177                                 uint64_t timestamp_ms);
178 
179   /*
180    * Stop logging a Bluetooth session and pushes it to the log queue
181    *
182    * If no Bluetooth session exist, this method exits immediately
183    *
184    * Parameters:
185    *    disconnect_reason : A string representation of disconnect reason
186    *    timestamp_ms : the timestamp of session end, 0 means now
187    *
188    */
189   void LogBluetoothSessionEnd(disconnect_reason_t disconnect_reason,
190                               uint64_t timestamp_ms);
191 
192   /*
193    * Log information about remote device in a current Bluetooth session
194    *
195    * If a Bluetooth session does not exist, create one with default parameter
196    * and timestamp now
197    *
198    * Parameters:
199    *    device_class : device_class defined in btm_api_types.h
200    *    device_type : type of remote device
201    */
202   void LogBluetoothSessionDeviceInfo(uint32_t device_class,
203                                      device_type_t device_type);
204 
205   /*
206    * Log A2DP Audio Session Information
207    *
208    * - Repeated calls to this method will override previous metrics if in the
209    *   same Bluetooth connection
210    * - If a Bluetooth session does not exist, create one with default parameter
211    *   and timestamp now
212    *
213    * Parameters:
214    *    a2dp_session_metrics - pointer to struct holding a2dp stats
215    *
216    */
217   void LogA2dpSession(const A2dpSessionMetrics& a2dp_session_metrics);
218 
219   /**
220    * Log Headset profile RFCOMM connection event
221    *
222    * @param service_id the BTA service ID for this headset connection
223    */
224   void LogHeadsetProfileRfcConnection(tBTA_SERVICE_ID service_id);
225 
226   /*
227    * Writes the metrics, in base64 protobuf format, into the descriptor FD,
228    * metrics events are always cleared after dump
229    */
230   void WriteBase64(int fd);
231   void WriteBase64String(std::string* serialized);
232   void WriteString(std::string* serialized);
233 
234   /*
235    * Reset the metrics logger by cleaning up its staging queues and existing
236    * protobuf objects.
237    */
238   void Reset();
239 
240   /*
241    * Maximum number of log entries for each session or event
242    */
243   static const size_t kMaxNumBluetoothSession = 50;
244   static const size_t kMaxNumPairEvent = 50;
245   static const size_t kMaxNumWakeEvent = 1000;
246   static const size_t kMaxNumScanEvent = 50;
247 
248  private:
249   BluetoothMetricsLogger();
250 
251   /*
252    * When a Bluetooth session is on and the user initiates a metrics dump, we
253    * need to be able to upload whatever we have first. This method breaks the
254    * ongoing Bluetooth session into two sessions with the previous one labeled
255    * as "METRICS_DUMP" for the disconnect reason.
256    */
257   void CutoffSession();
258 
259   /*
260    * Build the internal metrics object using information gathered
261    */
262   void Build();
263 
264   /*
265    * Reset objects related to current Bluetooth session
266    */
267   void ResetSession();
268 
269   /*
270    * Reset the underlining BluetoothLog object
271    */
272   void ResetLog();
273 
274   /*
275    * PIMPL style implementation to hide internal dependencies
276    */
277   struct impl;
278   std::unique_ptr<impl> const pimpl_;
279 };
280 
281 /**
282  * Unknown connection handle for metrics purpose
283  */
284 static const uint32_t kUnknownConnectionHandle = 0xFFFF;
285 
286 /**
287  * Log link layer connection event
288  *
289  * @param address Stack wide consistent Bluetooth address of this event,
290  *                nullptr if unknown
291  * @param connection_handle connection handle of this event,
292  *                          {@link kUnknownConnectionHandle} if unknown
293  * @param direction direction of this connection
294  * @param link_type type of the link
295  * @param hci_cmd HCI command opecode associated with this event, if any
296  * @param hci_event HCI event code associated with this event, if any
297  * @param hci_ble_event HCI BLE event code associated with this event, if any
298  * @param cmd_status Command status associated with this event, if any
299  * @param reason_code Reason code associated with this event, if any
300  */
301 void LogLinkLayerConnectionEvent(const RawAddress* address,
302                                  uint32_t connection_handle,
303                                  android::bluetooth::DirectionEnum direction,
304                                  uint16_t link_type, uint32_t hci_cmd,
305                                  uint16_t hci_event, uint16_t hci_ble_event,
306                                  uint16_t cmd_status, uint16_t reason_code);
307 
308 /**
309  * Logs when Bluetooth controller failed to reply with command status within
310  * a timeout period after receiving an HCI command from the host
311  *
312  * @param hci_cmd opcode of HCI command that caused this timeout
313  */
314 void LogHciTimeoutEvent(uint32_t hci_cmd);
315 
316 /**
317  * Logs when we receive Bluetooth Read Remote Version Information Complete
318  * Event from the remote device, as documented by the Bluetooth Core HCI
319  * specification
320  *
321  * Reference: 5.0 Core Specification, Vol 2, Part E, Page 1118
322  *
323  * @param handle handle of associated ACL connection
324  * @param status HCI command status of this event
325  * @param version version code from read remote version complete event
326  * @param manufacturer_name manufacturer code from read remote version complete
327  *                          event
328  * @param subversion subversion code from read remote version complete event
329  */
330 void LogRemoteVersionInfo(uint16_t handle, uint8_t status, uint8_t version,
331                           uint16_t manufacturer_name, uint16_t subversion);
332 
333 /**
334  * Log A2DP audio buffer underrun event
335  *
336  * @param address A2DP device associated with this event
337  * @param encoding_interval_millis encoding interval in milliseconds
338  * @param num_missing_pcm_bytes number of PCM bytes that cannot be read from
339  *                              the source
340  */
341 void LogA2dpAudioUnderrunEvent(const RawAddress& address,
342                                uint64_t encoding_interval_millis,
343                                int num_missing_pcm_bytes);
344 
345 /**
346  * Log A2DP audio buffer overrun event
347  *
348  * @param address A2DP device associated with this event
349  * @param encoding_interval_millis encoding interval in milliseconds
350  * @param num_dropped_buffers number of encoded buffers dropped from Tx queue
351  * @param num_dropped_encoded_frames number of encoded frames dropped from Tx
352  *                                   queue
353  * @param num_dropped_encoded_bytes number of encoded bytes dropped from Tx
354  *                                  queue
355  */
356 void LogA2dpAudioOverrunEvent(const RawAddress& address,
357                               uint64_t encoding_interval_millis,
358                               int num_dropped_buffers,
359                               int num_dropped_encoded_frames,
360                               int num_dropped_encoded_bytes);
361 
362 /**
363  * Log read RSSI result
364  *
365  * @param address device associated with this event
366  * @param handle connection handle of this event,
367  *               {@link kUnknownConnectionHandle} if unknown
368  * @param cmd_status command status from read RSSI command
369  * @param rssi rssi value in dBm
370  */
371 void LogReadRssiResult(const RawAddress& address, uint16_t handle,
372                        uint32_t cmd_status, int8_t rssi);
373 
374 /**
375  * Log failed contact counter report
376  *
377  * @param address device associated with this event
378  * @param handle connection handle of this event,
379  *               {@link kUnknownConnectionHandle} if unknown
380  * @param cmd_status command status from read failed contact counter command
381  * @param failed_contact_counter Number of consecutive failed contacts for a
382  *                               connection corresponding to the Handle
383  */
384 void LogReadFailedContactCounterResult(const RawAddress& address,
385                                        uint16_t handle, uint32_t cmd_status,
386                                        int32_t failed_contact_counter);
387 
388 /**
389  * Log transmit power level for a particular device after read
390  *
391  * @param address device associated with this event
392  * @param handle connection handle of this event,
393  *               {@link kUnknownConnectionHandle} if unknown
394  * @param cmd_status command status from read failed contact counter command
395  * @param transmit_power_level transmit power level for connection to this
396  *                             device
397  */
398 void LogReadTxPowerLevelResult(const RawAddress& address, uint16_t handle,
399                                uint32_t cmd_status,
400                                int32_t transmit_power_level);
401 
402 /**
403  * Logs when there is an event related to Bluetooth Security Manager Protocol
404  *
405  * @param address address of associated device
406  * @param smp_cmd SMP command code associated with this event
407  * @param direction direction of this SMP command
408  * @param smp_fail_reason SMP pairing failure reason code from SMP spec
409  */
410 void LogSmpPairingEvent(const RawAddress& address, uint8_t smp_cmd,
411                         android::bluetooth::DirectionEnum direction,
412                         uint8_t smp_fail_reason);
413 
414 /**
415  * Logs there is an event related Bluetooth classic pairing
416  *
417  * @param address address of associated device
418  * @param handle connection handle of this event,
419  *               {@link kUnknownConnectionHandle} if unknown
420  * @param hci_cmd HCI command associated with this event
421  * @param hci_event HCI event associated with this event
422  * @param cmd_status Command status associated with this event
423  * @param reason_code Reason code associated with this event
424  * @param event_value A status value related to this specific event
425  */
426 void LogClassicPairingEvent(const RawAddress& address, uint16_t handle, uint32_t hci_cmd, uint16_t hci_event,
427                             uint16_t cmd_status, uint16_t reason_code, int64_t event_value);
428 
429 /**
430  * Logs when certain Bluetooth SDP attributes are discovered
431  *
432  * @param address address of associated device
433  * @param protocol_uuid 16 bit protocol UUID from Bluetooth Assigned Numbers
434  * @param attribute_id 16 bit attribute ID from Bluetooth Assigned Numbers
435  * @param attribute_size size of this attribute
436  * @param attribute_value pointer to the attribute data, must be larger than
437  *                        attribute_size
438  */
439 void LogSdpAttribute(const RawAddress& address, uint16_t protocol_uuid,
440                      uint16_t attribute_id, size_t attribute_size,
441                      const char* attribute_value);
442 
443 /**
444  * Logs when there is a change in Bluetooth socket connection state
445  *
446  * @param address address of associated device, empty if this is a server port
447  * @param port port of this socket connection
448  * @param type type of socket
449  * @param connection_state socket connection state
450  * @param tx_bytes number of bytes transmitted
451  * @param rx_bytes number of bytes received
452  * @param server_port server port of this socket, if any. When both
453  *        |server_port| and |port| fields are populated, |port| must be spawned
454  *        by |server_port|
455  * @param socket_role role of this socket, server or connection
456  * @param uid socket owner's uid
457  */
458 void LogSocketConnectionState(
459     const RawAddress& address, int port, int type,
460     android::bluetooth::SocketConnectionstateEnum connection_state,
461     int64_t tx_bytes, int64_t rx_bytes, int uid, int server_port,
462     android::bluetooth::SocketRoleEnum socket_role);
463 
464 /**
465  * Logs when a Bluetooth device's manufacturer information is learnt
466  *
467  * @param address address of associated device
468  * @param source_type where is this device info obtained from
469  * @param source_name name of the data source, internal or external
470  * @param manufacturer name of the manufacturer of this device
471  * @param model model of this device
472  * @param hardware_version hardware version of this device
473  * @param software_version software version of this device
474  */
475 void LogManufacturerInfo(const RawAddress& address,
476                          android::bluetooth::DeviceInfoSrcEnum source_type,
477                          const std::string& source_name,
478                          const std::string& manufacturer,
479                          const std::string& model,
480                          const std::string& hardware_version,
481                          const std::string& software_version);
482 }  // namespace common
483 
484 }  // namespace bluetooth
485