summaryrefslogtreecommitdiff
path: root/osi
diff options
context:
space:
mode:
authorMarie Janssen <jamuraa@google.com>2016-01-15 16:14:14 -0800
committerMarie Janssen <jamuraa@google.com>2016-02-12 08:27:46 -0800
commitaa11644f763b1d33123b3f71d1a6c3977e7d69cf (patch)
tree524f6c15944f1730a95a4cee19be740de2681f26 /osi
parent63b432ced6cc55bf6b1054e36d6cdb86410687ec (diff)
downloadandroid-system-bt-aa11644f763b1d33123b3f71d1a6c3977e7d69cf.tar.gz
android-system-bt-aa11644f763b1d33123b3f71d1a6c3977e7d69cf.tar.xz
osi: add metrics API
Add a metrics API, which supports creating events which are eventually passed up to the clearcut logging to track pairings and other events. Connect this to the dumpsys call when it is called. Change-Id: Idcf75541fd18b0413cc843d6c7e23a5f08a634a5
Diffstat (limited to 'osi')
-rw-r--r--osi/Android.mk32
-rw-r--r--osi/include/metrics.h71
-rw-r--r--osi/src/metrics.cpp170
-rw-r--r--osi/src/protos/bluetooth.proto201
-rw-r--r--osi/src/wakelock.c5
5 files changed, 475 insertions, 4 deletions
diff --git a/osi/Android.mk b/osi/Android.mk
index 1f906af..9eb5719 100644
--- a/osi/Android.mk
+++ b/osi/Android.mk
@@ -39,6 +39,7 @@ btosiCommonSrc := \
./src/hash_map.c \
./src/hash_map_utils.c \
./src/list.c \
+ ./src/metrics.cpp \
./src/mutex.c \
./src/reactor.c \
./src/ringbuffer.c \
@@ -79,6 +80,27 @@ btosiCommonIncludes := \
btosiCommonCFlags := -std=c99 -Wall -Werror -UNDEBUG -fvisibility=hidden \
$(bdroid_CFLAGS)
+
+# protobuf library for bluetooth
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbt-protos
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+generated_sources_dir := $(call local-generated-sources-dir)
+LOCAL_EXPORT_C_INCLUDE_DIRS += \
+ $(generated_sources_dir)/proto/system/bt
+LOCAL_SRC_FILES := $(call all-proto-files-under,src/protos/)
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbt-protos
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+generated_sources_dir := $(call local-generated-sources-dir)
+LOCAL_EXPORT_C_INCLUDE_DIRS += \
+ $(generated_sources_dir)/proto/system/bt
+LOCAL_SRC_FILES := $(call all-proto-files-under,src/protos/)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
# libosi static library for target
# ========================================================
include $(CLEAR_VARS)
@@ -90,6 +112,7 @@ LOCAL_CLANG_CFLAGS += -Wno-error=typedef-redefinition
LOCAL_MODULE := libosi
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libc liblog
+LOCAL_STATIC_LIBRARIES := libbt-protos
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
include $(BUILD_STATIC_LIBRARY)
@@ -110,6 +133,7 @@ LOCAL_CLANG_CFLAGS += -Wno-error=typedef-redefinition
LOCAL_MODULE := libosi-host
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_STATIC_LIBRARIES := libbt-protos
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
include $(BUILD_HOST_STATIC_LIBRARY)
endif
@@ -125,8 +149,8 @@ LOCAL_SRC_FILES := $(btosiCommonTestSrc)
LOCAL_CFLAGS := -Wall -UNDEBUG
LOCAL_MODULE := net_test_osi
LOCAL_MODULE_TAGS := tests
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_STATIC_LIBRARIES := libosi
+LOCAL_SHARED_LIBRARIES := liblog libprotobuf-cpp-full
+LOCAL_STATIC_LIBRARIES := libosi libbt-protos
include $(BUILD_NATIVE_TEST)
# libosi unit tests for host
@@ -139,7 +163,7 @@ LOCAL_CFLAGS := -Wall -UNDEBUG
LOCAL_LDLIBS := -lrt -lpthread
LOCAL_MODULE := net_test_osi
LOCAL_MODULE_TAGS := tests
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_STATIC_LIBRARIES := libosi-host
+LOCAL_SHARED_LIBRARIES := liblog libprotobuf-cpp-full
+LOCAL_STATIC_LIBRARIES := libosi-host libbt-protos
include $(BUILD_HOST_NATIVE_TEST)
endif
diff --git a/osi/include/metrics.h b/osi/include/metrics.h
new file mode 100644
index 0000000..85360f5
--- /dev/null
+++ b/osi/include/metrics.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+typedef enum {
+ DEVICE_TYPE_UNKNOWN,
+ DEVICE_TYPE_BREDR,
+ DEVICE_TYPE_LE,
+ DEVICE_TYPE_DUMO,
+} device_type_t;
+
+// Record a pairing event at Unix epoch time |timestamp_ms|
+// |device_class| and |device_type| denote the type of device paired.
+// |disconnect_reason| is the HCI reason for pairing disconnection,
+// see stack/include/hcidefs.h
+void metrics_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
+ uint32_t device_class, device_type_t device_type);
+
+typedef enum {
+ WAKE_EVENT_UNKNOWN,
+ WAKE_EVENT_ACQUIRED,
+ WAKE_EVENT_RELEASED,
+} wake_event_type_t;
+
+// Record a wake event at Unix epoch time |timestamp_ms|.
+// |type| specifies whether it was acquired or relased,
+// |requestor| if provided is the service requesting the wake lock.
+// |name| is the name of the wake lock held.
+void metrics_wake_event(wake_event_type_t type, const char *requestor,
+ const char *name, uint64_t timestamp_ms);
+
+typedef enum {
+ SCAN_TYPE_UNKNOWN,
+ SCAN_TECH_TYPE_LE,
+ SCAN_TECH_TYPE_BREDR,
+ SCAN_TECH_TYPE_BOTH,
+} scan_tech_t;
+
+// Record a scan event at Unix epoch time |timestamp_ms|.
+// |start| is true if this is the beginning of the scan.
+// |initiator| is a unique ID identifying the app starting the scan.
+// |type| is whether the scan reports BR/EDR, LE, or both.
+// |results| is the number of results to be reported.
+void metrics_scan_event(bool start, const char *initator, scan_tech_t type,
+ uint32_t results, uint64_t timestamp_ms);
+
+// Writes the metrics, in packed protobuf format, into the descriptor |fd|.
+// If |clear| is true, metrics events are cleared afterwards.
+void metrics_write(int fd, bool clear);
+
+// Writes the metrics, in human-readable protobuf format, into the descriptor
+// |fd|. If |clear| is true, metrics events are cleared afterwards.
+void metrics_print(int fd, bool clear);
diff --git a/osi/src/metrics.cpp b/osi/src/metrics.cpp
new file mode 100644
index 0000000..c1ccfc4
--- /dev/null
+++ b/osi/src/metrics.cpp
@@ -0,0 +1,170 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+
+#define LOG_TAG "bt_osi_metrics"
+
+extern "C" {
+#include "osi/include/metrics.h"
+
+#include <errno.h>
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+}
+
+#include "osi/src/protos/bluetooth.pb.h"
+
+#include <google/protobuf/text_format.h>
+
+using clearcut::connectivity::BluetoothLog;
+using clearcut::connectivity::DeviceInfo;
+using clearcut::connectivity::DeviceInfo_DeviceType;
+using clearcut::connectivity::PairEvent;
+using clearcut::connectivity::ScanEvent;
+using clearcut::connectivity::ScanEvent_ScanTechnologyType;
+using clearcut::connectivity::ScanEvent_ScanEventType;
+using clearcut::connectivity::WakeEvent;
+using clearcut::connectivity::WakeEvent_WakeEventType;
+
+BluetoothLog *pending;
+
+static void lazy_initialize(void) {
+ if (pending == nullptr) {
+ pending = BluetoothLog::default_instance().New();
+ }
+}
+
+void metrics_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
+ uint32_t device_class, device_type_t device_type) {
+ lazy_initialize();
+
+ PairEvent *event = pending->add_pair_event();
+
+ DeviceInfo *info = event->mutable_device_paired_with();
+
+ info->set_device_class(device_class);
+
+ DeviceInfo_DeviceType type = DeviceInfo::DEVICE_TYPE_UNKNOWN;
+
+ if (device_type == DEVICE_TYPE_BREDR)
+ type = DeviceInfo::DEVICE_TYPE_BREDR;
+ if (device_type == DEVICE_TYPE_LE)
+ type = DeviceInfo::DEVICE_TYPE_LE;
+ if (device_type == DEVICE_TYPE_DUMO)
+ type = DeviceInfo::DEVICE_TYPE_DUMO;
+
+ info->set_device_type(type);
+
+ event->set_disconnect_reason(disconnect_reason);
+
+ event->set_event_time_millis(timestamp_ms);
+
+}
+
+void metrics_wake_event(wake_event_type_t type, const char *requestor,
+ const char *name, uint64_t timestamp) {
+ lazy_initialize();
+
+ WakeEvent *event = pending->add_wake_event();
+
+ WakeEvent_WakeEventType waketype = WakeEvent::UNKNOWN;
+
+ if (type == WAKE_EVENT_ACQUIRED)
+ waketype = WakeEvent::ACQUIRED;
+ if (type == WAKE_EVENT_RELEASED)
+ waketype = WakeEvent::RELEASED;
+
+ event->set_wake_event_type(waketype);
+
+ if (requestor)
+ event->set_requestor(requestor);
+
+ if (name)
+ event->set_name(name);
+
+ event->set_event_time_millis(timestamp);
+}
+
+
+void metrics_scan_event(bool start, const char *initator, scan_tech_t type,
+ uint32_t results, uint64_t timestamp_ms) {
+ lazy_initialize();
+
+ ScanEvent *event = pending->add_scan_event();
+
+ if (start)
+ event->set_scan_event_type(ScanEvent::SCAN_EVENT_START);
+ else
+ event->set_scan_event_type(ScanEvent::SCAN_EVENT_STOP);
+
+ if (initator)
+ event->set_initiator(initator);
+
+ ScanEvent_ScanTechnologyType scantype = ScanEvent::SCAN_TYPE_UNKNOWN;
+
+ if (type == SCAN_TECH_TYPE_LE)
+ scantype = ScanEvent::SCAN_TECH_TYPE_LE;
+ if (type == SCAN_TECH_TYPE_BREDR)
+ scantype = ScanEvent::SCAN_TECH_TYPE_BREDR;
+ if (type == SCAN_TECH_TYPE_BOTH)
+ scantype = ScanEvent::SCAN_TECH_TYPE_BOTH;
+
+ event->set_scan_technology_type(scantype);
+
+ event->set_number_results(results);
+
+ event->set_event_time_millis(timestamp_ms);
+}
+
+void metrics_write(int fd, bool clear) {
+ LOG_DEBUG(LOG_TAG, "%s serializing metrics", __func__);
+ lazy_initialize();
+
+ std::string serialized;
+ if (!pending->SerializeToString(&serialized)) {
+ LOG_ERROR(LOG_TAG, "%s: error serializing metrics", __func__);
+ return;
+ }
+
+ if (write(fd, serialized.c_str(), serialized.size()) == -1) {
+ LOG_ERROR(LOG_TAG, "%s: error writing to dumpsys fd: %s (%d)", __func__,
+ strerror(errno), errno);
+ }
+
+ if (clear) {
+ pending->Clear();
+ }
+}
+
+void metrics_print(int fd, bool clear) {
+ LOG_DEBUG(LOG_TAG, "%s printing metrics", __func__);
+ lazy_initialize();
+
+ std::string pretty_output;
+ google::protobuf::TextFormat::PrintToString(*pending, &pretty_output);
+
+ if (write(fd, pretty_output.c_str(), pretty_output.size()) == -1) {
+ LOG_ERROR(LOG_TAG, "%s: error writing to dumpsys fd: %s (%d)", __func__,
+ strerror(errno), errno);
+ }
+
+ if (clear) {
+ pending->Clear();
+ }
+}
diff --git a/osi/src/protos/bluetooth.proto b/osi/src/protos/bluetooth.proto
new file mode 100644
index 0000000..9a233ad
--- /dev/null
+++ b/osi/src/protos/bluetooth.proto
@@ -0,0 +1,201 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+// Author: pkanwar@google.com (Pankaj Kanwar)
+// Protos for uploading bluetooth metrics.
+
+syntax = "proto2";
+
+package clearcut.connectivity;
+
+option java_package = "com.google.wireless.android.play.playlog.connectivity";
+//option (datapol.file_vetting_status) = "latest";
+
+// import "storage/datapol/annotations/proto/semantic_annotations.proto";
+
+message BluetoothLog {
+
+ // Session information that gets logged for every BT connection.
+ repeated BluetoothSession session = 1;
+
+ // Session information that gets logged for every Pair event.
+ repeated PairEvent pair_event = 2;
+
+ // Information for Wake locks.
+ repeated WakeEvent wake_event = 3;
+
+ // Scan event information.
+ repeated ScanEvent scan_event = 4;
+}
+
+// The information about the device.
+message DeviceInfo {
+
+ // Device type.
+ enum DeviceType {
+
+ // Type is unknown.
+ DEVICE_TYPE_UNKNOWN = 0;
+
+ DEVICE_TYPE_BREDR = 1;
+
+ DEVICE_TYPE_LE = 2;
+
+ DEVICE_TYPE_DUMO = 3;
+ }
+
+ // Device class
+ // https://cs.corp.google.com/#android/system/bt/stack/include/btm_api.h&q=major_computer.
+ optional int32 device_class = 1;
+
+ // Device type.
+ optional DeviceType device_type = 2;
+}
+
+// Information that gets logged for every Bluetooth connection.
+message BluetoothSession {
+
+ // Type of technology used in the connection.
+ enum ConnectionTechnologyType {
+
+ CONNECTION_TECHNOLOGY_TYPE_UNKNOWN = 0;
+
+ CONNECTION_TECHNOLOGY_TYPE_LE = 1;
+
+ CONNECTION_TECHNOLOGY_TYPE_BREDR = 2;
+ }
+
+ // Duration of the session.
+ optional int64 session_duration_sec = 2;
+
+ // Technology type.
+ optional ConnectionTechnologyType connection_technology_type = 3;
+
+ // Reason for disconnecting.
+ optional string disconnect_reason = 4;
+
+ // The information about the device which it is connected to.
+ optional DeviceInfo device_connected_to = 5;
+
+ // The information about the RFComm session.
+ optional RFCommSession rfcomm_session = 6;
+
+ // The information about the A2DP session.
+ optional A2DPSession a2dp_session = 7;
+}
+
+message RFCommSession {
+
+ // bytes transmitted.
+ optional int32 rx_bytes = 1;
+
+ // bytes transmitted.
+ optional int32 tx_bytes = 2;
+}
+
+// Session information that gets logged for every A2DP session.
+message A2DPSession {
+
+ // Media timer in milliseconds.
+ optional int32 media_timer_min_millis = 1;
+
+ // Media timer in milliseconds.
+ optional int32 media_timer_max_millis = 2;
+
+ // Media timer in milliseconds.
+ optional int32 media_timer_avg_millis = 3;
+
+ // Buffer overruns count.
+ optional int32 buffer_overruns_max_count = 4;
+
+ // Buffer overruns total.
+ optional int32 buffer_overruns_total = 5;
+
+ // Buffer underruns average.
+ optional float buffer_underruns_average = 6;
+
+ // Buffer underruns count.
+ optional int32 buffer_underruns_count = 7;
+}
+
+message PairEvent {
+
+ // The reason for disconnecting
+ // https://cs.corp.google.com/#android/system/bt/stack/include/hcidefs.h&q=failed_establish.
+ optional int32 disconnect_reason = 1;
+
+ // Pair event time
+ optional int64 event_time_millis = 2; // [(datapol.semantic_type) = ST_TIMESTAMP];
+
+ // The information about the device which it is paired to.
+ optional DeviceInfo device_paired_with = 3;
+}
+
+message WakeEvent {
+
+ // Information about the wake event type.
+ enum WakeEventType {
+
+ // Type is unknown.
+ UNKNOWN = 0;
+
+ // WakeLock was acquired.
+ ACQUIRED = 1;
+
+ // WakeLock was released.
+ RELEASED = 2;
+ }
+
+ // Information about the wake event type.
+ optional WakeEventType wake_event_type = 1;
+
+ // Initiator of the scan. Only the first three names will be stored.
+ // e.g. com.google.gms.
+ optional string requestor = 2;
+
+ // Name of the wakelock (e.g. bluedroid_timer).
+ optional string name = 3;
+
+ // Time of the event.
+ optional int64 event_time_millis = 4; // [(datapol.semantic_type) = ST_TIMESTAMP];
+}
+
+message ScanEvent {
+
+ // Scan type.
+ enum ScanTechnologyType {
+
+ // Scan Type is unknown.
+ SCAN_TYPE_UNKNOWN = 0;
+
+ SCAN_TECH_TYPE_LE = 1;
+
+ SCAN_TECH_TYPE_BREDR = 2;
+
+ SCAN_TECH_TYPE_BOTH = 3;
+ }
+
+ // Scan event type.
+ enum ScanEventType {
+
+ // Scan started.
+ SCAN_EVENT_START = 0;
+
+ // Scan stopped.
+ SCAN_EVENT_STOP = 1;
+ }
+
+ // Scan event type.
+ optional ScanEventType scan_event_type = 1;
+
+ // Initiator of the scan. Only the first three names will be stored.
+ // e.g. com.google.gms.
+ optional string initiator = 2;
+
+ // Technology used for scanning.
+ optional ScanTechnologyType scan_technology_type = 3;
+
+ // Number of results returned.
+ optional int32 number_results = 4;
+
+ // Time of the event.
+ optional int64 event_time_millis = 5; // [(datapol.semantic_type) = ST_TIMESTAMP];
+}
diff --git a/osi/src/wakelock.c b/osi/src/wakelock.c
index e67f62e..4053248 100644
--- a/osi/src/wakelock.c
+++ b/osi/src/wakelock.c
@@ -31,6 +31,7 @@
#include "osi/include/alarm.h"
#include "osi/include/allocator.h"
#include "osi/include/log.h"
+#include "osi/include/metrics.h"
#include "osi/include/osi.h"
#include "osi/include/thread.h"
#include "osi/include/wakelock.h"
@@ -285,6 +286,8 @@ static void update_wakelock_acquired_stats(bt_status_t acquired_status) {
wakelock_stats.last_acquired_timestamp_ms = now_ms;
pthread_mutex_unlock(&monitor);
+
+ metrics_wake_event(WAKE_EVENT_ACQUIRED, NULL, WAKE_LOCK_ID, now_ms);
}
//
@@ -325,6 +328,8 @@ static void update_wakelock_released_stats(bt_status_t released_status) {
wakelock_stats.total_acquired_interval_ms += delta_ms;
pthread_mutex_unlock(&monitor);
+
+ metrics_wake_event(WAKE_EVENT_RELEASED, NULL, WAKE_LOCK_ID, now_ms);
}
void wakelock_debug_dump(int fd) {