Metrics: Log remote device information to statsd

* Log device information through +XAPL HFP VSC
* Log deivce information through Bluetooth metadata APIs
* Do not respond to +XAPL VSC if the device info segment is badly
  formatted

Bug: 112969790
Test: make, test drive with statsd
Change-Id: Id3dd3009042f833254dde17dd3030e8527846df3
diff --git a/src/com/android/bluetooth/btservice/storage/DatabaseManager.java b/src/com/android/bluetooth/btservice/storage/DatabaseManager.java
index 50f5272..fd25da4 100644
--- a/src/com/android/bluetooth/btservice/storage/DatabaseManager.java
+++ b/src/com/android/bluetooth/btservice/storage/DatabaseManager.java
@@ -20,17 +20,20 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothProtoEnums;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.provider.Settings;
 import android.util.Log;
+import android.util.StatsLog;
 
 import com.android.bluetooth.btservice.AdapterService;
 import com.android.internal.annotations.VisibleForTesting;
@@ -219,6 +222,7 @@
                 }
                 return true;
             }
+            logManufacturerInfo(device, key, newValue);
             data.setCustomizedMeta(key, newValue);
 
             updateDatabase(data);
@@ -745,4 +749,34 @@
         message.obj = data.getAddress();
         mHandler.sendMessage(message);
     }
+
+    private void logManufacturerInfo(BluetoothDevice device, int key, String value) {
+        String callingApp = mAdapterService.getPackageManager().getNameForUid(
+                Binder.getCallingUid());
+        String manufacturerName = "";
+        String modelName = "";
+        String hardwareVersion = "";
+        String softwareVersion = "";
+        switch (key) {
+            case BluetoothDevice.METADATA_MANUFACTURER_NAME:
+                manufacturerName = value;
+                break;
+            case BluetoothDevice.METADATA_MODEL_NAME:
+                modelName = value;
+                break;
+            case BluetoothDevice.METADATA_HARDWARE_VERSION:
+                hardwareVersion = value;
+                break;
+            case BluetoothDevice.METADATA_SOFTWARE_VERSION:
+                softwareVersion = value;
+                break;
+            default:
+                // Do not log anything if metadata doesn't fall into above categories
+                return;
+        }
+        StatsLog.write(StatsLog.BLUETOOTH_DEVICE_INFO_REPORTED,
+                mAdapterService.obfuscateAddress(device),
+                BluetoothProtoEnums.DEVICE_INFO_EXTERNAL, callingApp, manufacturerName, modelName,
+                hardwareVersion, softwareVersion);
+    }
 }
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index 18f1ea4..c5485f9 100644
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -21,6 +21,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothProtoEnums;
 import android.bluetooth.hfp.BluetoothHfpProtoEnums;
 import android.content.Intent;
 import android.media.AudioManager;
@@ -1833,6 +1834,18 @@
             Log.w(TAG, "processAtXapl() argument types not match");
             return;
         }
+        String[] deviceInfo = ((String) args[0]).split("-");
+        if (deviceInfo.length != 3) {
+            Log.w(TAG, "processAtXapl() deviceInfo length " + deviceInfo.length + " is wrong");
+            return;
+        }
+        String vendorId = deviceInfo[0];
+        String productId = deviceInfo[1];
+        String version = deviceInfo[2];
+        StatsLog.write(StatsLog.BLUETOOTH_DEVICE_INFO_REPORTED,
+                mAdapterService.obfuscateAddress(device), BluetoothProtoEnums.DEVICE_INFO_INTERNAL,
+                BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_XAPL, vendorId, productId, version,
+                null);
         // feature = 2 indicates that we support battery level reporting only
         mNativeInterface.atResponseString(device, "+XAPL=iPhone," + String.valueOf(2));
     }
diff --git a/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java b/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
index 8daaebe..becdb3a 100644
--- a/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
+++ b/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
@@ -69,6 +69,8 @@
         mDatabase = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getTargetContext(),
                 MetadataDatabase.class).build();
 
+        when(mAdapterService.getPackageManager()).thenReturn(
+                InstrumentationRegistry.getTargetContext().getPackageManager());
         mDatabaseManager = new DatabaseManager(mAdapterService);
 
         BluetoothDevice[] bondedDevices = {mTestDevice};