diff options
29 files changed, 804 insertions, 225 deletions
@@ -5,6 +5,7 @@ girardier@google.com #{LAST_RESORT_SUGGESTION} muhammadfalam@google.com #{LAST_RESORT_SUGGESTION} siyuanh@google.com #{LAST_RESORT_SUGGESTION} okamil@google.com #{LAST_RESORT_SUGGESTION} +wescande@google.com #{LAST_RESORT_SUGGESTION} # Per-file ownership diff --git a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java index 957b02c322..72648cbcfd 100644 --- a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java +++ b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java @@ -1297,9 +1297,9 @@ public class BassClientService extends ProfileService { return devices; } - private boolean isValidBroadcastSourceAddition( + private int checkDuplicateSourceAdditionAndGetSourceId( BluetoothDevice device, BluetoothLeBroadcastMetadata metaData) { - boolean retval = true; + int sourceId = BassConstants.INVALID_SOURCE_ID; List<BluetoothLeBroadcastReceiveState> currentAllSources = getAllSources(device); for (int i = 0; i < currentAllSources.size(); i++) { BluetoothLeBroadcastReceiveState state = currentAllSources.get(i); @@ -1307,17 +1307,12 @@ public class BassClientService extends ProfileService { && metaData.getSourceAddressType() == state.getSourceAddressType() && metaData.getSourceAdvertisingSid() == state.getSourceAdvertisingSid() && metaData.getBroadcastId() == state.getBroadcastId()) { - retval = false; - Log.e( - TAG, - "isValidBroadcastSourceAddition: fail for " - + device - + " metaData: " - + metaData); + sourceId = state.getSourceId(); + log("DuplicatedSourceAddition: for " + device + " metaData: " + metaData); break; } } - return retval; + return sourceId; } private boolean hasRoomForBroadcastSourceAddition(BluetoothDevice device) { @@ -1512,45 +1507,77 @@ public class BassClientService extends ProfileService { } } - private int areValidParametersToModifySource( - BluetoothLeBroadcastMetadata updatedMetadata, - BassClientStateMachine stateMachine, - Integer deviceSourceId, - BluetoothDevice device) { - if (updatedMetadata == null || stateMachine == null) { - log( - "areValidParametersToModifySource: Error bad parameters: sourceId = " - + deviceSourceId - + " updatedMetadata = " - + updatedMetadata); + private int validateParametersForSourceOperation( + BassClientStateMachine stateMachine, BluetoothDevice device) { + if (stateMachine == null) { + log("validateParameters: stateMachine is null for device: " + device); return BluetoothStatusCodes.ERROR_BAD_PARAMETERS; } - if (deviceSourceId == BassConstants.INVALID_SOURCE_ID) { - log("areValidParametersToModifySource: no such sourceId for device: " + device); - return BluetoothStatusCodes.ERROR_LE_BROADCAST_ASSISTANT_INVALID_SOURCE_ID; - } + if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) { - log("areValidParametersToModifySource: device is not connected"); + log("validateParameters: device is not connected, device: " + device); return BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR; } - byte[] code = updatedMetadata.getBroadcastCode(); + + return BluetoothStatusCodes.SUCCESS; + } + + private int validateParametersForSourceOperation( + BassClientStateMachine stateMachine, + BluetoothDevice device, + BluetoothLeBroadcastMetadata metadata) { + int status = validateParametersForSourceOperation(stateMachine, device); + if (status != BluetoothStatusCodes.SUCCESS) { + return status; + } + + if (metadata == null) { + log("validateParameters: metadata is null for device: " + device); + return BluetoothStatusCodes.ERROR_BAD_PARAMETERS; + } + + byte[] code = metadata.getBroadcastCode(); if ((code != null) && (code.length != 0)) { if ((code.length > 16) || (code.length < 4)) { log( - "areValidParametersToModifySource: Invalid broadcast code length: " + "validateParameters: Invalid broadcast code length: " + code.length + ", should be between 4 and 16 octets"); return BluetoothStatusCodes.ERROR_BAD_PARAMETERS; } } - if (stateMachine.hasPendingSourceOperation()) { - Log.w( - TAG, - "modifySource: source operation already pending, device: " - + device - + ", broadcastId: " - + updatedMetadata.getBroadcastId()); - return BluetoothStatusCodes.ERROR_ALREADY_IN_TARGET_STATE; + + return BluetoothStatusCodes.SUCCESS; + } + + private int validateParametersForSourceOperation( + BassClientStateMachine stateMachine, BluetoothDevice device, Integer sourceId) { + int status = validateParametersForSourceOperation(stateMachine, device); + if (status != BluetoothStatusCodes.SUCCESS) { + return status; + } + + if (sourceId == BassConstants.INVALID_SOURCE_ID) { + log("validateParameters: no such sourceId for device: " + device); + return BluetoothStatusCodes.ERROR_LE_BROADCAST_ASSISTANT_INVALID_SOURCE_ID; + } + + return BluetoothStatusCodes.SUCCESS; + } + + private int validateParametersForSourceOperation( + BassClientStateMachine stateMachine, + BluetoothDevice device, + BluetoothLeBroadcastMetadata metadata, + Integer sourceId) { + int status = validateParametersForSourceOperation(stateMachine, device, metadata); + if (status != BluetoothStatusCodes.SUCCESS) { + return status; + } + + if (sourceId == BassConstants.INVALID_SOURCE_ID) { + log("validateParameters: no such sourceId for device: " + device); + return BluetoothStatusCodes.ERROR_LE_BROADCAST_ASSISTANT_INVALID_SOURCE_ID; } return BluetoothStatusCodes.SUCCESS; @@ -2942,16 +2969,10 @@ public class BassClientService extends ProfileService { byte[] code = sourceMetadata.getBroadcastCode(); for (BluetoothDevice device : devices) { BassClientStateMachine stateMachine = getOrCreateStateMachine(device); - if (stateMachine == null) { - log("addSource: Error bad parameter: no state machine for " + device); - mCallbacks.notifySourceAddFailed( - device, sourceMetadata, BluetoothStatusCodes.ERROR_BAD_PARAMETERS); - continue; - } - if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) { - log("addSource: device is not connected"); - mCallbacks.notifySourceAddFailed( - device, sourceMetadata, BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR); + int statusCode = + validateParametersForSourceOperation(stateMachine, device, sourceMetadata); + if (statusCode != BluetoothStatusCodes.SUCCESS) { + mCallbacks.notifySourceAddFailed(device, sourceMetadata, statusCode); continue; } if (stateMachine.hasPendingSourceOperation()) { @@ -2965,12 +2986,19 @@ public class BassClientService extends ProfileService { device, sourceMetadata, BluetoothStatusCodes.ERROR_ALREADY_IN_TARGET_STATE); continue; } + if (leaudioBroadcastResyncHelper()) { + int sourceId = checkDuplicateSourceAdditionAndGetSourceId(device, sourceMetadata); + if (sourceId != BassConstants.INVALID_SOURCE_ID) { + updateSourceToResumeBroadcast(device, sourceId, sourceMetadata); + continue; + } + } if (!hasRoomForBroadcastSourceAddition(device)) { log("addSource: device has no room"); - Integer sourceId = getSourceIdToRemove(device); - if (sourceId != BassConstants.INVALID_SOURCE_ID) { + Integer sourceIdToRemove = getSourceIdToRemove(device); + if (sourceIdToRemove != BassConstants.INVALID_SOURCE_ID) { BluetoothLeBroadcastMetadata metaData = - stateMachine.getCurrentBroadcastMetadata(sourceId); + stateMachine.getCurrentBroadcastMetadata(sourceIdToRemove); if (metaData != null) { // Add host intentional pause if previous broadcast is different than // current @@ -2983,7 +3011,7 @@ public class BassClientService extends ProfileService { TAG, "Switch Broadcast Source: " + ("device: " + device) - + (", old SourceId: " + sourceId) + + (", old SourceId: " + sourceIdToRemove) + (", new broadcastId: " + sourceMetadata.getBroadcastId()) + (", new broadcastName: " + sourceMetadata.getBroadcastName())); @@ -2993,7 +3021,9 @@ public class BassClientService extends ProfileService { // mark group op for both remove and add source // so setSourceGroupManaged will be updated accordingly in callbacks enqueueSourceGroupOp( - device, BassClientStateMachine.REMOVE_BCAST_SOURCE, sourceId); + device, + BassClientStateMachine.REMOVE_BCAST_SOURCE, + sourceIdToRemove); enqueueSourceGroupOp( device, BassClientStateMachine.ADD_BCAST_SOURCE, sourceMetadata); } @@ -3004,7 +3034,7 @@ public class BassClientService extends ProfileService { Message message = stateMachine.obtainMessage(BassClientStateMachine.SWITCH_BCAST_SOURCE); message.obj = sourceMetadata; - message.arg1 = sourceId; + message.arg1 = sourceIdToRemove; stateMachine.sendMessage(message); } else { mCallbacks.notifySourceAddFailed( @@ -3014,22 +3044,14 @@ public class BassClientService extends ProfileService { } continue; } - if (!isValidBroadcastSourceAddition(device, sourceMetadata)) { - log("addSource: not a valid broadcast source addition"); - mCallbacks.notifySourceAddFailed( - device, - sourceMetadata, - BluetoothStatusCodes.ERROR_LE_BROADCAST_ASSISTANT_DUPLICATE_ADDITION); - continue; - } - if ((code != null) && (code.length != 0)) { - if ((code.length > 16) || (code.length < 4)) { - log( - "Invalid broadcast code length: " - + code.length - + ", should be between 4 and 16 octets"); + if (!leaudioBroadcastResyncHelper()) { + int sourceId = checkDuplicateSourceAdditionAndGetSourceId(device, sourceMetadata); + if (sourceId != BassConstants.INVALID_SOURCE_ID) { + log("addSource: not a valid broadcast source addition"); mCallbacks.notifySourceAddFailed( - device, sourceMetadata, BluetoothStatusCodes.ERROR_BAD_PARAMETERS); + device, + sourceMetadata, + BluetoothStatusCodes.ERROR_LE_BROADCAST_ASSISTANT_DUPLICATE_ADDITION); continue; } } @@ -3106,14 +3128,24 @@ public class BassClientService extends ProfileService { BluetoothDevice device = deviceSourceIdPair.getKey(); Integer deviceSourceId = deviceSourceIdPair.getValue(); BassClientStateMachine stateMachine = getOrCreateStateMachine(device); - int statusCode = - areValidParametersToModifySource( - updatedMetadata, stateMachine, deviceSourceId, device); + validateParametersForSourceOperation( + stateMachine, device, updatedMetadata, deviceSourceId); if (statusCode != BluetoothStatusCodes.SUCCESS) { mCallbacks.notifySourceModifyFailed(device, sourceId, statusCode); continue; } + if (stateMachine.hasPendingSourceOperation()) { + Log.w( + TAG, + "modifySource: source operation already pending, device: " + + device + + ", broadcastId: " + + updatedMetadata.getBroadcastId()); + mCallbacks.notifySourceModifyFailed( + device, sourceId, BluetoothStatusCodes.ERROR_ALREADY_IN_TARGET_STATE); + continue; + } sEventLogger.logd( TAG, @@ -3158,32 +3190,17 @@ public class BassClientService extends ProfileService { Map<BluetoothDevice, Integer> devices = getGroupManagedDeviceSources(sink, sourceId).second; for (Map.Entry<BluetoothDevice, Integer> deviceSourceIdPair : devices.entrySet()) { BluetoothDevice device = deviceSourceIdPair.getKey(); - Integer deviceSourceId = deviceSourceIdPair.getValue(); - BassClientStateMachine stateMachine = getOrCreateStateMachine(device); - /* Removes metadata for sink device if not paused */ if (!mPausedBroadcastSinks.contains(device)) { mBroadcastMetadataMap.remove(device); } - if (stateMachine == null) { - log("removeSource: Error bad parameters: device = " + device); - mCallbacks.notifySourceRemoveFailed( - device, sourceId, BluetoothStatusCodes.ERROR_BAD_PARAMETERS); - continue; - } - if (deviceSourceId == BassConstants.INVALID_SOURCE_ID) { - log("removeSource: no such sourceId for device: " + device); - mCallbacks.notifySourceRemoveFailed( - device, - sourceId, - BluetoothStatusCodes.ERROR_LE_BROADCAST_ASSISTANT_INVALID_SOURCE_ID); - continue; - } - if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) { - log("removeSource: device is not connected"); - mCallbacks.notifySourceRemoveFailed( - device, sourceId, BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR); + Integer deviceSourceId = deviceSourceIdPair.getValue(); + BassClientStateMachine stateMachine = getOrCreateStateMachine(device); + int statusCode = + validateParametersForSourceOperation(stateMachine, device, deviceSourceId); + if (statusCode != BluetoothStatusCodes.SUCCESS) { + mCallbacks.notifySourceRemoveFailed(device, sourceId, statusCode); continue; } @@ -3796,36 +3813,7 @@ public class BassClientService extends ProfileService { || activeSyncedSrc.contains( getSyncHandleForBroadcastId(metadata.getBroadcastId())))) { int sourceId = receiveState.get().getSourceId(); - int statusCode = - areValidParametersToModifySource( - metadata, stateMachine, sourceId, sink); - - if (statusCode != BluetoothStatusCodes.SUCCESS) { - mCallbacks.notifySourceModifyFailed(sink, sourceId, statusCode); - // remove the device from mPausedBroadcastSinks - iterator.remove(); - continue; - } - - sEventLogger.logd( - TAG, - "Modify Broadcast Source (resume): " - + ("device: " + sink) - + (", sourceId: " + sourceId) - + (", updatedBroadcastId: " + metadata.getBroadcastId()) - + (", updatedBroadcastName: " + metadata.getBroadcastName())); - Message message = - stateMachine.obtainMessage(BassClientStateMachine.UPDATE_BCAST_SOURCE); - message.arg1 = sourceId; - message.arg2 = - DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_BLUETOOTH, - "persist.vendor.service.bt.defNoPAS", - false) - ? BassConstants.PA_SYNC_PAST_NOT_AVAILABLE - : BassConstants.PA_SYNC_PAST_AVAILABLE; - message.obj = metadata; - stateMachine.sendMessage(message); + updateSourceToResumeBroadcast(sink, sourceId, metadata); } else { addSource(sink, metadata, false); } @@ -3848,6 +3836,44 @@ public class BassClientService extends ProfileService { logPausedBroadcastsAndSinks(); } + private void updateSourceToResumeBroadcast( + BluetoothDevice sink, int sourceId, BluetoothLeBroadcastMetadata metadata) { + BassClientStateMachine stateMachine = getOrCreateStateMachine(sink); + int statusCode = + validateParametersForSourceOperation(stateMachine, sink, metadata, sourceId); + if (statusCode != BluetoothStatusCodes.SUCCESS) { + return; + } + if (stateMachine.hasPendingSourceOperation()) { + Log.w( + TAG, + "updateSourceToResumeBroadcast: source operation already pending, device: " + + sink + + ", broadcastId: " + + metadata.getBroadcastId()); + return; + } + + sEventLogger.logd( + TAG, + "Modify Broadcast Source (resume): " + + ("device: " + sink) + + (", sourceId: " + sourceId) + + (", updatedBroadcastId: " + metadata.getBroadcastId()) + + (", updatedBroadcastName: " + metadata.getBroadcastName())); + Message message = stateMachine.obtainMessage(BassClientStateMachine.UPDATE_BCAST_SOURCE); + message.arg1 = sourceId; + message.arg2 = + DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_BLUETOOTH, + "persist.vendor.service.bt.defNoPAS", + false) + ? BassConstants.PA_SYNC_PAST_NOT_AVAILABLE + : BassConstants.PA_SYNC_PAST_AVAILABLE; + message.obj = metadata; + stateMachine.sendMessage(message); + } + /** Handle Unicast source stream status change */ public void handleUnicastSourceStreamStatusChange(int status) { mUnicastSourceStreamStatus = Optional.of(status); diff --git a/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java b/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java index 021b73289b..5954b827b0 100644 --- a/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java +++ b/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java @@ -1151,6 +1151,7 @@ class BassClientStateMachine extends StateMachine { log("processBroadcastReceiverState: invalid index: " + recvState.getSourceId()); return; } + int sourceId = recvState.getSourceId(); BluetoothLeBroadcastReceiveState oldRecvState = mBluetoothLeBroadcastReceiveStates.get(characteristic.getInstanceId()); if (oldRecvState == null) { @@ -1178,7 +1179,7 @@ class BassClientStateMachine extends StateMachine { .notifySourceAdded( mDevice, recvState, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); if (mPendingMetadata != null) { - setCurrentBroadcastMetadata(recvState.getSourceId(), mPendingMetadata); + setCurrentBroadcastMetadata(sourceId, mPendingMetadata); mPendingMetadata = null; } checkAndUpdateBroadcastCode(recvState); @@ -1224,28 +1225,28 @@ class BassClientStateMachine extends StateMachine { } else { log("update to an existing recvState"); if (mPendingMetadata != null) { - setCurrentBroadcastMetadata(recvState.getSourceId(), mPendingMetadata); + setCurrentBroadcastMetadata(sourceId, mPendingMetadata); mPendingMetadata = null; } removeMessages(CANCEL_PENDING_SOURCE_OPERATION); mService.getCallbacks() .notifySourceModified( mDevice, - recvState.getSourceId(), + sourceId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); checkAndUpdateBroadcastCode(recvState); processPASyncState(recvState); processSyncStateChangeStats(recvState); - if (isPendingRemove(recvState.getSourceId())) { + if (isPendingRemove(sourceId) && !isSyncedToTheSource(sourceId)) { Message message = obtainMessage(REMOVE_BCAST_SOURCE); - message.arg1 = recvState.getSourceId(); + message.arg1 = sourceId; sendMessage(message); } } } } - broadcastReceiverState(recvState, recvState.getSourceId()); + broadcastReceiverState(recvState, sourceId); } // Implements callback methods for GATT events that the app cares about. @@ -1916,7 +1917,7 @@ class BassClientStateMachine extends StateMachine { res[offset++] = (byte) numSubGroups; for (int i = 0; i < numSubGroups; i++) { - int bisIndexValue = existingState.getBisSyncState().get(i).intValue(); + int bisIndexValue = 0xFFFFFFFF; if (paSync == BassConstants.PA_SYNC_DO_NOT_SYNC) { bisIndexValue = 0; } else if (metaData != null @@ -1929,6 +1930,8 @@ class BassClientStateMachine extends StateMachine { if (bisIndexValue == 0) { bisIndexValue = 0xFFFFFFFF; } + } else if (i < existingState.getBisSyncState().size()) { + bisIndexValue = existingState.getBisSyncState().get(i).intValue(); } log("UPDATE_BCAST_SOURCE: bisIndexValue : " + bisIndexValue); // BIS_Sync diff --git a/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java b/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java index 6909bc6d49..6d5bb49338 100644 --- a/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java +++ b/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java @@ -545,6 +545,7 @@ final class BondStateMachine extends StateMachine { if (oldState == newState) { return; } + MetricsLogger.getInstance().logBondStateMachineEvent(device, newState); BluetoothStatsLog.write( BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, mAdapterService.obfuscateAddress(device), diff --git a/android/app/src/com/android/bluetooth/btservice/MedicalDeviceBloomfilterGenerator.java b/android/app/src/com/android/bluetooth/btservice/MedicalDeviceBloomfilterGenerator.java new file mode 100644 index 0000000000..06055cfc8f --- /dev/null +++ b/android/app/src/com/android/bluetooth/btservice/MedicalDeviceBloomfilterGenerator.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * 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. + */ +package com.android.bluetooth.btservice; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +/** Class to generate a medical device bloomfilter */ +public class MedicalDeviceBloomfilterGenerator { + + public static final String BLOOM_FILTER_DEFAULT = + "01070000003C01002106584044800850055" + + "002308488410020D9A00001138410510000" + + "000042004200000000000C2000000040064" + + "0120080020110412A500090520210040C40" + + "4002601040005004400148414006198A041" + + "00890000600400000800210041810600800" + + "0142208000721A030000028102448201110" + + "0002007120020101448C211490A2B000084" + + "C010004004C00C080808200026210608110" + + "200011200000015000000212C4400040802" + + "00111114840000001002080040186000404" + + "81C064400052381109017039900000200C9" + + "C0002E6480000101C40000601064001A018" + + "40440280A810001000040455A0404617034" + + "50000140040D020020C6204100804041600" + + "80840002000800804280028000440000122" + + "00808409905022000590000110448080400" + + "561004210020430092602000040C0090C00" + + "C18480020000519C1482100111011120390" + + "02C0000228208104800C050440000004040" + + "00871400882400140080000005308124900" + + "104000040002410508CA349000200000202" + + "90200920181890100800110220A20874820" + + "0428080054A0005101C0820060090080040" + + "6820C480F40081014010201800000018101" + + "208914100321008006520002030010800C4" + + "1022C000048206002010041220000008021" + + "002080314040000100030002008"; + + /** Provide byte[] version of a given string */ + public static byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = + (byte) + ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i + 1), 16)); + } + return data; + } + + /** Generate bloom filter file given filePath */ + public static void generateDefaultBloomfilter(String filePath) throws IOException { + File outputFile = new File(filePath); + outputFile.createNewFile(); // if file already exists will do nothing + FileOutputStream fos = new FileOutputStream(filePath); + fos.write(hexStringToByteArray(BLOOM_FILTER_DEFAULT)); + fos.close(); + } +} diff --git a/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java b/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java index 98040486db..b74220c9ea 100644 --- a/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java +++ b/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java @@ -15,6 +15,7 @@ */ package com.android.bluetooth.btservice; +import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__BOND; import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__PROFILE_CONNECTION; import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__PROFILE_CONNECTION_A2DP; import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__PROFILE_CONNECTION_A2DP_SINK; @@ -31,6 +32,8 @@ import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVEN import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__PROFILE_CONNECTION_PAN; import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__PROFILE_CONNECTION_PBAP_CLIENT; import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__PROFILE_CONNECTION_VOLUME_CONTROL; +import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__STATE_BONDED; +import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__STATE_NONE; import static com.android.bluetooth.BtRestrictedStatsLog.RESTRICTED_BLUETOOTH_DEVICE_NAME_REPORTED; import android.app.AlarmManager; @@ -96,7 +99,10 @@ public class MetricsLogger { private static final String TAG = "BluetoothMetricsLogger"; private static final String BLOOMFILTER_PATH = "/data/misc/bluetooth"; private static final String BLOOMFILTER_FILE = "/devices_for_metrics_v3"; + private static final String MEDICAL_DEVICE_BLOOMFILTER_FILE = "/medical_devices_for_metrics_v1"; public static final String BLOOMFILTER_FULL_PATH = BLOOMFILTER_PATH + BLOOMFILTER_FILE; + public static final String MEDICAL_DEVICE_BLOOMFILTER_FULL_PATH = + BLOOMFILTER_PATH + MEDICAL_DEVICE_BLOOMFILTER_FILE; // 6 hours timeout for counter metrics private static final long BLUETOOTH_COUNTER_METRICS_ACTION_DURATION_MILLIS = 6L * 3600L * 1000L; @@ -114,6 +120,10 @@ public class MetricsLogger { private BloomFilter<byte[]> mBloomFilter = null; protected boolean mBloomFilterInitialized = false; + private BloomFilter<byte[]> mMedicalDeviceBloomFilter = null; + + protected boolean mMedicalDeviceBloomFilterInitialized = false; + private AlarmManager.OnAlarmListener mOnAlarmListener = new AlarmManager.OnAlarmListener() { @Override @@ -185,10 +195,48 @@ public class MetricsLogger { return true; } + /** Initialize medical device bloom filter */ + public boolean initMedicalDeviceBloomFilter(String path) { + try { + File medicalDeviceFile = new File(path); + if (!medicalDeviceFile.exists()) { + Log.w(TAG, "MetricsLogger is creating a new medical device Bloomfilter file"); + MedicalDeviceBloomfilterGenerator.generateDefaultBloomfilter(path); + } + + FileInputStream inputStream = new FileInputStream(new File(path)); + mMedicalDeviceBloomFilter = + BloomFilter.readFrom(inputStream, Funnels.byteArrayFunnel()); + mMedicalDeviceBloomFilterInitialized = true; + } catch (IOException e1) { + Log.w(TAG, "MetricsLogger can't read the medical device BloomFilter file."); + byte[] bloomfilterData = + MedicalDeviceBloomfilterGenerator.hexStringToByteArray( + MedicalDeviceBloomfilterGenerator.BLOOM_FILTER_DEFAULT); + try { + mMedicalDeviceBloomFilter = + BloomFilter.readFrom( + new ByteArrayInputStream(bloomfilterData), + Funnels.byteArrayFunnel()); + mMedicalDeviceBloomFilterInitialized = true; + Log.i(TAG, "The medical device bloomfilter is used"); + return true; + } catch (IOException e2) { + Log.w(TAG, "The medical device bloomfilter can't be used."); + } + return false; + } + return true; + } + protected void setBloomfilter(BloomFilter bloomfilter) { mBloomFilter = bloomfilter; } + protected void setMedicalDeviceBloomfilter(BloomFilter bloomfilter) { + mMedicalDeviceBloomFilter = bloomfilter; + } + void init(AdapterService adapterService, RemoteDevices remoteDevices) { if (mInitialized) { return; @@ -203,6 +251,12 @@ public class MetricsLogger { // We still want to use this class even if the bloomfilter isn't initialized // so still return true here. } + if (!initMedicalDeviceBloomFilter(MEDICAL_DEVICE_BLOOMFILTER_FULL_PATH)) { + Log.w(TAG, "MetricsLogger can't initialize the medical device bloomfilter"); + // The class is for multiple metrics tasks. + // We still want to use this class even if the bloomfilter isn't initialized + // so still return true here. + } IntentFilter filter = new IntentFilter(); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); @@ -289,7 +343,8 @@ public class MetricsLogger { BluetoothDevice device = connIntent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); int state = connIntent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); int metricId = mAdapterService.getMetricId(device); - byte[] remoteDeviceInfoBytes = getRemoteDeviceInfoProto(device); + boolean includeMedicalDevices = false; + byte[] remoteDeviceInfoBytes = getRemoteDeviceInfoProto(device, includeMedicalDevices); if (state == BluetoothProfile.STATE_CONNECTING) { String deviceName = mRemoteDevices.getName(device); BluetoothStatsLog.write( @@ -417,6 +472,7 @@ public class MetricsLogger { mAdapterService = null; mInitialized = false; mBloomFilterInitialized = false; + mMedicalDeviceBloomFilterInitialized = false; } protected void cancelPendingDrain() { @@ -446,15 +502,31 @@ public class MetricsLogger { /** * Retrieves a byte array containing serialized remote device information for the specified - * BluetoothDevice. This data can be used for remote device identification and logging. + * BluetoothDevice. This data can be used for remote device identification and logging. Does not + * include medical remote devices. * * @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) { - if (!mInitialized) { - return null; - } + return mInitialized ? buildRemoteDeviceInfoProto(device, false) : null; + } + + /** + * 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. + * @param includeMedicalDevices Should be true only if logging as de-identified metric, + * otherwise false. + * @return A byte array containing the serialized remote device information. + */ + public byte[] getRemoteDeviceInfoProto(BluetoothDevice device, boolean includeMedicalDevices) { + return mInitialized ? buildRemoteDeviceInfoProto(device, includeMedicalDevices) : null; + } + + private byte[] buildRemoteDeviceInfoProto( + BluetoothDevice device, boolean includeMedicalDevices) { ProtoOutputStream proto = new ProtoOutputStream(); // write Allowlisted Device Name Hash @@ -463,7 +535,8 @@ public class MetricsLogger { ProtoOutputStream.FIELD_TYPE_STRING, ProtoOutputStream.FIELD_COUNT_SINGLE, BluetoothRemoteDeviceInformation.ALLOWLISTED_DEVICE_NAME_HASH_FIELD_NUMBER, - getAllowlistedDeviceNameHash(mAdapterService.getRemoteName(device))); + getAllowlistedDeviceNameHash( + mAdapterService.getRemoteName(device), includeMedicalDevices)); // write COD writeFieldIfNotNull( @@ -567,7 +640,7 @@ public class MetricsLogger { } } - private String getMatchedString(List<String> wordBreakdownList) { + private String getMatchedString(List<String> wordBreakdownList, boolean includeMedicalDevices) { if (!mBloomFilterInitialized || wordBreakdownList.isEmpty()) { return ""; } @@ -579,6 +652,21 @@ public class MetricsLogger { matchedString = word; } } + + return (matchedString.equals("") && includeMedicalDevices) + ? getMatchedStringForMedicalDevice(wordBreakdownList) + : matchedString; + } + + private String getMatchedStringForMedicalDevice(List<String> wordBreakdownList) { + String matchedString = ""; + for (String word : wordBreakdownList) { + byte[] sha256 = getSha256(word); + if (mMedicalDeviceBloomFilter.mightContain(sha256) + && word.length() > matchedString.length()) { + matchedString = word; + } + } return matchedString; } @@ -664,16 +752,18 @@ public class MetricsLogger { advDurationMs); } - protected String getAllowlistedDeviceNameHash(String deviceName) { + protected String getAllowlistedDeviceNameHash( + String deviceName, boolean includeMedicalDevices) { List<String> wordBreakdownList = getWordBreakdownList(deviceName); - String matchedString = getMatchedString(wordBreakdownList); + String matchedString = getMatchedString(wordBreakdownList, includeMedicalDevices); return getSha256String(matchedString); } protected String logAllowlistedDeviceNameHash( int metricId, String deviceName, boolean logRestrictedNames) { List<String> wordBreakdownList = getWordBreakdownList(deviceName); - String matchedString = getMatchedString(wordBreakdownList); + boolean includeMedicalDevices = false; + String matchedString = getMatchedString(wordBreakdownList, includeMedicalDevices); if (logRestrictedNames) { // Log the restricted bluetooth device name if (SdkLevel.isAtLeastU()) { @@ -695,7 +785,7 @@ public class MetricsLogger { public void logBluetoothEvent(BluetoothDevice device, int eventType, int state, int uid) { - if (mAdapterService.getMetricId(device) == 0 || !mInitialized) { + if (!mInitialized || mAdapterService.getMetricId(device) == 0) { return; } @@ -705,7 +795,7 @@ public class MetricsLogger { state, uid, mAdapterService.getMetricId(device), - getRemoteDeviceInfoProto(device)); + getRemoteDeviceInfoProto(device, false)); } protected static String getSha256String(String name) { @@ -815,6 +905,27 @@ public class MetricsLogger { sessionStatus); } + /** Logs Bond State Machine event */ + public void logBondStateMachineEvent(BluetoothDevice device, int bondState) { + switch (bondState) { + case BluetoothDevice.BOND_NONE: + logBluetoothEvent( + device, + BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__BOND, + BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__STATE_NONE, + 0); + break; + case BluetoothDevice.BOND_BONDED: + logBluetoothEvent( + device, + BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__BOND, + BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__STATE_BONDED, + 0); + break; + default: + } + } + /** Logs LE Audio Broadcast audio sync. */ public void logLeAudioBroadcastAudioSync( BluetoothDevice device, @@ -836,6 +947,6 @@ public class MetricsLogger { latencyPaSyncMs, latencyBisSyncMs, syncStatus, - getRemoteDeviceInfoProto(device)); + getRemoteDeviceInfoProto(device, false)); } } diff --git a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java index 696526bb26..685bd05839 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java @@ -2701,6 +2701,60 @@ public class BassClientStateMachineTest { assertThat(mBassClientStateMachine.mPendingSourceId).isEqualTo(sourceId); } + @Test + public void updateBroadcastSource_pendingSourceToRemove() { + prepareInitialReceiveStateForGatt(); + + generateBroadcastReceiveStatesAndVerify( + mSourceTestDevice, + TEST_SOURCE_ID, + BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED, + BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING, + 0x1L); + + BassClientStateMachine.BluetoothGattTestableWrapper btGatt = + Mockito.mock(BassClientStateMachine.BluetoothGattTestableWrapper.class); + mBassClientStateMachine.mBluetoothGatt = btGatt; + BluetoothGattCharacteristic scanControlPoint = + Mockito.mock(BluetoothGattCharacteristic.class); + mBassClientStateMachine.mBroadcastScanControlPoint = scanControlPoint; + + BluetoothLeBroadcastMetadata metadata = createBroadcastMetadata(); + mBassClientStateMachine.mPendingMetadata = metadata; + + sendMessageAndVerifyTransition( + mBassClientStateMachine.obtainMessage( + UPDATE_BCAST_SOURCE, + TEST_SOURCE_ID, + BassConstants.PA_SYNC_DO_NOT_SYNC, + metadata), + BassClientStateMachine.ConnectedProcessing.class); + assertThat(mBassClientStateMachine.mPendingOperation).isEqualTo(UPDATE_BCAST_SOURCE); + assertThat(mBassClientStateMachine.mPendingSourceId).isEqualTo(TEST_SOURCE_ID); + + mBassClientStateMachine.mPendingOperation = 0; + mBassClientStateMachine.mPendingSourceId = 0; + // Verify not removing source when PA is still synced + generateBroadcastReceiveStatesAndVerify( + mSourceTestDevice, + TEST_SOURCE_ID, + BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED, + BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, + 0x0L); + assertThat(mBassClientStateMachine.mPendingOperation).isEqualTo(0); + assertThat(mBassClientStateMachine.mPendingSourceId).isEqualTo(0); + + // Verify removing source when PA is unsynced + generateBroadcastReceiveStatesAndVerify( + mSourceTestDevice, + TEST_SOURCE_ID, + BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, + BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, + 0x0L); + assertThat(mBassClientStateMachine.mPendingOperation).isEqualTo(REMOVE_BCAST_SOURCE); + assertThat(mBassClientStateMachine.mPendingSourceId).isEqualTo(TEST_SOURCE_ID); + } + private void initToConnectingState() { allowConnection(true); allowConnectGatt(true); diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java index 3f0331f2b8..018fccff17 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java @@ -270,6 +270,28 @@ public class MetricsLoggerTest { } @Test + public void testGetAllowlistedDeviceNameHashForMedicalDevice() { + String deviceName = "Sam's rphonak hearing aid"; + String expectMedicalDeviceSha256 = MetricsLogger.getSha256String("rphonakhearingaid"); + + String actualMedicalDeviceSha256 = + mTestableMetricsLogger.getAllowlistedDeviceNameHash(deviceName, true); + + Assert.assertEquals(expectMedicalDeviceSha256, actualMedicalDeviceSha256); + } + + @Test + public void testGetAllowlistedDeviceNameHashForMedicalDeviceIdentifiedLogging() { + String deviceName = "Sam's rphonak hearing aid"; + String expectMedicalDeviceSha256 = ""; + + String actualMedicalDeviceSha256 = + mTestableMetricsLogger.getAllowlistedDeviceNameHash(deviceName, false); + + Assert.assertEquals(expectMedicalDeviceSha256, actualMedicalDeviceSha256); + } + + @Test public void uploadEmptyDeviceName() { initTestingBloomfilter(); Assert.assertEquals("", mTestableMetricsLogger.logAllowlistedDeviceNameHash(1, "", true)); diff --git a/flags/gap.aconfig b/flags/gap.aconfig index 2b2b5cdd55..36a83faa6f 100644 --- a/flags/gap.aconfig +++ b/flags/gap.aconfig @@ -236,6 +236,19 @@ flag { namespace: "bluetooth" description: "Support MSFT HCI extension for LE Scanning. go/bt-msft-aosp-dd" bug: "365787977" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "le_impl_ack_pause_disarmed" + namespace: "bluetooth" + description: "Let le_impl AckPause when disarmed to prevent stuck in pausing state" + bug: "357024179" + metadata { + purpose: PURPOSE_BUGFIX + } } flag { @@ -257,3 +270,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "initial_conn_params_p1" + namespace: "bluetooth" + description: "Use aggressive connection parameters when <2 connections exist. go/initial-connection-parameter-optimization" + bug: "378595485" + metadata { + purpose: PURPOSE_BUGFIX + } +}
\ No newline at end of file diff --git a/flags/opp.aconfig b/flags/opp.aconfig index adc94796d5..6e32ab0b75 100644 --- a/flags/opp.aconfig +++ b/flags/opp.aconfig @@ -28,3 +28,12 @@ flag { } } +flag { + name: "opp_set_insets_for_edge_to_edge" + namespace: "bluetooth" + description: "Set proper insets in BluetoothOppTransferHistory to adapt to edge-to-edge." + bug: "378813445" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/pairing.aconfig b/flags/pairing.aconfig index 6662aee382..152f262bcb 100644 --- a/flags/pairing.aconfig +++ b/flags/pairing.aconfig @@ -199,4 +199,14 @@ flag { metadata { purpose: PURPOSE_BUGFIX } +} + +flag { + name: "prevent_service_connections_on_remove_bond" + namespace: "bluetooth" + description: "Disable service connections on remove bond" + bug: "378736590" + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt index 5e52c1f8fb..10cb58064b 100644 --- a/framework/api/system-current.txt +++ b/framework/api/system-current.txt @@ -1275,7 +1275,7 @@ package android.bluetooth.le { method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback); } - @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public final class ChannelSoundingParams implements android.os.Parcelable { + public final class ChannelSoundingParams implements android.os.Parcelable { method public int describeContents(); method public int getCsSecurityLevel(); method public int getLocationType(); @@ -1304,8 +1304,8 @@ package android.bluetooth.le { } public final class DistanceMeasurementManager { - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getChannelSoundingMaxSupportedSecurityLevel(@NonNull android.bluetooth.BluetoothDevice); - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getLocalChannelSoundingMaxSupportedSecurityLevel(); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getChannelSoundingMaxSupportedSecurityLevel(@NonNull android.bluetooth.BluetoothDevice); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getLocalChannelSoundingMaxSupportedSecurityLevel(); method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.le.DistanceMeasurementMethod> getSupportedMethods(); method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.os.CancellationSignal startMeasurementSession(@NonNull android.bluetooth.le.DistanceMeasurementParams, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.le.DistanceMeasurementSession.Callback); } @@ -1319,7 +1319,7 @@ package android.bluetooth.le { method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.DistanceMeasurementMethod> CREATOR; field public static final int DISTANCE_MEASUREMENT_METHOD_AUTO = 0; // 0x0 - field @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public static final int DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING = 2; // 0x2 + field public static final int DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING = 2; // 0x2 field public static final int DISTANCE_MEASUREMENT_METHOD_RSSI = 1; // 0x1 } @@ -1332,7 +1332,7 @@ package android.bluetooth.le { public final class DistanceMeasurementParams implements android.os.Parcelable { method public int describeContents(); - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") @Nullable public android.bluetooth.le.ChannelSoundingParams getChannelSoundingParams(); + method @Nullable public android.bluetooth.le.ChannelSoundingParams getChannelSoundingParams(); method public static int getDefaultDurationSeconds(); method @NonNull public android.bluetooth.BluetoothDevice getDevice(); method @IntRange(from=0) public int getDurationSeconds(); @@ -1349,7 +1349,7 @@ package android.bluetooth.le { public static final class DistanceMeasurementParams.Builder { ctor public DistanceMeasurementParams.Builder(@NonNull android.bluetooth.BluetoothDevice); method @NonNull public android.bluetooth.le.DistanceMeasurementParams build(); - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") @NonNull public android.bluetooth.le.DistanceMeasurementParams.Builder setChannelSoundingParams(@NonNull android.bluetooth.le.ChannelSoundingParams); + method @NonNull public android.bluetooth.le.DistanceMeasurementParams.Builder setChannelSoundingParams(@NonNull android.bluetooth.le.ChannelSoundingParams); method @NonNull public android.bluetooth.le.DistanceMeasurementParams.Builder setDurationSeconds(@IntRange(from=0) int); method @NonNull public android.bluetooth.le.DistanceMeasurementParams.Builder setFrequency(int); method @NonNull public android.bluetooth.le.DistanceMeasurementParams.Builder setMethodId(int); @@ -1359,25 +1359,25 @@ package android.bluetooth.le { method public int describeContents(); method @FloatRange(from=-90.0, to=90.0) public double getAltitudeAngle(); method @FloatRange(from=0.0, to=360.0) public double getAzimuthAngle(); - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel(); - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public double getDelaySpreadMeters(); - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public int getDetectedAttackLevel(); + method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel(); + method public double getDelaySpreadMeters(); + method public int getDetectedAttackLevel(); method public double getErrorAltitudeAngle(); method public double getErrorAzimuthAngle(); method @FloatRange(from=0.0) public double getErrorMeters(); method @FlaggedApi("com.android.bluetooth.flags.channel_sounding_25q2_apis") public long getMeasurementTimestampNanos(); method public double getResultMeters(); - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public double getVelocityMetersPerSecond(); + method public double getVelocityMetersPerSecond(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.DistanceMeasurementResult> CREATOR; - field @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public static final int NADM_ATTACK_IS_EXTREMELY_LIKELY = 6; // 0x6 - field @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public static final int NADM_ATTACK_IS_EXTREMELY_UNLIKELY = 0; // 0x0 - field @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public static final int NADM_ATTACK_IS_LIKELY = 4; // 0x4 - field @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public static final int NADM_ATTACK_IS_POSSIBLE = 3; // 0x3 - field @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public static final int NADM_ATTACK_IS_UNLIKELY = 2; // 0x2 - field @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public static final int NADM_ATTACK_IS_VERY_LIKELY = 5; // 0x5 - field @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public static final int NADM_ATTACK_IS_VERY_UNLIKELY = 1; // 0x1 - field @FlaggedApi("com.android.bluetooth.flags.channel_sounding") public static final int NADM_UNKNOWN = 255; // 0xff + field public static final int NADM_ATTACK_IS_EXTREMELY_LIKELY = 6; // 0x6 + field public static final int NADM_ATTACK_IS_EXTREMELY_UNLIKELY = 0; // 0x0 + field public static final int NADM_ATTACK_IS_LIKELY = 4; // 0x4 + field public static final int NADM_ATTACK_IS_POSSIBLE = 3; // 0x3 + field public static final int NADM_ATTACK_IS_UNLIKELY = 2; // 0x2 + field public static final int NADM_ATTACK_IS_VERY_LIKELY = 5; // 0x5 + field public static final int NADM_ATTACK_IS_VERY_UNLIKELY = 1; // 0x1 + field public static final int NADM_UNKNOWN = 255; // 0xff } public static final class DistanceMeasurementResult.Builder { @@ -1385,13 +1385,13 @@ package android.bluetooth.le { method @NonNull public android.bluetooth.le.DistanceMeasurementResult build(); method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setAltitudeAngle(@FloatRange(from=-90.0, to=90.0) double); method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setAzimuthAngle(@FloatRange(from=0.0, to=360.0) double); - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setConfidenceLevel(@FloatRange(from=0.0, to=1.0) double); - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setDelaySpreadMeters(double); - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setDetectedAttackLevel(int); + method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setConfidenceLevel(@FloatRange(from=0.0, to=1.0) double); + method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setDelaySpreadMeters(double); + method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setDetectedAttackLevel(int); method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setErrorAltitudeAngle(@FloatRange(from=0.0, to=180.0) double); method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setErrorAzimuthAngle(@FloatRange(from=0.0, to=360.0) double); method @FlaggedApi("com.android.bluetooth.flags.channel_sounding_25q2_apis") @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setMeasurementTimestampNanos(long); - method @FlaggedApi("com.android.bluetooth.flags.channel_sounding") @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setVelocityMetersPerSecond(double); + method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setVelocityMetersPerSecond(double); } public final class DistanceMeasurementSession { diff --git a/framework/java/android/bluetooth/le/ChannelSoundingParams.java b/framework/java/android/bluetooth/le/ChannelSoundingParams.java index 7c6baf1cff..ab5b8b4b40 100644 --- a/framework/java/android/bluetooth/le/ChannelSoundingParams.java +++ b/framework/java/android/bluetooth/le/ChannelSoundingParams.java @@ -16,15 +16,12 @@ package android.bluetooth.le; -import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; -import com.android.bluetooth.flags.Flags; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -35,7 +32,6 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ -@FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public final class ChannelSoundingParams implements Parcelable { diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementManager.java b/framework/java/android/bluetooth/le/DistanceMeasurementManager.java index 75ef152ef6..7a5eb37268 100644 --- a/framework/java/android/bluetooth/le/DistanceMeasurementManager.java +++ b/framework/java/android/bluetooth/le/DistanceMeasurementManager.java @@ -19,7 +19,6 @@ package android.bluetooth.le; import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; -import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -36,8 +35,6 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; -import com.android.bluetooth.flags.Flags; - import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -169,7 +166,6 @@ public final class DistanceMeasurementManager { * when Channel Sounding is not supported or encounters an internal error. * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi @RequiresBluetoothConnectPermission @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) @@ -200,7 +196,6 @@ public final class DistanceMeasurementManager { * when Channel Sounding is not supported or encounters an internal error. * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi @RequiresBluetoothConnectPermission @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementMethod.java b/framework/java/android/bluetooth/le/DistanceMeasurementMethod.java index 12b1a940f1..eb4032057d 100644 --- a/framework/java/android/bluetooth/le/DistanceMeasurementMethod.java +++ b/framework/java/android/bluetooth/le/DistanceMeasurementMethod.java @@ -73,7 +73,6 @@ public final class DistanceMeasurementMethod implements Parcelable { * * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public static final int DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING = 2; diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementParams.java b/framework/java/android/bluetooth/le/DistanceMeasurementParams.java index f3116ed95a..04b3febe55 100644 --- a/framework/java/android/bluetooth/le/DistanceMeasurementParams.java +++ b/framework/java/android/bluetooth/le/DistanceMeasurementParams.java @@ -16,7 +16,6 @@ package android.bluetooth.le; -import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -27,8 +26,6 @@ import android.bluetooth.le.DistanceMeasurementMethod.DistanceMeasurementMethodI import android.os.Parcel; import android.os.Parcelable; -import com.android.bluetooth.flags.Flags; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -143,7 +140,6 @@ public final class DistanceMeasurementParams implements Parcelable { * * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public @Nullable ChannelSoundingParams getChannelSoundingParams() { return mChannelSoundingParams; @@ -312,7 +308,6 @@ public final class DistanceMeasurementParams implements Parcelable { * @return the same Builder instance * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public @NonNull Builder setChannelSoundingParams( @NonNull ChannelSoundingParams channelSoundingParams) { diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementResult.java b/framework/java/android/bluetooth/le/DistanceMeasurementResult.java index 9fb3416a85..e69e895fba 100644 --- a/framework/java/android/bluetooth/le/DistanceMeasurementResult.java +++ b/framework/java/android/bluetooth/le/DistanceMeasurementResult.java @@ -64,7 +64,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public static final int NADM_ATTACK_IS_EXTREMELY_UNLIKELY = 0; @@ -73,7 +72,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public static final int NADM_ATTACK_IS_VERY_UNLIKELY = 1; @@ -82,7 +80,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public static final int NADM_ATTACK_IS_UNLIKELY = 2; @@ -91,7 +88,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public static final int NADM_ATTACK_IS_POSSIBLE = 3; @@ -100,7 +96,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public static final int NADM_ATTACK_IS_LIKELY = 4; @@ -109,7 +104,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public static final int NADM_ATTACK_IS_VERY_LIKELY = 5; @@ -118,7 +112,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public static final int NADM_ATTACK_IS_EXTREMELY_LIKELY = 6; @@ -127,7 +120,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public static final int NADM_UNKNOWN = 0xFF; @@ -269,7 +261,6 @@ public final class DistanceMeasurementResult implements Parcelable { * @return delay spread in meters in degrees or Double.NaN if not available * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public double getDelaySpreadMeters() { return mDelaySpreadMeters; @@ -282,7 +273,6 @@ public final class DistanceMeasurementResult implements Parcelable { * @return confidence of estimated distance or Double.NaN if not available * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi @FloatRange(from = 0.0, to = 1.0) public double getConfidenceLevel() { @@ -295,7 +285,6 @@ public final class DistanceMeasurementResult implements Parcelable { * @return Nadm that represents the chance of being attacked for the measurement. * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi @Nadm public int getDetectedAttackLevel() { @@ -310,7 +299,6 @@ public final class DistanceMeasurementResult implements Parcelable { * object in meters/sec. * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi public double getVelocityMetersPerSecond() { return mVelocityMetersPerSecond; @@ -532,7 +520,6 @@ public final class DistanceMeasurementResult implements Parcelable { * @throws IllegalArgumentException if value is invalid * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi @NonNull public Builder setDelaySpreadMeters(double delaySpreadMeters) { @@ -551,7 +538,6 @@ public final class DistanceMeasurementResult implements Parcelable { * @throws IllegalArgumentException if value is invalid * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi @NonNull public Builder setConfidenceLevel( @@ -573,7 +559,6 @@ public final class DistanceMeasurementResult implements Parcelable { * @throws IllegalArgumentException if value is invalid * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi @NonNull public Builder setDetectedAttackLevel(@Nadm int detectedAttackLevel) { @@ -601,7 +586,6 @@ public final class DistanceMeasurementResult implements Parcelable { * @param velocityMetersPerSecond estimated velocity in meters/sec. * @hide */ - @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING) @SystemApi @NonNull public Builder setVelocityMetersPerSecond(double velocityMetersPerSecond) { diff --git a/system/bta/hh/bta_hh_act.cc b/system/bta/hh/bta_hh_act.cc index 118a4b72f4..e32500a4ed 100644 --- a/system/bta/hh/bta_hh_act.cc +++ b/system/bta/hh/bta_hh_act.cc @@ -978,6 +978,9 @@ void bta_hh_maint_dev_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { /* remove from known device list in BTA */ bta_hh_clean_up_kdev(p_cb); + } else if (com::android::bluetooth::flags::remove_pending_hid_connection()) { + log::warn("Failed to remove device {}", dev_info.link_spec); + bta_hh_clean_up_kdev(p_cb); } } break; diff --git a/system/btif/include/btif_bqr.h b/system/btif/include/btif_bqr.h index 909335b411..38bfa8badc 100644 --- a/system/btif/include/btif_bqr.h +++ b/system/btif/include/btif_bqr.h @@ -200,8 +200,10 @@ enum BqrQualityReportId : uint8_t { QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY = 0x03, QUALITY_REPORT_ID_SCO_VOICE_CHOPPY = 0x04, QUALITY_REPORT_ID_ROOT_INFLAMMATION = 0x05, + QUALITY_REPORT_ID_ENERGY_MONITOR = 0x06, QUALITY_REPORT_ID_LE_AUDIO_CHOPPY = 0x07, QUALITY_REPORT_ID_CONNECT_FAIL = 0x08, + QUALITY_REPORT_ID_RF_STATS = 0x09, QUALITY_REPORT_ID_VENDOR_SPECIFIC_QUALITY = 0x10, QUALITY_REPORT_ID_LMP_LL_MESSAGE_TRACE = 0x11, QUALITY_REPORT_ID_BT_SCHEDULING_TRACE = 0x12, @@ -330,6 +332,112 @@ typedef struct { const uint8_t* vendor_specific_parameter; } BqrLinkQualityEvent; +// Energy Monitor BQR event +typedef struct { + // Quality report ID. + uint8_t quality_report_id; + // Average current consumption of all activities consumed by the controller (mA) + uint16_t avg_current_consume; + // Total time in the idle (low power states, sleep) state. (ms) + uint32_t idle_total_time; + // Indicates how many times the controller enters the idle state. + uint32_t idle_state_enter_count; + // Total time in the active (inquiring, paging, ACL/SCO/eSCO/BIS/CIS traffic, processing any task) + // state. (ms) + uint32_t active_total_time; + // Indicates how many times the controller enters the active states. + uint32_t active_state_enter_count; + // Total time in the BR/EDR specific Tx(Transmitting for ACL/SCO/eSCO traffic)state (ms) + uint32_t bredr_tx_total_time; + // Indicates how many times the controller enters the BR/EDR specific Tx state. + uint32_t bredr_tx_state_enter_count; + // Average Tx power level of all the BR/EDR link(s) (dBm) + uint8_t bredr_tx_avg_power_lv; + // Total time in the BR/EDR specific Rx (Receiving from ACL/SCO/eSCO traffic) state. (ms) + uint32_t bredr_rx_total_time; + // Indicates how many times the controller enters the BR/EDR specific Rx state. (ms) + uint32_t bredr_rx_state_enter_count; + // Total time in the LE specific Tx (Transmitting for either ACL/BIS/CIS or LE advertising + // traffic) state (ms) + uint32_t le_tx_total_time; + // Indicates how many times the controller enters theLE specific Tx state. + uint32_t le_tx_state_enter_count; + // Average Tx power level of all the LE link(s) (dBm) + uint8_t le_tx_avg_power_lv; + // Total time in the LE specific Rx (Receiving from either ACL/BIS/CIS or LE scanning traffic) + // state. (ms) + uint32_t le_rx_total_time; + // Indicates how many times the controller enters the LE specific Rx state + uint32_t le_rx_state_enter_count; + // The total time duration to collect power related information (ms) + uint32_t tm_period; + // The time duration of RX active in one chain + uint32_t rx_active_one_chain_time; + // The time duration of RX active in two chain + uint32_t rx_active_two_chain_time; + // The time duration of internal TX active in one chain + uint32_t tx_ipa_active_one_chain_time; + // The time duration of internal TX active in two chain + uint32_t tx_ipa_active_two_chain_time; + // The time duration of external TX active in one chain + uint32_t tx_epa_active_one_chain_time; + // The time duration of external TX active in two chain + uint32_t tx_epa_active_two_chain_time; +} __attribute__((__packed__)) BqrEnergyMonitorEvent; + +static constexpr uint8_t kEnergyMonitorParamTotalLen = sizeof(BqrEnergyMonitorEvent); + +// RF Stats BQR event +typedef struct { + // Quality report ID. + uint8_t quality_report_id; + // Extension for Further usage = 0x01 for BQRv6 + uint8_t ext_info; + // time period (ms) + uint32_t tm_period; + // Packet counter of iPA BF + uint32_t tx_pw_ipa_bf; + // Packet counter of ePA BF + uint32_t tx_pw_epa_bf; + // Packet counter of iPA Div + uint32_t tx_pw_ipa_div; + // Packet counter of ePA Div + uint32_t tx_pw_epa_div; + // Packet counter of RSSI chain > -50 dBm + uint32_t rssi_ch_50; + // Packet counter of RSSI chain between -50 dBm ~ >-55 dBm + uint32_t rssi_ch_50_55; + // Packet counter of RSSI chain between -55 dBm ~ >-60 dBm + uint32_t rssi_ch_55_60; + // Packet counter of RSSI chain between -60 dBm ~ >-65 dBm + uint32_t rssi_ch_60_65; + // Packet counter of RSSI chain between -65 dBm ~ >-70 dBm + uint32_t rssi_ch_65_70; + // Packet counter of RSSI chain between -70 dBm ~ >-75 dBm + uint32_t rssi_ch_70_75; + // Packet counter of RSSI chain between -75 dBm ~ >-80 dBm + uint32_t rssi_ch_75_80; + // Packet counter of RSSI chain between -80 dBm ~ >-85 dBm + uint32_t rssi_ch_80_85; + // Packet counter of RSSI chain between -85 dBm ~ >-90 dBm + uint32_t rssi_ch_85_90; + // Packet counter of RSSI chain < -90 dBm + uint32_t rssi_ch_90; + // Packet counter of RSSI delta < 2 dBm + uint32_t rssi_delta_2_down; + // Packet counter of RSSI delta between 2 dBm ~ 5 dBm + uint32_t rssi_delta_2_5; + // Packet counter of RSSI delta between 5 dBm ~ 8 dB + uint32_t rssi_delta_5_8; + // Packet counter of RSSI delta between 8 dBm ~ 11 dBm + uint32_t rssi_delta_8_11; + // Packet counter of RSSI delta > 11 dBm + uint32_t rssi_delta_11_up; +} __attribute__((__packed__)) BqrRFStatsEvent; + +// Total length of all parameters of the RF Stats event +static constexpr uint8_t kRFStatsParamTotalLen = sizeof(BqrRFStatsEvent); + // Log dump related BQR event typedef struct { // Quality report ID. @@ -348,6 +456,20 @@ public: // @param length Total length of all parameters contained in the sub-event. // @param p_param_buf A pointer to the parameters contained in the sub-event. void ParseBqrLinkQualityEvt(uint8_t length, const uint8_t* p_param_buf); + // Parse the Energy Monitor BQR event. + // + // @param length Total length of all parameters contained in the sub-event. + // @param p_param_buf A pointer to the parameters contained in the sub-event. + // + // @return true if the event was parsed successfully, false otherwise. + bool ParseBqrEnergyMonitorEvt(uint8_t length, const uint8_t* p_param_buf); + // Parse the RF Stats BQR event. + // + // @param length Total length of all parameters contained in the sub-event. + // @param p_param_buf A pointer to the parameters contained in the sub-event. + // + // @return true if the event was parsed successfully, false otherwise. + bool ParseBqrRFStatsEvt(uint8_t length, const uint8_t* p_param_buf); // Write the LMP/LL message trace to the log file. // // @param fd The File Descriptor of the log file. @@ -372,6 +494,10 @@ public: virtual ~BqrVseSubEvt() = default; // Link Quality related BQR event BqrLinkQualityEvent bqr_link_quality_event_ = {}; + // Energy Monitor BQR event + BqrEnergyMonitorEvent bqr_energy_monitor_event_ = {}; + // RF Stats BQR event + BqrRFStatsEvent bqr_rf_stats_event_ = {}; // Log Dump related BQR event BqrLogDumpEvent bqr_log_dump_event_ = {}; // Local wall clock timestamp of receiving BQR VSE sub-event diff --git a/system/btif/src/btif_bqr.cc b/system/btif/src/btif_bqr.cc index 5e7eb73dad..37ce06a935 100644 --- a/system/btif/src/btif_bqr.cc +++ b/system/btif/src/btif_bqr.cc @@ -15,6 +15,7 @@ */ #include <bluetooth/log.h> +#include <com_android_bluetooth_flags.h> #include <fcntl.h> #ifdef __ANDROID__ #include <statslog_bt.h> @@ -155,6 +156,79 @@ void BqrVseSubEvt::ParseBqrLinkQualityEvt(uint8_t length, const uint8_t* p_param localtime_r(&now, &tm_timestamp_); } +bool BqrVseSubEvt::ParseBqrEnergyMonitorEvt(uint8_t length, const uint8_t* p_param_buf) { + if (length < kEnergyMonitorParamTotalLen) { + log::fatal( + "Parameter total length: {} is abnormal. It shall be not shorter than: " + "{}", + length, kEnergyMonitorParamTotalLen); + return false; + } + + STREAM_TO_UINT8(bqr_energy_monitor_event_.quality_report_id, p_param_buf); + bqr_link_quality_event_.quality_report_id = bqr_energy_monitor_event_.quality_report_id; + STREAM_TO_UINT16(bqr_energy_monitor_event_.avg_current_consume, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.idle_total_time, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.idle_state_enter_count, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.active_total_time, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.active_state_enter_count, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.bredr_tx_total_time, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.bredr_tx_state_enter_count, p_param_buf); + STREAM_TO_UINT8(bqr_energy_monitor_event_.bredr_tx_avg_power_lv, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.bredr_rx_total_time, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.bredr_rx_state_enter_count, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.le_tx_total_time, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.le_tx_state_enter_count, p_param_buf); + STREAM_TO_UINT8(bqr_energy_monitor_event_.le_tx_avg_power_lv, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.le_rx_total_time, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.le_rx_state_enter_count, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.tm_period, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.rx_active_one_chain_time, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.rx_active_two_chain_time, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.tx_ipa_active_one_chain_time, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.tx_ipa_active_two_chain_time, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.tx_epa_active_one_chain_time, p_param_buf); + STREAM_TO_UINT32(bqr_energy_monitor_event_.tx_epa_active_two_chain_time, p_param_buf); + return true; +} + +bool BqrVseSubEvt::ParseBqrRFStatsEvt(uint8_t length, const uint8_t* p_param_buf) { + if (length < kRFStatsParamTotalLen) { + log::fatal( + "Parameter total length: {} is abnormal. It shall be not shorter than: " + "{}", + length, kRFStatsParamTotalLen); + return false; + } + + STREAM_TO_UINT8(bqr_rf_stats_event_.quality_report_id, p_param_buf); + bqr_link_quality_event_.quality_report_id = bqr_rf_stats_event_.quality_report_id; + STREAM_TO_UINT8(bqr_rf_stats_event_.ext_info, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.tm_period, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.tx_pw_ipa_bf, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.tx_pw_epa_bf, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.tx_pw_ipa_div, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.tx_pw_epa_div, p_param_buf); + + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_50, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_50_55, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_55_60, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_60_65, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_65_70, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_70_75, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_75_80, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_80_85, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_85_90, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_ch_90, p_param_buf); + + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_delta_2_down, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_delta_2_5, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_delta_5_8, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_delta_8_11, p_param_buf); + STREAM_TO_UINT32(bqr_rf_stats_event_.rssi_delta_11_up, p_param_buf); + return true; +} + void BqrVseSubEvt::WriteLmpLlTraceLogFile(int fd, uint8_t length, const uint8_t* p_param_buf) { const auto now = system_clock::to_time_t(system_clock::now()); localtime_r(&now, &tm_timestamp_); @@ -226,7 +300,19 @@ std::string BqrVseSubEvt::ToString() const { << ", CRCError: " << std::to_string(bqr_link_quality_event_.crc_error_packets) << ", RxDuplicate: " << std::to_string(bqr_link_quality_event_.rx_duplicate_packets); } - + if (QUALITY_REPORT_ID_ENERGY_MONITOR == bqr_link_quality_event_.quality_report_id) { + ss << ", TotalTime: " << std::to_string(bqr_energy_monitor_event_.tm_period) + << ", ActiveTime: " << std::to_string(bqr_energy_monitor_event_.active_total_time) + << ", IdleTime: " << std::to_string(bqr_energy_monitor_event_.idle_total_time) + << ", AvgCurrent: " << std::to_string(bqr_energy_monitor_event_.avg_current_consume); + } + if (QUALITY_REPORT_ID_RF_STATS == bqr_link_quality_event_.quality_report_id) { + ss << ", TotalTime: " << std::to_string(bqr_rf_stats_event_.tm_period) + << ", TxiPABF: " << std::to_string(bqr_rf_stats_event_.tx_pw_ipa_bf) + << ", TxePABF: " << std::to_string(bqr_rf_stats_event_.tx_pw_epa_bf) + << ", TxiPADiv: " << std::to_string(bqr_rf_stats_event_.tx_pw_ipa_div) + << ", TxePADiv: " << std::to_string(bqr_rf_stats_event_.tx_pw_epa_div); + } return ss.str(); } @@ -248,6 +334,10 @@ static std::string QualityReportIdToString(uint8_t quality_report_id) { return "LE Audio Choppy"; case QUALITY_REPORT_ID_CONNECT_FAIL: return "Connect Fail"; + case QUALITY_REPORT_ID_ENERGY_MONITOR: + return "Energy Monitor"; + case QUALITY_REPORT_ID_RF_STATS: + return "RF Stats"; default: return "Invalid"; } @@ -589,6 +679,9 @@ static void ConfigureBqrCmpl(uint32_t current_evt_mask) { } static void AddLinkQualityEventToQueue(uint8_t length, const uint8_t* p_link_quality_event); +static void AddEnergyMonitorEventToQueue(uint8_t length, const uint8_t* p_link_quality_event); +static void AddRFStatsEventToQueue(uint8_t length, const uint8_t* p_link_quality_event); +static void AddLinkQualityEventToQueue(uint8_t length, const uint8_t* p_link_quality_event); // Categorize the incoming Bluetooth Quality Report. // // @param length Lengths of the quality report sent from the Bluetooth @@ -631,6 +724,34 @@ static void CategorizeBqrEvent(uint8_t length, const uint8_t* p_bqr_event) { log::warn("Unexpected ID: 0x{:x}", quality_report_id); break; + case QUALITY_REPORT_ID_ENERGY_MONITOR: + if (length < kEnergyMonitorParamTotalLen) { + log::fatal( + "Parameter total length: {} is abnormal. It shall be not shorter " + "than: {}", + length, kEnergyMonitorParamTotalLen); + return; + } + + if (com::android::bluetooth::flags::support_bluetooth_quality_report_v6()) { + AddEnergyMonitorEventToQueue(length, p_bqr_event); + } + break; + + case QUALITY_REPORT_ID_RF_STATS: + if (length < kRFStatsParamTotalLen) { + log::fatal( + "Parameter total length: {} is abnormal. It shall be not shorter " + "than: {}", + length, kRFStatsParamTotalLen); + return; + } + + if (com::android::bluetooth::flags::support_bluetooth_quality_report_v6()) { + AddRFStatsEventToQueue(length, p_bqr_event); + } + break; + default: log::warn("Unknown ID: 0x{:x}", quality_report_id); break; @@ -705,6 +826,42 @@ static void AddLinkQualityEventToQueue(uint8_t length, const uint8_t* p_link_qua kpBqrEventQueue.Enqueue(p_bqr_event.release()); } +static void AddEnergyMonitorEventToQueue(uint8_t length, const uint8_t* p_energy_monitor_event) { + std::unique_ptr<BqrVseSubEvt> p_bqr_event = std::make_unique<BqrVseSubEvt>(); + + if (!p_bqr_event->ParseBqrEnergyMonitorEvt(length, p_energy_monitor_event)) { + log::warn("failed to parse BQR energy monitor event"); + return; + } + + BluetoothQualityReportInterface* bqrItf = getBluetoothQualityReportInterface(); + + if (bqrItf == NULL) { + log::warn("failed to deliver BQR, bqrItf is NULL"); + return; + } + + bqrItf->bqr_delivery_event(RawAddress::kAny, p_energy_monitor_event, length); +} + +static void AddRFStatsEventToQueue(uint8_t length, const uint8_t* p_rf_stats_event) { + std::unique_ptr<BqrVseSubEvt> p_bqr_event = std::make_unique<BqrVseSubEvt>(); + + if (!p_bqr_event->ParseBqrRFStatsEvt(length, p_rf_stats_event)) { + log::warn("failed to parse BQR RF stats event"); + return; + } + + BluetoothQualityReportInterface* bqrItf = getBluetoothQualityReportInterface(); + + if (bqrItf == NULL) { + log::warn("failed to deliver BQR, bqrItf is NULL"); + return; + } + + bqrItf->bqr_delivery_event(RawAddress::kAny, p_rf_stats_event, length); +} + static int OpenLmpLlTraceLogFile(); // Dump the LMP/LL message handshaking with the remote device to a log file. diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc index 2259ebcb23..70762b7c64 100644 --- a/system/btif/src/btif_dm.cc +++ b/system/btif/src/btif_dm.cc @@ -563,18 +563,7 @@ static void bond_state_changed(bt_status_t status, const RawAddress& bd_addr, if (pairing_cb.bond_type == BOND_TYPE_TEMPORARY) { state = BT_BOND_STATE_NONE; - } else { - if (state == BT_BOND_STATE_NONE) { - bluetooth::os::LogMetricBluetoothEvent(ToGdAddress(bd_addr), - android::bluetooth::EventType::BOND, - android::bluetooth::State::STATE_NONE); - } else if (state == BT_BOND_STATE_BONDED) { - bluetooth::os::LogMetricBluetoothEvent(ToGdAddress(bd_addr), - android::bluetooth::EventType::BOND, - android::bluetooth::State::STATE_BONDED); - } } - log::info( "Bond state changed to state={}[0:none, 1:bonding, " "2:bonded],prev_state={}, sdp_attempts={}", diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc index e908807275..1a9855ef31 100644 --- a/system/btif/src/btif_hh.cc +++ b/system/btif/src/btif_hh.cc @@ -977,6 +977,11 @@ void btif_hh_remove_device(const tAclLinkSpec& link_spec) { } else { log::warn("device_num = 0"); } + + if (com::android::bluetooth::flags::remove_pending_hid_connection()) { + BTA_HhRemoveDev(p_dev->dev_handle); // Remove the connection, in case it was pending + } + bta_hh_co_close(p_dev); p_dev->dev_status = BTHH_CONN_STATE_UNKNOWN; p_dev->dev_handle = BTA_HH_INVALID_HANDLE; diff --git a/system/gd/rust/topshim/btav/btav_shim.cc b/system/gd/rust/topshim/btav/btav_shim.cc index 3838d03b66..eed0d54190 100644 --- a/system/gd/rust/topshim/btav/btav_shim.cc +++ b/system/gd/rust/topshim/btav/btav_shim.cc @@ -239,18 +239,15 @@ static ::rust::Vec<A2dpCodecConfig> to_rust_codec_config_vec( return rconfigs; } -static A2dpError to_rust_error(const btav_error_t& error) { +static void connection_state_cb(const RawAddress& addr, btav_connection_state_t state, + const btav_error_t& error) { + // CAUTION: The error_msg field is a reference and could refer to a rvalue on the stack. + // DO NOT make this conversion into a helper function. A2dpError a2dp_error = { .status = error.status, .error_code = error.error_code, .error_msg = error.error_msg.value_or(""), }; - return a2dp_error; -} - -static void connection_state_cb(const RawAddress& addr, btav_connection_state_t state, - const btav_error_t& error) { - A2dpError a2dp_error = to_rust_error(error); rusty::connection_state_callback(addr, state, a2dp_error); } static void audio_state_cb(const RawAddress& addr, btav_audio_state_t state) { diff --git a/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc b/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc index 8b38b9b15a..d2999d9a2c 100644 --- a/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc +++ b/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc @@ -32,18 +32,15 @@ namespace rust { namespace internal { static A2dpSinkIntf* g_a2dp_sink_if; -static A2dpError to_rust_error(const btav_error_t& error) { +static void connection_state_cb(const RawAddress& addr, btav_connection_state_t state, + const btav_error_t& error) { + // CAUTION: The error_msg field is a reference and could refer to a rvalue on the stack. + // DO NOT make this conversion into a helper function. A2dpError a2dp_error = { .status = error.status, .error_code = error.error_code, .error_msg = error.error_msg.value_or(""), }; - return a2dp_error; -} - -static void connection_state_cb(const RawAddress& addr, btav_connection_state_t state, - const btav_error_t& error) { - A2dpError a2dp_error = to_rust_error(error); rusty::sink_connection_state_callback(addr, state, a2dp_error); } static void audio_state_cb(const RawAddress& addr, btav_audio_state_t state) { diff --git a/system/stack/bnep/bnep_api.cc b/system/stack/bnep/bnep_api.cc index 25e4ac474d..85fb0bf04d 100644 --- a/system/stack/bnep/bnep_api.cc +++ b/system/stack/bnep/bnep_api.cc @@ -30,7 +30,6 @@ #include <cstdint> #include "bnep_int.h" -#include "bt_transport.h" #include "bta/include/bta_sec_api.h" #include "internal_include/bt_target.h" #include "osi/include/alarm.h" @@ -40,6 +39,7 @@ #include "stack/include/bt_psm_types.h" #include "stack/include/l2cap_interface.h" #include "types/bluetooth/uuid.h" +#include "types/bt_transport.h" #include "types/raw_address.h" using namespace bluetooth; diff --git a/system/stack/bnep/bnep_main.cc b/system/stack/bnep/bnep_main.cc index 1cbea82777..add8bad93d 100644 --- a/system/stack/bnep/bnep_main.cc +++ b/system/stack/bnep/bnep_main.cc @@ -29,7 +29,6 @@ #include "bnep_api.h" #include "bnep_int.h" -#include "bt_transport.h" #include "bta/include/bta_sec_api.h" #include "hci/controller_interface.h" #include "internal_include/bt_target.h" @@ -44,6 +43,7 @@ #include "stack/include/bt_psm_types.h" #include "stack/include/bt_types.h" #include "stack/include/l2cap_interface.h" +#include "types/bt_transport.h" #include "types/raw_address.h" using namespace bluetooth; diff --git a/system/stack/bnep/bnep_utils.cc b/system/stack/bnep/bnep_utils.cc index 1d3bf444bc..921e16992c 100644 --- a/system/stack/bnep/bnep_utils.cc +++ b/system/stack/bnep/bnep_utils.cc @@ -30,7 +30,6 @@ #include "bnep_api.h" #include "bnep_int.h" -#include "bt_transport.h" #include "hci/controller_interface.h" #include "internal_include/bt_target.h" #include "l2cap_types.h" @@ -43,6 +42,7 @@ #include "stack/include/bt_types.h" #include "stack/include/l2cap_interface.h" #include "types/bluetooth/uuid.h" +#include "types/bt_transport.h" #include "types/raw_address.h" // TODO(b/369381361) Enfore -Wmissing-prototypes diff --git a/system/stack/hid/hidd_conn.cc b/system/stack/hid/hidd_conn.cc index 99ebe08242..b50516d8a8 100644 --- a/system/stack/hid/hidd_conn.cc +++ b/system/stack/hid/hidd_conn.cc @@ -31,7 +31,6 @@ #include <cstdint> #include <cstring> -#include "bt_transport.h" #include "bta/include/bta_sec_api.h" #include "hid_conn.h" #include "hidd_api.h" @@ -45,6 +44,7 @@ #include "stack/include/l2cap_interface.h" #include "stack/include/l2cdefs.h" #include "stack/include/stack_metrics_logging.h" +#include "types/bt_transport.h" #include "types/raw_address.h" using namespace bluetooth; diff --git a/system/stack/hid/hidh_conn.cc b/system/stack/hid/hidh_conn.cc index ce36edca9d..cc2a480b57 100644 --- a/system/stack/hid/hidh_conn.cc +++ b/system/stack/hid/hidh_conn.cc @@ -30,7 +30,6 @@ #include <cstdint> -#include "bt_transport.h" #include "bta/include/bta_sec_api.h" #include "hci_error_code.h" #include "hid_conn.h" @@ -50,6 +49,7 @@ #include "stack/include/btm_log_history.h" #include "stack/include/l2cap_interface.h" #include "stack/include/stack_metrics_logging.h" +#include "types/bt_transport.h" #include "types/raw_address.h" using namespace bluetooth; |