From f7435f2f832ab1faa9ca254143796e9516905c63 Mon Sep 17 00:00:00 2001 From: Ajay Panicker Date: Tue, 16 Feb 2016 10:38:53 -0800 Subject: [PATCH] Add Java Protobuf dump and ScanEvent Protobuf Add Protobuf dumping for the Java layer. Also add ScanEvent Protobuf to already existing scan event logging. Change-Id: Ib05973c8d98df3bead84b22b3773c42effb25c87 --- Android.mk | 4 +- .../bluetooth/btservice/AdapterService.java | 24 ++- .../bluetooth/btservice/ProfileService.java | 4 + .../android/bluetooth/btservice/bluetooth.proto | 202 +++++++++++++++++++++ src/com/android/bluetooth/gatt/ContextMap.java | 50 ++++- src/com/android/bluetooth/gatt/GattService.java | 7 + 6 files changed, 286 insertions(+), 5 deletions(-) create mode 100644 src/com/android/bluetooth/btservice/bluetooth.proto diff --git a/Android.mk b/Android.mk index 7b724d04..09cbaf42 100644 --- a/Android.mk +++ b/Android.mk @@ -15,7 +15,8 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ - $(call all-java-files-under, src) + $(call all-java-files-under, src) \ + $(call all-proto-files-under, src) LOCAL_PACKAGE_NAME := Bluetooth LOCAL_CERTIFICATE := platform @@ -23,6 +24,7 @@ LOCAL_CERTIFICATE := platform LOCAL_JNI_SHARED_LIBRARIES := libbluetooth_jni LOCAL_JAVA_LIBRARIES := javax.obex telephony-common libprotobuf-java-micro LOCAL_STATIC_JAVA_LIBRARIES := com.android.vcard bluetooth.mapsapi sap-api-java-static android-support-v4 +LOCAL_PROTOC_OPTIMIZE_TYPE := micro LOCAL_REQUIRED_MODULES := bluetooth.default LOCAL_MULTILIB := 32 diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java index cccb8630..f5c9c835 100644 --- a/src/com/android/bluetooth/btservice/AdapterService.java +++ b/src/com/android/bluetooth/btservice/AdapterService.java @@ -2098,8 +2098,11 @@ public class AdapterService extends Service { debugLog("dumpsys arguments, skipping normal dumpsys: " + TextUtils.join(" ", args)); if (args[0].startsWith("--proto")) { - dumpNative(fd, args); - // TODO(jamuraa): gather protobuf details here and merge + if (args[0].equals("--proto-java-bin")) { + dumpJava(fd); + } else { + dumpNative(fd, args); + } } return; } @@ -2128,10 +2131,25 @@ public class AdapterService extends Service { writer.write(sb.toString()); writer.flush(); - // Add native logs dumpNative(fd, args); } + private void dumpJava(FileDescriptor fd) { + BluetoothProto.BluetoothLog log = new BluetoothProto.BluetoothLog(); + + for (ProfileService profile : mProfiles) { + profile.dumpProto(log); + } + + try { + FileOutputStream protoOut = new FileOutputStream(fd); + protoOut.write(log.toByteArray()); + protoOut.close(); + } catch (IOException e) { + errorLog("Unable to write Java protobuf to file descriptor."); + } + } + private void debugLog(String msg) { if (DBG) Log.d(TAG, msg); } diff --git a/src/com/android/bluetooth/btservice/ProfileService.java b/src/com/android/bluetooth/btservice/ProfileService.java index 7a6908f0..02029472 100644 --- a/src/com/android/bluetooth/btservice/ProfileService.java +++ b/src/com/android/bluetooth/btservice/ProfileService.java @@ -164,6 +164,10 @@ public abstract class ProfileService extends Service { sb.append("\nProfile: " + mName + "\n"); } + public void dumpProto(BluetoothProto.BluetoothLog proto) { + // Do nothing + } + // with indenting for subclasses public static void println(StringBuilder sb, String s) { sb.append(" "); diff --git a/src/com/android/bluetooth/btservice/bluetooth.proto b/src/com/android/bluetooth/btservice/bluetooth.proto new file mode 100644 index 00000000..11311ea5 --- /dev/null +++ b/src/com/android/bluetooth/btservice/bluetooth.proto @@ -0,0 +1,202 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// Author: pkanwar@google.com (Pankaj Kanwar) +// Protos for uploading bluetooth metrics. + +syntax = "proto2"; + +package com.android.bluetooth.btservice; + +option java_package = "com.android.bluetooth.btservice"; +option java_outer_classname = "BluetoothProto"; +//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/src/com/android/bluetooth/gatt/ContextMap.java b/src/com/android/bluetooth/gatt/ContextMap.java index 7bb5bc37..bb797d13 100644 --- a/src/com/android/bluetooth/gatt/ContextMap.java +++ b/src/com/android/bluetooth/gatt/ContextMap.java @@ -33,6 +33,8 @@ import java.util.UUID; import java.util.HashMap; import java.util.Map; +import com.android.bluetooth.btservice.BluetoothProto; + /** * Helper class that keeps track of registered GATT applications. * This class manages application callbacks and keeps track of GATT connections. @@ -41,6 +43,10 @@ import java.util.Map; /*package*/ class ContextMap { private static final String TAG = GattServiceConfig.TAG_PREFIX + "ContextMap"; + static final int NUM_SCAN_EVENTS_KEPT = 20; + ArrayList mScanEvents = + new ArrayList(NUM_SCAN_EVENTS_KEPT); + /** * ScanStats class helps keep track of information about scans * on a per application basis. @@ -48,6 +54,7 @@ import java.util.Map; class ScanStats { static final int NUM_SCAN_DURATIONS_KEPT = 5; + String appName; int scansStarted = 0; int scansStopped = 0; boolean isScanning = false; @@ -59,10 +66,25 @@ import java.util.Map; long startTime = 0; long stopTime = 0; + public ScanStats(String name) { + appName = name; + } + void startScan() { this.scansStarted++; isScanning = true; startTime = System.currentTimeMillis(); + + BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); + scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_START); + scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); + scanEvent.setInitiator(appName); + scanEvent.setEventTimeMillis(System.currentTimeMillis()); + synchronized(mScanEvents) { + if(mScanEvents.size() == NUM_SCAN_EVENTS_KEPT) + mScanEvents.remove(0); + mScanEvents.add(scanEvent); + } } void stopScan() { @@ -78,6 +100,17 @@ import java.util.Map; if (lastScans.size() > NUM_SCAN_DURATIONS_KEPT) { lastScans.remove(0); } + + BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); + scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_STOP); + scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); + scanEvent.setInitiator(appName); + scanEvent.setEventTimeMillis(System.currentTimeMillis()); + synchronized(mScanEvents) { + if (mScanEvents.size() == NUM_SCAN_EVENTS_KEPT) + mScanEvents.remove(0); + mScanEvents.add(scanEvent); + } } } @@ -190,7 +223,7 @@ import java.util.Map; mApps.add(new App(uuid, callback, appName)); ScanStats scanStats = mScanStats.get(appName); if (scanStats == null) { - scanStats = new ScanStats(); + scanStats = new ScanStats(appName); mScanStats.put(appName, scanStats); } scanStats.isRegistered = true; @@ -312,6 +345,13 @@ import java.util.Map; } /** + * Get Logging info by application name + */ + ScanStats getScanStatsByName(String name) { + return mScanStats.get(name); + } + + /** * Get the device addresses for all connected devices */ Set getConnectedDevices() { @@ -492,4 +532,12 @@ import java.util.Map; sb.append("\n"); } } + + void dumpProto(BluetoothProto.BluetoothLog proto) { + synchronized(mScanEvents) { + for (BluetoothProto.ScanEvent event : mScanEvents) { + proto.addScanEvent(event); + } + } + } } diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java index 36acae56..4377e11e 100644 --- a/src/com/android/bluetooth/gatt/GattService.java +++ b/src/com/android/bluetooth/gatt/GattService.java @@ -46,6 +46,7 @@ import android.util.Log; import com.android.bluetooth.R; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; +import com.android.bluetooth.btservice.BluetoothProto; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.util.NumberUtils; import com.android.internal.annotations.VisibleForTesting; @@ -2369,6 +2370,12 @@ public class GattService extends ProfileService { mHandleMap.dump(sb); } + @Override + public void dumpProto(BluetoothProto.BluetoothLog proto) { + mClientMap.dumpProto(proto); + mServerMap.dumpProto(proto); + } + /************************************************************************** * GATT Test functions *************************************************************************/ -- 2.11.0