Add persistent logging for BT events

Add a persistent log for BluetoothDeviceManager that gets dumped to
dumpsys. This is to help better debug BT issues that may be caused by
something that happens hours before any bugreport is taken.

Bug: 140607681
Test: manual
Change-Id: I6981fc70c4066338ec9e5246ff86136f6dbabacb
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 6167260..bfbd5d23 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -516,6 +516,13 @@
         pw.increaseIndent();
         mCallAudioRouteStateMachine.dumpPendingMessages(pw);
         pw.decreaseIndent();
+
+        pw.println("BluetoothDeviceManager:");
+        pw.increaseIndent();
+        if (mBluetoothStateReceiver.getBluetoothDeviceManager() != null) {
+            mBluetoothStateReceiver.getBluetoothDeviceManager().dump(pw);
+        }
+        pw.decreaseIndent();
     }
 
     @VisibleForTesting
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index 23a086b..92de536 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -22,7 +22,9 @@
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.telecom.Log;
+import android.util.LocalLog;
 
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.telecom.BluetoothAdapterProxy;
 import com.android.server.telecom.BluetoothHeadsetProxy;
 
@@ -43,18 +45,21 @@
                     Log.startSession("BMSL.oSC");
                     try {
                         synchronized (mLock) {
+                            String logString;
                             if (profile == BluetoothProfile.HEADSET) {
                                 mBluetoothHeadsetService =
                                         new BluetoothHeadsetProxy((BluetoothHeadset) proxy);
-                                Log.i(this, "- Got BluetoothHeadset: " + mBluetoothHeadsetService);
+                                logString = "Got BluetoothHeadset: " + mBluetoothHeadsetService;
                             } else if (profile == BluetoothProfile.HEARING_AID) {
                                 mBluetoothHearingAidService = (BluetoothHearingAid) proxy;
-                                Log.i(this, "- Got BluetoothHearingAid: "
-                                        + mBluetoothHearingAidService);
+                                logString = "Got BluetoothHearingAid: "
+                                        + mBluetoothHearingAidService;
                             } else {
-                                Log.w(this, "Connected to non-requested bluetooth service." +
-                                        " Not changing bluetooth headset.");
+                                logString = "Connected to non-requested bluetooth service." +
+                                        " Not changing bluetooth headset.";
                             }
+                            Log.i(BluetoothDeviceManager.this, logString);
+                            mLocalLog.log(logString);
                         }
                     } finally {
                         Log.endSession();
@@ -67,23 +72,25 @@
                     try {
                         synchronized (mLock) {
                             LinkedHashMap<String, BluetoothDevice> lostServiceDevices;
+                            String logString;
                             if (profile == BluetoothProfile.HEADSET) {
                                 mBluetoothHeadsetService = null;
-                                Log.i(BluetoothDeviceManager.this,
-                                        "Lost BluetoothHeadset service. " +
-                                                "Removing all tracked devices.");
                                 lostServiceDevices = mHfpDevicesByAddress;
                                 mBluetoothRouteManager.onActiveDeviceChanged(null, false);
+                                logString = "Lost BluetoothHeadset service. " +
+                                        "Removing all tracked devices";
                             } else if (profile == BluetoothProfile.HEARING_AID) {
                                 mBluetoothHearingAidService = null;
-                                Log.i(BluetoothDeviceManager.this,
-                                        "Lost BluetoothHearingAid service. " +
-                                                "Removing all tracked devices.");
+                                logString = "Lost BluetoothHearingAid service. " +
+                                        "Removing all tracked devices.";
                                 lostServiceDevices = mHearingAidDevicesByAddress;
                                 mBluetoothRouteManager.onActiveDeviceChanged(null, true);
                             } else {
                                 return;
                             }
+                            Log.i(BluetoothDeviceManager.this, logString);
+                            mLocalLog.log(logString);
+
                             List<BluetoothDevice> devicesToRemove = new LinkedList<>(
                                     lostServiceDevices.values());
                             lostServiceDevices.clear();
@@ -103,6 +110,7 @@
             new LinkedHashMap<>();
     private final LinkedHashMap<BluetoothDevice, Long> mHearingAidDeviceSyncIds =
             new LinkedHashMap<>();
+    private final LocalLog mLocalLog = new LocalLog(20);
 
     // This lock only protects internal state -- it doesn't lock on anything going into Telecom.
     private final Object mLock = new Object();
@@ -188,6 +196,8 @@
     }
 
     void onDeviceConnected(BluetoothDevice device, boolean isHearingAid) {
+        mLocalLog.log("Device connected -- address: " + device.getAddress() + " isHeadingAid: "
+                + isHearingAid);
         synchronized (mLock) {
             LinkedHashMap<String, BluetoothDevice> targetDeviceMap;
             if (isHearingAid) {
@@ -213,6 +223,8 @@
     }
 
     void onDeviceDisconnected(BluetoothDevice device, boolean isHearingAid) {
+        mLocalLog.log("Device disconnected -- address: " + device.getAddress() + " isHeadingAid: "
+                + isHearingAid);
         synchronized (mLock) {
             LinkedHashMap<String, BluetoothDevice> targetDeviceMap;
             if (isHearingAid) {
@@ -297,4 +309,7 @@
         }
     }
 
+    public void dump(IndentingPrintWriter pw) {
+        mLocalLog.dump(pw);
+    }
 }
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
index 9e64b56..7671abd 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
@@ -152,6 +152,10 @@
         }
     }
 
+    public BluetoothDeviceManager getBluetoothDeviceManager() {
+        return mBluetoothDeviceManager;
+    }
+
     public BluetoothStateReceiver(BluetoothDeviceManager deviceManager,
             BluetoothRouteManager routeManager) {
         mBluetoothDeviceManager = deviceManager;