Loading android/app/src/com/android/bluetooth/btservice/AdapterService.java +2 −1 Original line number Diff line number Diff line Loading @@ -942,6 +942,7 @@ public class AdapterService extends Service { int metricId = getMetricId(device); long currentTime = System.nanoTime(); long endToEndLatencyNanos = currentTime - socketCreationTimeNanos; byte[] remoteDeviceInfoBytes = MetricsLogger.getInstance().getRemoteDeviceInfoProto(device); BluetoothStatsLog.write( BluetoothStatsLog.BLUETOOTH_RFCOMM_CONNECTION_ATTEMPTED, metricId, Loading @@ -952,7 +953,7 @@ public class AdapterService extends Service { resultCode, isSerialPort, appUid, new byte[0]); remoteDeviceInfoBytes); } @RequiresPermission( Loading android/app/src/com/android/bluetooth/btservice/MetricsLogger.java +103 −35 Original line number Diff line number Diff line Loading @@ -18,14 +18,17 @@ package com.android.bluetooth.btservice; import static com.android.bluetooth.BtRestrictedStatsLog.RESTRICTED_BLUETOOTH_DEVICE_NAME_REPORTED; import android.app.AlarmManager; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.os.Build; import android.os.SystemClock; import android.util.Log; import android.util.proto.ProtoOutputStream; import androidx.annotation.RequiresApi; import com.android.bluetooth.BluetoothMetricsProto.BluetoothLog; import com.android.bluetooth.BluetoothMetricsProto.BluetoothRemoteDeviceInformation; import com.android.bluetooth.BluetoothMetricsProto.ProfileConnectionStats; import com.android.bluetooth.BluetoothMetricsProto.ProfileId; import com.android.bluetooth.BluetoothStatsLog; Loading @@ -34,6 +37,7 @@ import com.android.bluetooth.Utils; import com.android.modules.utils.build.SdkLevel; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Ascii; import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; Loading @@ -48,9 +52,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * Class of Bluetooth Metrics */ /** Class of Bluetooth Metrics */ public class MetricsLogger { private static final String TAG = "BluetoothMetricsLogger"; private static final String BLOOMFILTER_PATH = "/data/misc/bluetooth"; Loading @@ -68,11 +70,12 @@ public class MetricsLogger { private Context mContext = null; private AlarmManager mAlarmManager = null; private boolean mInitialized = false; static final private Object mLock = new Object(); private static final Object sLock = new Object(); private BloomFilter<byte[]> mBloomFilter = null; protected boolean mBloomFilterInitialized = false; private AlarmManager.OnAlarmListener mOnAlarmListener = new AlarmManager.OnAlarmListener () { private AlarmManager.OnAlarmListener mOnAlarmListener = new AlarmManager.OnAlarmListener() { @Override public void onAlarm() { drainBufferedCounters(); Loading @@ -82,7 +85,7 @@ public class MetricsLogger { public static MetricsLogger getInstance() { if (sInstance == null) { synchronized (mLock) { synchronized (sLock) { if (sInstance == null) { sInstance = new MetricsLogger(); } Loading @@ -99,7 +102,7 @@ public class MetricsLogger { @VisibleForTesting public static void setInstanceForTesting(MetricsLogger instance) { Utils.enforceInstrumentationTestMode(); synchronized (mLock) { synchronized (sLock) { Log.d(TAG, "setInstanceForTesting(), set to " + instance); sInstance = instance; } Loading @@ -122,11 +125,14 @@ public class MetricsLogger { mBloomFilterInitialized = true; } catch (IOException e1) { Log.w(TAG, "MetricsLogger can't read the BloomFilter file."); byte[] bloomfilterData = DeviceBloomfilterGenerator.hexStringToByteArray( byte[] bloomfilterData = DeviceBloomfilterGenerator.hexStringToByteArray( DeviceBloomfilterGenerator.BLOOM_FILTER_DEFAULT); try { mBloomFilter = BloomFilter.readFrom( new ByteArrayInputStream(bloomfilterData), Funnels.byteArrayFunnel()); mBloomFilter = BloomFilter.readFrom( new ByteArrayInputStream(bloomfilterData), Funnels.byteArrayFunnel()); mBloomFilterInitialized = true; Log.i(TAG, "The default bloomfilter is used"); return true; Loading Loading @@ -169,7 +175,7 @@ public class MetricsLogger { } long total = 0; synchronized (mLock) { synchronized (sLock) { if (mCounters.containsKey(key)) { total = mCounters.get(key); } Loading @@ -184,9 +190,9 @@ public class MetricsLogger { } /** * Log profile connection event by incrementing an internal counter for that profile. * This log persists over adapter enable/disable and only get cleared when metrics are * dumped or when Bluetooth process is killed. * Log profile connection event by incrementing an internal counter for that profile. This log * persists over adapter enable/disable and only get cleared when metrics are dumped or when * Bluetooth process is killed. * * @param profileId Bluetooth profile that is connected at this event */ Loading @@ -197,15 +203,15 @@ public class MetricsLogger { } /** * Dump collected metrics into proto using a builder. * Clean up internal data after the dump. * Dump collected metrics into proto using a builder. Clean up internal data after the dump. * * @param metricsBuilder proto builder for {@link BluetoothLog} */ public static void dumpProto(BluetoothLog.Builder metricsBuilder) { synchronized (sProfileConnectionCounts) { sProfileConnectionCounts.forEach( (key, value) -> metricsBuilder.addProfileConnectionStats( (key, value) -> metricsBuilder.addProfileConnectionStats( ProfileConnectionStats.newBuilder() .setProfileId(key) .setNumTimesConnected(value) Loading Loading @@ -236,14 +242,13 @@ public class MetricsLogger { Log.w(TAG, "count is not larger than 0. count: " + count + " key: " + key); return false; } BluetoothStatsLog.write( BluetoothStatsLog.BLUETOOTH_CODE_PATH_COUNTER, key, count); BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_CODE_PATH_COUNTER, key, count); return true; } protected void drainBufferedCounters() { Log.i(TAG, "drainBufferedCounters()."); synchronized (mLock) { synchronized (sLock) { // send mCounters to statsd for (int key : mCounters.keySet()) { count(key, mCounters.get(key)); Loading @@ -265,10 +270,75 @@ public class MetricsLogger { mBloomFilterInitialized = false; return true; } protected void cancelPendingDrain() { mAlarmManager.cancel(mOnAlarmListener); } private void writeFieldIfNotNull( ProtoOutputStream proto, long fieldType, long fieldCount, long fieldNumber, Object value) { if (value != null) { try { if (fieldType == ProtoOutputStream.FIELD_TYPE_STRING) { proto.write(fieldType | fieldCount | fieldNumber, value.toString()); } if (fieldType == ProtoOutputStream.FIELD_TYPE_INT32) { proto.write(fieldType | fieldCount | fieldNumber, (Integer) value); } } catch (Exception e) { Log.e(TAG, "Error writing field " + fieldNumber + ": " + e.getMessage()); } } } /** * Retrieves a byte array containing serialized remote device information for the specified * BluetoothDevice. This data can be used for remote device identification and logging. * * @param device The BluetoothDevice for which to retrieve device information. * @return A byte array containing the serialized remote device information. */ public byte[] getRemoteDeviceInfoProto(BluetoothDevice device) { ProtoOutputStream proto = new ProtoOutputStream(); // write Allowlisted Device Name Hash writeFieldIfNotNull( proto, ProtoOutputStream.FIELD_TYPE_STRING, ProtoOutputStream.FIELD_COUNT_SINGLE, BluetoothRemoteDeviceInformation.ALLOWLISTED_DEVICE_NAME_HASH_FIELD_NUMBER, getAllowlistedDeviceNameHash(device.getName())); // write COD writeFieldIfNotNull( proto, ProtoOutputStream.FIELD_TYPE_INT32, ProtoOutputStream.FIELD_COUNT_SINGLE, BluetoothRemoteDeviceInformation.CLASS_OF_DEVICE_FIELD_NUMBER, device.getBluetoothClass() != null ? device.getBluetoothClass().getClassOfDevice() : null); // write OUI writeFieldIfNotNull( proto, ProtoOutputStream.FIELD_TYPE_INT32, ProtoOutputStream.FIELD_COUNT_SINGLE, BluetoothRemoteDeviceInformation.OUI_FIELD_NUMBER, getOui(device)); return proto.getBytes(); } private int getOui(BluetoothDevice device) { return Integer.parseInt(device.getAddress().replace(":", "").substring(0, 6), 16); } private List<String> getWordBreakdownList(String deviceName) { if (deviceName == null) { return new ArrayList<String>(); Loading @@ -276,8 +346,7 @@ public class MetricsLogger { // remove more than one spaces in a row deviceName = deviceName.trim().replaceAll(" +", " "); // remove non alphanumeric characters and spaces, and transform to lower cases. String[] words = deviceName.replaceAll( "[^a-zA-Z0-9 ]", "").toLowerCase().split(" "); String[] words = Ascii.toLowerCase(deviceName.replaceAll("[^a-zA-Z0-9 ]", "")).split(" "); if (words.length > MAX_WORDS_ALLOWED_IN_DEVICE_NAME) { // Validity checking here to avoid excessively long sequences Loading Loading @@ -343,8 +412,7 @@ public class MetricsLogger { protected void statslogBluetoothDeviceNames(int metricId, String matchedString) { String sha256 = getSha256String(matchedString); Log.d(TAG, "Uploading sha256 hash of matched bluetooth device name: " + sha256); Log.d(TAG, "Uploading sha256 hash of matched bluetooth device name: " + sha256); BluetoothStatsLog.write( BluetoothStatsLog.BLUETOOTH_HASHED_DEVICE_NAME_REPORTED, metricId, sha256); } Loading android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java +26 −2 Original line number Diff line number Diff line Loading @@ -18,15 +18,21 @@ package com.android.bluetooth.btservice; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.BluetoothMetricsProto.BluetoothLog; import com.android.bluetooth.BluetoothMetricsProto.BluetoothRemoteDeviceInformation; import com.android.bluetooth.BluetoothMetricsProto.ProfileConnectionStats; import com.android.bluetooth.BluetoothMetricsProto.ProfileId; import com.android.bluetooth.TestUtils; import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import com.google.protobuf.InvalidProtocolBufferException; import org.junit.After; import org.junit.Assert; Loading Loading @@ -87,8 +93,7 @@ public class MetricsLoggerTest { private TestableMetricsLogger mTestableMetricsLogger; @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); @Mock private AdapterService mMockAdapterService; @Mock private AdapterService mMockAdapterService; public class TestableMetricsLogger extends MetricsLogger { public HashMap<Integer, Long> mTestableCounters = new HashMap<>(); Loading Loading @@ -256,6 +261,25 @@ public class MetricsLoggerTest { } } @Test public void testOuiFromBluetoothDevice() { BluetoothDevice bluetoothDevice = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); byte[] remoteDeviceInformationBytes = MetricsLogger.getInstance().getRemoteDeviceInfoProto(bluetoothDevice); try { BluetoothRemoteDeviceInformation bluetoothRemoteDeviceInformation = BluetoothRemoteDeviceInformation.parseFrom(remoteDeviceInformationBytes); int oui = (0 << 16) | (1 << 8) | 2; // OUI from the above mac address Assert.assertEquals(bluetoothRemoteDeviceInformation.getOui(), oui); } catch (InvalidProtocolBufferException e) { Assert.assertNull(e.getMessage()); // test failure here } } @Test public void uploadEmptyDeviceName() { initTestingBloomfilter(); Loading system/gd/proto/bluetooth/metrics/bluetooth.proto +20 −1 Original line number Diff line number Diff line Loading @@ -294,3 +294,22 @@ message HeadsetProfileConnectionStats { // Number of times this type of headset profile is connected optional int32 num_times_connected = 2; } /** * Encapsulates Remote Device Information. Needs to be kept consistent with * BluetoothRemoteDeviceInformation * in frameworks/proto_logging/stats/atoms/bluetooth/bluetooth_extension_atoms.proto * * Logged from: * packages/modules/Bluetooth */ message BluetoothRemoteDeviceInformation { // SHA256 hashed Bluetooth device name. optional string allowlisted_device_name_hash = 1; // Class of Device optional int32 class_of_device = 2; // The first three bytes of MAC address optional int32 oui = 3; } Loading
android/app/src/com/android/bluetooth/btservice/AdapterService.java +2 −1 Original line number Diff line number Diff line Loading @@ -942,6 +942,7 @@ public class AdapterService extends Service { int metricId = getMetricId(device); long currentTime = System.nanoTime(); long endToEndLatencyNanos = currentTime - socketCreationTimeNanos; byte[] remoteDeviceInfoBytes = MetricsLogger.getInstance().getRemoteDeviceInfoProto(device); BluetoothStatsLog.write( BluetoothStatsLog.BLUETOOTH_RFCOMM_CONNECTION_ATTEMPTED, metricId, Loading @@ -952,7 +953,7 @@ public class AdapterService extends Service { resultCode, isSerialPort, appUid, new byte[0]); remoteDeviceInfoBytes); } @RequiresPermission( Loading
android/app/src/com/android/bluetooth/btservice/MetricsLogger.java +103 −35 Original line number Diff line number Diff line Loading @@ -18,14 +18,17 @@ package com.android.bluetooth.btservice; import static com.android.bluetooth.BtRestrictedStatsLog.RESTRICTED_BLUETOOTH_DEVICE_NAME_REPORTED; import android.app.AlarmManager; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.os.Build; import android.os.SystemClock; import android.util.Log; import android.util.proto.ProtoOutputStream; import androidx.annotation.RequiresApi; import com.android.bluetooth.BluetoothMetricsProto.BluetoothLog; import com.android.bluetooth.BluetoothMetricsProto.BluetoothRemoteDeviceInformation; import com.android.bluetooth.BluetoothMetricsProto.ProfileConnectionStats; import com.android.bluetooth.BluetoothMetricsProto.ProfileId; import com.android.bluetooth.BluetoothStatsLog; Loading @@ -34,6 +37,7 @@ import com.android.bluetooth.Utils; import com.android.modules.utils.build.SdkLevel; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Ascii; import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; Loading @@ -48,9 +52,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * Class of Bluetooth Metrics */ /** Class of Bluetooth Metrics */ public class MetricsLogger { private static final String TAG = "BluetoothMetricsLogger"; private static final String BLOOMFILTER_PATH = "/data/misc/bluetooth"; Loading @@ -68,11 +70,12 @@ public class MetricsLogger { private Context mContext = null; private AlarmManager mAlarmManager = null; private boolean mInitialized = false; static final private Object mLock = new Object(); private static final Object sLock = new Object(); private BloomFilter<byte[]> mBloomFilter = null; protected boolean mBloomFilterInitialized = false; private AlarmManager.OnAlarmListener mOnAlarmListener = new AlarmManager.OnAlarmListener () { private AlarmManager.OnAlarmListener mOnAlarmListener = new AlarmManager.OnAlarmListener() { @Override public void onAlarm() { drainBufferedCounters(); Loading @@ -82,7 +85,7 @@ public class MetricsLogger { public static MetricsLogger getInstance() { if (sInstance == null) { synchronized (mLock) { synchronized (sLock) { if (sInstance == null) { sInstance = new MetricsLogger(); } Loading @@ -99,7 +102,7 @@ public class MetricsLogger { @VisibleForTesting public static void setInstanceForTesting(MetricsLogger instance) { Utils.enforceInstrumentationTestMode(); synchronized (mLock) { synchronized (sLock) { Log.d(TAG, "setInstanceForTesting(), set to " + instance); sInstance = instance; } Loading @@ -122,11 +125,14 @@ public class MetricsLogger { mBloomFilterInitialized = true; } catch (IOException e1) { Log.w(TAG, "MetricsLogger can't read the BloomFilter file."); byte[] bloomfilterData = DeviceBloomfilterGenerator.hexStringToByteArray( byte[] bloomfilterData = DeviceBloomfilterGenerator.hexStringToByteArray( DeviceBloomfilterGenerator.BLOOM_FILTER_DEFAULT); try { mBloomFilter = BloomFilter.readFrom( new ByteArrayInputStream(bloomfilterData), Funnels.byteArrayFunnel()); mBloomFilter = BloomFilter.readFrom( new ByteArrayInputStream(bloomfilterData), Funnels.byteArrayFunnel()); mBloomFilterInitialized = true; Log.i(TAG, "The default bloomfilter is used"); return true; Loading Loading @@ -169,7 +175,7 @@ public class MetricsLogger { } long total = 0; synchronized (mLock) { synchronized (sLock) { if (mCounters.containsKey(key)) { total = mCounters.get(key); } Loading @@ -184,9 +190,9 @@ public class MetricsLogger { } /** * Log profile connection event by incrementing an internal counter for that profile. * This log persists over adapter enable/disable and only get cleared when metrics are * dumped or when Bluetooth process is killed. * Log profile connection event by incrementing an internal counter for that profile. This log * persists over adapter enable/disable and only get cleared when metrics are dumped or when * Bluetooth process is killed. * * @param profileId Bluetooth profile that is connected at this event */ Loading @@ -197,15 +203,15 @@ public class MetricsLogger { } /** * Dump collected metrics into proto using a builder. * Clean up internal data after the dump. * Dump collected metrics into proto using a builder. Clean up internal data after the dump. * * @param metricsBuilder proto builder for {@link BluetoothLog} */ public static void dumpProto(BluetoothLog.Builder metricsBuilder) { synchronized (sProfileConnectionCounts) { sProfileConnectionCounts.forEach( (key, value) -> metricsBuilder.addProfileConnectionStats( (key, value) -> metricsBuilder.addProfileConnectionStats( ProfileConnectionStats.newBuilder() .setProfileId(key) .setNumTimesConnected(value) Loading Loading @@ -236,14 +242,13 @@ public class MetricsLogger { Log.w(TAG, "count is not larger than 0. count: " + count + " key: " + key); return false; } BluetoothStatsLog.write( BluetoothStatsLog.BLUETOOTH_CODE_PATH_COUNTER, key, count); BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_CODE_PATH_COUNTER, key, count); return true; } protected void drainBufferedCounters() { Log.i(TAG, "drainBufferedCounters()."); synchronized (mLock) { synchronized (sLock) { // send mCounters to statsd for (int key : mCounters.keySet()) { count(key, mCounters.get(key)); Loading @@ -265,10 +270,75 @@ public class MetricsLogger { mBloomFilterInitialized = false; return true; } protected void cancelPendingDrain() { mAlarmManager.cancel(mOnAlarmListener); } private void writeFieldIfNotNull( ProtoOutputStream proto, long fieldType, long fieldCount, long fieldNumber, Object value) { if (value != null) { try { if (fieldType == ProtoOutputStream.FIELD_TYPE_STRING) { proto.write(fieldType | fieldCount | fieldNumber, value.toString()); } if (fieldType == ProtoOutputStream.FIELD_TYPE_INT32) { proto.write(fieldType | fieldCount | fieldNumber, (Integer) value); } } catch (Exception e) { Log.e(TAG, "Error writing field " + fieldNumber + ": " + e.getMessage()); } } } /** * Retrieves a byte array containing serialized remote device information for the specified * BluetoothDevice. This data can be used for remote device identification and logging. * * @param device The BluetoothDevice for which to retrieve device information. * @return A byte array containing the serialized remote device information. */ public byte[] getRemoteDeviceInfoProto(BluetoothDevice device) { ProtoOutputStream proto = new ProtoOutputStream(); // write Allowlisted Device Name Hash writeFieldIfNotNull( proto, ProtoOutputStream.FIELD_TYPE_STRING, ProtoOutputStream.FIELD_COUNT_SINGLE, BluetoothRemoteDeviceInformation.ALLOWLISTED_DEVICE_NAME_HASH_FIELD_NUMBER, getAllowlistedDeviceNameHash(device.getName())); // write COD writeFieldIfNotNull( proto, ProtoOutputStream.FIELD_TYPE_INT32, ProtoOutputStream.FIELD_COUNT_SINGLE, BluetoothRemoteDeviceInformation.CLASS_OF_DEVICE_FIELD_NUMBER, device.getBluetoothClass() != null ? device.getBluetoothClass().getClassOfDevice() : null); // write OUI writeFieldIfNotNull( proto, ProtoOutputStream.FIELD_TYPE_INT32, ProtoOutputStream.FIELD_COUNT_SINGLE, BluetoothRemoteDeviceInformation.OUI_FIELD_NUMBER, getOui(device)); return proto.getBytes(); } private int getOui(BluetoothDevice device) { return Integer.parseInt(device.getAddress().replace(":", "").substring(0, 6), 16); } private List<String> getWordBreakdownList(String deviceName) { if (deviceName == null) { return new ArrayList<String>(); Loading @@ -276,8 +346,7 @@ public class MetricsLogger { // remove more than one spaces in a row deviceName = deviceName.trim().replaceAll(" +", " "); // remove non alphanumeric characters and spaces, and transform to lower cases. String[] words = deviceName.replaceAll( "[^a-zA-Z0-9 ]", "").toLowerCase().split(" "); String[] words = Ascii.toLowerCase(deviceName.replaceAll("[^a-zA-Z0-9 ]", "")).split(" "); if (words.length > MAX_WORDS_ALLOWED_IN_DEVICE_NAME) { // Validity checking here to avoid excessively long sequences Loading Loading @@ -343,8 +412,7 @@ public class MetricsLogger { protected void statslogBluetoothDeviceNames(int metricId, String matchedString) { String sha256 = getSha256String(matchedString); Log.d(TAG, "Uploading sha256 hash of matched bluetooth device name: " + sha256); Log.d(TAG, "Uploading sha256 hash of matched bluetooth device name: " + sha256); BluetoothStatsLog.write( BluetoothStatsLog.BLUETOOTH_HASHED_DEVICE_NAME_REPORTED, metricId, sha256); } Loading
android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java +26 −2 Original line number Diff line number Diff line Loading @@ -18,15 +18,21 @@ package com.android.bluetooth.btservice; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.BluetoothMetricsProto.BluetoothLog; import com.android.bluetooth.BluetoothMetricsProto.BluetoothRemoteDeviceInformation; import com.android.bluetooth.BluetoothMetricsProto.ProfileConnectionStats; import com.android.bluetooth.BluetoothMetricsProto.ProfileId; import com.android.bluetooth.TestUtils; import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import com.google.protobuf.InvalidProtocolBufferException; import org.junit.After; import org.junit.Assert; Loading Loading @@ -87,8 +93,7 @@ public class MetricsLoggerTest { private TestableMetricsLogger mTestableMetricsLogger; @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); @Mock private AdapterService mMockAdapterService; @Mock private AdapterService mMockAdapterService; public class TestableMetricsLogger extends MetricsLogger { public HashMap<Integer, Long> mTestableCounters = new HashMap<>(); Loading Loading @@ -256,6 +261,25 @@ public class MetricsLoggerTest { } } @Test public void testOuiFromBluetoothDevice() { BluetoothDevice bluetoothDevice = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); byte[] remoteDeviceInformationBytes = MetricsLogger.getInstance().getRemoteDeviceInfoProto(bluetoothDevice); try { BluetoothRemoteDeviceInformation bluetoothRemoteDeviceInformation = BluetoothRemoteDeviceInformation.parseFrom(remoteDeviceInformationBytes); int oui = (0 << 16) | (1 << 8) | 2; // OUI from the above mac address Assert.assertEquals(bluetoothRemoteDeviceInformation.getOui(), oui); } catch (InvalidProtocolBufferException e) { Assert.assertNull(e.getMessage()); // test failure here } } @Test public void uploadEmptyDeviceName() { initTestingBloomfilter(); Loading
system/gd/proto/bluetooth/metrics/bluetooth.proto +20 −1 Original line number Diff line number Diff line Loading @@ -294,3 +294,22 @@ message HeadsetProfileConnectionStats { // Number of times this type of headset profile is connected optional int32 num_times_connected = 2; } /** * Encapsulates Remote Device Information. Needs to be kept consistent with * BluetoothRemoteDeviceInformation * in frameworks/proto_logging/stats/atoms/bluetooth/bluetooth_extension_atoms.proto * * Logged from: * packages/modules/Bluetooth */ message BluetoothRemoteDeviceInformation { // SHA256 hashed Bluetooth device name. optional string allowlisted_device_name_hash = 1; // Class of Device optional int32 class_of_device = 2; // The first three bytes of MAC address optional int32 oui = 3; }