Snap for 9640974 from 3958f204af9c774049a800e84158783f17eedec2 to mainline-permission-release
Change-Id: I0c770ae00241d5257fcf6df90773e4adf6d6f503
diff --git a/TEST_MAPPING b/TEST_MAPPING
index d398fd8..c1b9e29 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,119 +1,220 @@
{
- "postsubmit" : [
+ "presubmit": [
+ // android_test targets
{
- "name" : "bluetooth_test_common"
+ "name": "CtsBluetoothTestCases"
},
{
- "name" : "bluetoothtbd_test"
+ "name": "BluetoothInstrumentationTests"
},
{
- "name" : "net_test_audio_a2dp_hw"
+ "name": "GoogleBluetoothInstrumentationTests"
},
{
- "name" : "net_test_avrcp"
+ "name": "FrameworkBluetoothTests"
},
{
- "name" : "net_test_btcore"
+ "name": "ServiceBluetoothTests"
+ },
+ // device only tests
+ // Broken
+ //{
+ // "name": "bluetooth-test-audio-hal-interface"
+ //},
+ {
+ "name": "net_test_audio_a2dp_hw"
},
{
- "name" : "net_test_btif"
+ "name": "net_test_audio_hearing_aid_hw"
+ },
+ // TODO (b/267212763)
+ // {
+ // "name": "net_test_bluetooth"
+ // },
+ // {
+ // "name": "net_test_bta"
+ // },
+ // {
+ // "name": "net_test_btif"
+ // },
+ {
+ "name": "net_test_btif_hf_client_service"
},
{
- "name" : "net_test_btif_profile_queue"
+ "name": "net_test_btif_profile_queue"
},
{
- "name" : "net_test_btpackets"
+ "name": "net_test_device"
},
{
- "name" : "net_test_device"
+ "name": "net_test_gatt_conn_multiplexing"
+ },
+ // TODO (b/267212763)
+ // {
+ // "name": "net_test_hci"
+ // },
+ {
+ "name": "net_test_hf_client_add_record"
+ },
+ // TODO (b/267212763)
+ // {
+ // "name": "net_test_stack"
+ // },
+ {
+ "name": "net_test_stack_ad_parser"
},
{
- "name" : "net_test_eatt"
+ "name": "net_test_stack_multi_adv"
+ },
+ // go/a-unit-tests tests (unit_test: true)
+ // Thoses test run on the host in the CI automatically.
+ // Run the one that are available on the device on the
+ // device as well
+ // TODO (b/267212763)
+ // {
+ // "name": "bluetooth_csis_test"
+ // },
+ {
+ "name": "bluetooth_flatbuffer_tests"
+ },
+ // TODO (b/267212763)
+ // {
+ // "name": "bluetooth_groups_test"
+ // },
+ // {
+ // "name": "bluetooth_has_test"
+ // },
+ {
+ "name": "bluetooth_hh_test"
+ },
+ // TODO (b/267212763)
+ // {
+ // "name": "bluetooth_le_audio_client_test"
+ // },
+ {
+ "name": "bluetooth_le_audio_test"
},
{
- "name" : "net_test_hci"
+ "name": "bluetooth_packet_parser_test"
+ },
+ // TODO (b/267212763)
+ // {
+ // "name": "bluetooth_test_broadcaster"
+ // },
+ // {
+ // "name": "bluetooth_test_broadcaster_state_machine"
+ // },
+ {
+ "name": "bluetooth_test_common"
},
{
- "name" : "net_test_performance"
+ "name": "bluetooth_test_gd_unit"
},
{
- "name" : "net_test_stack"
+ "name": "bluetooth_test_sdp"
+ },
+ // TODO (b/267212763)
+ // {
+ // "name": "bluetooth_vc_test"
+ // },
+ // {
+ // "name": "bluetoothtbd_test"
+ // },
+ // {
+ // "name": "bt_host_test_bta"
+ // },
+ {
+ "name": "libaptx_enc_tests"
},
{
- "name" : "net_test_stack_ad_parser"
+ "name": "libaptxhd_enc_tests"
},
{
- "name" : "net_test_stack_multi_adv"
+ "name": "net_test_avrcp"
},
{
- "name" : "net_test_stack_rfcomm"
+ "name": "net_test_btcore"
},
{
- "name" : "net_test_stack_smp"
+ "name": "net_test_btif_config_cache"
+ },
+ // TODO (b/267212763)
+ // {
+ // "name": "net_test_btif_hh"
+ // },
+ {
+ "name": "net_test_btif_rc"
+ },
+ // TODO (b/267212763)
+ // {
+ // "name": "net_test_btif_stack"
+ // },
+ {
+ "name": "net_test_btm_iso"
},
{
- "name" : "net_test_types"
- }
- ],
- "presubmit" : [
- {
- "name" : "net_test_hf_client_add_record"
+ "name": "net_test_btpackets"
},
{
- "name" : "net_test_btif_hf_client_service"
+ "name": "net_test_eatt"
},
{
- "name" : "libaptx_enc_tests"
+ "name": "net_test_hci_fragmenter_native"
},
{
- "name" : "libaptxhd_enc_tests"
+ "name": "net_test_main_shim"
},
{
- "name" : "net_test_stack_btm"
+ "name": "net_test_osi"
},
{
- "name" : "BluetoothInstrumentationTests",
- "options" : [{
- // b/259422308
- "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_MSG_CONNECT_TIMEOUT"
- }, {
- // b/259422308
- "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_MSG_SHARE_INTERRUPTED_batchFailed"
- }, {
- // b/259422308
- "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_TRANSPORT_ERROR_connectThreadIsNull"
- }, {
- // b/259422308
- "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#onBatchCanceled_checkStatus"
- }, {
- // b/259422308
- "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppUtilityTest#openReceivedFile_fileNotExist"
- }]
+ "name": "net_test_performance"
},
{
- "name" : "GoogleBluetoothInstrumentationTests",
- "options" : [{
- // b/259422308
- "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_MSG_CONNECT_TIMEOUT"
- }, {
- // b/259422308
- "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_MSG_SHARE_INTERRUPTED_batchFailed"
- }, {
- // b/259422308
- "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_TRANSPORT_ERROR_connectThreadIsNull"
- }, {
- // b/259422308
- "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#onBatchCanceled_checkStatus"
- }, {
- // b/259422308
- "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppUtilityTest#openReceivedFile_fileNotExist"
- }]
+ "name": "net_test_stack_a2dp_native"
},
{
- "name" : "FrameworkBluetoothTests"
+ "name": "net_test_stack_acl"
},
{
- "name" : "ServiceBluetoothTests"
+ "name": "net_test_stack_avdtp"
+ },
+ // TODO (b/267212763)
+ // {
+ // "name": "net_test_stack_btm"
+ // },
+ {
+ "name": "net_test_stack_btu"
+ },
+ {
+ "name": "net_test_stack_gatt"
+ },
+ {
+ "name": "net_test_stack_gatt_native"
+ },
+ {
+ "name": "net_test_stack_gatt_sr_hash_native"
+ },
+ {
+ "name": "net_test_stack_hci"
+ },
+ {
+ "name": "net_test_stack_hid"
+ },
+ {
+ "name": "net_test_stack_l2cap"
+ },
+ {
+ "name": "net_test_stack_rfcomm"
+ },
+ {
+ "name": "net_test_stack_sdp"
+ },
+ {
+ "name": "net_test_stack_smp"
+ },
+ {
+ "name": "net_test_types"
}
]
}
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
index 9bc4fad..7ca6166 100644
--- a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -106,7 +106,6 @@
boolean mA2dpOffloadEnabled = false;
private BroadcastReceiver mBondStateChangedReceiver;
- private BroadcastReceiver mConnectionStateChangedReceiver;
public static boolean isEnabled() {
return BluetoothProperties.isProfileA2dpSourceEnabled().orElse(false);
@@ -169,10 +168,6 @@
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
mBondStateChangedReceiver = new BondStateChangedReceiver();
registerReceiver(mBondStateChangedReceiver, filter);
- filter = new IntentFilter();
- filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
- mConnectionStateChangedReceiver = new ConnectionStateChangedReceiver();
- registerReceiver(mConnectionStateChangedReceiver, filter);
// Step 8: Mark service as started
setA2dpService(this);
@@ -208,8 +203,6 @@
setA2dpService(null);
// Step 7: Unregister broadcast receivers
- unregisterReceiver(mConnectionStateChangedReceiver);
- mConnectionStateChangedReceiver = null;
unregisterReceiver(mBondStateChangedReceiver);
mBondStateChangedReceiver = null;
@@ -1242,7 +1235,7 @@
}
}
- private void connectionStateChanged(BluetoothDevice device, int fromState, int toState) {
+ void connectionStateChanged(BluetoothDevice device, int fromState, int toState) {
if ((device == null) || (fromState == toState)) {
return;
}
@@ -1269,27 +1262,6 @@
}
/**
- * Receiver for processing device connection state changes.
- *
- * <ul>
- * <li> Update codec support per device when device is (re)connected
- * <li> Delete the state machine instance if the device is disconnected and unbond
- * </ul>
- */
- private class ConnectionStateChangedReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
- return;
- }
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- int toState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
- int fromState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
- connectionStateChanged(device, fromState, toState);
- }
- }
-
- /**
* Retrieves the most recently connected device in the A2DP connected devices list.
*/
public BluetoothDevice getFallbackDevice() {
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java b/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
index 9e7323f..11d33ad 100644
--- a/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
@@ -701,6 +701,7 @@
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ mA2dpService.connectionStateChanged(mDevice, prevState, newState);
mA2dpService.sendBroadcast(intent, BLUETOOTH_CONNECT,
Utils.getTempAllowlistBroadcastOptions());
}
diff --git a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
index 127fa31..03160d4 100644
--- a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
+++ b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
@@ -20,13 +20,13 @@
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -690,9 +690,9 @@
if (headsetService == null) {
return;
}
- BluetoothAudioPolicy audioPolicy = headsetService.getHfpCallAudioPolicy(device);
- if (audioPolicy == null || audioPolicy.getConnectingTimePolicy()
- != BluetoothAudioPolicy.POLICY_NOT_ALLOWED) {
+ BluetoothSinkAudioPolicy audioPolicy = headsetService.getHfpCallAudioPolicy(device);
+ if (audioPolicy == null || audioPolicy.getActiveDevicePolicyAfterConnection()
+ != BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED) {
if (!headsetService.setActiveDevice(device)) {
return;
}
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterService.java b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
index 9d9f887..7e36914 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
@@ -42,7 +42,6 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter.ActiveDeviceProfile;
import android.bluetooth.BluetoothAdapter.ActiveDeviceUse;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothFrameworkInitializer;
@@ -51,6 +50,7 @@
import android.bluetooth.BluetoothProtoEnums;
import android.bluetooth.BluetoothSap;
import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.BluetoothSocket;
import android.bluetooth.BluetoothStatusCodes;
import android.bluetooth.BluetoothUuid;
@@ -3671,70 +3671,73 @@
}
@Override
- public void getAudioPolicyRemoteSupported(BluetoothDevice device,
+ public void isRequestAudioPolicyAsSinkSupported(BluetoothDevice device,
AttributionSource source, SynchronousResultReceiver receiver) {
try {
- receiver.send(getAudioPolicyRemoteSupported(device, source));
+ receiver.send(isRequestAudioPolicyAsSinkSupported(device, source));
} catch (RuntimeException e) {
receiver.propagateException(e);
}
}
- private int getAudioPolicyRemoteSupported(BluetoothDevice device,
+ private int isRequestAudioPolicyAsSinkSupported(BluetoothDevice device,
AttributionSource source) {
AdapterService service = getService();
if (service == null
|| !callerIsSystemOrActiveOrManagedUser(service, TAG,
- "getAudioPolicyRemoteSupported")
+ "isRequestAudioPolicyAsSinkSupported")
|| !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) {
- return BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE;
+ return BluetoothStatusCodes.FEATURE_NOT_CONFIGURED;
}
enforceBluetoothPrivilegedPermission(service);
- return service.getAudioPolicyRemoteSupported(device);
+ return service.isRequestAudioPolicyAsSinkSupported(device);
}
@Override
- public void setAudioPolicy(BluetoothDevice device, BluetoothAudioPolicy policies,
- AttributionSource source, SynchronousResultReceiver receiver) {
+ public void requestAudioPolicyAsSink(BluetoothDevice device,
+ BluetoothSinkAudioPolicy policies, AttributionSource source,
+ SynchronousResultReceiver receiver) {
try {
- receiver.send(setAudioPolicy(device, policies, source));
+ receiver.send(requestAudioPolicyAsSink(device, policies, source));
} catch (RuntimeException e) {
receiver.propagateException(e);
}
}
- private int setAudioPolicy(BluetoothDevice device, BluetoothAudioPolicy policies,
- AttributionSource source) {
+ private int requestAudioPolicyAsSink(BluetoothDevice device,
+ BluetoothSinkAudioPolicy policies, AttributionSource source) {
AdapterService service = getService();
if (service == null) {
return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
- } else if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "setAudioPolicy")) {
+ } else if (!callerIsSystemOrActiveOrManagedUser(service,
+ TAG, "requestAudioPolicyAsSink")) {
return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED;
} else if (!Utils.checkConnectPermissionForDataDelivery(
service, source, TAG)) {
return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
}
enforceBluetoothPrivilegedPermission(service);
- return service.setAudioPolicy(device, policies);
+ return service.requestAudioPolicyAsSink(device, policies);
}
@Override
- public void getAudioPolicy(BluetoothDevice device,
+ public void getRequestedAudioPolicyAsSink(BluetoothDevice device,
AttributionSource source, SynchronousResultReceiver receiver) {
try {
- receiver.send(getAudioPolicy(device, source));
+ receiver.send(getRequestedAudioPolicyAsSink(device, source));
} catch (RuntimeException e) {
receiver.propagateException(e);
}
}
- private BluetoothAudioPolicy getAudioPolicy(BluetoothDevice device,
+ private BluetoothSinkAudioPolicy getRequestedAudioPolicyAsSink(BluetoothDevice device,
AttributionSource source) {
AdapterService service = getService();
if (service == null
- || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getAudioPolicy")
+ || !callerIsSystemOrActiveOrManagedUser(service,
+ TAG, "getRequestedAudioPolicyAsSink")
|| !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) {
return null;
}
enforceBluetoothPrivilegedPermission(service);
- return service.getAudioPolicy(device);
+ return service.getRequestedAudioPolicyAsSink(device);
}
@Override
@@ -5582,12 +5585,12 @@
* @param device Bluetooth device to be checked for audio policy support
* @return int status of the remote support for audio policy feature
*/
- public int getAudioPolicyRemoteSupported(BluetoothDevice device) {
+ public int isRequestAudioPolicyAsSinkSupported(BluetoothDevice device) {
if (mHeadsetClientService != null) {
return mHeadsetClientService.getAudioPolicyRemoteSupported(device);
} else {
Log.e(TAG, "No audio transport connected");
- return BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE;
+ return BluetoothStatusCodes.FEATURE_NOT_CONFIGURED;
}
}
@@ -5595,19 +5598,19 @@
* Set audio policy for remote device
*
* @param device Bluetooth device to be set policy for
- * @return int result status for setAudioPolicy API
+ * @return int result status for requestAudioPolicyAsSink API
*/
- public int setAudioPolicy(BluetoothDevice device, BluetoothAudioPolicy policies) {
+ public int requestAudioPolicyAsSink(BluetoothDevice device, BluetoothSinkAudioPolicy policies) {
DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
if (deviceProp == null) {
return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED;
}
if (mHeadsetClientService != null) {
- if (getAudioPolicyRemoteSupported(device)
- != BluetoothAudioPolicy.FEATURE_SUPPORTED_BY_REMOTE) {
- Log.w(TAG, "Audio Policy feature not supported by AG");
- return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
+ if (isRequestAudioPolicyAsSinkSupported(device)
+ != BluetoothStatusCodes.FEATURE_SUPPORTED) {
+ throw new UnsupportedOperationException(
+ "Request Audio Policy As Sink not supported");
}
deviceProp.setHfAudioPolicyForRemoteAg(policies);
mHeadsetClientService.setAudioPolicy(device, policies);
@@ -5622,9 +5625,9 @@
* Get audio policy for remote device
*
* @param device Bluetooth device to be set policy for
- * @return {@link BluetoothAudioPolicy} policy stored for the device
+ * @return {@link BluetoothSinkAudioPolicy} policy stored for the device
*/
- public BluetoothAudioPolicy getAudioPolicy(BluetoothDevice device) {
+ public BluetoothSinkAudioPolicy getRequestedAudioPolicyAsSink(BluetoothDevice device) {
DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
if (deviceProp == null) {
return null;
diff --git a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
index 163a3cd..6d2e838 100644
--- a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
+++ b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
@@ -355,10 +355,12 @@
BluetoothProfile.PAN, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
+ boolean isLeAudioProfileAllowed = false;
if ((leAudioService != null) && Utils.arrayContains(uuids,
BluetoothUuid.LE_AUDIO) && (leAudioService.getConnectionPolicy(device)
== BluetoothProfile.CONNECTION_POLICY_UNKNOWN)) {
debugLog("setting le audio profile priority for device " + device);
+ isLeAudioProfileAllowed = true;
mAdapterService.getDatabase().setProfileConnectionPolicy(device,
BluetoothProfile.LE_AUDIO, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
if (mPreferLeAudioOnlyMode) {
@@ -384,9 +386,13 @@
if ((hearingAidService != null) && Utils.arrayContains(uuids,
BluetoothUuid.HEARING_AID) && (hearingAidService.getConnectionPolicy(device)
== BluetoothProfile.CONNECTION_POLICY_UNKNOWN)) {
- debugLog("setting hearing aid profile priority for device " + device);
- mAdapterService.getDatabase().setProfileConnectionPolicy(device,
- BluetoothProfile.HEARING_AID, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (isLeAudioProfileAllowed) {
+ debugLog("LE Audio preferred over ASHA for device " + device);
+ } else {
+ debugLog("setting hearing aid profile priority for device " + device);
+ mAdapterService.getDatabase().setProfileConnectionPolicy(device,
+ BluetoothProfile.HEARING_AID, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ }
}
if ((volumeControlService != null) && Utils.arrayContains(uuids,
diff --git a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
index dd1297c..d18cafc 100644
--- a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -22,12 +22,12 @@
import android.app.admin.SecurityLog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAssignedNumbers;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.IBluetoothConnectionCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -313,7 +313,7 @@
@VisibleForTesting int mBondState;
@VisibleForTesting int mDeviceType;
@VisibleForTesting ParcelUuid[] mUuids;
- private BluetoothAudioPolicy mAudioPolicy;
+ private BluetoothSinkAudioPolicy mAudioPolicy;
DeviceProperties() {
mBondState = BluetoothDevice.BOND_NONE;
@@ -502,11 +502,11 @@
}
}
- public void setHfAudioPolicyForRemoteAg(BluetoothAudioPolicy policies) {
+ public void setHfAudioPolicyForRemoteAg(BluetoothSinkAudioPolicy policies) {
mAudioPolicy = policies;
}
- public BluetoothAudioPolicy getHfAudioPolicyForRemoteAg() {
+ public BluetoothSinkAudioPolicy getHfAudioPolicyForRemoteAg() {
return mAudioPolicy;
}
}
diff --git a/android/app/src/com/android/bluetooth/btservice/storage/AudioPolicyEntity.java b/android/app/src/com/android/bluetooth/btservice/storage/AudioPolicyEntity.java
index 8a302ff..d5ec422 100644
--- a/android/app/src/com/android/bluetooth/btservice/storage/AudioPolicyEntity.java
+++ b/android/app/src/com/android/bluetooth/btservice/storage/AudioPolicyEntity.java
@@ -16,7 +16,7 @@
package com.android.bluetooth.btservice.storage;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
@@ -31,9 +31,9 @@
public int inBandRingtoneAudioPolicy;
AudioPolicyEntity() {
- callEstablishAudioPolicy = BluetoothAudioPolicy.POLICY_UNCONFIGURED;
- connectingTimeAudioPolicy = BluetoothAudioPolicy.POLICY_UNCONFIGURED;
- inBandRingtoneAudioPolicy = BluetoothAudioPolicy.POLICY_UNCONFIGURED;
+ callEstablishAudioPolicy = BluetoothSinkAudioPolicy.POLICY_UNCONFIGURED;
+ connectingTimeAudioPolicy = BluetoothSinkAudioPolicy.POLICY_UNCONFIGURED;
+ inBandRingtoneAudioPolicy = BluetoothSinkAudioPolicy.POLICY_UNCONFIGURED;
}
AudioPolicyEntity(int callEstablishAudioPolicy, int connectingTimeAudioPolicy,
diff --git a/android/app/src/com/android/bluetooth/btservice/storage/DatabaseManager.java b/android/app/src/com/android/bluetooth/btservice/storage/DatabaseManager.java
index df8505e..cd81c9d 100644
--- a/android/app/src/com/android/bluetooth/btservice/storage/DatabaseManager.java
+++ b/android/app/src/com/android/bluetooth/btservice/storage/DatabaseManager.java
@@ -20,10 +20,10 @@
import android.bluetooth.BluetoothA2dp.OptionalCodecsPreferenceStatus;
import android.bluetooth.BluetoothA2dp.OptionalCodecsSupportStatus;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProtoEnums;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -288,7 +288,8 @@
* Set audio policy metadata to database with requested key
*/
@VisibleForTesting
- public boolean setAudioPolicyMetadata(BluetoothDevice device, BluetoothAudioPolicy policies) {
+ public boolean setAudioPolicyMetadata(BluetoothDevice device,
+ BluetoothSinkAudioPolicy policies) {
synchronized (mMetadataCache) {
if (device == null) {
Log.e(TAG, "setAudioPolicyMetadata: device is null");
@@ -302,7 +303,7 @@
Metadata data = mMetadataCache.get(address);
AudioPolicyEntity entity = data.audioPolicyMetadata;
entity.callEstablishAudioPolicy = policies.getCallEstablishPolicy();
- entity.connectingTimeAudioPolicy = policies.getConnectingTimePolicy();
+ entity.connectingTimeAudioPolicy = policies.getActiveDevicePolicyAfterConnection();
entity.inBandRingtoneAudioPolicy = policies.getInBandRingtonePolicy();
updateDatabase(data);
@@ -314,7 +315,7 @@
* Get audio policy metadata from database with requested key
*/
@VisibleForTesting
- public BluetoothAudioPolicy getAudioPolicyMetadata(BluetoothDevice device) {
+ public BluetoothSinkAudioPolicy getAudioPolicyMetadata(BluetoothDevice device) {
synchronized (mMetadataCache) {
if (device == null) {
Log.e(TAG, "getAudioPolicyMetadata: device is null");
@@ -329,9 +330,9 @@
}
AudioPolicyEntity entity = mMetadataCache.get(address).audioPolicyMetadata;
- return new BluetoothAudioPolicy.Builder()
+ return new BluetoothSinkAudioPolicy.Builder()
.setCallEstablishPolicy(entity.callEstablishAudioPolicy)
- .setConnectingTimePolicy(entity.connectingTimeAudioPolicy)
+ .setActiveDevicePolicyAfterConnection(entity.connectingTimeAudioPolicy)
.setInBandRingtonePolicy(entity.inBandRingtoneAudioPolicy)
.build();
}
diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
index 536c054..856f7dd 100644
--- a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -23,11 +23,11 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.BluetoothStatusCodes;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothHeadset;
@@ -58,6 +58,7 @@
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.btservice.storage.DatabaseManager;
+import com.android.bluetooth.hfpclient.HeadsetClientService;
import com.android.bluetooth.le_audio.LeAudioService;
import com.android.bluetooth.telephony.BluetoothInCallService;
import com.android.internal.annotations.VisibleForTesting;
@@ -1368,9 +1369,9 @@
* Get the Bluetooth Audio Policy stored in the state machine
*
* @param device the device to change silence mode
- * @return a {@link BluetoothAudioPolicy} object
+ * @return a {@link BluetoothSinkAudioPolicy} object
*/
- public BluetoothAudioPolicy getHfpCallAudioPolicy(BluetoothDevice device) {
+ public BluetoothSinkAudioPolicy getHfpCallAudioPolicy(BluetoothDevice device) {
synchronized (mStateMachines) {
final HeadsetStateMachine stateMachine = mStateMachines.get(device);
if (stateMachine == null) {
@@ -1915,9 +1916,9 @@
if (stateMachine == null) {
Log.d(TAG, "phoneStateChanged: CALL_STATE_IDLE, mActiveDevice is Null");
} else {
- BluetoothAudioPolicy currentPolicy = stateMachine.getHfpCallAudioPolicy();
- if (currentPolicy != null && currentPolicy.getConnectingTimePolicy()
- == BluetoothAudioPolicy.POLICY_NOT_ALLOWED) {
+ BluetoothSinkAudioPolicy currentPolicy = stateMachine.getHfpCallAudioPolicy();
+ if (currentPolicy != null && currentPolicy.getActiveDevicePolicyAfterConnection()
+ == BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED) {
/**
* If the active device was set because of the pick up audio policy
* and the connecting policy is NOT_ALLOWED, then after the call is
@@ -1981,10 +1982,10 @@
List<BluetoothDevice> audioConnectableDevices = getConnectedDevices();
if (audioConnectableDevices.size() == 1) {
BluetoothDevice connectedDevice = audioConnectableDevices.get(0);
- BluetoothAudioPolicy callAudioPolicy =
+ BluetoothSinkAudioPolicy callAudioPolicy =
getHfpCallAudioPolicy(connectedDevice);
if (callAudioPolicy != null && callAudioPolicy.getInBandRingtonePolicy()
- == BluetoothAudioPolicy.POLICY_NOT_ALLOWED) {
+ == BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED) {
inbandRingtoneAllowedByPolicy = false;
}
}
@@ -1992,7 +1993,16 @@
return isInbandRingingSupported && !SystemProperties.getBoolean(
DISABLE_INBAND_RINGING_PROPERTY, false)
&& !mInbandRingingRuntimeDisable
- && inbandRingtoneAllowedByPolicy;
+ && inbandRingtoneAllowedByPolicy
+ && !isHeadsetClientConnected();
+ }
+
+ private boolean isHeadsetClientConnected() {
+ HeadsetClientService headsetClientService = HeadsetClientService.getHeadsetClientService();
+ if (headsetClientService == null) {
+ return false;
+ }
+ return !(headsetClientService.getConnectedDevices().isEmpty());
}
/**
@@ -2007,30 +2017,53 @@
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void onConnectionStateChangedFromStateMachine(BluetoothDevice device, int fromState,
int toState) {
- synchronized (mStateMachines) {
- List<BluetoothDevice> audioConnectableDevices =
- getDevicesMatchingConnectionStates(CONNECTING_CONNECTED_STATES);
- if (fromState != BluetoothProfile.STATE_CONNECTED
- && toState == BluetoothProfile.STATE_CONNECTED) {
- if (audioConnectableDevices.size() > 1) {
- mInbandRingingRuntimeDisable = true;
- doForEachConnectedStateMachine(
- stateMachine -> stateMachine.sendMessage(HeadsetStateMachine.SEND_BSIR,
- 0));
- }
- MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.HEADSET);
+ if (fromState != BluetoothProfile.STATE_CONNECTED
+ && toState == BluetoothProfile.STATE_CONNECTED) {
+ updateInbandRinging(device, true);
+ MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.HEADSET);
+ }
+ if (fromState != BluetoothProfile.STATE_DISCONNECTED
+ && toState == BluetoothProfile.STATE_DISCONNECTED) {
+ updateInbandRinging(device, false);
+ if (device.equals(mActiveDevice)) {
+ setActiveDevice(null);
}
- if (fromState != BluetoothProfile.STATE_DISCONNECTED
- && toState == BluetoothProfile.STATE_DISCONNECTED) {
- if (audioConnectableDevices.size() <= 1) {
- mInbandRingingRuntimeDisable = false;
- doForEachConnectedStateMachine(
- stateMachine -> stateMachine.sendMessage(HeadsetStateMachine.SEND_BSIR,
- 1));
- }
- if (device.equals(mActiveDevice)) {
- setActiveDevice(null);
- }
+ }
+ }
+
+ /**
+ * Called from {@link HeadsetClientStateMachine} to update inband ringing status.
+ */
+ public void updateInbandRinging(BluetoothDevice device, boolean connected) {
+ synchronized (mStateMachines) {
+ List<BluetoothDevice> audioConnectableDevices = getConnectedDevices();
+ final int enabled;
+ final boolean inbandRingingRuntimeDisable = mInbandRingingRuntimeDisable;
+
+ if (audioConnectableDevices.size() > 1 || isHeadsetClientConnected()) {
+ mInbandRingingRuntimeDisable = true;
+ enabled = 0;
+ } else {
+ mInbandRingingRuntimeDisable = false;
+ enabled = 1;
+ }
+
+ final boolean updateAll = inbandRingingRuntimeDisable != mInbandRingingRuntimeDisable;
+
+ Log.i(TAG, "updateInbandRinging():"
+ + " Device=" + device
+ + " enabled=" + enabled
+ + " connected=" + connected
+ + " Update all=" + updateAll);
+
+ StateMachineTask sendBsirTask = stateMachine -> stateMachine
+ .sendMessage(HeadsetStateMachine.SEND_BSIR, enabled);
+
+ if (updateAll) {
+ doForEachConnectedStateMachine(sendBsirTask);
+ } else if (connected) {
+ // Same Inband ringing status, send +BSIR only to the new connected device
+ doForStateMachine(device, sendBsirTask);
}
}
}
diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index cec0a39..03ea3fa 100644
--- a/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -21,11 +21,11 @@
import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAssignedNumbers;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProtoEnums;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.BluetoothStatusCodes;
import android.bluetooth.hfp.BluetoothHfpProtoEnums;
import android.content.Intent;
@@ -160,7 +160,7 @@
static final int HFP_SET_AUDIO_POLICY = 1;
- private BluetoothAudioPolicy mHsClientAudioPolicy;
+ private BluetoothSinkAudioPolicy mHsClientAudioPolicy;
// Keys are AT commands, and values are the company IDs.
private static final Map<String, Integer> VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID;
@@ -199,10 +199,11 @@
"DatabaseManager cannot be null when HeadsetClientStateMachine is created");
mDeviceSilenced = false;
- BluetoothAudioPolicy storedAudioPolicy = mDatabaseManager.getAudioPolicyMetadata(device);
+ BluetoothSinkAudioPolicy storedAudioPolicy =
+ mDatabaseManager.getAudioPolicyMetadata(device);
if (storedAudioPolicy == null) {
Log.w(TAG, "Audio Policy not created in database! Creating...");
- mHsClientAudioPolicy = new BluetoothAudioPolicy.Builder().build();
+ mHsClientAudioPolicy = new BluetoothSinkAudioPolicy.Builder().build();
mDatabaseManager.setAudioPolicyMetadata(device, mHsClientAudioPolicy);
} else {
Log.i(TAG, "Audio Policy found in database!");
@@ -2019,9 +2020,9 @@
int connectingTimePolicy = (Integer) args[2];
int inbandPolicy = (Integer) args[3];
- setHfpCallAudioPolicy(new BluetoothAudioPolicy.Builder()
+ setHfpCallAudioPolicy(new BluetoothSinkAudioPolicy.Builder()
.setCallEstablishPolicy(callEstablishPolicy)
- .setConnectingTimePolicy(connectingTimePolicy)
+ .setActiveDevicePolicyAfterConnection(connectingTimePolicy)
.setInBandRingtonePolicy(inbandPolicy)
.build());
}
@@ -2031,7 +2032,7 @@
*
* @param policies policies to be set and stored
*/
- public void setHfpCallAudioPolicy(BluetoothAudioPolicy policies) {
+ public void setHfpCallAudioPolicy(BluetoothSinkAudioPolicy policies) {
mHsClientAudioPolicy = policies;
mDatabaseManager.setAudioPolicyMetadata(mDevice, policies);
}
@@ -2040,7 +2041,7 @@
* get the audio policy of the client device
*
*/
- public BluetoothAudioPolicy getHfpCallAudioPolicy() {
+ public BluetoothSinkAudioPolicy getHfpCallAudioPolicy() {
return mHsClientAudioPolicy;
}
diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java b/android/app/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java
index 0820544..bbf4e36 100644
--- a/android/app/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java
+++ b/android/app/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java
@@ -19,9 +19,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Intent;
@@ -163,10 +163,10 @@
}
BluetoothInCallService bluetoothInCallService = getBluetoothInCallServiceInstance();
if (bluetoothInCallService != null) {
- BluetoothAudioPolicy callAudioPolicy =
+ BluetoothSinkAudioPolicy callAudioPolicy =
mHeadsetService.getHfpCallAudioPolicy(device);
if (callAudioPolicy == null || callAudioPolicy.getCallEstablishPolicy()
- != BluetoothAudioPolicy.POLICY_NOT_ALLOWED) {
+ != BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED) {
mHeadsetService.setActiveDevice(device);
}
bluetoothInCallService.answerCall();
diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
index bce1c79..9221d98 100644
--- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
+++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
@@ -17,11 +17,12 @@
package com.android.bluetooth.hfpclient;
import android.annotation.RequiresPermission;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothHeadsetClientCall;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
+import android.bluetooth.BluetoothStatusCodes;
import android.bluetooth.IBluetoothHeadsetClient;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
@@ -33,6 +34,7 @@
import android.os.Bundle;
import android.os.HandlerThread;
import android.os.Message;
+import android.os.SystemProperties;
import android.sysprop.BluetoothProperties;
import android.util.Log;
@@ -927,13 +929,13 @@
}
/**
- * sends the {@link BluetoothAudioPolicy} object to the state machine of the corresponding
+ * sends the {@link BluetoothSinkAudioPolicy} object to the state machine of the corresponding
* device to store and send to the remote device using Android specific AT commands.
*
* @param device for whom the policies to be set
* @param policies to be set policies
*/
- public void setAudioPolicy(BluetoothDevice device, BluetoothAudioPolicy policies) {
+ public void setAudioPolicy(BluetoothDevice device, BluetoothSinkAudioPolicy policies) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
Log.i(TAG, "setAudioPolicy: device=" + device + ", " + policies.toString() + ", "
+ Utils.getUidPidString());
@@ -970,7 +972,7 @@
if (sm != null) {
return sm.getAudioPolicyRemoteSupported();
}
- return BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE;
+ return BluetoothStatusCodes.FEATURE_NOT_CONFIGURED;
}
public boolean connectAudio(BluetoothDevice device) {
@@ -1128,6 +1130,14 @@
return null;
}
+ // Some platform does not support three way calling (ex: watch)
+ final boolean support_three_way_calling = SystemProperties
+ .getBoolean("bluetooth.headset_client.three_way_calling.enabled", true);
+ if (!support_three_way_calling && !getCurrentCalls(device).isEmpty()) {
+ Log.e(TAG, String.format("dial(%s): Line is busy, reject dialing", device));
+ return null;
+ }
+
HfpClientCall call = new HfpClientCall(device,
HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID,
HfpClientCall.CALL_STATE_DIALING, number, false /* multiparty */,
diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
index 581b258..804dadd 100644
--- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
+++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
@@ -37,11 +37,12 @@
import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothHeadsetClient.NetworkServiceState;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
+import android.bluetooth.BluetoothStatusCodes;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.hfp.BluetoothHfpProtoEnums;
import android.content.Intent;
@@ -64,6 +65,7 @@
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
+import com.android.bluetooth.hfp.HeadsetService;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IState;
import com.android.internal.util.State;
@@ -148,6 +150,7 @@
private long mClccTimer = 0;
private final HeadsetClientService mService;
+ private final HeadsetService mHeadsetService;
// Set of calls that represent the accurate state of calls that exists on AG and the calls that
// are currently in process of being notified to the AG from HF.
@@ -186,7 +189,7 @@
private static final int CALL_AUDIO_POLICY_FEATURE_ID = 1;
public int mAudioPolicyRemoteSupported;
- private BluetoothAudioPolicy mHsClientAudioPolicy;
+ private BluetoothSinkAudioPolicy mHsClientAudioPolicy;
private boolean mAudioWbs;
private int mVoiceRecognitionActive;
@@ -860,12 +863,13 @@
return (bitfield & mask) == mask;
}
- HeadsetClientStateMachine(HeadsetClientService context, Looper looper,
- NativeInterface nativeInterface) {
+ HeadsetClientStateMachine(HeadsetClientService context, HeadsetService headsetService,
+ Looper looper, NativeInterface nativeInterface) {
super(TAG, looper);
mService = context;
mNativeInterface = nativeInterface;
mAudioManager = mService.getAudioManager();
+ mHeadsetService = headsetService;
mVendorProcessor = new VendorCommandResponseProcessor(mService, mNativeInterface);
@@ -877,7 +881,7 @@
mAudioRouteAllowed = context.getResources().getBoolean(
R.bool.headset_client_initial_audio_route_allowed);
- mHsClientAudioPolicy = new BluetoothAudioPolicy.Builder().build();
+ mHsClientAudioPolicy = new BluetoothSinkAudioPolicy.Builder().build();
mIndicatorNetworkState = HeadsetClientHalConstants.NETWORK_STATE_NOT_AVAILABLE;
mIndicatorNetworkType = HeadsetClientHalConstants.SERVICE_TYPE_HOME;
@@ -909,11 +913,12 @@
setInitialState(mDisconnected);
}
- static HeadsetClientStateMachine make(HeadsetClientService context, Looper looper,
- NativeInterface nativeInterface) {
+ static HeadsetClientStateMachine make(HeadsetClientService context,
+ HeadsetService headsetService,
+ Looper looper, NativeInterface nativeInterface) {
logD("make");
- HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, looper,
- nativeInterface);
+ HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, headsetService,
+ looper, nativeInterface);
hfcsm.start();
return hfcsm;
}
@@ -1022,6 +1027,9 @@
Log.e(TAG, "Disconnected: Illegal state transition from " + mPrevState.getName()
+ " to Disconnected, mCurrentDevice=" + mCurrentDevice);
}
+ if (mHeadsetService != null && mCurrentDevice != null) {
+ mHeadsetService.updateInbandRinging(mCurrentDevice, false);
+ }
mCurrentDevice = null;
}
@@ -1309,6 +1317,9 @@
if (mPrevState == mConnecting) {
broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING);
+ if (mHeadsetService != null) {
+ mHeadsetService.updateInbandRinging(mCurrentDevice, true);
+ }
MetricsLogger.logProfileConnectionEvent(
BluetoothMetricsProto.ProfileId.HEADSET_CLIENT);
} else if (mPrevState != mAudioOn) {
@@ -2152,13 +2163,13 @@
mAudioRouteAllowed = allowed;
int establishPolicy = allowed
- ? BluetoothAudioPolicy.POLICY_ALLOWED :
- BluetoothAudioPolicy.POLICY_NOT_ALLOWED;
+ ? BluetoothSinkAudioPolicy.POLICY_ALLOWED :
+ BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED;
/*
* Backward compatibility for mAudioRouteAllowed
*/
- setAudioPolicy(new BluetoothAudioPolicy.Builder(mHsClientAudioPolicy)
+ setAudioPolicy(new BluetoothSinkAudioPolicy.Builder(mHsClientAudioPolicy)
.setCallEstablishPolicy(establishPolicy).build());
}
@@ -2166,26 +2177,26 @@
return mAudioRouteAllowed;
}
- private String createMaskString(BluetoothAudioPolicy policies) {
+ private String createMaskString(BluetoothSinkAudioPolicy policies) {
StringBuilder mask = new StringBuilder();
mask.append(Integer.toString(CALL_AUDIO_POLICY_FEATURE_ID));
mask.append("," + policies.getCallEstablishPolicy());
- mask.append("," + policies.getConnectingTimePolicy());
+ mask.append("," + policies.getActiveDevicePolicyAfterConnection());
mask.append("," + policies.getInBandRingtonePolicy());
return mask.toString();
}
/**
- * sets the {@link BluetoothAudioPolicy} object device and send to the remote
+ * sets the {@link BluetoothSinkAudioPolicy} object device and send to the remote
* device using Android specific AT commands.
*
* @param policies to be set policies
*/
- public void setAudioPolicy(BluetoothAudioPolicy policies) {
+ public void setAudioPolicy(BluetoothSinkAudioPolicy policies) {
logD("setAudioPolicy: " + policies);
mHsClientAudioPolicy = policies;
- if (mAudioPolicyRemoteSupported != BluetoothAudioPolicy.FEATURE_SUPPORTED_BY_REMOTE) {
+ if (mAudioPolicyRemoteSupported != BluetoothStatusCodes.FEATURE_SUPPORTED) {
Log.e(TAG, "Audio Policy feature not supported!");
return;
}
@@ -2213,9 +2224,9 @@
*/
public void setAudioPolicyRemoteSupported(boolean supported) {
if (supported) {
- mAudioPolicyRemoteSupported = BluetoothAudioPolicy.FEATURE_SUPPORTED_BY_REMOTE;
+ mAudioPolicyRemoteSupported = BluetoothStatusCodes.FEATURE_SUPPORTED;
} else {
- mAudioPolicyRemoteSupported = BluetoothAudioPolicy.FEATURE_NOT_SUPPORTED_BY_REMOTE;
+ mAudioPolicyRemoteSupported = BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
}
}
diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java
index b0c7265..b21f537 100644
--- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java
+++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java
@@ -18,6 +18,8 @@
import android.os.HandlerThread;
+import com.android.bluetooth.hfp.HeadsetService;
+
// Factory so that StateMachine objected can be mocked
public class HeadsetClientStateMachineFactory {
/**
@@ -26,6 +28,7 @@
*/
public HeadsetClientStateMachine make(HeadsetClientService context, HandlerThread t,
NativeInterface nativeInterface) {
- return HeadsetClientStateMachine.make(context, t.getLooper(), nativeInterface);
+ return HeadsetClientStateMachine.make(context, HeadsetService.getHeadsetService(),
+ t.getLooper(), nativeInterface);
}
}
diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
index 8eab0d5..9921c33 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
@@ -77,7 +77,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
/**
* Provides Bluetooth LeAudio profile, as a service in the Bluetooth application.
@@ -91,7 +90,7 @@
private static final int SM_THREAD_JOIN_TIMEOUT_MS = 1000;
// Upper limit of all LeAudio devices: Bonded or Connected
- private static final int MAX_LE_AUDIO_STATE_MACHINES = 10;
+ private static final int MAX_LE_AUDIO_DEVICES = 10;
private static LeAudioService sLeAudioService;
/**
@@ -156,16 +155,27 @@
BluetoothDevice mLostLeadDeviceWhileStreaming;
}
+ private static class LeAudioDeviceDescriptor {
+ LeAudioDeviceDescriptor() {
+ mStateMachine = null;
+ mGroupId = LE_AUDIO_GROUP_ID_INVALID;
+ mSinkAudioLocation = BluetoothLeAudio.AUDIO_LOCATION_INVALID;
+ mDirection = AUDIO_DIRECTION_NONE;
+ }
+
+ public LeAudioStateMachine mStateMachine;
+ public Integer mGroupId;
+ public Integer mSinkAudioLocation;
+ public Integer mDirection;
+ }
+
List<BluetoothLeAudioCodecConfig> mInputLocalCodecCapabilities = new ArrayList<>();
List<BluetoothLeAudioCodecConfig> mOutputLocalCodecCapabilities = new ArrayList<>();
@GuardedBy("mGroupLock")
private final Map<Integer, LeAudioGroupDescriptor> mGroupDescriptors = new LinkedHashMap<>();
- private final Map<BluetoothDevice, LeAudioStateMachine> mStateMachines = new LinkedHashMap<>();
-
- @GuardedBy("mGroupLock")
- private final Map<BluetoothDevice, Integer> mDeviceGroupIdMap = new ConcurrentHashMap<>();
- private final Map<BluetoothDevice, Integer> mDeviceAudioLocationMap = new ConcurrentHashMap<>();
+ private final Map<BluetoothDevice, LeAudioDeviceDescriptor> mDeviceDescriptors =
+ new LinkedHashMap<>();
private BroadcastReceiver mBondStateChangedReceiver;
private BroadcastReceiver mConnectionStateChangedReceiver;
@@ -219,17 +229,15 @@
"AudioManager cannot be null when LeAudioService starts");
// Start handler thread for state machines
- mStateMachines.clear();
mStateMachinesThread = new HandlerThread("LeAudioService.StateMachines");
mStateMachinesThread.start();
- mDeviceAudioLocationMap.clear();
mBroadcastStateMap.clear();
mBroadcastMetadataList.clear();
mBroadcastsPlaybackMap.clear();
synchronized (mGroupLock) {
- mDeviceGroupIdMap.clear();
+ mDeviceDescriptors.clear();
mGroupDescriptors.clear();
}
@@ -326,7 +334,18 @@
break;
}
}
- mDeviceGroupIdMap.clear();
+
+ // Destroy state machines and stop handler thread
+ for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
+ LeAudioStateMachine sm = descriptor.mStateMachine;
+ if (sm == null) {
+ continue;
+ }
+ sm.doQuit();
+ sm.cleanup();
+ }
+
+ mDeviceDescriptors.clear();
mGroupDescriptors.clear();
}
@@ -352,16 +371,6 @@
unregisterReceiver(mMuteStateChangedReceiver);
mMuteStateChangedReceiver = null;
- // Destroy state machines and stop handler thread
- synchronized (mStateMachines) {
- for (LeAudioStateMachine sm : mStateMachines.values()) {
- sm.doQuit();
- sm.cleanup();
- }
- mStateMachines.clear();
- }
-
- mDeviceAudioLocationMap.clear();
if (mBroadcastCallbacks != null) {
mBroadcastCallbacks.kill();
@@ -439,6 +448,27 @@
return mVolumeControlService.getAudioDeviceGroupVolume(groupId);
}
+ LeAudioDeviceDescriptor createDeviceDescriptor(BluetoothDevice device) {
+ LeAudioDeviceDescriptor descriptor = mDeviceDescriptors.get(device);
+ if (descriptor == null) {
+
+ // Limit the maximum number of devices to avoid DoS attack
+ if (mDeviceDescriptors.size() >= MAX_LE_AUDIO_DEVICES) {
+ Log.e(TAG, "Maximum number of LeAudio state machines reached: "
+ + MAX_LE_AUDIO_DEVICES);
+ return null;
+ }
+
+ mDeviceDescriptors.put(device, new LeAudioDeviceDescriptor());
+ descriptor = mDeviceDescriptors.get(device);
+ Log.d(TAG, "Created descriptor for device: " + device);
+ } else {
+ Log.w(TAG, "Device: " + device + ", already exists");
+ }
+
+ return descriptor;
+ }
+
public boolean connect(BluetoothDevice device) {
if (DBG) {
Log.d(TAG, "connect(): " + device);
@@ -454,7 +484,11 @@
return false;
}
- synchronized (mStateMachines) {
+ synchronized (mGroupLock) {
+ if (createDeviceDescriptor(device) == null) {
+ return false;
+ }
+
LeAudioStateMachine sm = getOrCreateStateMachine(device);
if (sm == null) {
Log.e(TAG, "Ignored connect request for " + device + " : no state machine");
@@ -477,9 +511,14 @@
Log.d(TAG, "disconnect(): " + device);
}
- // Disconnect this device
- synchronized (mStateMachines) {
- LeAudioStateMachine sm = mStateMachines.get(device);
+ synchronized (mGroupLock) {
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ Log.e(TAG, "disconnect: No valid descriptor for device: " + device);
+ return false;
+ }
+
+ LeAudioStateMachine sm = descriptor.mStateMachine;
if (sm == null) {
Log.e(TAG, "Ignored disconnect request for " + device
+ " : no state machine");
@@ -492,10 +531,11 @@
}
public List<BluetoothDevice> getConnectedDevices() {
- synchronized (mStateMachines) {
+ synchronized (mGroupLock) {
List<BluetoothDevice> devices = new ArrayList<>();
- for (LeAudioStateMachine sm : mStateMachines.values()) {
- if (sm.isConnected()) {
+ for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
+ LeAudioStateMachine sm = descriptor.mStateMachine;
+ if (sm != null && sm.isConnected()) {
devices.add(sm.getDevice());
}
}
@@ -504,11 +544,31 @@
}
BluetoothDevice getConnectedGroupLeadDevice(int groupId) {
+ BluetoothDevice device = null;
+
if (mActiveAudioOutDevice != null
&& getGroupId(mActiveAudioOutDevice) == groupId) {
- return mActiveAudioOutDevice;
+ device = mActiveAudioOutDevice;
+ } else {
+ device = getFirstDeviceFromGroup(groupId);
}
- return getFirstDeviceFromGroup(groupId);
+
+ if (device == null) {
+ return device;
+ }
+
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ Log.e(TAG, "getConnectedGroupLeadDevice: No valid descriptor for device: " + device);
+ return null;
+ }
+
+ LeAudioStateMachine sm = descriptor.mStateMachine;
+ if (sm != null && sm.getConnectionState() == BluetoothProfile.STATE_CONNECTED) {
+ return device;
+ }
+
+ return null;
}
List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
@@ -520,14 +580,21 @@
if (bondedDevices == null) {
return devices;
}
- synchronized (mStateMachines) {
+ synchronized (mGroupLock) {
for (BluetoothDevice device : bondedDevices) {
final ParcelUuid[] featureUuids = device.getUuids();
if (!Utils.arrayContains(featureUuids, BluetoothUuid.LE_AUDIO)) {
continue;
}
int connectionState = BluetoothProfile.STATE_DISCONNECTED;
- LeAudioStateMachine sm = mStateMachines.get(device);
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ Log.e(TAG, "getDevicesMatchingConnectionStates: "
+ + "No valid descriptor for device: " + device);
+ return null;
+ }
+
+ LeAudioStateMachine sm = descriptor.mStateMachine;
if (sm != null) {
connectionState = sm.getConnectionState();
}
@@ -550,9 +617,11 @@
@VisibleForTesting
List<BluetoothDevice> getDevices() {
List<BluetoothDevice> devices = new ArrayList<>();
- synchronized (mStateMachines) {
- for (LeAudioStateMachine sm : mStateMachines.values()) {
- devices.add(sm.getDevice());
+ synchronized (mGroupLock) {
+ for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
+ if (descriptor.mStateMachine != null) {
+ devices.add(descriptor.mStateMachine.getDevice());
+ }
}
return devices;
}
@@ -568,8 +637,13 @@
* {@link BluetoothProfile#STATE_DISCONNECTING} if this profile is being disconnected
*/
public int getConnectionState(BluetoothDevice device) {
- synchronized (mStateMachines) {
- LeAudioStateMachine sm = mStateMachines.get(device);
+ synchronized (mGroupLock) {
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ LeAudioStateMachine sm = descriptor.mStateMachine;
if (sm == null) {
return BluetoothProfile.STATE_DISCONNECTED;
}
@@ -610,8 +684,10 @@
* @param group_id group Id to verify
* @return true given group exists, otherwise false
*/
- public boolean isValidDeviceGroup(int group_id) {
- return group_id != LE_AUDIO_GROUP_ID_INVALID && mDeviceGroupIdMap.containsValue(group_id);
+ public boolean isValidDeviceGroup(int groupId) {
+ synchronized (mGroupLock) {
+ return groupId != LE_AUDIO_GROUP_ID_INVALID && mGroupDescriptors.containsKey(groupId);
+ }
}
/**
@@ -627,8 +703,9 @@
}
synchronized (mGroupLock) {
- for (Map.Entry<BluetoothDevice, Integer> entry : mDeviceGroupIdMap.entrySet()) {
- if (entry.getValue() == groupId) {
+ for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
+ : mDeviceDescriptors.entrySet()) {
+ if (entry.getValue().mGroupId == groupId) {
result.add(entry.getKey());
}
}
@@ -772,15 +849,16 @@
return null;
}
synchronized (mGroupLock) {
- for (Map.Entry<BluetoothDevice, Integer> entry : mDeviceGroupIdMap.entrySet()) {
- if (entry.getValue() != groupId) {
+ for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
+ if (!descriptor.mGroupId.equals(groupId)) {
continue;
}
- LeAudioStateMachine sm = mStateMachines.get(entry.getKey());
+
+ LeAudioStateMachine sm = descriptor.mStateMachine;
if (sm == null || sm.getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
continue;
}
- return entry.getKey();
+ return sm.getDevice();
}
}
return null;
@@ -802,8 +880,13 @@
}
if (device != null && mActiveAudioInDevice != null) {
- int previousGroupId = getGroupId(mActiveAudioInDevice);
- if (previousGroupId == groupId) {
+ LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+ if (deviceDescriptor == null) {
+ Log.e(TAG, "updateActiveInDevice: No valid descriptor for device: " + device);
+ return false;
+ }
+
+ if (deviceDescriptor.mGroupId.equals(groupId)) {
/* This is thes same group as aleady notified to the system.
* Therefore do not change the device we have connected to the group,
* unless, previous one is disconnected now
@@ -811,9 +894,9 @@
if (mActiveAudioInDevice.isConnected()) {
device = mActiveAudioInDevice;
}
- } else if (previousGroupId != LE_AUDIO_GROUP_ID_INVALID) {
+ } else if (deviceDescriptor.mGroupId != LE_AUDIO_GROUP_ID_INVALID) {
/* Mark old group as no active */
- LeAudioGroupDescriptor descriptor = getGroupDescriptor(previousGroupId);
+ LeAudioGroupDescriptor descriptor = getGroupDescriptor(deviceDescriptor.mGroupId);
if (descriptor != null) {
descriptor.mIsActive = false;
}
@@ -859,8 +942,13 @@
}
if (device != null && mActiveAudioOutDevice != null) {
- int previousGroupId = getGroupId(mActiveAudioOutDevice);
- if (previousGroupId == groupId) {
+ LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+ if (deviceDescriptor == null) {
+ Log.e(TAG, "updateActiveOutDevice: No valid descriptor for device: " + device);
+ return false;
+ }
+
+ if (deviceDescriptor.mGroupId.equals(groupId)) {
/* This is the same group as already notified to the system.
* Therefore do not change the device we have connected to the group,
* unless, previous one is disconnected now
@@ -868,10 +956,11 @@
if (mActiveAudioOutDevice.isConnected()) {
device = mActiveAudioOutDevice;
}
- } else if (previousGroupId != LE_AUDIO_GROUP_ID_INVALID) {
- Log.i(TAG, " Switching active group from " + previousGroupId + " to " + groupId);
+ } else if (deviceDescriptor.mGroupId != LE_AUDIO_GROUP_ID_INVALID) {
+ Log.i(TAG, " Switching active group from " + deviceDescriptor.mGroupId + " to "
+ + groupId);
/* Mark old group as no active */
- LeAudioGroupDescriptor descriptor = getGroupDescriptor(previousGroupId);
+ LeAudioGroupDescriptor descriptor = getGroupDescriptor(deviceDescriptor.mGroupId);
if (descriptor != null) {
descriptor.mIsActive = false;
}
@@ -1033,7 +1122,13 @@
int groupId = LE_AUDIO_GROUP_ID_INVALID;
if (device != null) {
- groupId = mDeviceGroupIdMap.getOrDefault(device, LE_AUDIO_GROUP_ID_INVALID);
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ Log.e(TAG, "setActiveGroupWithDevice: No valid descriptor for device: " + device);
+ return;
+ }
+
+ groupId = descriptor.mGroupId;
}
int currentlyActiveGroupId = getActiveGroupId();
@@ -1128,21 +1223,30 @@
}
void connectSet(BluetoothDevice device) {
- int groupId = getGroupId(device);
- if (groupId == LE_AUDIO_GROUP_ID_INVALID) {
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ Log.e(TAG, "connectSet: No valid descriptor for device: " + device);
+ return;
+ }
+ if (descriptor.mGroupId == LE_AUDIO_GROUP_ID_INVALID) {
return;
}
if (DBG) {
- Log.d(TAG, "connect() others from group id: " + groupId);
+ Log.d(TAG, "connect() others from group id: " + descriptor.mGroupId);
}
- for (BluetoothDevice storedDevice : mDeviceGroupIdMap.keySet()) {
+ Integer setGroupId = descriptor.mGroupId;
+
+ for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
+ : mDeviceDescriptors.entrySet()) {
+ BluetoothDevice storedDevice = entry.getKey();
+ descriptor = entry.getValue();
if (device.equals(storedDevice)) {
continue;
}
- if (getGroupId(storedDevice) != groupId) {
+ if (!descriptor.mGroupId.equals(setGroupId)) {
continue;
}
@@ -1150,7 +1254,7 @@
Log.d(TAG, "connect(): " + storedDevice);
}
- synchronized (mStateMachines) {
+ synchronized (mGroupLock) {
LeAudioStateMachine sm = getOrCreateStateMachine(storedDevice);
if (sm == null) {
Log.e(TAG, "Ignored connect request for " + storedDevice
@@ -1198,8 +1302,15 @@
Log.d(TAG, "Clearing lost dev: " + descriptor.mLostLeadDeviceWhileStreaming);
}
- LeAudioStateMachine sm =
- mStateMachines.get(descriptor.mLostLeadDeviceWhileStreaming);
+ LeAudioDeviceDescriptor deviceDescriptor =
+ getDeviceDescriptor(descriptor.mLostLeadDeviceWhileStreaming);
+ if (deviceDescriptor == null) {
+ Log.e(TAG, "clearLostDevicesWhileStreaming: No valid descriptor for device: "
+ + descriptor.mLostLeadDeviceWhileStreaming);
+ return;
+ }
+
+ LeAudioStateMachine sm = deviceDescriptor.mStateMachine;
if (sm != null) {
LeAudioStackEvent stackEvent =
new LeAudioStackEvent(
@@ -1283,12 +1394,17 @@
void messageFromNative(LeAudioStackEvent stackEvent) {
Log.d(TAG, "Message from native: " + stackEvent);
BluetoothDevice device = stackEvent.device;
- Intent intent = null;
if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) {
// Some events require device state machine
- synchronized (mStateMachines) {
- LeAudioStateMachine sm = mStateMachines.get(device);
+ synchronized (mGroupLock) {
+ LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+ if (deviceDescriptor == null) {
+ Log.e(TAG, "messageFromNative: No valid descriptor for device: " + device);
+ return;
+ }
+
+ LeAudioStateMachine sm = deviceDescriptor.mStateMachine;
if (sm != null) {
/*
* To improve scenario when lead Le Audio device is disconnected for the
@@ -1298,41 +1414,39 @@
* the hood and keep using lead device as a audio device indetifier in
* the audio framework in order to not stop the stream.
*/
- int groupId = getGroupId(device);
- synchronized (mGroupLock) {
- LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
- switch (stackEvent.valueInt1) {
- case LeAudioStackEvent.CONNECTION_STATE_DISCONNECTING:
- case LeAudioStackEvent.CONNECTION_STATE_DISCONNECTED:
- boolean disconnectDueToUnbond =
- (BluetoothDevice.BOND_NONE
- == mAdapterService.getBondState(device));
- if (descriptor != null && (Objects.equals(device,
- mActiveAudioOutDevice)
- || Objects.equals(device, mActiveAudioInDevice))
- && (getConnectedPeerDevices(groupId).size() > 1)
- && !disconnectDueToUnbond) {
+ int groupId = deviceDescriptor.mGroupId;
+ LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
+ switch (stackEvent.valueInt1) {
+ case LeAudioStackEvent.CONNECTION_STATE_DISCONNECTING:
+ case LeAudioStackEvent.CONNECTION_STATE_DISCONNECTED:
+ boolean disconnectDueToUnbond =
+ (BluetoothDevice.BOND_NONE
+ == mAdapterService.getBondState(device));
+ if (descriptor != null && (Objects.equals(device,
+ mActiveAudioOutDevice)
+ || Objects.equals(device, mActiveAudioInDevice))
+ && (getConnectedPeerDevices(groupId).size() > 1)
+ && !disconnectDueToUnbond) {
- if (DBG) Log.d(TAG, "Adding to lost devices : " + device);
- descriptor.mLostLeadDeviceWhileStreaming = device;
- return;
+ if (DBG) Log.d(TAG, "Adding to lost devices : " + device);
+ descriptor.mLostLeadDeviceWhileStreaming = device;
+ return;
+ }
+ break;
+ case LeAudioStackEvent.CONNECTION_STATE_CONNECTED:
+ case LeAudioStackEvent.CONNECTION_STATE_CONNECTING:
+ if (descriptor != null
+ && Objects.equals(
+ descriptor.mLostLeadDeviceWhileStreaming,
+ device)) {
+ if (DBG) {
+ Log.d(TAG, "Removing from lost devices : " + device);
}
- break;
- case LeAudioStackEvent.CONNECTION_STATE_CONNECTED:
- case LeAudioStackEvent.CONNECTION_STATE_CONNECTING:
- if (descriptor != null
- && Objects.equals(
- descriptor.mLostLeadDeviceWhileStreaming,
- device)) {
- if (DBG) {
- Log.d(TAG, "Removing from lost devices : " + device);
- }
- descriptor.mLostLeadDeviceWhileStreaming = null;
- /* Try to connect other devices from the group */
- connectSet(device);
- }
- break;
- }
+ descriptor.mLostLeadDeviceWhileStreaming = null;
+ /* Try to connect other devices from the group */
+ connectSet(device);
+ }
+ break;
}
} else {
/* state machine does not exist yet */
@@ -1410,26 +1524,36 @@
int src_audio_location = stackEvent.valueInt4;
int available_contexts = stackEvent.valueInt5;
- LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
- if (descriptor != null) {
- if (descriptor.mIsActive) {
- descriptor.mIsActive =
- updateActiveDevices(groupId, descriptor.mDirection, direction,
- descriptor.mIsActive);
- if (!descriptor.mIsActive) {
- notifyGroupStatusChanged(groupId, BluetoothLeAudio.GROUP_STATUS_INACTIVE);
+ synchronized (mGroupLock) {
+ LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
+ if (descriptor != null) {
+ if (descriptor.mIsActive) {
+ descriptor.mIsActive =
+ updateActiveDevices(groupId, descriptor.mDirection, direction,
+ descriptor.mIsActive);
+ if (!descriptor.mIsActive) {
+ notifyGroupStatusChanged(groupId,
+ BluetoothLeAudio.GROUP_STATUS_INACTIVE);
+ }
}
+ descriptor.mDirection = direction;
+ } else {
+ Log.e(TAG, "no descriptors for group: " + groupId);
}
- descriptor.mDirection = direction;
- } else {
- Log.e(TAG, "no descriptors for group: " + groupId);
}
} else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE) {
Objects.requireNonNull(stackEvent.device,
"Device should never be null, event: " + stackEvent);
int sink_audio_location = stackEvent.valueInt1;
- mDeviceAudioLocationMap.put(device, sink_audio_location);
+
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ Log.e(TAG, "messageFromNative: No valid descriptor for device: " + device);
+ return;
+ }
+
+ descriptor.mSinkAudioLocation = sink_audio_location;
if (DBG) {
Log.i(TAG, "EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE:" + device
@@ -1557,10 +1681,6 @@
setCcidInformation(userUuid, ccidInformation.first, ccidInformation.second);
}
}
-
- if (intent != null) {
- sendBroadcast(intent, BLUETOOTH_CONNECT);
- }
}
private LeAudioStateMachine getOrCreateStateMachine(BluetoothDevice device) {
@@ -1568,25 +1688,26 @@
Log.e(TAG, "getOrCreateStateMachine failed: device cannot be null");
return null;
}
- synchronized (mStateMachines) {
- LeAudioStateMachine sm = mStateMachines.get(device);
- if (sm != null) {
- return sm;
- }
- // Limit the maximum number of state machines to avoid DoS attack
- if (mStateMachines.size() >= MAX_LE_AUDIO_STATE_MACHINES) {
- Log.e(TAG, "Maximum number of LeAudio state machines reached: "
- + MAX_LE_AUDIO_STATE_MACHINES);
- return null;
- }
- if (DBG) {
- Log.d(TAG, "Creating a new state machine for " + device);
- }
- sm = LeAudioStateMachine.make(device, this,
- mLeAudioNativeInterface, mStateMachinesThread.getLooper());
- mStateMachines.put(device, sm);
+
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ Log.e(TAG, "getOrCreateStateMachine: No valid descriptor for device: " + device);
+ return null;
+ }
+
+ LeAudioStateMachine sm = descriptor.mStateMachine;
+ if (sm != null) {
return sm;
}
+
+ if (DBG) {
+ Log.d(TAG, "Creating a new state machine for " + device);
+ }
+
+ sm = LeAudioStateMachine.make(device, this,
+ mLeAudioNativeInterface, mStateMachinesThread.getLooper());
+ descriptor.mStateMachine = sm;
+ return sm;
}
// Remove state machine if the bonding for a device is removed
@@ -1623,16 +1744,23 @@
return;
}
- int groupId = getGroupId(device);
- if (groupId != LE_AUDIO_GROUP_ID_INVALID) {
- /* In case device is still in the group, let's remove it */
- mLeAudioNativeInterface.groupRemoveNode(groupId, device);
- }
+ synchronized (mGroupLock) {
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ Log.e(TAG, "bondStateChanged: No valid descriptor for device: " + device);
+ return;
+ }
- mDeviceGroupIdMap.remove(device);
- mDeviceAudioLocationMap.remove(device);
- synchronized (mStateMachines) {
- LeAudioStateMachine sm = mStateMachines.get(device);
+ if (descriptor.mGroupId != LE_AUDIO_GROUP_ID_INVALID) {
+ /* In case device is still in the group, let's remove it */
+ mLeAudioNativeInterface.groupRemoveNode(descriptor.mGroupId, device);
+ }
+
+ descriptor.mGroupId = LE_AUDIO_GROUP_ID_INVALID;
+ descriptor.mSinkAudioLocation = BluetoothLeAudio.AUDIO_LOCATION_INVALID;
+ descriptor.mDirection = AUDIO_DIRECTION_NONE;
+
+ LeAudioStateMachine sm = descriptor.mStateMachine;
if (sm == null) {
return;
}
@@ -1642,12 +1770,19 @@
return;
}
removeStateMachine(device);
+ mDeviceDescriptors.remove(device);
}
}
private void removeStateMachine(BluetoothDevice device) {
- synchronized (mStateMachines) {
- LeAudioStateMachine sm = mStateMachines.get(device);
+ synchronized (mGroupLock) {
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ Log.e(TAG, "removeStateMachine: No valid descriptor for device: " + device);
+ return;
+ }
+
+ LeAudioStateMachine sm = descriptor.mStateMachine;
if (sm == null) {
Log.w(TAG, "removeStateMachine: device " + device
+ " does not have a state machine");
@@ -1656,7 +1791,7 @@
Log.i(TAG, "removeStateMachine: removing state machine for device: " + device);
sm.doQuit();
sm.cleanup();
- mStateMachines.remove(device);
+ descriptor.mStateMachine = null;
}
}
@@ -1678,21 +1813,27 @@
+ " fromState=" + fromState + " toState=" + toState);
return;
}
+
+ LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+ if (deviceDescriptor == null) {
+ Log.e(TAG, "connectionStateChanged: No valid descriptor for device: " + device);
+ return;
+ }
+
if (toState == BluetoothProfile.STATE_CONNECTED) {
- int myGroupId = getGroupId(device);
- if (myGroupId == LE_AUDIO_GROUP_ID_INVALID
- || getConnectedPeerDevices(myGroupId).size() == 1) {
+ if (deviceDescriptor.mGroupId == LE_AUDIO_GROUP_ID_INVALID
+ || getConnectedPeerDevices(deviceDescriptor.mGroupId).size() == 1) {
// Log LE Audio connection event if we are the first device in a set
// Or when the GroupId has not been found
// MetricsLogger.logProfileConnectionEvent(
// BluetoothMetricsProto.ProfileId.LE_AUDIO);
}
- LeAudioGroupDescriptor descriptor = getGroupDescriptor(myGroupId);
+ LeAudioGroupDescriptor descriptor = getGroupDescriptor(deviceDescriptor.mGroupId);
if (descriptor != null) {
descriptor.mIsConnected = true;
} else {
- Log.e(TAG, "no descriptors for group: " + myGroupId);
+ Log.e(TAG, "no descriptors for group: " + deviceDescriptor.mGroupId);
}
}
// Check if the device is disconnected - if unbond, remove the state machine
@@ -1705,14 +1846,14 @@
removeStateMachine(device);
}
- int myGroupId = getGroupId(device);
- LeAudioGroupDescriptor descriptor = getGroupDescriptor(myGroupId);
+ LeAudioGroupDescriptor descriptor = getGroupDescriptor(deviceDescriptor.mGroupId);
if (descriptor == null) {
- Log.e(TAG, "no descriptors for group: " + myGroupId);
+ Log.e(TAG, "no descriptors for group: " + deviceDescriptor.mGroupId);
return;
}
- List<BluetoothDevice> connectedDevices = getConnectedPeerDevices(myGroupId);
+ List<BluetoothDevice> connectedDevices =
+ getConnectedPeerDevices(deviceDescriptor.mGroupId);
/* Let's check if the last connected device is really connected */
if (connectedDevices.size() == 1 && Objects.equals(
connectedDevices.get(0), descriptor.mLostLeadDeviceWhileStreaming)) {
@@ -1720,14 +1861,14 @@
return;
}
- if (getConnectedPeerDevices(myGroupId).isEmpty()) {
+ if (getConnectedPeerDevices(deviceDescriptor.mGroupId).isEmpty()) {
descriptor.mIsConnected = false;
if (descriptor.mIsActive) {
/* Notify Native layer */
setActiveDevice(null);
descriptor.mIsActive = false;
/* Update audio framework */
- updateActiveDevices(myGroupId,
+ updateActiveDevices(deviceDescriptor.mGroupId,
descriptor.mDirection,
descriptor.mDirection,
descriptor.mIsActive);
@@ -1736,7 +1877,7 @@
}
if (descriptor.mIsActive) {
- updateActiveDevices(myGroupId,
+ updateActiveDevices(deviceDescriptor.mGroupId,
descriptor.mDirection,
descriptor.mDirection,
descriptor.mIsActive);
@@ -1833,8 +1974,14 @@
if (device == null) {
return BluetoothLeAudio.AUDIO_LOCATION_INVALID;
}
- return mDeviceAudioLocationMap.getOrDefault(device,
- BluetoothLeAudio.AUDIO_LOCATION_INVALID);
+
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ Log.e(TAG, "getAudioLocation: No valid descriptor for device: " + device);
+ return BluetoothLeAudio.AUDIO_LOCATION_INVALID;
+ }
+
+ return descriptor.mSinkAudioLocation;
}
/**
@@ -1925,8 +2072,15 @@
if (device == null) {
return LE_AUDIO_GROUP_ID_INVALID;
}
+
synchronized (mGroupLock) {
- return mDeviceGroupIdMap.getOrDefault(device, LE_AUDIO_GROUP_ID_INVALID);
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (descriptor == null) {
+ Log.e(TAG, "getGroupId: No valid descriptor for device: " + device);
+ return LE_AUDIO_GROUP_ID_INVALID;
+ }
+
+ return descriptor.mGroupId;
}
}
@@ -1998,7 +2152,7 @@
mBluetoothEnabled = true;
synchronized (mGroupLock) {
- if (mDeviceGroupIdMap.isEmpty()) {
+ if (mDeviceDescriptors.isEmpty()) {
return;
}
}
@@ -2010,7 +2164,12 @@
}
synchronized (mGroupLock) {
- for (Map.Entry<BluetoothDevice, Integer> entry : mDeviceGroupIdMap.entrySet()) {
+ for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
+ : mDeviceDescriptors.entrySet()) {
+ if (entry.getValue().mGroupId == LE_AUDIO_GROUP_ID_INVALID) {
+ continue;
+ }
+
mcpService.setDeviceAuthorized(entry.getKey(), true);
}
}
@@ -2022,13 +2181,35 @@
}
}
+ private LeAudioDeviceDescriptor getDeviceDescriptor(BluetoothDevice device) {
+ synchronized (mGroupLock) {
+ return mDeviceDescriptors.get(device);
+ }
+ }
+
private void handleGroupNodeAdded(BluetoothDevice device, int groupId) {
synchronized (mGroupLock) {
if (DBG) {
Log.d(TAG, "Device " + device + " added to group " + groupId);
}
- mDeviceGroupIdMap.put(device, groupId);
+ LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+ if (deviceDescriptor == null) {
+ deviceDescriptor = createDeviceDescriptor(device);
+ if (deviceDescriptor == null) {
+ Log.e(TAG, "handleGroupNodeAdded: Can't create descriptor for added from"
+ + " storage device: " + device);
+ return;
+ }
+
+ LeAudioStateMachine sm = getOrCreateStateMachine(device);
+ if (getOrCreateStateMachine(device) == null) {
+ Log.e(TAG, "Can't get state machine for device: " + device);
+ return;
+ }
+ }
+ deviceDescriptor.mGroupId = groupId;
+
LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
if (descriptor == null) {
mGroupDescriptors.put(groupId, new LeAudioGroupDescriptor());
@@ -2070,17 +2251,39 @@
Log.d(TAG, "Removing device " + device + " grom group " + groupId);
}
- LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
- if (DBG) {
- Log.d(TAG, "Lost lead device is " + descriptor.mLostLeadDeviceWhileStreaming);
- }
- if (Objects.equals(device, descriptor.mLostLeadDeviceWhileStreaming)) {
- clearLostDevicesWhileStreaming(descriptor);
- }
-
synchronized (mGroupLock) {
- mDeviceGroupIdMap.remove(device);
- if (!mDeviceGroupIdMap.containsValue(groupId)) {
+ LeAudioGroupDescriptor groupDescriptor = getGroupDescriptor(groupId);
+ if (DBG) {
+ Log.d(TAG, "Lost lead device is " + groupDescriptor.mLostLeadDeviceWhileStreaming);
+ }
+ if (Objects.equals(device, groupDescriptor.mLostLeadDeviceWhileStreaming)) {
+ clearLostDevicesWhileStreaming(groupDescriptor);
+ }
+
+ LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+ if (deviceDescriptor == null) {
+ Log.e(TAG, "handleGroupNodeRemoved: No valid descriptor for device: " + device);
+ return;
+ }
+ deviceDescriptor.mGroupId = LE_AUDIO_GROUP_ID_INVALID;
+
+ boolean isGroupEmpty = true;
+
+ for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
+ if (descriptor.mGroupId == groupId) {
+ isGroupEmpty = false;
+ break;
+ }
+ }
+
+ if (isGroupEmpty) {
+ /* Device is currently an active device. Group needs to be inactivated before
+ * removing
+ */
+ if (Objects.equals(device, mActiveAudioOutDevice)
+ || Objects.equals(device, mActiveAudioInDevice)) {
+ handleGroupTransitToInactive(groupId);
+ }
mGroupDescriptors.remove(groupId);
}
notifyGroupNodeRemoved(device, groupId);
@@ -2910,16 +3113,22 @@
@Override
public void dump(StringBuilder sb) {
super.dump(sb);
- ProfileService.println(sb, "State machines: ");
- for (LeAudioStateMachine sm : mStateMachines.values()) {
- sm.dump(sb);
- }
ProfileService.println(sb, "Active Groups information: ");
ProfileService.println(sb, " currentlyActiveGroupId: " + getActiveGroupId());
ProfileService.println(sb, " mActiveAudioOutDevice: " + mActiveAudioOutDevice);
ProfileService.println(sb, " mActiveAudioInDevice: " + mActiveAudioInDevice);
ProfileService.println(sb, " mHfpHandoverDevice:" + mHfpHandoverDevice);
+ for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
+ : mDeviceDescriptors.entrySet()) {
+ LeAudioDeviceDescriptor descriptor = entry.getValue();
+
+ descriptor.mStateMachine.dump(sb);
+ ProfileService.println(sb, " mGroupId: " + descriptor.mGroupId);
+ ProfileService.println(sb, " mSinkAudioLocation: " + descriptor.mSinkAudioLocation);
+ ProfileService.println(sb, " mDirection: " + descriptor.mDirection);
+ }
+
for (Map.Entry<Integer, LeAudioGroupDescriptor> entry : mGroupDescriptors.entrySet()) {
LeAudioGroupDescriptor descriptor = entry.getValue();
Integer groupId = entry.getKey();
diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java
index a838cbb..95c4e0f 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java
@@ -55,8 +55,6 @@
import android.util.Log;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
-import android.annotation.RequiresPermission;
-
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.ProfileService;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/android/app/src/com/android/bluetooth/mapclient/MapClientContent.java b/android/app/src/com/android/bluetooth/mapclient/MapClientContent.java
index 36d4535..aa60b5b 100644
--- a/android/app/src/com/android/bluetooth/mapclient/MapClientContent.java
+++ b/android/app/src/com/android/bluetooth/mapclient/MapClientContent.java
@@ -137,6 +137,10 @@
SubscriptionManager subscriptionManager =
context.getSystemService(SubscriptionManager.class);
List<SubscriptionInfo> subscriptions = subscriptionManager.getActiveSubscriptionInfoList();
+ if (subscriptions == null) {
+ Log.w(TAG, "Active subscription list is missing");
+ return;
+ }
for (SubscriptionInfo info : subscriptions) {
if (info.getSubscriptionType() == SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM) {
clearMessages(context, info.getSubscriptionId());
diff --git a/android/app/src/com/android/bluetooth/mapclient/MapClientService.java b/android/app/src/com/android/bluetooth/mapclient/MapClientService.java
index ff38353..25a8a2f 100644
--- a/android/app/src/com/android/bluetooth/mapclient/MapClientService.java
+++ b/android/app/src/com/android/bluetooth/mapclient/MapClientService.java
@@ -166,9 +166,6 @@
}
private synchronized void addDeviceToMapAndConnect(BluetoothDevice device) {
- if (Utils.isInstrumentationTestMode()) {
- Log.d(TAG, "addDeviceToMapAndConnect: device=" + device, new Exception());
- }
// When creating a new statemachine, its state is set to CONNECTING - which will trigger
// connect.
MceStateMachine mapStateMachine = new MceStateMachine(this, device);
@@ -358,6 +355,7 @@
}
stateMachine.doQuit();
}
+ mMapInstanceMap.clear();
return true;
}
@@ -367,10 +365,6 @@
Log.d(TAG, "in Cleanup");
}
removeUncleanAccounts();
- mMapInstanceMap.clear();
- if (Utils.isInstrumentationTestMode()) {
- Log.d(TAG, "cleanup() called.", new Exception());
- }
// TODO(b/72948646): should be moved to stop()
setMapClientService(null);
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
index 5574b87..c6ed3c1 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
@@ -26,13 +26,13 @@
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
@@ -125,7 +125,7 @@
when(mA2dpService.setActiveDevice(any())).thenReturn(true);
when(mHeadsetService.getHfpCallAudioPolicy(any())).thenReturn(
- new BluetoothAudioPolicy.Builder().build());
+ new BluetoothSinkAudioPolicy.Builder().build());
when(mHeadsetService.setActiveDevice(any())).thenReturn(true);
when(mHearingAidService.setActiveDevice(any())).thenReturn(true);
when(mLeAudioService.setActiveDevice(any())).thenReturn(true);
@@ -319,10 +319,11 @@
public void notAllowedConnectingPolicyHeadsetConnected_noSetActiveDevice() {
// setting connecting policy to NOT ALLOWED
when(mHeadsetService.getHfpCallAudioPolicy(mHeadsetDevice))
- .thenReturn(new BluetoothAudioPolicy.Builder()
- .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
- .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_NOT_ALLOWED)
- .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
+ .thenReturn(new BluetoothSinkAudioPolicy.Builder()
+ .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+ .setActiveDevicePolicyAfterConnection(
+ BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED)
+ .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
.build());
headsetConnected(mHeadsetDevice);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceFactoryResetTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceFactoryResetTest.java
new file mode 100644
index 0000000..6acc5a0
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceFactoryResetTest.java
@@ -0,0 +1,477 @@
+/*
+ * Copyright 2017 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 static android.Manifest.permission.BLUETOOTH_SCAN;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+import android.app.AlarmManager;
+import android.app.admin.DevicePolicyManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.IBluetoothCallback;
+import android.content.AttributionSource;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.content.res.Resources;
+import android.media.AudioManager;
+import android.os.AsyncTask;
+import android.os.BatteryStatsManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.permission.PermissionCheckerManager;
+import android.permission.PermissionManager;
+import android.provider.Settings;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.bluetooth.TestUtils;
+import com.android.bluetooth.Utils;
+import com.android.bluetooth.a2dp.A2dpService;
+import com.android.bluetooth.a2dpsink.A2dpSinkService;
+import com.android.bluetooth.avrcp.AvrcpTargetService;
+import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
+import com.android.bluetooth.bas.BatteryService;
+import com.android.bluetooth.bass_client.BassClientService;
+import com.android.bluetooth.csip.CsipSetCoordinatorService;
+import com.android.bluetooth.gatt.GattService;
+import com.android.bluetooth.hap.HapClientService;
+import com.android.bluetooth.hearingaid.HearingAidService;
+import com.android.bluetooth.hfp.HeadsetService;
+import com.android.bluetooth.hfpclient.HeadsetClientService;
+import com.android.bluetooth.hid.HidDeviceService;
+import com.android.bluetooth.hid.HidHostService;
+import com.android.bluetooth.le_audio.LeAudioService;
+import com.android.bluetooth.map.BluetoothMapService;
+import com.android.bluetooth.mapclient.MapClientService;
+import com.android.bluetooth.mcp.McpService;
+import com.android.bluetooth.opp.BluetoothOppService;
+import com.android.bluetooth.pan.PanService;
+import com.android.bluetooth.pbap.BluetoothPbapService;
+import com.android.bluetooth.pbapclient.PbapClientService;
+import com.android.bluetooth.sap.SapService;
+import com.android.bluetooth.tbs.TbsService;
+import com.android.bluetooth.vc.VolumeControlService;
+import com.android.internal.app.IBatteryStats;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.HashMap;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AdapterServiceFactoryResetTest {
+ private static final String TAG = AdapterServiceFactoryResetTest.class.getSimpleName();
+
+ private AdapterService mAdapterService;
+ private AdapterService.AdapterServiceBinder mServiceBinder;
+
+ private @Mock Context mMockContext;
+ private @Mock ApplicationInfo mMockApplicationInfo;
+ private @Mock AlarmManager mMockAlarmManager;
+ private @Mock Resources mMockResources;
+ private @Mock UserManager mMockUserManager;
+ private @Mock DevicePolicyManager mMockDevicePolicyManager;
+ private @Mock ProfileService mMockGattService;
+ private @Mock ProfileService mMockService;
+ private @Mock ProfileService mMockService2;
+ private @Mock IBluetoothCallback mIBluetoothCallback;
+ private @Mock Binder mBinder;
+ private @Mock AudioManager mAudioManager;
+ private @Mock android.app.Application mApplication;
+ private @Mock MetricsLogger mMockMetricsLogger;
+
+ // BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
+ // underlying binder calls.
+ final BatteryStatsManager mBatteryStatsManager =
+ new BatteryStatsManager(mock(IBatteryStats.class));
+
+ private static final int CONTEXT_SWITCH_MS = 100;
+ private static final int PROFILE_SERVICE_TOGGLE_TIME_MS = 200;
+ private static final int GATT_START_TIME_MS = 1000;
+ private static final int ONE_SECOND_MS = 1000;
+ private static final int NATIVE_INIT_MS = 8000;
+
+ private final AttributionSource mAttributionSource = new AttributionSource.Builder(
+ Process.myUid()).build();
+
+ private BluetoothManager mBluetoothManager;
+ private PowerManager mPowerManager;
+ private PermissionCheckerManager mPermissionCheckerManager;
+ private PermissionManager mPermissionManager;
+ private PackageManager mMockPackageManager;
+ private MockContentResolver mMockContentResolver;
+ private HashMap<String, HashMap<String, String>> mAdapterConfig;
+ private int mForegroundUserId;
+
+ private void configureEnabledProfiles() {
+ Log.e(TAG, "configureEnabledProfiles");
+ Config.setProfileEnabled(PanService.class, true);
+ Config.setProfileEnabled(BluetoothPbapService.class, true);
+ Config.setProfileEnabled(GattService.class, true);
+
+ Config.setProfileEnabled(A2dpService.class, false);
+ Config.setProfileEnabled(A2dpSinkService.class, false);
+ Config.setProfileEnabled(AvrcpTargetService.class, false);
+ Config.setProfileEnabled(AvrcpControllerService.class, false);
+ Config.setProfileEnabled(BassClientService.class, false);
+ Config.setProfileEnabled(BatteryService.class, false);
+ Config.setProfileEnabled(CsipSetCoordinatorService.class, false);
+ Config.setProfileEnabled(HapClientService.class, false);
+ Config.setProfileEnabled(HeadsetService.class, false);
+ Config.setProfileEnabled(HeadsetClientService.class, false);
+ Config.setProfileEnabled(HearingAidService.class, false);
+ Config.setProfileEnabled(HidDeviceService.class, false);
+ Config.setProfileEnabled(HidHostService.class, false);
+ Config.setProfileEnabled(LeAudioService.class, false);
+ Config.setProfileEnabled(TbsService.class, false);
+ Config.setProfileEnabled(BluetoothMapService.class, false);
+ Config.setProfileEnabled(MapClientService.class, false);
+ Config.setProfileEnabled(McpService.class, false);
+ Config.setProfileEnabled(BluetoothOppService.class, false);
+ Config.setProfileEnabled(PbapClientService.class, false);
+ Config.setProfileEnabled(SapService.class, false);
+ Config.setProfileEnabled(VolumeControlService.class, false);
+ }
+
+ @BeforeClass
+ public static void setupClass() {
+ Log.e(TAG, "setupClass");
+ // Bring native layer up and down to make sure config files are properly loaded
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ Assert.assertNotNull(Looper.myLooper());
+ AdapterService adapterService = new AdapterService();
+ adapterService.initNative(false /* is_restricted */, false /* is_common_criteria_mode */,
+ 0 /* config_compare_result */, new String[0], false, "");
+ adapterService.cleanupNative();
+ HashMap<String, HashMap<String, String>> adapterConfig = TestUtils.readAdapterConfig();
+ Assert.assertNotNull(adapterConfig);
+ Assert.assertNotNull("metrics salt is null: " + adapterConfig.toString(),
+ AdapterServiceTest.getMetricsSalt(adapterConfig));
+ }
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException {
+ Log.e(TAG, "setUp()");
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ Assert.assertNotNull(Looper.myLooper());
+
+ // Dispatch all async work through instrumentation so we can wait until
+ // it's drained below
+ AsyncTask.setDefaultExecutor((r) -> {
+ androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
+ .runOnMainSync(r);
+ });
+ androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity();
+
+ androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().runOnMainSync(
+ () -> mAdapterService = new AdapterService());
+ mServiceBinder = new AdapterService.AdapterServiceBinder(mAdapterService);
+ mMockPackageManager = mock(PackageManager.class);
+ when(mMockPackageManager.getPermissionInfo(any(), anyInt()))
+ .thenReturn(new PermissionInfo());
+
+ mMockContentResolver = new MockContentResolver(InstrumentationRegistry.getTargetContext());
+ mMockContentResolver.addProvider(Settings.AUTHORITY, new MockContentProvider() {
+ @Override
+ public Bundle call(String method, String request, Bundle args) {
+ return Bundle.EMPTY;
+ }
+ });
+
+ mPowerManager = InstrumentationRegistry.getTargetContext()
+ .getSystemService(PowerManager.class);
+ mPermissionCheckerManager = InstrumentationRegistry.getTargetContext()
+ .getSystemService(PermissionCheckerManager.class);
+
+ mPermissionManager = InstrumentationRegistry.getTargetContext()
+ .getSystemService(PermissionManager.class);
+
+ mBluetoothManager = InstrumentationRegistry.getTargetContext()
+ .getSystemService(BluetoothManager.class);
+
+ when(mMockContext.getCacheDir()).thenReturn(InstrumentationRegistry.getTargetContext()
+ .getCacheDir());
+ when(mMockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo);
+ when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
+ when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
+ when(mMockContext.createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0)).thenReturn(
+ mMockContext);
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+ when(mMockContext.getUserId()).thenReturn(Process.BLUETOOTH_UID);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
+ when(mMockContext.getSystemServiceName(UserManager.class)).thenReturn(Context.USER_SERVICE);
+ when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+ mMockDevicePolicyManager);
+ when(mMockContext.getSystemServiceName(DevicePolicyManager.class))
+ .thenReturn(Context.DEVICE_POLICY_SERVICE);
+ when(mMockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager);
+ when(mMockContext.getSystemServiceName(PowerManager.class))
+ .thenReturn(Context.POWER_SERVICE);
+ when(mMockContext.getSystemServiceName(PermissionCheckerManager.class))
+ .thenReturn(Context.PERMISSION_CHECKER_SERVICE);
+ when(mMockContext.getSystemService(Context.PERMISSION_CHECKER_SERVICE))
+ .thenReturn(mPermissionCheckerManager);
+ when(mMockContext.getSystemServiceName(PermissionManager.class))
+ .thenReturn(Context.PERMISSION_SERVICE);
+ when(mMockContext.getSystemService(Context.PERMISSION_SERVICE))
+ .thenReturn(mPermissionManager);
+ when(mMockContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mMockAlarmManager);
+ when(mMockContext.getSystemServiceName(AlarmManager.class))
+ .thenReturn(Context.ALARM_SERVICE);
+ when(mMockContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager);
+ when(mMockContext.getSystemServiceName(AudioManager.class))
+ .thenReturn(Context.AUDIO_SERVICE);
+ when(mMockContext.getSystemService(Context.BATTERY_STATS_SERVICE))
+ .thenReturn(mBatteryStatsManager);
+ when(mMockContext.getSystemServiceName(BatteryStatsManager.class))
+ .thenReturn(Context.BATTERY_STATS_SERVICE);
+ when(mMockContext.getSystemService(Context.BLUETOOTH_SERVICE))
+ .thenReturn(mBluetoothManager);
+ when(mMockContext.getSystemServiceName(BluetoothManager.class))
+ .thenReturn(Context.BLUETOOTH_SERVICE);
+ when(mMockContext.getSharedPreferences(anyString(), anyInt()))
+ .thenReturn(InstrumentationRegistry.getTargetContext()
+ .getSharedPreferences("AdapterServiceTestPrefs", Context.MODE_PRIVATE));
+
+ when(mMockContext.getAttributionSource()).thenReturn(mAttributionSource);
+ doAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ return InstrumentationRegistry.getTargetContext().getDatabasePath((String) args[0]);
+ }).when(mMockContext).getDatabasePath(anyString());
+
+ // Sets the foreground user id to match that of the tests (restored in tearDown)
+ mForegroundUserId = Utils.getForegroundUserId();
+ int callingUid = Binder.getCallingUid();
+ UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
+ Utils.setForegroundUserId(callingUser.getIdentifier());
+
+ when(mMockDevicePolicyManager.isCommonCriteriaModeEnabled(any())).thenReturn(false);
+
+ when(mIBluetoothCallback.asBinder()).thenReturn(mBinder);
+
+ doReturn(Process.BLUETOOTH_UID).when(mMockPackageManager)
+ .getPackageUidAsUser(any(), anyInt(), anyInt());
+
+ when(mMockGattService.getName()).thenReturn("GattService");
+ when(mMockService.getName()).thenReturn("Service1");
+ when(mMockService2.getName()).thenReturn("Service2");
+
+ when(mMockMetricsLogger.init(any())).thenReturn(true);
+ when(mMockMetricsLogger.close()).thenReturn(true);
+
+ configureEnabledProfiles();
+ Config.init(mMockContext);
+
+ mAdapterService.setMetricsLogger(mMockMetricsLogger);
+
+ // Attach a context to the service for permission checks.
+ mAdapterService.attach(mMockContext, null, null, null, mApplication, null);
+ mAdapterService.onCreate();
+
+ // Wait for any async events to drain
+ androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ mServiceBinder.registerCallback(mIBluetoothCallback, mAttributionSource);
+
+ mAdapterConfig = TestUtils.readAdapterConfig();
+ Assert.assertNotNull(mAdapterConfig);
+ }
+
+ @After
+ public void tearDown() {
+ Log.e(TAG, "tearDown()");
+
+ // Enable the stack to re-create the config. Next tests rely on it.
+ doEnable(0, false);
+
+ // Restores the foregroundUserId to the ID prior to the test setup
+ Utils.setForegroundUserId(mForegroundUserId);
+
+ mServiceBinder.unregisterCallback(mIBluetoothCallback, mAttributionSource);
+ mAdapterService.cleanup();
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ AsyncTask.setDefaultExecutor(AsyncTask.SERIAL_EXECUTOR);
+ }
+
+ private void verifyStateChange(int prevState, int currState, int callNumber, int timeoutMs) {
+ try {
+ verify(mIBluetoothCallback, timeout(timeoutMs).times(callNumber))
+ .onBluetoothStateChange(prevState, currState);
+ } catch (RemoteException e) {
+ // the mocked onBluetoothStateChange doesn't throw RemoteException
+ }
+ }
+
+ private void doEnable(int invocationNumber, boolean onlyGatt) {
+ Log.e(TAG, "doEnable() start");
+ Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+
+ int startServiceCalls;
+ startServiceCalls = 2 * (onlyGatt ? 1 : 3); // Start and stop GATT + 2
+
+ mAdapterService.enable(false);
+
+ verifyStateChange(BluetoothAdapter.STATE_OFF, BluetoothAdapter.STATE_BLE_TURNING_ON,
+ invocationNumber + 1, CONTEXT_SWITCH_MS);
+
+ // Start GATT
+ verify(mMockContext, timeout(GATT_START_TIME_MS).times(
+ startServiceCalls * invocationNumber + 1)).startService(any());
+ mAdapterService.addProfile(mMockGattService);
+ mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_ON);
+
+ verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON, BluetoothAdapter.STATE_BLE_ON,
+ invocationNumber + 1, NATIVE_INIT_MS);
+
+ mServiceBinder.onLeServiceUp(mAttributionSource);
+
+ verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_TURNING_ON,
+ invocationNumber + 1, CONTEXT_SWITCH_MS);
+
+ if (!onlyGatt) {
+ // Start Mock PBAP and PAN services
+ verify(mMockContext, timeout(ONE_SECOND_MS).times(
+ startServiceCalls * invocationNumber + 3)).startService(any());
+
+ mAdapterService.addProfile(mMockService);
+ mAdapterService.addProfile(mMockService2);
+ mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_ON);
+ mAdapterService.onProfileServiceStateChanged(mMockService2, BluetoothAdapter.STATE_ON);
+ }
+
+ verifyStateChange(BluetoothAdapter.STATE_TURNING_ON, BluetoothAdapter.STATE_ON,
+ invocationNumber + 1, PROFILE_SERVICE_TOGGLE_TIME_MS);
+
+ verify(mMockContext, timeout(CONTEXT_SWITCH_MS).times(2 * invocationNumber + 2))
+ .sendBroadcast(any(), eq(BLUETOOTH_SCAN),
+ any(Bundle.class));
+ final int scanMode = mServiceBinder.getScanMode(mAttributionSource);
+ Assert.assertTrue(scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE
+ || scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+
+ Log.e(TAG, "doEnable() complete success");
+ }
+
+ /**
+ * Test: Verify that obfuscated Bluetooth address changes after factory reset
+ *
+ * There are 4 types of factory reset that we are talking about:
+ * 1. Factory reset all user data from Settings -> Will restart phone
+ * 2. Factory reset WiFi and Bluetooth from Settings -> Will only restart WiFi and BT
+ * 3. Call BluetoothAdapter.factoryReset() -> Will disable Bluetooth and reset config in
+ * memory and disk
+ * 4. Call AdapterService.factoryReset() -> Will only reset config in memory
+ *
+ * We can only use No. 4 here
+ */
+ @Ignore("AdapterService.factoryReset() does not reload config into memory and hence old salt"
+ + " is still used until next time Bluetooth library is initialized. However Bluetooth"
+ + " cannot be used until Bluetooth process restart any way. Thus it is almost"
+ + " guaranteed that user has to re-enable Bluetooth and hence re-generate new salt"
+ + " after factory reset")
+ @Test
+ public void testObfuscateBluetoothAddress_FactoryReset() {
+ Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+ BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
+ byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
+ Assert.assertTrue(obfuscatedAddress1.length > 0);
+ Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress1));
+ mServiceBinder.factoryReset(mAttributionSource);
+ byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
+ Assert.assertTrue(obfuscatedAddress2.length > 0);
+ Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress2));
+ Assert.assertFalse(Arrays.equals(obfuscatedAddress2,
+ obfuscatedAddress1));
+ doEnable(0, false);
+ byte[] obfuscatedAddress3 = mAdapterService.obfuscateAddress(device);
+ Assert.assertTrue(obfuscatedAddress3.length > 0);
+ Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress3));
+ Assert.assertArrayEquals(obfuscatedAddress3,
+ obfuscatedAddress2);
+ mServiceBinder.factoryReset(mAttributionSource);
+ byte[] obfuscatedAddress4 = mAdapterService.obfuscateAddress(device);
+ Assert.assertTrue(obfuscatedAddress4.length > 0);
+ Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress4));
+ Assert.assertFalse(Arrays.equals(obfuscatedAddress4,
+ obfuscatedAddress3));
+ }
+
+ /**
+ * Test: Verify that obfuscated Bluetooth address changes after factory reset and reloading
+ * native layer
+ */
+ @Test
+ public void testObfuscateBluetoothAddress_FactoryResetAndReloadNativeLayer() throws
+ PackageManager.NameNotFoundException {
+ byte[] metricsSalt1 = AdapterServiceTest.getMetricsSalt(mAdapterConfig);
+ Assert.assertNotNull(metricsSalt1);
+ Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+ BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
+ byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
+ Assert.assertTrue(obfuscatedAddress1.length > 0);
+ Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress1));
+ Assert.assertArrayEquals(AdapterServiceTest.obfuscateInJava(metricsSalt1, device),
+ obfuscatedAddress1);
+ mServiceBinder.factoryReset(mAttributionSource);
+ tearDown();
+ setUp();
+ // Cannot verify metrics salt since it is not written to disk until native cleanup
+ byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
+ Assert.assertTrue(obfuscatedAddress2.length > 0);
+ Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress2));
+ Assert.assertFalse(Arrays.equals(obfuscatedAddress2,
+ obfuscatedAddress1));
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceRestartTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceRestartTest.java
new file mode 100644
index 0000000..c93837b
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceRestartTest.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2017 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 static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+import android.app.AlarmManager;
+import android.app.admin.DevicePolicyManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.IBluetoothCallback;
+import android.content.AttributionSource;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.content.res.Resources;
+import android.media.AudioManager;
+import android.os.AsyncTask;
+import android.os.BatteryStatsManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.permission.PermissionCheckerManager;
+import android.permission.PermissionManager;
+import android.provider.Settings;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.bluetooth.TestUtils;
+import com.android.bluetooth.Utils;
+import com.android.bluetooth.a2dp.A2dpService;
+import com.android.bluetooth.a2dpsink.A2dpSinkService;
+import com.android.bluetooth.avrcp.AvrcpTargetService;
+import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
+import com.android.bluetooth.bas.BatteryService;
+import com.android.bluetooth.bass_client.BassClientService;
+import com.android.bluetooth.csip.CsipSetCoordinatorService;
+import com.android.bluetooth.gatt.GattService;
+import com.android.bluetooth.hap.HapClientService;
+import com.android.bluetooth.hearingaid.HearingAidService;
+import com.android.bluetooth.hfp.HeadsetService;
+import com.android.bluetooth.hfpclient.HeadsetClientService;
+import com.android.bluetooth.hid.HidDeviceService;
+import com.android.bluetooth.hid.HidHostService;
+import com.android.bluetooth.le_audio.LeAudioService;
+import com.android.bluetooth.map.BluetoothMapService;
+import com.android.bluetooth.mapclient.MapClientService;
+import com.android.bluetooth.mcp.McpService;
+import com.android.bluetooth.opp.BluetoothOppService;
+import com.android.bluetooth.pan.PanService;
+import com.android.bluetooth.pbap.BluetoothPbapService;
+import com.android.bluetooth.pbapclient.PbapClientService;
+import com.android.bluetooth.sap.SapService;
+import com.android.bluetooth.tbs.TbsService;
+import com.android.bluetooth.vc.VolumeControlService;
+import com.android.internal.app.IBatteryStats;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashMap;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AdapterServiceRestartTest {
+ private static final String TAG = AdapterServiceTest.class.getSimpleName();
+
+ private AdapterService mAdapterService;
+ private AdapterService.AdapterServiceBinder mServiceBinder;
+
+ private @Mock Context mMockContext;
+ private @Mock ApplicationInfo mMockApplicationInfo;
+ private @Mock AlarmManager mMockAlarmManager;
+ private @Mock Resources mMockResources;
+ private @Mock UserManager mMockUserManager;
+ private @Mock DevicePolicyManager mMockDevicePolicyManager;
+ private @Mock IBluetoothCallback mIBluetoothCallback;
+ private @Mock Binder mBinder;
+ private @Mock AudioManager mAudioManager;
+ private @Mock android.app.Application mApplication;
+ private @Mock MetricsLogger mMockMetricsLogger;
+
+ // BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
+ // underlying binder calls.
+ final BatteryStatsManager mBatteryStatsManager =
+ new BatteryStatsManager(mock(IBatteryStats.class));
+
+ private final AttributionSource mAttributionSource = new AttributionSource.Builder(
+ Process.myUid()).build();
+
+ private BluetoothManager mBluetoothManager;
+ private PowerManager mPowerManager;
+ private PermissionCheckerManager mPermissionCheckerManager;
+ private PermissionManager mPermissionManager;
+ private PackageManager mMockPackageManager;
+ private MockContentResolver mMockContentResolver;
+ private HashMap<String, HashMap<String, String>> mAdapterConfig;
+ private int mForegroundUserId;
+
+ private void configureEnabledProfiles() {
+ Log.e(TAG, "configureEnabledProfiles");
+ Config.setProfileEnabled(PanService.class, true);
+ Config.setProfileEnabled(BluetoothPbapService.class, true);
+ Config.setProfileEnabled(GattService.class, true);
+
+ Config.setProfileEnabled(A2dpService.class, false);
+ Config.setProfileEnabled(A2dpSinkService.class, false);
+ Config.setProfileEnabled(AvrcpTargetService.class, false);
+ Config.setProfileEnabled(AvrcpControllerService.class, false);
+ Config.setProfileEnabled(BassClientService.class, false);
+ Config.setProfileEnabled(BatteryService.class, false);
+ Config.setProfileEnabled(CsipSetCoordinatorService.class, false);
+ Config.setProfileEnabled(HapClientService.class, false);
+ Config.setProfileEnabled(HeadsetService.class, false);
+ Config.setProfileEnabled(HeadsetClientService.class, false);
+ Config.setProfileEnabled(HearingAidService.class, false);
+ Config.setProfileEnabled(HidDeviceService.class, false);
+ Config.setProfileEnabled(HidHostService.class, false);
+ Config.setProfileEnabled(LeAudioService.class, false);
+ Config.setProfileEnabled(TbsService.class, false);
+ Config.setProfileEnabled(BluetoothMapService.class, false);
+ Config.setProfileEnabled(MapClientService.class, false);
+ Config.setProfileEnabled(McpService.class, false);
+ Config.setProfileEnabled(BluetoothOppService.class, false);
+ Config.setProfileEnabled(PbapClientService.class, false);
+ Config.setProfileEnabled(SapService.class, false);
+ Config.setProfileEnabled(VolumeControlService.class, false);
+ }
+
+ @BeforeClass
+ public static void setupClass() {
+ Log.e(TAG, "setupClass");
+ // Bring native layer up and down to make sure config files are properly loaded
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ Assert.assertNotNull(Looper.myLooper());
+ AdapterService adapterService = new AdapterService();
+ adapterService.initNative(false /* is_restricted */, false /* is_common_criteria_mode */,
+ 0 /* config_compare_result */, new String[0], false, "");
+ adapterService.cleanupNative();
+ HashMap<String, HashMap<String, String>> adapterConfig = TestUtils.readAdapterConfig();
+ Assert.assertNotNull(adapterConfig);
+ Assert.assertNotNull("metrics salt is null: " + adapterConfig.toString(),
+ AdapterServiceTest.getMetricsSalt(adapterConfig));
+ }
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException {
+ Log.e(TAG, "setUp()");
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ Assert.assertNotNull(Looper.myLooper());
+
+ // Dispatch all async work through instrumentation so we can wait until
+ // it's drained below
+ AsyncTask.setDefaultExecutor((r) -> {
+ androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
+ .runOnMainSync(r);
+ });
+ androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity();
+
+ androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().runOnMainSync(
+ () -> mAdapterService = new AdapterService());
+ mServiceBinder = new AdapterService.AdapterServiceBinder(mAdapterService);
+ mMockPackageManager = mock(PackageManager.class);
+ when(mMockPackageManager.getPermissionInfo(any(), anyInt()))
+ .thenReturn(new PermissionInfo());
+
+ mMockContentResolver = new MockContentResolver(InstrumentationRegistry.getTargetContext());
+ mMockContentResolver.addProvider(Settings.AUTHORITY, new MockContentProvider() {
+ @Override
+ public Bundle call(String method, String request, Bundle args) {
+ return Bundle.EMPTY;
+ }
+ });
+
+ mPowerManager = InstrumentationRegistry.getTargetContext()
+ .getSystemService(PowerManager.class);
+ mPermissionCheckerManager = InstrumentationRegistry.getTargetContext()
+ .getSystemService(PermissionCheckerManager.class);
+
+ mPermissionManager = InstrumentationRegistry.getTargetContext()
+ .getSystemService(PermissionManager.class);
+
+ mBluetoothManager = InstrumentationRegistry.getTargetContext()
+ .getSystemService(BluetoothManager.class);
+
+ when(mMockContext.getCacheDir()).thenReturn(InstrumentationRegistry.getTargetContext()
+ .getCacheDir());
+ when(mMockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo);
+ when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
+ when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
+ when(mMockContext.createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0)).thenReturn(
+ mMockContext);
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+ when(mMockContext.getUserId()).thenReturn(Process.BLUETOOTH_UID);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
+ when(mMockContext.getSystemServiceName(UserManager.class)).thenReturn(Context.USER_SERVICE);
+ when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+ mMockDevicePolicyManager);
+ when(mMockContext.getSystemServiceName(DevicePolicyManager.class))
+ .thenReturn(Context.DEVICE_POLICY_SERVICE);
+ when(mMockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager);
+ when(mMockContext.getSystemServiceName(PowerManager.class))
+ .thenReturn(Context.POWER_SERVICE);
+ when(mMockContext.getSystemServiceName(PermissionCheckerManager.class))
+ .thenReturn(Context.PERMISSION_CHECKER_SERVICE);
+ when(mMockContext.getSystemService(Context.PERMISSION_CHECKER_SERVICE))
+ .thenReturn(mPermissionCheckerManager);
+ when(mMockContext.getSystemServiceName(PermissionManager.class))
+ .thenReturn(Context.PERMISSION_SERVICE);
+ when(mMockContext.getSystemService(Context.PERMISSION_SERVICE))
+ .thenReturn(mPermissionManager);
+ when(mMockContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mMockAlarmManager);
+ when(mMockContext.getSystemServiceName(AlarmManager.class))
+ .thenReturn(Context.ALARM_SERVICE);
+ when(mMockContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager);
+ when(mMockContext.getSystemServiceName(AudioManager.class))
+ .thenReturn(Context.AUDIO_SERVICE);
+ when(mMockContext.getSystemService(Context.BATTERY_STATS_SERVICE))
+ .thenReturn(mBatteryStatsManager);
+ when(mMockContext.getSystemServiceName(BatteryStatsManager.class))
+ .thenReturn(Context.BATTERY_STATS_SERVICE);
+ when(mMockContext.getSystemService(Context.BLUETOOTH_SERVICE))
+ .thenReturn(mBluetoothManager);
+ when(mMockContext.getSystemServiceName(BluetoothManager.class))
+ .thenReturn(Context.BLUETOOTH_SERVICE);
+ when(mMockContext.getSharedPreferences(anyString(), anyInt()))
+ .thenReturn(InstrumentationRegistry.getTargetContext()
+ .getSharedPreferences("AdapterServiceTestPrefs", Context.MODE_PRIVATE));
+
+ when(mMockContext.getAttributionSource()).thenReturn(mAttributionSource);
+ doAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ return InstrumentationRegistry.getTargetContext().getDatabasePath((String) args[0]);
+ }).when(mMockContext).getDatabasePath(anyString());
+
+ // Sets the foreground user id to match that of the tests (restored in tearDown)
+ mForegroundUserId = Utils.getForegroundUserId();
+ int callingUid = Binder.getCallingUid();
+ UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
+ Utils.setForegroundUserId(callingUser.getIdentifier());
+
+ when(mMockDevicePolicyManager.isCommonCriteriaModeEnabled(any())).thenReturn(false);
+
+ when(mIBluetoothCallback.asBinder()).thenReturn(mBinder);
+
+ doReturn(Process.BLUETOOTH_UID).when(mMockPackageManager)
+ .getPackageUidAsUser(any(), anyInt(), anyInt());
+
+ when(mMockMetricsLogger.init(any())).thenReturn(true);
+ when(mMockMetricsLogger.close()).thenReturn(true);
+
+ configureEnabledProfiles();
+ Config.init(mMockContext);
+
+ mAdapterService.setMetricsLogger(mMockMetricsLogger);
+
+ // Attach a context to the service for permission checks.
+ mAdapterService.attach(mMockContext, null, null, null, mApplication, null);
+ mAdapterService.onCreate();
+
+ // Wait for any async events to drain
+ androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ mServiceBinder.registerCallback(mIBluetoothCallback, mAttributionSource);
+
+ mAdapterConfig = TestUtils.readAdapterConfig();
+ Assert.assertNotNull(mAdapterConfig);
+ }
+
+ @After
+ public void tearDown() {
+ Log.e(TAG, "tearDown()");
+
+ // Restores the foregroundUserId to the ID prior to the test setup
+ Utils.setForegroundUserId(mForegroundUserId);
+
+ mServiceBinder.unregisterCallback(mIBluetoothCallback, mAttributionSource);
+ mAdapterService.cleanup();
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ AsyncTask.setDefaultExecutor(AsyncTask.SERIAL_EXECUTOR);
+ }
+
+ /**
+ * Test: Check if obfuscated Bluetooth address stays the same after re-initializing
+ * {@link AdapterService}
+ */
+ @Test
+ public void testObfuscateBluetoothAddress_PersistentBetweenAdapterServiceInitialization() throws
+ PackageManager.NameNotFoundException {
+ byte[] metricsSalt = AdapterServiceTest.getMetricsSalt(mAdapterConfig);
+ Assert.assertNotNull(metricsSalt);
+ Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+ BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
+ byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
+ Assert.assertTrue(obfuscatedAddress1.length > 0);
+ Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress1));
+ Assert.assertArrayEquals(AdapterServiceTest.obfuscateInJava(metricsSalt, device),
+ obfuscatedAddress1);
+ tearDown();
+ setUp();
+
+ byte[] metricsSalt2 = AdapterServiceTest.getMetricsSalt(mAdapterConfig);
+ Assert.assertNotNull(metricsSalt2);
+ Assert.assertArrayEquals(metricsSalt, metricsSalt2);
+
+ Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+ byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
+ Assert.assertTrue(obfuscatedAddress2.length > 0);
+ Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress2));
+ Assert.assertArrayEquals(obfuscatedAddress2,
+ obfuscatedAddress1);
+ }
+
+ /**
+ * Test: Check if id gotten stays the same after re-initializing
+ * {@link AdapterService}
+ */
+ @Test
+ public void testgetMetricId_PersistentBetweenAdapterServiceInitialization() throws
+ PackageManager.NameNotFoundException {
+ Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+ BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
+ int id1 = mAdapterService.getMetricId(device);
+ Assert.assertTrue(id1 > 0);
+ tearDown();
+ setUp();
+ Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+ int id2 = mAdapterService.getMetricId(device);
+ Assert.assertEquals(id2, id1);
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
index a229499..c320b35 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
@@ -101,7 +101,6 @@
import java.io.PrintWriter;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
import java.util.HashMap;
import javax.crypto.Mac;
@@ -742,7 +741,6 @@
/**
* Test: Check if obfuscated Bluetooth address stays the same after toggling Bluetooth
*/
- @Ignore("b/265588558")
@Test
public void testObfuscateBluetoothAddress_PersistentBetweenToggle() {
Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
@@ -772,103 +770,6 @@
obfuscatedAddress1);
}
- /**
- * Test: Check if obfuscated Bluetooth address stays the same after re-initializing
- * {@link AdapterService}
- */
- @Test
- public void testObfuscateBluetoothAddress_PersistentBetweenAdapterServiceInitialization() throws
- PackageManager.NameNotFoundException {
- byte[] metricsSalt = getMetricsSalt(mAdapterConfig);
- Assert.assertNotNull(metricsSalt);
- Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
- BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
- byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
- Assert.assertTrue(obfuscatedAddress1.length > 0);
- Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress1));
- Assert.assertArrayEquals(obfuscateInJava(metricsSalt, device),
- obfuscatedAddress1);
- tearDown();
- setUp();
- Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
- byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
- Assert.assertTrue(obfuscatedAddress2.length > 0);
- Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress2));
- Assert.assertArrayEquals(obfuscatedAddress2,
- obfuscatedAddress1);
- }
-
- /**
- * Test: Verify that obfuscated Bluetooth address changes after factory reset
- *
- * There are 4 types of factory reset that we are talking about:
- * 1. Factory reset all user data from Settings -> Will restart phone
- * 2. Factory reset WiFi and Bluetooth from Settings -> Will only restart WiFi and BT
- * 3. Call BluetoothAdapter.factoryReset() -> Will disable Bluetooth and reset config in
- * memory and disk
- * 4. Call AdapterService.factoryReset() -> Will only reset config in memory
- *
- * We can only use No. 4 here
- */
- @Ignore("AdapterService.factoryReset() does not reload config into memory and hence old salt"
- + " is still used until next time Bluetooth library is initialized. However Bluetooth"
- + " cannot be used until Bluetooth process restart any way. Thus it is almost"
- + " guaranteed that user has to re-enable Bluetooth and hence re-generate new salt"
- + " after factory reset")
- @Test
- public void testObfuscateBluetoothAddress_FactoryReset() {
- Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
- BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
- byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
- Assert.assertTrue(obfuscatedAddress1.length > 0);
- Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress1));
- mServiceBinder.factoryReset(mAttributionSource);
- byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
- Assert.assertTrue(obfuscatedAddress2.length > 0);
- Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress2));
- Assert.assertFalse(Arrays.equals(obfuscatedAddress2,
- obfuscatedAddress1));
- doEnable(0, false);
- byte[] obfuscatedAddress3 = mAdapterService.obfuscateAddress(device);
- Assert.assertTrue(obfuscatedAddress3.length > 0);
- Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress3));
- Assert.assertArrayEquals(obfuscatedAddress3,
- obfuscatedAddress2);
- mServiceBinder.factoryReset(mAttributionSource);
- byte[] obfuscatedAddress4 = mAdapterService.obfuscateAddress(device);
- Assert.assertTrue(obfuscatedAddress4.length > 0);
- Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress4));
- Assert.assertFalse(Arrays.equals(obfuscatedAddress4,
- obfuscatedAddress3));
- }
-
- /**
- * Test: Verify that obfuscated Bluetooth address changes after factory reset and reloading
- * native layer
- */
- @Test
- public void testObfuscateBluetoothAddress_FactoryResetAndReloadNativeLayer() throws
- PackageManager.NameNotFoundException {
- byte[] metricsSalt1 = getMetricsSalt(mAdapterConfig);
- Assert.assertNotNull(metricsSalt1);
- Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
- BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
- byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
- Assert.assertTrue(obfuscatedAddress1.length > 0);
- Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress1));
- Assert.assertArrayEquals(obfuscateInJava(metricsSalt1, device),
- obfuscatedAddress1);
- mServiceBinder.factoryReset(mAttributionSource);
- tearDown();
- setUp();
- // Cannot verify metrics salt since it is not written to disk until native cleanup
- byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
- Assert.assertTrue(obfuscatedAddress2.length > 0);
- Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress2));
- Assert.assertFalse(Arrays.equals(obfuscatedAddress2,
- obfuscatedAddress1));
- }
-
@Test
public void testAddressConsolidation() {
// Create device properties
@@ -886,7 +787,7 @@
Assert.assertEquals(identityAddress, TEST_BT_ADDR_2);
}
- private static byte[] getMetricsSalt(HashMap<String, HashMap<String, String>> adapterConfig) {
+ public static byte[] getMetricsSalt(HashMap<String, HashMap<String, String>> adapterConfig) {
HashMap<String, String> metricsSection = adapterConfig.get("Metrics");
if (metricsSection == null) {
Log.e(TAG, "Metrics section is null: " + adapterConfig.toString());
@@ -905,7 +806,7 @@
return metricsSalt;
}
- private static byte[] obfuscateInJava(byte[] key, BluetoothDevice device) {
+ public static byte[] obfuscateInJava(byte[] key, BluetoothDevice device) {
String algorithm = "HmacSHA256";
try {
Mac hmac256 = Mac.getInstance(algorithm);
@@ -917,7 +818,7 @@
}
}
- private static boolean isByteArrayAllZero(byte[] byteArray) {
+ public static boolean isByteArrayAllZero(byte[] byteArray) {
for (byte i : byteArray) {
if (i != 0) {
return false;
@@ -985,24 +886,6 @@
Assert.assertEquals(id3, id1);
}
- /**
- * Test: Check if id gotten stays the same after re-initializing
- * {@link AdapterService}
- */
- @Test
- public void testgetMetricId_PersistentBetweenAdapterServiceInitialization() throws
- PackageManager.NameNotFoundException {
- Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
- BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
- int id1 = mAdapterService.getMetricId(device);
- Assert.assertTrue(id1 > 0);
- tearDown();
- setUp();
- Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
- int id2 = mAdapterService.getMetricId(device);
- Assert.assertEquals(id2, id1);
- }
-
@Test
public void testDump_doesNotCrash() {
FileDescriptor fd = new FileDescriptor();
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java
index 22df72c..86875f2 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java
@@ -6,11 +6,11 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAssignedNumbers;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.content.Intent;
import android.os.Bundle;
import android.os.HandlerThread;
@@ -527,10 +527,10 @@
mRemoteDevices.addDeviceProperties(Utils.getBytesFromAddress(TEST_BT_ADDR_1));
DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(mDevice1);
- BluetoothAudioPolicy policies = new BluetoothAudioPolicy.Builder()
- .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
- .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
- .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
+ BluetoothSinkAudioPolicy policies = new BluetoothSinkAudioPolicy.Builder()
+ .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+ .setActiveDevicePolicyAfterConnection(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+ .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
.build();
deviceProp.setHfAudioPolicyForRemoteAg(policies);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
index 2bf7302..cd306f4 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
@@ -28,9 +28,9 @@
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
@@ -460,10 +460,10 @@
@Test
public void testSetGetAudioPolicyMetaData() {
int badKey = 100;
- BluetoothAudioPolicy value = new BluetoothAudioPolicy.Builder()
- .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
- .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_NOT_ALLOWED)
- .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
+ BluetoothSinkAudioPolicy value = new BluetoothSinkAudioPolicy.Builder()
+ .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+ .setActiveDevicePolicyAfterConnection(BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED)
+ .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
.build();
// Device is not in database
@@ -1481,8 +1481,8 @@
}
void testSetGetAudioPolicyMetadataCase(boolean stored,
- BluetoothAudioPolicy policy, boolean expectedResult) {
- BluetoothAudioPolicy testPolicy = new BluetoothAudioPolicy.Builder().build();
+ BluetoothSinkAudioPolicy policy, boolean expectedResult) {
+ BluetoothSinkAudioPolicy testPolicy = new BluetoothSinkAudioPolicy.Builder().build();
if (stored) {
Metadata data = new Metadata(TEST_BT_ADDR);
mDatabaseManager.mMetadataCache.put(TEST_BT_ADDR, data);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
index fb27a2a..c41cbce 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
@@ -26,7 +26,7 @@
import android.app.Activity;
import android.app.Instrumentation;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
@@ -67,6 +67,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import org.mockito.InOrder;
import java.lang.reflect.Method;
import java.util.Collections;
@@ -182,8 +183,8 @@
.getBondState(any(BluetoothDevice.class));
doAnswer(invocation -> mBondedDevices.toArray(new BluetoothDevice[]{})).when(
mAdapterService).getBondedDevices();
- doReturn(new BluetoothAudioPolicy.Builder().build()).when(mAdapterService)
- .getAudioPolicy(any(BluetoothDevice.class));
+ doReturn(new BluetoothSinkAudioPolicy.Builder().build()).when(mAdapterService)
+ .getRequestedAudioPolicyAsSink(any(BluetoothDevice.class));
// Mock system interface
doNothing().when(mSystemInterface).stop();
when(mSystemInterface.getHeadsetPhoneState()).thenReturn(mPhoneState);
@@ -666,6 +667,7 @@
Assert.assertTrue(mHeadsetService.setActiveDevice(device));
verify(mNativeInterface).setActiveDevice(device);
Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+ verify(mNativeInterface).sendBsir(eq(device), eq(true));
// Start voice recognition
startVoiceRecognitionFromHf(device);
}
@@ -689,6 +691,7 @@
Assert.assertTrue(mHeadsetService.setActiveDevice(device));
verify(mNativeInterface).setActiveDevice(device);
Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+ verify(mNativeInterface).sendBsir(eq(device), eq(true));
// Start voice recognition
startVoiceRecognitionFromHf(device);
// Stop voice recognition
@@ -723,6 +726,7 @@
Assert.assertTrue(mHeadsetService.setActiveDevice(device));
verify(mNativeInterface).setActiveDevice(device);
Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+ verify(mNativeInterface).sendBsir(eq(device), eq(true));
// Start voice recognition
HeadsetStackEvent startVrEvent =
new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED,
@@ -755,6 +759,7 @@
Assert.assertTrue(mHeadsetService.setActiveDevice(device));
verify(mNativeInterface).setActiveDevice(device);
Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+ verify(mNativeInterface).sendBsir(eq(device), eq(true));
// Start voice recognition
HeadsetStackEvent startVrEvent =
new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED,
@@ -787,6 +792,7 @@
Assert.assertTrue(mHeadsetService.setActiveDevice(device));
verify(mNativeInterface).setActiveDevice(device);
Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+ verify(mNativeInterface).sendBsir(eq(device), eq(true));
// Start voice recognition
startVoiceRecognitionFromAg();
}
@@ -860,6 +866,7 @@
Assert.assertTrue(mHeadsetService.setActiveDevice(device));
verify(mNativeInterface).setActiveDevice(device);
Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+ verify(mNativeInterface).sendBsir(eq(device), eq(true));
// Start voice recognition
startVoiceRecognitionFromAg();
// Stop voice recognition
@@ -908,8 +915,10 @@
connectTestDevice(deviceA);
BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1);
connectTestDevice(deviceB);
- verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false);
- verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false);
+ InOrder inOrder = inOrder(mNativeInterface);
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true));
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false));
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false));
// Set active device to device B
Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB));
verify(mNativeInterface).setActiveDevice(deviceB);
@@ -960,8 +969,10 @@
connectTestDevice(deviceA);
BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1);
connectTestDevice(deviceB);
- verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false);
- verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false);
+ InOrder inOrder = inOrder(mNativeInterface);
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true));
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false));
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false));
// Set active device to device B
Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB));
verify(mNativeInterface).setActiveDevice(deviceB);
@@ -1012,8 +1023,10 @@
connectTestDevice(deviceA);
BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1);
connectTestDevice(deviceB);
- verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false);
- verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false);
+ InOrder inOrder = inOrder(mNativeInterface);
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true));
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false));
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false));
// Set active device to device B
Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB));
verify(mNativeInterface).setActiveDevice(deviceB);
@@ -1051,8 +1064,10 @@
connectTestDevice(deviceA);
BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1);
connectTestDevice(deviceB);
- verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false);
- verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false);
+ InOrder inOrder = inOrder(mNativeInterface);
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true));
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false));
+ inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false));
// Set active device to device B
Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB));
verify(mNativeInterface).setActiveDevice(deviceB);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
index 817ea8b..09fe7cc 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
@@ -19,7 +19,7 @@
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
@@ -117,8 +117,8 @@
Set<BluetoothDevice> keys = mStateMachines.keySet();
return keys.toArray(new BluetoothDevice[keys.size()]);
}).when(mAdapterService).getBondedDevices();
- doReturn(new BluetoothAudioPolicy.Builder().build()).when(mAdapterService)
- .getAudioPolicy(any(BluetoothDevice.class));
+ doReturn(new BluetoothSinkAudioPolicy.Builder().build()).when(mAdapterService)
+ .getRequestedAudioPolicyAsSink(any(BluetoothDevice.class));
// Mock system interface
doNothing().when(mSystemInterface).stop();
when(mSystemInterface.getHeadsetPhoneState()).thenReturn(mPhoneState);
@@ -1012,19 +1012,21 @@
BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED);
when(mStateMachines.get(mCurrentDevice).getHfpCallAudioPolicy()).thenReturn(
- new BluetoothAudioPolicy.Builder()
- .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
- .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
- .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
+ new BluetoothSinkAudioPolicy.Builder()
+ .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+ .setActiveDevicePolicyAfterConnection(
+ BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+ .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
.build()
);
Assert.assertEquals(true, mHeadsetService.isInbandRingingEnabled());
when(mStateMachines.get(mCurrentDevice).getHfpCallAudioPolicy()).thenReturn(
- new BluetoothAudioPolicy.Builder()
- .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
- .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
- .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_NOT_ALLOWED)
+ new BluetoothSinkAudioPolicy.Builder()
+ .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+ .setActiveDevicePolicyAfterConnection(
+ BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+ .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED)
.build()
);
Assert.assertEquals(false, mHeadsetService.isInbandRingingEnabled());
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
index bc335a5..be9df4b 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
@@ -27,7 +27,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
@@ -159,9 +159,9 @@
BluetoothAdapter.getDefaultAdapter().getRemoteDevice("00:01:02:03:04:05");
mService.getStateMachineMap().put(device, mStateMachine);
- mService.setAudioPolicy(device, new BluetoothAudioPolicy.Builder().build());
+ mService.setAudioPolicy(device, new BluetoothSinkAudioPolicy.Builder().build());
verify(mStateMachine, timeout(STANDARD_WAIT_MILLIS).times(1))
- .setAudioPolicy(any(BluetoothAudioPolicy.class));
+ .setAudioPolicy(any(BluetoothSinkAudioPolicy.class));
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
index f64cda7..dc8683d 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
@@ -1,5 +1,26 @@
+/*
+ * Copyright 2016 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.hfpclient;
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
+import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
+import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTING;
+
import static com.android.bluetooth.hfpclient.HeadsetClientStateMachine.AT_OK;
import static com.android.bluetooth.hfpclient.HeadsetClientStateMachine.ENTER_PRIVATE_MODE;
import static com.android.bluetooth.hfpclient.HeadsetClientStateMachine.EXPLICIT_CALL_TRANSFER;
@@ -13,7 +34,7 @@
import android.bluetooth.BluetoothAssignedNumbers;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
@@ -21,6 +42,7 @@
import android.media.AudioManager;
import android.os.Bundle;
import android.os.HandlerThread;
+import android.os.Looper;
import android.os.Message;
import android.util.Pair;
@@ -36,6 +58,8 @@
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
+import com.android.bluetooth.hfp.HeadsetService;
+import com.android.bluetooth.hfp.HeadsetStackEvent;
import org.hamcrest.core.AllOf;
import org.hamcrest.core.IsInstanceOf;
@@ -47,18 +71,22 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.hamcrest.MockitoHamcrest;
import java.util.List;
import java.util.Set;
+/**
+ * Test cases for {@link HeadsetClientStateMachine}.
+ */
@LargeTest
@RunWith(AndroidJUnit4.class)
public class HeadsetClientStateMachineTest {
private BluetoothAdapter mAdapter;
private HandlerThread mHandlerThread;
- private HeadsetClientStateMachine mHeadsetClientStateMachine;
+ private TestHeadsetClientStateMachine mHeadsetClientStateMachine;
private BluetoothDevice mTestDevice;
private Context mTargetContext;
@@ -67,6 +95,8 @@
@Mock
private Resources mMockHfpResources;
@Mock
+ private HeadsetService mHeadsetService;
+ @Mock
private HeadsetClientService mHeadsetClientService;
@Mock
private AudioManager mAudioManager;
@@ -77,6 +107,7 @@
private static final int QUERY_CURRENT_CALLS_WAIT_MILLIS = 2000;
private static final int QUERY_CURRENT_CALLS_TEST_WAIT_MILLIS = QUERY_CURRENT_CALLS_WAIT_MILLIS
* 3 / 2;
+ private static final int TIMEOUT_MS = 1000;
@Before
public void setUp() throws Exception {
@@ -109,9 +140,8 @@
mHandlerThread = new HandlerThread("HeadsetClientStateMachineTestHandlerThread");
mHandlerThread.start();
// Manage looper execution in main test thread explicitly to guarantee timing consistency
- mHeadsetClientStateMachine =
- new HeadsetClientStateMachine(mHeadsetClientService, mHandlerThread.getLooper(),
- mNativeInterface);
+ mHeadsetClientStateMachine = new TestHeadsetClientStateMachine(mHeadsetClientService,
+ mHeadsetService, mHandlerThread.getLooper(), mNativeInterface);
mHeadsetClientStateMachine.start();
TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
}
@@ -122,9 +152,12 @@
return;
}
TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- TestUtils.clearAdapterService(mAdapterService);
+ mHeadsetClientStateMachine.allowConnect = null;
mHeadsetClientStateMachine.doQuit();
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
mHandlerThread.quit();
+ TestUtils.clearAdapterService(mAdapterService);
+ verifyNoMoreInteractions(mHeadsetService);
}
/**
@@ -217,6 +250,7 @@
// Check we are in connecting state now.
Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
}
/**
@@ -259,6 +293,7 @@
// Check we are in connecting state now.
Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class));
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
}
/**
@@ -310,6 +345,8 @@
Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
+
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_IN_BAND_RINGTONE);
event.valueInt = 0;
event.device = mTestDevice;
@@ -427,6 +464,7 @@
intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
startBroadcastIndex++;
return startBroadcastIndex;
@@ -1047,7 +1085,7 @@
expectedBroadcastIndex = setUpHfpClientConnection(expectedBroadcastIndex);
expectedBroadcastIndex = setUpServiceLevelConnection(expectedBroadcastIndex);
- BluetoothAudioPolicy dummyAudioPolicy = new BluetoothAudioPolicy.Builder().build();
+ BluetoothSinkAudioPolicy dummyAudioPolicy = new BluetoothSinkAudioPolicy.Builder().build();
mHeadsetClientStateMachine.setAudioPolicy(dummyAudioPolicy);
verify(mNativeInterface, never()).sendAndroidAt(mTestDevice, "+ANDROID:1,0,0,0");
}
@@ -1064,13 +1102,330 @@
expectedBroadcastIndex = setUpHfpClientConnection(expectedBroadcastIndex);
expectedBroadcastIndex = setUpServiceLevelConnection(expectedBroadcastIndex, true);
- BluetoothAudioPolicy dummyAudioPolicy = new BluetoothAudioPolicy.Builder()
- .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
- .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_NOT_ALLOWED)
- .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
+ BluetoothSinkAudioPolicy dummyAudioPolicy = new BluetoothSinkAudioPolicy.Builder()
+ .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+ .setActiveDevicePolicyAfterConnection(BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED)
+ .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
.build();
mHeadsetClientStateMachine.setAudioPolicy(dummyAudioPolicy);
verify(mNativeInterface).sendAndroidAt(mTestDevice, "+ANDROID=1,1,2,1");
}
+
+ @Test
+ public void testDumpDoesNotCrash() {
+ mHeadsetClientStateMachine.dump(new StringBuilder());
+ }
+
+ @Test
+ public void testProcessDisconnectMessage_onDisconnectedState() {
+ mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ Assert.assertEquals(STATE_DISCONNECTED,
+ mHeadsetClientStateMachine.getConnectionState(mTestDevice));
+ }
+
+ @Test
+ public void testProcessConnectMessage_onDisconnectedState() {
+ doReturn(true).when(mNativeInterface).connect(any(BluetoothDevice.class));
+ sendMessageAndVerifyTransition(
+ mHeadsetClientStateMachine
+ .obtainMessage(HeadsetClientStateMachine.CONNECT, mTestDevice),
+ HeadsetClientStateMachine.Connecting.class);
+ }
+
+ @Test
+ public void testStackEvent_toConnectingState_onDisconnectedState() {
+ allowConnection(true);
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+ event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
+ event.device = mTestDevice;
+ sendMessageAndVerifyTransition(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event),
+ HeadsetClientStateMachine.Connecting.class);
+ }
+
+ @Test
+ public void testStackEvent_toConnectingState_disallowConnection_onDisconnectedState() {
+ allowConnection(false);
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+ event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
+ event.device = mTestDevice;
+ sendMessageAndVerifyTransition(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event),
+ HeadsetClientStateMachine.Disconnected.class);
+ }
+
+ @Test
+ public void testProcessConnectMessage_onConnectingState() {
+ initToConnectingState();
+ mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ Assert.assertTrue(mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.CONNECT));
+ }
+
+ @Test
+ public void testProcessStackEvent_ConnectionStateChanged_Disconnected_onConnectingState() {
+ initToConnectingState();
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+ event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED;
+ event.device = mTestDevice;
+ sendMessageAndVerifyTransition(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event),
+ HeadsetClientStateMachine.Disconnected.class);
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
+ }
+
+ @Test
+ public void testProcessStackEvent_ConnectionStateChanged_Connected_onConnectingState() {
+ initToConnectingState();
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+ event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
+ event.device = mTestDevice;
+ mHeadsetClientStateMachine.sendMessage(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class));
+ }
+
+ @Test
+ public void testProcessStackEvent_ConnectionStateChanged_Connecting_onConnectingState() {
+ initToConnectingState();
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+ event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTING;
+ event.device = mTestDevice;
+ mHeadsetClientStateMachine.sendMessage(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class));
+ }
+
+ @Test
+ public void testProcessStackEvent_Call_onConnectingState() {
+ initToConnectingState();
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALL);
+ event.valueInt = StackEvent.EVENT_TYPE_CALL;
+ event.device = mTestDevice;
+ mHeadsetClientStateMachine.sendMessage(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ Assert.assertTrue(mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ StackEvent.STACK_EVENT));
+ }
+
+ @Test
+ public void testProcessStackEvent_CmdResultWithEmptyQueuedActions_onConnectingState() {
+ initToConnectingState();
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT);
+ event.valueInt = StackEvent.CMD_RESULT_TYPE_OK;
+ event.device = mTestDevice;
+ mHeadsetClientStateMachine.sendMessage(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class));
+ }
+
+ @Test
+ public void testProcessStackEvent_Unknown_onConnectingState() {
+ String atCommand = "+ANDROID: 1";
+
+ initToConnectingState();
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_UNKNOWN_EVENT);
+ event.valueString = atCommand;
+ event.device = mTestDevice;
+ mHeadsetClientStateMachine.sendMessage(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
+ }
+
+ @Test
+ public void testProcessConnectTimeoutMessage_onConnectingState() {
+ initToConnectingState();
+ Message msg = mHeadsetClientStateMachine
+ .obtainMessage(HeadsetClientStateMachine.CONNECTING_TIMEOUT);
+ sendMessageAndVerifyTransition(msg, HeadsetClientStateMachine.Disconnected.class);
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
+ }
+
+ @Test
+ public void testProcessConnectMessage_onConnectedState() {
+ initToConnectedState();
+ mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ }
+
+ @Test
+ public void testProcessDisconnectMessage_onConnectedState() {
+ initToConnectedState();
+ mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT, mTestDevice);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ verify(mNativeInterface).disconnect(any(BluetoothDevice.class));
+ }
+
+ @Test
+ public void testProcessConnectAudioMessage_onConnectedState() {
+ initToConnectedState();
+ mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ verify(mNativeInterface).connectAudio(any(BluetoothDevice.class));
+ }
+
+ @Test
+ public void testProcessDisconnectAudioMessage_onConnectedState() {
+ initToConnectedState();
+ mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ verify(mNativeInterface).disconnectAudio(any(BluetoothDevice.class));
+ }
+
+ @Test
+ public void testProcessVoiceRecognitionStartMessage_onConnectedState() {
+ initToConnectedState();
+ mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.VOICE_RECOGNITION_START);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ verify(mNativeInterface).startVoiceRecognition(any(BluetoothDevice.class));
+ }
+
+ @Test
+ public void testProcessDisconnectMessage_onAudioOnState() {
+ initToAudioOnState();
+ mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT, mTestDevice);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ Assert.assertTrue(mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.DISCONNECT));
+ }
+
+ @Test
+ public void testProcessDisconnectAudioMessage_onAudioOnState() {
+ initToAudioOnState();
+ mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO,
+ mTestDevice);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ verify(mNativeInterface).disconnectAudio(any(BluetoothDevice.class));
+ }
+
+ @Test
+ public void testProcessHoldCall_onAudioOnState() {
+ initToAudioOnState();
+ HfpClientCall call = new HfpClientCall(mTestDevice, 0, HfpClientCall.CALL_STATE_ACTIVE,
+ "1", true, false, false);
+ mHeadsetClientStateMachine.mCalls.put(0, call);
+ int[] states = new int[1];
+ states[0] = HfpClientCall.CALL_STATE_ACTIVE;
+ mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.HOLD_CALL,
+ mTestDevice);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ verify(mNativeInterface).handleCallAction(any(BluetoothDevice.class), anyInt(), eq(0));
+ }
+
+ @Test
+ public void testProcessStackEvent_ConnectionStateChanged_onAudioOnState() {
+ initToAudioOnState();
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(HeadsetClientStateMachine.AudioOn.class));
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+ event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED;
+ event.device = mTestDevice;
+ mHeadsetClientStateMachine.sendMessage(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class));
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
+ }
+
+ @Test
+ public void testProcessStackEvent_AudioStateChanged_onAudioOnState() {
+ initToAudioOnState();
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(HeadsetClientStateMachine.AudioOn.class));
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
+ event.valueInt = HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED;
+ event.device = mTestDevice;
+ mHeadsetClientStateMachine.sendMessage(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ }
+
+ /**
+ * Allow/disallow connection to any device
+ *
+ * @param allow if true, connection is allowed
+ */
+ private void allowConnection(boolean allow) {
+ mHeadsetClientStateMachine.allowConnect = allow;
+ }
+
+ private void initToConnectingState() {
+ doReturn(true).when(mNativeInterface).connect(any(BluetoothDevice.class));
+ sendMessageAndVerifyTransition(
+ mHeadsetClientStateMachine
+ .obtainMessage(HeadsetClientStateMachine.CONNECT, mTestDevice),
+ HeadsetClientStateMachine.Connecting.class);
+ }
+
+ private void initToConnectedState() {
+ String atCommand = "+ANDROID: 1";
+ initToConnectingState();
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_UNKNOWN_EVENT);
+ event.valueString = atCommand;
+ event.device = mTestDevice;
+ mHeadsetClientStateMachine.sendMessage(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
+ }
+
+ private void initToAudioOnState() {
+ mHeadsetClientStateMachine.setAudioRouteAllowed(true);
+ initToConnectedState();
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
+ event.valueInt = HeadsetClientHalConstants.AUDIO_STATE_CONNECTED;
+ event.device = mTestDevice;
+ mHeadsetClientStateMachine.sendMessage(
+ mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(HeadsetClientStateMachine.AudioOn.class));
+ }
+
+ private <T> void sendMessageAndVerifyTransition(Message msg, Class<T> type) {
+ Mockito.clearInvocations(mHeadsetClientService);
+ mHeadsetClientStateMachine.sendMessage(msg);
+ // Verify that one connection state broadcast is executed
+ verify(mHeadsetClientService, timeout(TIMEOUT_MS)).sendBroadcastMultiplePermissions(
+ any(Intent.class), any(String[].class), any(BroadcastOptions.class)
+ );
+ Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+ IsInstanceOf.instanceOf(type));
+ }
+
+ public static class TestHeadsetClientStateMachine extends HeadsetClientStateMachine {
+
+ Boolean allowConnect = null;
+
+ TestHeadsetClientStateMachine(HeadsetClientService context, HeadsetService headsetService,
+ Looper looper, NativeInterface nativeInterface) {
+ super(context, headsetService, looper, nativeInterface);
+ }
+
+ public boolean doesSuperHaveDeferredMessages(int what) {
+ return super.hasDeferredMessages(what);
+ }
+
+ @Override
+ public boolean okToConnect(BluetoothDevice device) {
+ return allowConnect != null ? allowConnect : super.okToConnect(device);
+ }
+ }
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
index d2c7cd1..d1d1727 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
@@ -643,6 +643,9 @@
doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
doReturn(true).when(mNativeInterface).disconnectLeAudio(any(BluetoothDevice.class));
+ // Create device descriptor with connect request
+ assertWithMessage("Connect failed").that(mService.connect(mLeftDevice)).isTrue();
+
// Le Audio stack event: CONNECTION_STATE_CONNECTING - state machine should be created
generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTING,
BluetoothProfile.STATE_DISCONNECTED);
@@ -710,6 +713,9 @@
doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
doReturn(true).when(mNativeInterface).disconnectLeAudio(any(BluetoothDevice.class));
+ // Create device descriptor with connect request
+ assertWithMessage("Connect failed").that(mService.connect(mLeftDevice)).isTrue();
+
// LeAudio stack event: CONNECTION_STATE_CONNECTING - state machine should be created
generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTING,
BluetoothProfile.STATE_DISCONNECTED);
@@ -777,6 +783,9 @@
doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
doReturn(true).when(mNativeInterface).disconnectLeAudio(any(BluetoothDevice.class));
+ // Create device descriptor with connect request
+ assertWithMessage("Connect failed").that(mService.connect(mLeftDevice)).isTrue();
+
// LeAudio stack event: CONNECTION_STATE_CONNECTING - state machine should be created
generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTING,
BluetoothProfile.STATE_DISCONNECTED);
@@ -1514,6 +1523,9 @@
@Test
public void testGetAudioLocation() {
+ doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
+ connectTestDevice(mSingleDevice, testGroupId);
+
assertThat(mService.getAudioLocation(null))
.isEqualTo(BluetoothLeAudio.AUDIO_LOCATION_INVALID);
@@ -1619,6 +1631,10 @@
public void testAuthorizeMcpServiceOnBluetoothEnableAndNodeRemoval() {
int groupId = 1;
+ doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
+ connectTestDevice(mLeftDevice, groupId);
+ connectTestDevice(mRightDevice, groupId);
+
generateGroupNodeAdded(mLeftDevice, groupId);
generateGroupNodeAdded(mRightDevice, groupId);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java
index 3249a42..7c80bff 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java
@@ -24,7 +24,6 @@
import android.bluetooth.IBluetoothMapClient;
import android.content.Context;
import android.os.UserHandle;
-import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
@@ -123,7 +122,6 @@
// is the statemachine created
Map<BluetoothDevice, MceStateMachine> map = mService.getInstanceMap();
- Log.d("MapClientTest", "map=" + map);
Assert.assertEquals(1, map.size());
Assert.assertNotNull(map.get(device));
diff --git a/android/pandora/server/configs/PtsBotTestMts.xml b/android/pandora/server/configs/PtsBotTestMts.xml
index a5953e2..d301e42 100644
--- a/android/pandora/server/configs/PtsBotTestMts.xml
+++ b/android/pandora/server/configs/PtsBotTestMts.xml
@@ -14,6 +14,7 @@
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.PythonVirtualenvPreparer">
+ <!-- TODO(b/267785204): Import python dependencies -->
<option name="dep-module" value="grpcio" />
<option name="dep-module" value="protobuf==3.20.1" />
<option name="dep-module" value="scipy" />
@@ -23,8 +24,8 @@
<!-- Creates a randomized temp dir for pts-bot binaries and avoid
conflicts when running multiple pts-bot on the same machine -->
<option name="create-bin-temp-dir" value="true"/>
- <!-- mmi2grpc is contained inside testcases folder -->
- <option name="mmi2grpc" value="testcases" />
+ <!-- mmi2grpc is contained inside pts-bot-mts folder -->
+ <option name="mmi2grpc" value="pts-bot-mts" />
<option name="tests-config-file" value="pts_bot_tests_config.json" />
<option name="max-flaky-tests" value="3" />
<option name="max-retries-per-test" value="3" />
diff --git a/framework/java/android/bluetooth/BluetoothDevice.java b/framework/java/android/bluetooth/BluetoothDevice.java
index 5646efb..58895ef 100644
--- a/framework/java/android/bluetooth/BluetoothDevice.java
+++ b/framework/java/android/bluetooth/BluetoothDevice.java
@@ -3248,14 +3248,14 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(
- prefix = { "REMOTE_STATUS_" },
+ prefix = { "FEATURE_" },
value = {
/** Remote support status of audio policy feature is unknown/unconfigured **/
- BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE,
+ BluetoothStatusCodes.FEATURE_NOT_CONFIGURED,
/** Remote support status of audio policy feature is supported **/
- BluetoothAudioPolicy.FEATURE_SUPPORTED_BY_REMOTE,
+ BluetoothStatusCodes.FEATURE_SUPPORTED,
/** Remote support status of audio policy feature is not supported **/
- BluetoothAudioPolicy.FEATURE_NOT_SUPPORTED_BY_REMOTE,
+ BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
}
)
@@ -3269,24 +3269,29 @@
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED,
BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
- BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED,
})
public @interface AudioPolicyReturnValues{}
/**
- * Returns whether the audio policy feature is supported by the remote.
- * This requires a vendor specific command, so the API returns
- * {@link BluetoothAudioPolicy#FEATURE_UNCONFIGURED_BY_REMOTE} to indicate the remote
+ * Returns whether the audio policy feature is supported by
+ * both the local and the remote device.
+ * This is configured during initiating the connection between the devices through
+ * one of the transport protocols (e.g. HFP Vendor specific protocol). So if the API
+ * is invoked before this initial configuration is completed, it returns
+ * {@link BluetoothStatusCodes#FEATURE_NOT_CONFIGURED} to indicate the remote
* device has not yet relayed this information. After the internal configuration,
* the support status will be set to either
- * {@link BluetoothAudioPolicy#FEATURE_NOT_SUPPORTED_BY_REMOTE} or
- * {@link BluetoothAudioPolicy#FEATURE_SUPPORTED_BY_REMOTE}.
+ * {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} or
+ * {@link BluetoothStatusCodes#FEATURE_SUPPORTED}.
* The rest of the APIs related to this feature in both {@link BluetoothDevice}
- * and {@link BluetoothAudioPolicy} should be invoked only after getting a
- * {@link BluetoothAudioPolicy#FEATURE_SUPPORTED_BY_REMOTE} response from this API.
+ * and {@link BluetoothSinkAudioPolicy} should be invoked only after getting a
+ * {@link BluetoothStatusCodes#FEATURE_SUPPORTED} response from this API.
+ * <p>Note that this API is intended to be used by a client device to send these requests
+ * to the server represented by this BluetoothDevice object.
*
- * @return if call audio policy feature is supported or not
+ * @return if call audio policy feature is supported by both local and remote
+ * device or not
*
* @hide
*/
@@ -3295,17 +3300,17 @@
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
- public @AudioPolicyRemoteSupport int getAudioPolicyRemoteSupported() {
- if (DBG) log("getAudioPolicyRemoteSupported()");
+ public @AudioPolicyRemoteSupport int isRequestAudioPolicyAsSinkSupported() {
+ if (DBG) log("isRequestAudioPolicyAsSinkSupported()");
final IBluetooth service = getService();
- final int defaultValue = BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE;
+ final int defaultValue = BluetoothStatusCodes.FEATURE_NOT_CONFIGURED;
if (service == null || !isBluetoothEnabled()) {
Log.e(TAG, "BT not enabled. Cannot retrieve audio policy support status.");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else {
try {
final SynchronousResultReceiver<Integer> recv = SynchronousResultReceiver.get();
- service.getAudioPolicyRemoteSupported(this, mAttributionSource, recv);
+ service.isRequestAudioPolicyAsSinkSupported(this, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
} catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
@@ -3319,9 +3324,15 @@
/**
* Sets call audio preferences and sends them to the remote device.
+ * <p>Note that the caller should check if the feature is supported by
+ * invoking {@link BluetoothDevice#isRequestAudioPolicyAsSinkSupported} first.
+ * <p>This API will throw an exception if the feature is not supported but still
+ * invoked.
+ * <p>Note that this API is intended to be used by a client device to send these requests
+ * to the server represented by this BluetoothDevice object.
*
* @param policies call audio policy preferences
- * @return whether audio policy was set successfully or not
+ * @return whether audio policy was requested successfully or not
*
* @hide
*/
@@ -3330,8 +3341,9 @@
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
- public @AudioPolicyReturnValues int setAudioPolicy(@NonNull BluetoothAudioPolicy policies) {
- if (DBG) log("setAudioPolicy");
+ public @AudioPolicyReturnValues int requestAudioPolicyAsSink(
+ @NonNull BluetoothSinkAudioPolicy policies) {
+ if (DBG) log("requestAudioPolicyAsSink");
final IBluetooth service = getService();
final int defaultValue = BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
if (service == null || !isBluetoothEnabled()) {
@@ -3340,7 +3352,7 @@
} else {
try {
final SynchronousResultReceiver<Integer> recv = SynchronousResultReceiver.get();
- service.setAudioPolicy(this, policies, mAttributionSource, recv);
+ service.requestAudioPolicyAsSink(this, policies, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
} catch (RemoteException | TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
@@ -3352,14 +3364,18 @@
/**
* Gets the call audio preferences for the remote device.
* <p>Note that the caller should check if the feature is supported by
- * invoking {@link BluetoothDevice#getAudioPolicyRemoteSupported} first.
+ * invoking {@link BluetoothDevice#isRequestAudioPolicyAsSinkSupported} first.
+ * <p>This API will throw an exception if the feature is not supported but still
+ * invoked.
* <p>This API will return null if
* 1. The bleutooth service is not started yet,
* 2. It is invoked for a device which is not bonded, or
* 3. The used transport, for example, HFP Client profile is not enabled or
* connected yet.
+ * <p>Note that this API is intended to be used by a client device to send these requests
+ * to the server represented by this BluetoothDevice object.
*
- * @return call audio policy as {@link BluetoothAudioPolicy} object
+ * @return call audio policy as {@link BluetoothSinkAudioPolicy} object
*
* @hide
*/
@@ -3368,17 +3384,17 @@
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
- public @Nullable BluetoothAudioPolicy getAudioPolicy() {
- if (DBG) log("getAudioPolicy");
+ public @Nullable BluetoothSinkAudioPolicy getRequestedAudioPolicyAsSink() {
+ if (DBG) log("getRequestedAudioPolicyAsSink");
final IBluetooth service = getService();
if (service == null || !isBluetoothEnabled()) {
Log.e(TAG, "Bluetooth is not enabled. Cannot get Audio Policy.");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else {
try {
- final SynchronousResultReceiver<BluetoothAudioPolicy>
+ final SynchronousResultReceiver<BluetoothSinkAudioPolicy>
recv = SynchronousResultReceiver.get();
- service.getAudioPolicy(this, mAttributionSource, recv);
+ service.getRequestedAudioPolicyAsSink(this, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
} catch (RemoteException | TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
diff --git a/framework/java/android/bluetooth/BluetoothServerSocket.java b/framework/java/android/bluetooth/BluetoothServerSocket.java
index bb4e354..5a23f7e3 100644
--- a/framework/java/android/bluetooth/BluetoothServerSocket.java
+++ b/framework/java/android/bluetooth/BluetoothServerSocket.java
@@ -75,7 +75,7 @@
public final class BluetoothServerSocket implements Closeable {
private static final String TAG = "BluetoothServerSocket";
- private static final boolean DBG = false;
+ private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
@UnsupportedAppUsage(publicAlternatives = "Use public {@link BluetoothServerSocket} API "
+ "instead.")
/*package*/ final BluetoothSocket mSocket;
diff --git a/framework/java/android/bluetooth/BluetoothAudioPolicy.java b/framework/java/android/bluetooth/BluetoothSinkAudioPolicy.java
similarity index 70%
rename from framework/java/android/bluetooth/BluetoothAudioPolicy.java
rename to framework/java/android/bluetooth/BluetoothSinkAudioPolicy.java
index 873abcd..8641e51 100644
--- a/framework/java/android/bluetooth/BluetoothAudioPolicy.java
+++ b/framework/java/android/bluetooth/BluetoothSinkAudioPolicy.java
@@ -33,29 +33,29 @@
* devices shall send objects of this class to send its preference to the AG/CG
* devices.
*
- * <p>HF/CT side applications on can use {@link BluetoothDevice#setAudioPolicy}
- * API to set and send a {@link BluetoothAudioPolicy} object containing the
+ * <p>HF/CT side applications on can use {@link BluetoothDevice#requestAudioPolicyAsSink}
+ * API to set and send a {@link BluetoothSinkAudioPolicy} object containing the
* preference/policy values. This object will be stored in the memory of HF/CT
* side, will be send to the AG/CG side using Android Specific AT Commands and will
* be stored in the AG side memory and database.
*
- * <p>HF/CT side API {@link BluetoothDevice#getAudioPolicy} can be used to retrieve
+ * <p>HF/CT side API {@link BluetoothDevice#getRequestedAudioPolicyAsSink} can be used to retrieve
* the stored audio policies currently.
*
* <p>Note that the setter APIs of this class will only set the values of the
- * object. To actually set the policies, API {@link BluetoothDevice#setAudioPolicy}
- * must need to be invoked with the {@link BluetoothAudioPolicy} object.
+ * object. To actually set the policies, API {@link BluetoothDevice#requestAudioPolicyAsSink}
+ * must need to be invoked with the {@link BluetoothSinkAudioPolicy} object.
*
* <p>Note that any API related to this feature should be used after configuring
* the support of the AG device and after checking whether the AG device supports
- * this feature or not by invoking {@link BluetoothDevice#getAudioPolicyRemoteSupported}.
- * Only after getting a {@link BluetoothAudioPolicy#FEATURE_SUPPORTED_BY_REMOTE} response
+ * this feature or not by invoking {@link BluetoothDevice#isRequestAudioPolicyAsSinkSupported}.
+ * Only after getting a {@link BluetoothStatusCodes#FEATURE_SUPPORTED} response
* from the API should the APIs related to this feature be used.
*
*
* @hide
*/
-public final class BluetoothAudioPolicy implements Parcelable {
+public final class BluetoothSinkAudioPolicy implements Parcelable {
/**
* @hide
@@ -102,28 +102,6 @@
*/
public static final int POLICY_NOT_ALLOWED = 2;
- /**
- * Remote support status of audio policy feature is unknown/unconfigured.
- *
- * @hide
- */
- public static final int FEATURE_UNCONFIGURED_BY_REMOTE = 0;
-
- /**
- * Remote support status of audio policy feature is supported.
- *
- * @hide
- */
- public static final int FEATURE_SUPPORTED_BY_REMOTE = 1;
-
- /**
- * Remote support status of audio policy feature is not supported.
- *
- * @hide
- */
- public static final int FEATURE_NOT_SUPPORTED_BY_REMOTE = 2;
-
-
@AudioPolicyValues private final int mCallEstablishPolicy;
@AudioPolicyValues private final int mConnectingTimePolicy;
@AudioPolicyValues private final int mInBandRingtonePolicy;
@@ -131,7 +109,7 @@
/**
* @hide
*/
- public BluetoothAudioPolicy(int callEstablishPolicy,
+ public BluetoothSinkAudioPolicy(int callEstablishPolicy,
int connectingTimePolicy, int inBandRingtonePolicy) {
mCallEstablishPolicy = callEstablishPolicy;
mConnectingTimePolicy = connectingTimePolicy;
@@ -139,10 +117,14 @@
}
/**
- * Get Call pick up audio policy.
+ * Get Call establishment policy audio policy.
+ * <p>This policy is used to determine the audio preference when the
+ * HF device makes or answers a call. That is, if this device
+ * makes or answers a call, is the audio preferred by HF.
*
* @return the call pick up audio policy value
*
+ * @hide
*/
public @AudioPolicyValues int getCallEstablishPolicy() {
return mCallEstablishPolicy;
@@ -150,19 +132,30 @@
/**
* Get during connection audio up policy.
+ * <p>This policy is used to determine the audio preference when the
+ * HF device connects with the AG device. That is, when the
+ * HF device gets connected, should the HF become active and get audio
+ * is decided by this policy. This also covers the case of during a call.
+ * If the HF connects with the AG during an ongoing call, should the call
+ * audio be routed to the HF will be decided by this policy.
*
* @return the during connection audio policy value
*
+ * @hide
*/
- public @AudioPolicyValues int getConnectingTimePolicy() {
+ public @AudioPolicyValues int getActiveDevicePolicyAfterConnection() {
return mConnectingTimePolicy;
}
/**
* Get In band ringtone audio up policy.
+ * <p>This policy is used to determine the audio preference of the
+ * in band ringtone. That is, if there is an incoming call, should the
+ * inband ringtone audio be routed to the HF will be decided by this policy.
*
* @return the in band ringtone audio policy value
*
+ * @hide
*/
public @AudioPolicyValues int getInBandRingtonePolicy() {
return mInBandRingtonePolicy;
@@ -170,7 +163,7 @@
@Override
public String toString() {
- StringBuilder builder = new StringBuilder("BluetoothAudioPolicy{");
+ StringBuilder builder = new StringBuilder("BluetoothSinkAudioPolicy{");
builder.append("mCallEstablishPolicy: ");
builder.append(mCallEstablishPolicy);
builder.append(", mConnectingTimePolicy: ");
@@ -184,17 +177,17 @@
/**
* {@link Parcelable.Creator} interface implementation.
*/
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothAudioPolicy>
- CREATOR = new Parcelable.Creator<BluetoothAudioPolicy>() {
+ public static final @android.annotation.NonNull Parcelable.Creator<BluetoothSinkAudioPolicy>
+ CREATOR = new Parcelable.Creator<BluetoothSinkAudioPolicy>() {
@Override
- public BluetoothAudioPolicy createFromParcel(@NonNull Parcel in) {
- return new BluetoothAudioPolicy(
+ public BluetoothSinkAudioPolicy createFromParcel(@NonNull Parcel in) {
+ return new BluetoothSinkAudioPolicy(
in.readInt(), in.readInt(), in.readInt());
}
@Override
- public BluetoothAudioPolicy[] newArray(int size) {
- return new BluetoothAudioPolicy[size];
+ public BluetoothSinkAudioPolicy[] newArray(int size) {
+ return new BluetoothSinkAudioPolicy[size];
}
};
@@ -215,8 +208,8 @@
@Override
public boolean equals(@Nullable Object o) {
- if (o instanceof BluetoothAudioPolicy) {
- BluetoothAudioPolicy other = (BluetoothAudioPolicy) o;
+ if (o instanceof BluetoothSinkAudioPolicy) {
+ BluetoothSinkAudioPolicy other = (BluetoothSinkAudioPolicy) o;
return (other.mCallEstablishPolicy == mCallEstablishPolicy
&& other.mConnectingTimePolicy == mConnectingTimePolicy
&& other.mInBandRingtonePolicy == mInBandRingtonePolicy);
@@ -236,9 +229,9 @@
}
/**
- * Builder for {@link BluetoothAudioPolicy}.
+ * Builder for {@link BluetoothSinkAudioPolicy}.
* <p> By default, the audio policy values will be set to
- * {@link BluetoothAudioPolicy#POLICY_UNCONFIGURED}.
+ * {@link BluetoothSinkAudioPolicy#POLICY_UNCONFIGURED}.
*/
public static final class Builder {
private int mCallEstablishPolicy = POLICY_UNCONFIGURED;
@@ -249,7 +242,7 @@
}
- public Builder(@NonNull BluetoothAudioPolicy policies) {
+ public Builder(@NonNull BluetoothSinkAudioPolicy policies) {
mCallEstablishPolicy = policies.mCallEstablishPolicy;
mConnectingTimePolicy = policies.mConnectingTimePolicy;
mInBandRingtonePolicy = policies.mInBandRingtonePolicy;
@@ -259,10 +252,15 @@
* Set Call Establish (pick up and answer) policy.
* <p>This policy is used to determine the audio preference when the
* HF device makes or answers a call. That is, if this device
- * makes or answers a call, is the audio preferred by HF should be decided
- * by this policy.
+ * makes or answers a call, is the audio preferred by HF.
+ * <p>If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, answering or making
+ * a call from the HF device will route the call audio to it.
+ * If set to {@link BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, answering or making
+ * a call from the HF device will NOT route the call audio to it.
*
* @return reference to the current object
+ *
+ * @hide
*/
public @NonNull Builder setCallEstablishPolicy(
@AudioPolicyValues int callEstablishPolicy) {
@@ -278,10 +276,16 @@
* is decided by this policy. This also covers the case of during a call.
* If the HF connects with the AG during an ongoing call, should the call
* audio be routed to the HF will be decided by this policy.
+ * <p>If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, connecting HF
+ * during a call will route the call audio to it.
+ * If set to {@link BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, connecting HF
+ * during a call will NOT route the call audio to it.
*
* @return reference to the current object
+ *
+ * @hide
*/
- public @NonNull Builder setConnectingTimePolicy(
+ public @NonNull Builder setActiveDevicePolicyAfterConnection(
@AudioPolicyValues int connectingTimePolicy) {
mConnectingTimePolicy = connectingTimePolicy;
return this;
@@ -292,9 +296,14 @@
* <p>This policy is used to determine the audio preference of the
* in band ringtone. That is, if there is an incoming call, should the
* inband ringtone audio be routed to the HF will be decided by this policy.
+ * <p>If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, there will be
+ * in band ringtone in the HF device during an incoming call.
+ * If set to {@link BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, there will NOT
+ * be in band ringtone in the HF device during an incoming call.
*
* @return reference to the current object
*
+ * @hide
*/
public @NonNull Builder setInBandRingtonePolicy(
@AudioPolicyValues int inBandRingtonePolicy) {
@@ -303,11 +312,13 @@
}
/**
- * Build {@link BluetoothAudioPolicy}.
- * @return new BluetoothAudioPolicy object
+ * Build {@link BluetoothSinkAudioPolicy}.
+ * @return new BluetoothSinkAudioPolicy object
+ *
+ * @hide
*/
- public @NonNull BluetoothAudioPolicy build() {
- return new BluetoothAudioPolicy(
+ public @NonNull BluetoothSinkAudioPolicy build() {
+ return new BluetoothSinkAudioPolicy(
mCallEstablishPolicy, mConnectingTimePolicy, mInBandRingtonePolicy);
}
}
diff --git a/framework/java/android/bluetooth/BluetoothSocket.java b/framework/java/android/bluetooth/BluetoothSocket.java
index ef2f7b8..b57bfca 100644
--- a/framework/java/android/bluetooth/BluetoothSocket.java
+++ b/framework/java/android/bluetooth/BluetoothSocket.java
@@ -285,7 +285,7 @@
BluetoothSocket as = new BluetoothSocket(this);
as.mSocketState = SocketState.CONNECTED;
FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors();
- if (DBG) Log.d(TAG, "socket fd passed by stack fds: " + Arrays.toString(fds));
+ if (DBG) Log.d(TAG, "acceptSocket: socket fd passed by stack fds:" + Arrays.toString(fds));
if (fds == null || fds.length != 1) {
Log.e(TAG, "socket fd passed from stack failed, fds: " + Arrays.toString(fds));
as.close();
@@ -450,6 +450,7 @@
throw new IOException("bt socket closed");
}
mSocketState = SocketState.CONNECTED;
+ if (DBG) Log.d(TAG, "connect(), socket connected");
}
} catch (RemoteException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
@@ -536,8 +537,8 @@
if (mSocketState != SocketState.LISTENING) {
throw new IOException("bt socket is not in listen state");
}
+ Log.d(TAG, "accept(), timeout (ms):" + timeout);
if (timeout > 0) {
- Log.d(TAG, "accept() set timeout (ms):" + timeout);
mSocket.setSoTimeout(timeout);
}
String RemoteAddr = waitSocketSignal(mSocketIS);
diff --git a/framework/java/android/bluetooth/BluetoothStatusCodes.java b/framework/java/android/bluetooth/BluetoothStatusCodes.java
index 35e03f5..24be7fc 100644
--- a/framework/java/android/bluetooth/BluetoothStatusCodes.java
+++ b/framework/java/android/bluetooth/BluetoothStatusCodes.java
@@ -216,6 +216,12 @@
public static final int ERROR_REMOTE_OPERATION_NOT_SUPPORTED = 27;
/**
+ * Indicates that the feature status is not configured yet.
+ * @hide
+ */
+ public static final int FEATURE_NOT_CONFIGURED = 30;
+
+ /**
* A GATT writeCharacteristic request is not permitted on the remote device.
*/
public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200;
diff --git a/system/audio_hal_interface/aidl/client_interface_aidl.cc b/system/audio_hal_interface/aidl/client_interface_aidl.cc
index efdc469..9af2803 100644
--- a/system/audio_hal_interface/aidl/client_interface_aidl.cc
+++ b/system/audio_hal_interface/aidl/client_interface_aidl.cc
@@ -55,9 +55,8 @@
}
bool BluetoothAudioClientInterface::is_aidl_available() {
- auto service = AServiceManager_checkService(
+ return AServiceManager_isDeclared(
kDefaultAudioProviderFactoryInterface.c_str());
- return (service != nullptr);
}
std::vector<AudioCapabilities>
@@ -72,7 +71,7 @@
return capabilities;
}
auto provider_factory = IBluetoothAudioProviderFactory::fromBinder(
- ::ndk::SpAIBinder(AServiceManager_getService(
+ ::ndk::SpAIBinder(AServiceManager_waitForService(
kDefaultAudioProviderFactoryInterface.c_str())));
if (provider_factory == nullptr) {
@@ -91,16 +90,15 @@
}
void BluetoothAudioClientInterface::FetchAudioProvider() {
- if (provider_ != nullptr) {
- LOG(WARNING) << __func__ << ": refetch";
- } else if (!is_aidl_available()) {
- // AIDL availability should only be checked at the beginning.
- // When refetching, AIDL may not be ready *yet* but it's expected to be
- // available later.
+ if (!is_aidl_available()) {
+ LOG(ERROR) << __func__ << ": aidl is not supported on this platform.";
return;
}
+ if (provider_ != nullptr) {
+ LOG(WARNING) << __func__ << ": refetch";
+ }
auto provider_factory = IBluetoothAudioProviderFactory::fromBinder(
- ::ndk::SpAIBinder(AServiceManager_getService(
+ ::ndk::SpAIBinder(AServiceManager_waitForService(
kDefaultAudioProviderFactoryInterface.c_str())));
if (provider_factory == nullptr) {
diff --git a/system/binder/android/bluetooth/BluetoothAudioPolicy.aidl b/system/binder/android/bluetooth/BluetoothSinkAudioPolicy.aidl
similarity index 94%
rename from system/binder/android/bluetooth/BluetoothAudioPolicy.aidl
rename to system/binder/android/bluetooth/BluetoothSinkAudioPolicy.aidl
index d06c286..740249c 100644
--- a/system/binder/android/bluetooth/BluetoothAudioPolicy.aidl
+++ b/system/binder/android/bluetooth/BluetoothSinkAudioPolicy.aidl
@@ -16,4 +16,4 @@
package android.bluetooth;
-parcelable BluetoothAudioPolicy;
+parcelable BluetoothSinkAudioPolicy;
diff --git a/system/binder/android/bluetooth/IBluetooth.aidl b/system/binder/android/bluetooth/IBluetooth.aidl
index d55dbc1..360220c 100644
--- a/system/binder/android/bluetooth/IBluetooth.aidl
+++ b/system/binder/android/bluetooth/IBluetooth.aidl
@@ -25,7 +25,7 @@
import android.bluetooth.IBluetoothSocketManager;
import android.bluetooth.IBluetoothStateChangeCallback;
import android.bluetooth.BluetoothActivityEnergyInfo;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.IncomingRfcommSocketInfo;
@@ -268,11 +268,11 @@
oneway void allowLowLatencyAudio(in boolean allowed, in BluetoothDevice device, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
- void getAudioPolicyRemoteSupported(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ void isRequestAudioPolicyAsSinkSupported(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
- void setAudioPolicy(in BluetoothDevice device, in BluetoothAudioPolicy policies, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ void requestAudioPolicyAsSink(in BluetoothDevice device, in BluetoothSinkAudioPolicy policies, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
- void getAudioPolicy(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ void getRequestedAudioPolicyAsSink(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
oneway void startRfcommListener(String name, in ParcelUuid uuid, in PendingIntent intent, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
diff --git a/system/binder/android/bluetooth/IBluetoothHeadsetClient.aidl b/system/binder/android/bluetooth/IBluetoothHeadsetClient.aidl
index d0adfdf..ad3316c 100644
--- a/system/binder/android/bluetooth/IBluetoothHeadsetClient.aidl
+++ b/system/binder/android/bluetooth/IBluetoothHeadsetClient.aidl
@@ -17,7 +17,7 @@
package android.bluetooth;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.BluetoothHeadsetClientCall;
import android.content.AttributionSource;
diff --git a/system/bta/gatt/bta_gattc_act.cc b/system/bta/gatt/bta_gattc_act.cc
index 48aa7b9..faa1bb1 100644
--- a/system/bta/gatt/bta_gattc_act.cc
+++ b/system/bta/gatt/bta_gattc_act.cc
@@ -34,6 +34,7 @@
#include "bta/hh/bta_hh_int.h"
#include "btif/include/btif_debug_conn.h"
#include "device/include/controller.h"
+#include "device/include/interop.h"
#include "main/shim/dumpsys.h"
#include "osi/include/allocator.h"
#include "osi/include/log.h"
@@ -802,6 +803,18 @@
p_clcb->p_srcb->srvc_hdl_db_hash = false;
}
+ // Some LMP 5.2 devices also don't support robust caching. This workaround
+ // conditionally disables the feature based on a combination of LMP
+ // version and OUI prefix.
+ if (lmp_version < 0x0c &&
+ interop_match_addr(INTEROP_DISABLE_ROBUST_CACHING, &p_clcb->bda)) {
+ LOG_WARN(
+ "Device LMP version 0x%02x <= Bluetooth 5.2 and MAC addr on "
+ "interop list, skipping robust caching",
+ lmp_version);
+ p_clcb->p_srcb->srvc_hdl_db_hash = false;
+ }
+
/* read db hash if db hash characteristic exists */
if (bta_gattc_is_robust_caching_enabled() &&
p_clcb->p_srcb->srvc_hdl_db_hash &&
diff --git a/system/bta/gatt/bta_gatts_act.cc b/system/bta/gatt/bta_gatts_act.cc
index 7f2457e..800fbf0 100644
--- a/system/bta/gatt/bta_gatts_act.cc
+++ b/system/bta/gatt/bta_gatts_act.cc
@@ -120,6 +120,8 @@
p_cb->enabled = true;
+ gatt_load_bonded();
+
if (!GATTS_NVRegister(&bta_gatts_nv_cback)) {
LOG(ERROR) << "BTA GATTS NV register failed.";
}
diff --git a/system/bta/gatt/bta_gatts_api.cc b/system/bta/gatt/bta_gatts_api.cc
index d0e4f44..5c69ab4 100644
--- a/system/bta/gatt/bta_gatts_api.cc
+++ b/system/bta/gatt/bta_gatts_api.cc
@@ -374,3 +374,11 @@
bta_sys_sendmsg(p_buf);
}
+
+void BTA_GATTS_InitBonded(void) {
+ LOG(INFO) << __func__;
+
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
+ p_buf->event = BTA_GATTS_API_INIT_BONDED_EVT;
+ bta_sys_sendmsg(p_buf);
+}
diff --git a/system/bta/gatt/bta_gatts_int.h b/system/bta/gatt/bta_gatts_int.h
index f989e09..7672130 100644
--- a/system/bta/gatt/bta_gatts_int.h
+++ b/system/bta/gatt/bta_gatts_int.h
@@ -51,7 +51,9 @@
BTA_GATTS_API_OPEN_EVT,
BTA_GATTS_API_CANCEL_OPEN_EVT,
BTA_GATTS_API_CLOSE_EVT,
- BTA_GATTS_API_DISABLE_EVT
+ BTA_GATTS_API_DISABLE_EVT,
+
+ BTA_GATTS_API_INIT_BONDED_EVT,
};
typedef uint16_t tBTA_GATTS_INT_EVT;
diff --git a/system/bta/gatt/bta_gatts_main.cc b/system/bta/gatt/bta_gatts_main.cc
index 97e9a3d..458f5e2 100644
--- a/system/bta/gatt/bta_gatts_main.cc
+++ b/system/bta/gatt/bta_gatts_main.cc
@@ -105,6 +105,10 @@
break;
}
+ case BTA_GATTS_API_INIT_BONDED_EVT:
+ gatt_load_bonded();
+ break;
+
default:
break;
}
diff --git a/system/bta/hd/bta_hd_api.cc b/system/bta/hd/bta_hd_api.cc
index a0d4802..93a9155 100644
--- a/system/bta/hd/bta_hd_api.cc
+++ b/system/bta/hd/bta_hd_api.cc
@@ -79,7 +79,10 @@
void BTA_HdDisable(void) {
APPL_TRACE_API("%s", __func__);
- bta_sys_deregister(BTA_ID_HD);
+ if (!bluetooth::common::init_flags::
+ delay_hidh_cleanup_until_hidh_ready_start_is_enabled()) {
+ bta_sys_deregister(BTA_ID_HD);
+ }
BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_HD_API_DISABLE_EVT;
diff --git a/system/bta/hearing_aid/hearing_aid.cc b/system/bta/hearing_aid/hearing_aid.cc
index d79e33d..8637f89 100644
--- a/system/bta/hearing_aid/hearing_aid.cc
+++ b/system/bta/hearing_aid/hearing_aid.cc
@@ -182,7 +182,8 @@
int read_rssi_start_interval_count = 0;
for (auto& d : devices) {
- VLOG(1) << __func__ << ": device=" << d.address << ", read_rssi_count=" << d.read_rssi_count;
+ LOG_DEBUG("device=%s, read_rssi_count=%d",
+ d.address.ToStringForLogging().c_str(), d.read_rssi_count);
// Reset the count
if (d.read_rssi_count <= 0) {
@@ -211,9 +212,8 @@
uint16_t handle, uint16_t len,
const uint8_t* value, void* data) {
if (status != GATT_SUCCESS) {
- LOG(ERROR) << __func__ << ": handle=" << handle << ", conn_id=" << conn_id
- << ", status=" << loghex(static_cast<uint8_t>(status))
- << ", length=" << len;
+ LOG_ERROR("handle= %hu, conn_id=%hu, status= %s, length=%u", handle,
+ conn_id, loghex(static_cast<uint8_t>(status)).c_str(), len);
}
}
@@ -222,7 +222,7 @@
inline void encoder_state_init() {
if (encoder_state_left != nullptr) {
- LOG(WARNING) << __func__ << ": encoder already initialized";
+ LOG_WARN("encoder already initialized");
return;
}
encoder_state_left = g722_encode_init(nullptr, 64000, G722_PACKED);
@@ -261,19 +261,16 @@
"persist.bluetooth.hearingaid.interval", (int32_t)HA_INTERVAL_20_MS);
if ((default_data_interval_ms != HA_INTERVAL_10_MS) &&
(default_data_interval_ms != HA_INTERVAL_20_MS)) {
- LOG(ERROR) << __func__
- << ": invalid interval=" << default_data_interval_ms
- << "ms. Overwriting back to default";
+ LOG_ERROR("invalid interval= %ums. Overwrriting back to default",
+ default_data_interval_ms);
default_data_interval_ms = HA_INTERVAL_20_MS;
}
- VLOG(2) << __func__
- << ", default_data_interval_ms=" << default_data_interval_ms;
+ LOG_DEBUG("default_data_interval_ms=%u", default_data_interval_ms);
overwrite_min_ce_len = (uint16_t)osi_property_get_int32(
"persist.bluetooth.hearingaidmincelen", 0);
if (overwrite_min_ce_len) {
- LOG(INFO) << __func__
- << ": Overwrites MIN_CE_LEN=" << overwrite_min_ce_len;
+ LOG_INFO("Overwrites MIN_CE_LEN=%u", overwrite_min_ce_len);
}
BTA_GATTC_AppRegister(
@@ -281,14 +278,15 @@
base::Bind(
[](Closure initCb, uint8_t client_id, uint8_t status) {
if (status != GATT_SUCCESS) {
- LOG(ERROR) << "Can't start Hearing Aid profile - no gatt "
- "clients left!";
+ LOG_ERROR(
+ "Can't start Hearing Aid profile - no gatt clients left!");
return;
}
instance->gatt_if = client_id;
initCb.Run();
},
- initCb), false);
+ initCb),
+ false);
}
uint16_t UpdateBleConnParams(const RawAddress& address) {
@@ -306,15 +304,15 @@
connection_interval = CONNECTION_INTERVAL_20MS_PARAM;
break;
default:
- LOG(ERROR) << __func__ << ":Error: invalid default_data_interval_ms="
- << default_data_interval_ms;
+ LOG_ERROR("invalid default_data_interval_ms=%u",
+ default_data_interval_ms);
min_ce_len = MIN_CE_LEN_10MS_CI;
connection_interval = CONNECTION_INTERVAL_10MS_PARAM;
}
if (overwrite_min_ce_len != 0) {
- VLOG(2) << __func__ << ": min_ce_len=" << min_ce_len
- << " is overwritten to " << overwrite_min_ce_len;
+ LOG_DEBUG("min_ce_len=%u is overwritten to %u", min_ce_len,
+ overwrite_min_ce_len);
min_ce_len = overwrite_min_ce_len;
}
@@ -323,22 +321,22 @@
return connection_interval;
}
- void Connect(const RawAddress& address) override {
- DVLOG(2) << __func__ << " " << address;
+ void Connect(const RawAddress& address) {
+ LOG_DEBUG("%s", address.ToStringForLogging().c_str());
hearingDevices.Add(HearingDevice(address, true));
BTA_GATTC_Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, false);
}
- void AddToAcceptlist(const RawAddress& address) override {
- VLOG(2) << __func__ << " address: " << address;
+ void AddToAcceptlist(const RawAddress& address) {
+ LOG_DEBUG("%s", address.ToStringForLogging().c_str());
hearingDevices.Add(HearingDevice(address, true));
BTA_GATTC_Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false);
}
void AddFromStorage(const HearingDevice& dev_info, uint16_t is_acceptlisted) {
- DVLOG(2) << __func__ << " " << dev_info.address
- << ", hiSyncId=" << loghex(dev_info.hi_sync_id)
- << ", isAcceptlisted=" << is_acceptlisted;
+ LOG_DEBUG("%s, hiSyncId=%s, isAcceptlisted=%u",
+ dev_info.address.ToStringForLogging().c_str(),
+ loghex(dev_info.hi_sync_id).c_str(), is_acceptlisted);
if (is_acceptlisted) {
hearingDevices.Add(dev_info);
@@ -364,13 +362,14 @@
if (!hearingDevice) {
/* When Hearing Aid is quickly disabled and enabled in settings, this case
* might happen */
- LOG(WARNING) << "Closing connection to non hearing-aid device, address="
- << address;
+ LOG_WARN("Closing connection to non hearing-aid device, address=%s",
+ address.ToStringForLogging().c_str());
BTA_GATTC_Close(conn_id);
return;
}
- LOG(INFO) << __func__ << ": address=" << address << ", conn_id=" << conn_id;
+ LOG_INFO("address=%s, conn_id=%u", address.ToStringForLogging().c_str(),
+ conn_id);
if (status != GATT_SUCCESS) {
if (!hearingDevice->connecting_actively) {
@@ -378,7 +377,7 @@
return;
}
- LOG(INFO) << "Failed to connect to Hearing Aid device";
+ LOG_INFO("Failed to connect to Hearing Aid device");
hearingDevices.Remove(address);
callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
return;
@@ -404,7 +403,7 @@
}
if (controller_get_interface()->supports_ble_2m_phy()) {
- LOG(INFO) << address << " set preferred 2M PHY";
+ LOG_INFO("%s set preferred 2M PHY", address.ToStringForLogging().c_str());
BTM_BleSetPhy(address, PHY_LE_2M, PHY_LE_2M, 0);
}
@@ -439,7 +438,7 @@
void OnConnectionUpdateComplete(uint16_t conn_id, tBTA_GATTC* p_data) {
HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
if (!hearingDevice) {
- DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+ LOG_DEBUG("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
return;
}
@@ -452,31 +451,29 @@
switch (hearingDevice->connection_update_status) {
case COMPLETED:
if (!same_conn_interval) {
- LOG(WARNING) << __func__
- << ": Unexpected change. Redo. connection interval="
- << p_data->conn_update.interval << ", expected="
- << hearingDevice->requested_connection_interval
- << ", conn_id=" << conn_id
- << ", connection_update_status="
- << hearingDevice->connection_update_status;
+ LOG_WARN(
+ "Unexpected change. Redo. connection interval=%u, "
+ "expected=%u, conn_id=%u, connection_update_status=%u",
+ p_data->conn_update.interval,
+ hearingDevice->requested_connection_interval, conn_id,
+ hearingDevice->connection_update_status);
// Redo this connection interval change.
hearingDevice->connection_update_status = AWAITING;
}
break;
case STARTED:
if (same_conn_interval) {
- LOG(INFO) << __func__
- << ": Connection update completed. conn_id=" << conn_id
- << ", device=" << hearingDevice->address;
+ LOG_INFO("Connection update completed. conn_id=%u, device=%s",
+ conn_id,
+ hearingDevice->address.ToStringForLogging().c_str());
hearingDevice->connection_update_status = COMPLETED;
} else {
- LOG(WARNING) << __func__
- << ": Ignored. Different connection interval="
- << p_data->conn_update.interval << ", expected="
- << hearingDevice->requested_connection_interval
- << ", conn_id=" << conn_id
- << ", connection_update_status="
- << hearingDevice->connection_update_status;
+ LOG_WARN(
+ "Ignored. Different connection interval=%u, expected=%u, "
+ "conn_id=%u, connection_update_status=%u",
+ p_data->conn_update.interval,
+ hearingDevice->requested_connection_interval, conn_id,
+ hearingDevice->connection_update_status);
// Wait for the right Connection Update Completion.
return;
}
@@ -494,16 +491,15 @@
send_state_change_to_other_side(hearingDevice, conn_update);
send_state_change(hearingDevice, conn_update);
} else {
- LOG(INFO) << __func__ << ": error status="
- << loghex(static_cast<uint8_t>(p_data->conn_update.status))
- << ", conn_id=" << conn_id
- << ", device=" << hearingDevice->address
- << ", connection_update_status="
- << hearingDevice->connection_update_status;
-
+ LOG_INFO(
+ "error status=%s, conn_id=%u,device=%s, "
+ "connection_update_status=%u",
+ loghex(static_cast<uint8_t>(p_data->conn_update.status)).c_str(),
+ conn_id, hearingDevice->address.ToStringForLogging().c_str(),
+ hearingDevice->connection_update_status);
if (hearingDevice->connection_update_status == STARTED) {
// Redo this connection interval change.
- LOG(ERROR) << __func__ << ": Redo Connection Interval change";
+ LOG_ERROR("Redo Connection Interval change");
hearingDevice->connection_update_status = AWAITING;
}
}
@@ -531,15 +527,18 @@
void OnReadRssiComplete(const RawAddress& address, int8_t rssi_value) {
HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
if (!hearingDevice) {
- LOG(INFO) << "Skipping unknown device" << address;
+ LOG_INFO("Skipping unknown device %s",
+ address.ToStringForLogging().c_str());
return;
}
- VLOG(1) << __func__ << ": device=" << address << ", rssi=" << (int)rssi_value;
+ LOG_DEBUG("device=%s, rss=%d", address.ToStringForLogging().c_str(),
+ (int)rssi_value);
if (hearingDevice->read_rssi_count <= 0) {
- LOG(ERROR) << __func__ << ": device=" << address
- << ", invalid read_rssi_count=" << hearingDevice->read_rssi_count;
+ LOG_ERROR(" device=%s, invalid read_rssi_count=%d",
+ address.ToStringForLogging().c_str(),
+ hearingDevice->read_rssi_count);
return;
}
@@ -548,7 +547,8 @@
if (hearingDevice->read_rssi_count == READ_RSSI_NUM_TRIES) {
// Store the timestamp only for the first one after packet flush
clock_gettime(CLOCK_REALTIME, &last_log_set.timestamp);
- LOG(INFO) << __func__ << ": store time. device=" << address << ", rssi=" << (int)rssi_value;
+ LOG_INFO("store time, device=%s, rssi=%d",
+ address.ToStringForLogging().c_str(), (int)rssi_value);
}
last_log_set.rssi.emplace_back(rssi_value);
@@ -558,12 +558,13 @@
void OnEncryptionComplete(const RawAddress& address, bool success) {
HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
if (!hearingDevice) {
- DVLOG(2) << "Skipping unknown device" << address;
+ LOG_DEBUG("Skipping unknown device %s",
+ address.ToStringForLogging().c_str());
return;
}
if (!success) {
- LOG(ERROR) << "encryption failed";
+ LOG_ERROR("encryption failed");
BTA_GATTC_Close(hearingDevice->conn_id);
if (hearingDevice->first_connection) {
callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
@@ -571,7 +572,7 @@
return;
}
- LOG(INFO) << __func__ << ": " << address;
+ LOG_INFO("%s", address.ToStringForLogging().c_str());
if (hearingDevice->audio_control_point_handle &&
hearingDevice->audio_status_handle &&
@@ -580,8 +581,8 @@
// Use cached data, jump to read PSM
ReadPSM(hearingDevice);
} else {
- LOG(INFO) << __func__ << ": " << address
- << ": do BTA_GATTC_ServiceSearchRequest";
+ LOG_INFO("%s: do BTA_GATTC_ServiceSearchRequest",
+ address.ToStringForLogging().c_str());
hearingDevice->first_connection = true;
BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
}
@@ -592,32 +593,34 @@
tGATT_STATUS status) {
HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
if (!hearingDevice) {
- DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+ LOG_DEBUG("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
return;
}
if (status != GATT_SUCCESS) {
- LOG(WARNING) << hearingDevice->address
- << " phy update fail with status: " << status;
+ LOG_WARN("%s phy update fail with status: %hu",
+ hearingDevice->address.ToStringForLogging().c_str(), status);
return;
}
if (tx_phys == PHY_LE_2M && rx_phys == PHY_LE_2M) {
- LOG(INFO) << hearingDevice->address << " phy update to 2M successful";
+ LOG_INFO("%s phy update to 2M successful",
+ hearingDevice->address.ToStringForLogging().c_str());
return;
}
- LOG(INFO)
- << hearingDevice->address
- << " phy update successful but not target phy, try again. tx_phys: "
- << tx_phys << ", rx_phys: " << rx_phys;
+ LOG_INFO(
+ "%s phy update successful but not target phy, try again. tx_phys: "
+ "%u,rx_phys: %u",
+ hearingDevice->address.ToStringForLogging().c_str(), tx_phys, rx_phys);
BTM_BleSetPhy(hearingDevice->address, PHY_LE_2M, PHY_LE_2M, 0);
}
void OnServiceChangeEvent(const RawAddress& address) {
HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
if (!hearingDevice) {
- VLOG(2) << "Skipping unknown device" << address;
+ LOG_DEBUG("Skipping unknown device %s",
+ address.ToStringForLogging().c_str());
return;
}
- LOG(INFO) << __func__ << ": address=" << address;
+ LOG_INFO("address=%s", address.ToStringForLogging().c_str());
hearingDevice->first_connection = true;
hearingDevice->service_changed_rcvd = true;
BtaGattQueue::Clean(hearingDevice->conn_id);
@@ -630,17 +633,18 @@
void OnServiceDiscDoneEvent(const RawAddress& address) {
HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
if (!hearingDevice) {
- VLOG(2) << "Skipping unknown device" << address;
+ LOG_DEBUG("Skipping unknown device %s",
+ address.ToStringForLogging().c_str());
return;
}
- LOG(INFO) << __func__ << ": " << address;
+ LOG_INFO("%s", address.ToStringForLogging().c_str());
if (hearingDevice->service_changed_rcvd ||
!(hearingDevice->audio_control_point_handle &&
hearingDevice->audio_status_handle &&
hearingDevice->audio_status_ccc_handle &&
hearingDevice->volume_handle && hearingDevice->read_psm_handle)) {
- LOG(INFO) << __func__ << ": " << address
- << ": do BTA_GATTC_ServiceSearchRequest";
+ LOG_INFO("%s: do BTA_GATTC_ServiceSearchRequest",
+ address.ToStringForLogging().c_str());
BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
}
}
@@ -648,7 +652,7 @@
void OnServiceSearchComplete(uint16_t conn_id, tGATT_STATUS status) {
HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
if (!hearingDevice) {
- DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+ LOG_DEBUG("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
return;
}
@@ -657,7 +661,7 @@
if (status != GATT_SUCCESS) {
/* close connection and report service discovery complete with error */
- LOG(ERROR) << "Service discovery failed";
+ LOG_ERROR("Service discovery failed");
if (hearingDevice->first_connection) {
callbacks->OnConnectionState(ConnectionState::DISCONNECTED,
hearingDevice->address);
@@ -670,18 +674,19 @@
const gatt::Service* service = nullptr;
for (const gatt::Service& tmp : *services) {
if (tmp.uuid == Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER)) {
- LOG(INFO) << "Found UUID_SERVCLASS_GATT_SERVER, handle="
- << loghex(tmp.handle);
+ LOG_INFO("Found UUID_SERVCLASS_GATT_SERVER, handle=%s",
+ loghex(tmp.handle).c_str());
const gatt::Service* service_changed_service = &tmp;
find_server_changed_ccc_handle(conn_id, service_changed_service);
} else if (tmp.uuid == HEARING_AID_UUID) {
- LOG(INFO) << "Found Hearing Aid service, handle=" << loghex(tmp.handle);
+ LOG_INFO("Found Hearing Aid service, handle=%s",
+ loghex(tmp.handle).c_str());
service = &tmp;
}
}
if (!service) {
- LOG(ERROR) << "No Hearing Aid service found";
+ LOG_ERROR("No Hearing Aid service found");
callbacks->OnConnectionState(ConnectionState::DISCONNECTED,
hearingDevice->address);
return;
@@ -693,8 +698,8 @@
hearingDevice->address, &hearingDevice->capabilities,
&hearingDevice->hi_sync_id, &hearingDevice->render_delay,
&hearingDevice->preparation_delay, &hearingDevice->codecs)) {
- VLOG(2) << "Reading read only properties "
- << loghex(charac.value_handle);
+ LOG_DEBUG("Reading read only properties %s",
+ loghex(charac.value_handle).c_str());
BtaGattQueue::ReadCharacteristic(
conn_id, charac.value_handle,
HearingAidImpl::OnReadOnlyPropertiesReadStatic, nullptr);
@@ -708,19 +713,20 @@
hearingDevice->audio_status_ccc_handle =
find_ccc_handle(conn_id, charac.value_handle);
if (!hearingDevice->audio_status_ccc_handle) {
- LOG(ERROR) << __func__ << ": cannot find Audio Status CCC descriptor";
+ LOG_ERROR("cannot find Audio Status CCC descriptor");
continue;
}
- LOG(INFO) << __func__
- << ": audio_status_handle=" << loghex(charac.value_handle)
- << ", ccc=" << loghex(hearingDevice->audio_status_ccc_handle);
+ LOG_INFO("audio_status_handle=%s, ccc=%s",
+ loghex(charac.value_handle).c_str(),
+ loghex(hearingDevice->audio_status_ccc_handle).c_str());
} else if (charac.uuid == VOLUME_UUID) {
hearingDevice->volume_handle = charac.value_handle;
} else if (charac.uuid == LE_PSM_UUID) {
hearingDevice->read_psm_handle = charac.value_handle;
} else {
- LOG(WARNING) << "Unknown characteristic found:" << charac.uuid;
+ LOG_WARN("Unknown characteristic found:%s",
+ charac.uuid.ToString().c_str());
}
}
@@ -733,8 +739,9 @@
void ReadPSM(HearingDevice* hearingDevice) {
if (hearingDevice->read_psm_handle) {
- LOG(INFO) << "Reading PSM " << loghex(hearingDevice->read_psm_handle)
- << ", device=" << hearingDevice->address;
+ LOG_INFO("Reading PSM %s, device=%s",
+ loghex(hearingDevice->read_psm_handle).c_str(),
+ hearingDevice->address.ToStringForLogging().c_str());
BtaGattQueue::ReadCharacteristic(
hearingDevice->conn_id, hearingDevice->read_psm_handle,
HearingAidImpl::OnPsmReadStatic, nullptr);
@@ -745,33 +752,29 @@
uint8_t* value) {
HearingDevice* device = hearingDevices.FindByConnId(conn_id);
if (!device) {
- LOG(INFO) << __func__
- << ": Skipping unknown device, conn_id=" << loghex(conn_id);
+ LOG_INFO("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
return;
}
if (device->audio_status_handle != handle) {
- LOG(INFO) << __func__ << ": Mismatched handle, "
- << loghex(device->audio_status_handle)
- << "!=" << loghex(handle);
+ LOG_INFO("Mismatched handle, %s!=%s",
+ loghex(device->audio_status_handle).c_str(),
+ loghex(handle).c_str());
return;
}
if (len < 1) {
- LOG(ERROR) << __func__ << ": Data Length too small, len=" << len
- << ", expecting at least 1";
+ LOG_ERROR("Data Length too small, len=%u, expecting at least 1", len);
return;
}
if (value[0] != 0) {
- LOG(INFO) << __func__
- << ": Invalid returned status. data=" << loghex(value[0]);
+ LOG_INFO("Invalid returned status. data=%s", loghex(value[0]).c_str());
return;
}
- LOG(INFO) << __func__
- << ": audio status success notification. command_acked="
- << device->command_acked;
+ LOG_INFO("audio status success notification. command_acked=%u",
+ device->command_acked);
device->command_acked = true;
}
@@ -780,11 +783,11 @@
void* data) {
HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
if (!hearingDevice) {
- DVLOG(2) << __func__ << "unknown conn_id=" << loghex(conn_id);
+ LOG_DEBUG("unknown conn_id=%s", loghex(conn_id).c_str());
return;
}
- VLOG(2) << __func__ << " " << base::HexEncode(value, len);
+ LOG_DEBUG("%s", base::HexEncode(value, len).c_str());
uint8_t* p = value;
@@ -792,13 +795,13 @@
STREAM_TO_UINT8(version, p);
if (version != 0x01) {
- LOG(WARNING) << "Unknown version: " << loghex(version);
+ LOG_WARN("Unknown version: %s", loghex(version).c_str());
return;
}
// version 0x01 of read only properties:
if (len < 17) {
- LOG(WARNING) << "Read only properties too short: " << loghex(len);
+ LOG_WARN("Read only properties too short: %s", loghex(len).c_str());
return;
}
uint8_t capabilities;
@@ -806,35 +809,34 @@
hearingDevice->capabilities = capabilities;
bool side = capabilities & CAPABILITY_SIDE;
bool standalone = capabilities & CAPABILITY_BINAURAL;
- VLOG(2) << __func__ << " capabilities: " << (side ? "right" : "left")
- << ", " << (standalone ? "binaural" : "monaural");
+ LOG_DEBUG("capabilities: %s, %s", (side ? "right" : "left"),
+ (standalone ? "binaural" : "monaural"));
if (capabilities & CAPABILITY_RESERVED) {
- LOG(WARNING) << __func__ << " reserved capabilities are set";
+ LOG_WARN("reserved capabilities are set");
}
STREAM_TO_UINT64(hearingDevice->hi_sync_id, p);
- VLOG(2) << __func__ << " hiSyncId: " << loghex(hearingDevice->hi_sync_id);
+ LOG_DEBUG("hiSyncId: %s", loghex(hearingDevice->hi_sync_id).c_str());
uint8_t feature_map;
STREAM_TO_UINT8(feature_map, p);
STREAM_TO_UINT16(hearingDevice->render_delay, p);
- VLOG(2) << __func__
- << " render delay: " << loghex(hearingDevice->render_delay);
+ LOG_DEBUG("render delay: %s", loghex(hearingDevice->render_delay).c_str());
STREAM_TO_UINT16(hearingDevice->preparation_delay, p);
- VLOG(2) << __func__ << " preparation delay: "
- << loghex(hearingDevice->preparation_delay);
+ LOG_DEBUG("preparation delay: %s",
+ loghex(hearingDevice->preparation_delay).c_str());
uint16_t codecs;
STREAM_TO_UINT16(codecs, p);
hearingDevice->codecs = codecs;
- VLOG(2) << __func__ << " supported codecs: " << loghex(codecs);
- if (codecs & (1 << CODEC_G722_16KHZ)) VLOG(2) << "\tG722@16kHz";
- if (codecs & (1 << CODEC_G722_24KHZ)) VLOG(2) << "\tG722@24kHz";
+ LOG_DEBUG("supported codecs: %s", loghex(codecs).c_str());
+ if (codecs & (1 << CODEC_G722_16KHZ)) LOG_INFO("%s\tG722@16kHz", __func__);
+ if (codecs & (1 << CODEC_G722_24KHZ)) LOG_INFO("%s\tG722@24kHz", __func__);
if (!(codecs & (1 << CODEC_G722_16KHZ))) {
- LOG(WARNING) << __func__ << " Mandatory codec, G722@16kHz not supported";
+ LOG_WARN("Mandatory codec, G722@16kHz not supported");
}
}
@@ -883,29 +885,31 @@
void OnAudioStatus(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
uint16_t len, uint8_t* value, void* data) {
- LOG(INFO) << __func__ << " " << base::HexEncode(value, len);
+ LOG_INFO("%s", base::HexEncode(value, len).c_str());
}
void OnPsmRead(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
uint16_t len, uint8_t* value, void* data) {
HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
if (!hearingDevice) {
- DVLOG(2) << "Skipping unknown read event, conn_id=" << loghex(conn_id);
+ LOG_DEBUG("Skipping unknown read event, conn_id=%s",
+ loghex(conn_id).c_str());
return;
}
if (status != GATT_SUCCESS) {
- LOG(ERROR) << "Error reading PSM for device" << hearingDevice->address;
+ LOG_ERROR("Error reading PSM for device %s",
+ hearingDevice->address.ToStringForLogging().c_str());
return;
}
if (len > 2) {
- LOG(ERROR) << "Bad PSM length";
+ LOG_ERROR("Bad PSM Lengh");
return;
}
uint16_t psm = *((uint16_t*)value);
- VLOG(2) << "read psm:" << loghex(psm);
+ LOG_DEBUG("read psm:%s", loghex(psm).c_str());
if (hearingDevice->gap_handle == GAP_INVALID_HANDLE &&
BTM_IsEncrypted(hearingDevice->address, BT_TRANSPORT_LE)) {
@@ -926,12 +930,12 @@
&cfg_info, nullptr, BTM_SEC_NONE /* TODO: request security ? */,
HearingAidImpl::GapCallbackStatic, BT_TRANSPORT_LE);
if (gap_handle == GAP_INVALID_HANDLE) {
- LOG(ERROR) << "UNABLE TO GET gap_handle";
+ LOG_ERROR("UNABLE TO GET gap_handle");
return;
}
hearingDevice->gap_handle = gap_handle;
- LOG(INFO) << "Successfully sent GAP connect request";
+ LOG_INFO("Successfully sent GAP connect request");
}
static void OnReadOnlyPropertiesReadStatic(uint16_t conn_id,
@@ -960,7 +964,8 @@
void OnDeviceReady(const RawAddress& address) {
HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
if (!hearingDevice) {
- LOG(INFO) << "Device not connected to profile" << address;
+ LOG_INFO("Device not connected to profile %s",
+ address.ToStringForLogging().c_str());
return;
}
@@ -970,19 +975,17 @@
hearingDevice->first_connection = false;
}
- LOG(INFO) << __func__ << ": audio_status_handle="
- << loghex(hearingDevice->audio_status_handle)
- << ", audio_status_ccc_handle="
- << loghex(hearingDevice->audio_status_ccc_handle);
+ LOG_INFO("audio_status_handle=%s, audio_status_ccc_handle=%s",
+ loghex(hearingDevice->audio_status_handle).c_str(),
+ loghex(hearingDevice->audio_status_ccc_handle).c_str());
/* Register and enable the Audio Status Notification */
tGATT_STATUS register_status;
register_status = BTA_GATTC_RegisterForNotifications(
gatt_if, address, hearingDevice->audio_status_handle);
if (register_status != GATT_SUCCESS) {
- LOG(ERROR) << __func__
- << ": BTA_GATTC_RegisterForNotifications failed, status="
- << loghex(static_cast<uint8_t>(register_status));
+ LOG_ERROR("BTA_GATTC_RegisterForNotifications failed, status=%s",
+ loghex(static_cast<uint8_t>(register_status)).c_str());
return;
}
std::vector<uint8_t> value(2);
@@ -1005,10 +1008,10 @@
hearingDevice->connecting_actively = false;
hearingDevice->accepting_audio = true;
- LOG(INFO) << __func__ << ": address=" << address
- << ", hi_sync_id=" << loghex(hearingDevice->hi_sync_id)
- << ", codec_in_use=" << loghex(codec_in_use)
- << ", audio_running=" << audio_running;
+ LOG_INFO("address=%s, hi_sync_id=%s, codec_in_use=%s, audio_running=%i",
+ address.ToStringForLogging().c_str(),
+ loghex(hearingDevice->hi_sync_id).c_str(),
+ loghex(codec_in_use).c_str(), audio_running);
StartSendingAudio(*hearingDevice);
@@ -1018,7 +1021,7 @@
}
void StartSendingAudio(const HearingDevice& hearingDevice) {
- VLOG(0) << __func__ << ": device=" << hearingDevice.address;
+ LOG_DEBUG("device=%s", hearingDevice.address.ToStringForLogging().c_str());
if (encoder_state_left == nullptr) {
encoder_state_init();
@@ -1048,9 +1051,9 @@
CHECK(stop_audio_ticks) << "stop_audio_ticks is empty";
if (!audio_running) {
- LOG(WARNING) << __func__ << ": Unexpected audio suspend";
+ LOG_WARN("Unexpected audio suspend");
} else {
- LOG(INFO) << __func__ << ": audio_running=" << audio_running;
+ LOG_INFO("audio_running=%i", audio_running);
}
audio_running = false;
stop_audio_ticks();
@@ -1060,11 +1063,11 @@
if (!device.accepting_audio) continue;
if (!device.playback_started) {
- LOG(WARNING) << __func__
- << ": Playback not started, skip send Stop cmd, device="
- << device.address;
+ LOG_WARN("Playback not started, skip send Stop cmd, device=%s",
+ device.address.ToStringForLogging().c_str());
} else {
- LOG(INFO) << __func__ << ": send Stop cmd, device=" << device.address;
+ LOG_INFO("send Stop cmd, device=%s",
+ device.address.ToStringForLogging().c_str());
device.playback_started = false;
device.command_acked = false;
BtaGattQueue::WriteCharacteristic(device.conn_id,
@@ -1078,9 +1081,9 @@
CHECK(start_audio_ticks) << "start_audio_ticks is empty";
if (audio_running) {
- LOG(ERROR) << __func__ << ": Unexpected Audio Resume";
+ LOG_ERROR("Unexpected Audio Resume");
} else {
- LOG(INFO) << __func__ << ": audio_running=" << audio_running;
+ LOG_INFO("audio_running=%i", audio_running);
}
for (auto& device : hearingDevices.devices) {
@@ -1090,8 +1093,7 @@
}
if (!audio_running) {
- LOG(INFO) << __func__ << ": No device (0/" << GetDeviceCount()
- << ") ready to start";
+ LOG_INFO("No device (0/%d) ready to start", GetDeviceCount());
return;
}
@@ -1119,8 +1121,8 @@
}
void SendEnableServiceChangedInd(HearingDevice* device) {
- VLOG(2) << __func__ << " Enable " << device->address
- << "service changed ind.";
+ LOG_DEBUG("Enable service changed ind.%s",
+ device->address.ToStringForLogging().c_str());
std::vector<uint8_t> value(2);
uint8_t* ptr = value.data();
UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_INDICTION);
@@ -1136,13 +1138,11 @@
if (!audio_running) {
if (!device->playback_started) {
- LOG(INFO) << __func__
- << ": Skip Send Start since audio is not running, device="
- << device->address;
+ LOG_INFO("Skip Send Start since audio is not running, device=%s",
+ device->address.ToStringForLogging().c_str());
} else {
- LOG(ERROR) << __func__
- << ": Audio not running but Playback has started, device="
- << device->address;
+ LOG_ERROR("Audio not running but Playback has started, device=%s",
+ device->address.ToStringForLogging().c_str());
}
return;
}
@@ -1150,15 +1150,16 @@
if (current_volume == VOLUME_UNKNOWN) start[3] = (uint8_t)VOLUME_MIN;
if (device->playback_started) {
- LOG(ERROR) << __func__
- << ": Playback already started, skip send Start cmd, device="
- << device->address;
+ LOG_ERROR("Playback already started, skip send Start cmd, device=%s",
+ device->address.ToStringForLogging().c_str());
} else {
start[4] = GetOtherSideStreamStatus(device);
- LOG(INFO) << __func__ << ": send Start cmd, volume=" << loghex(start[3])
- << ", audio type=" << loghex(start[2])
- << ", device=" << device->address
- << ", other side streaming=" << loghex(start[4]);
+ LOG_INFO(
+ "send Start cmd, volume=%s, audio type=%s, device=%s, other side "
+ "streaming=%s",
+ loghex(start[3]).c_str(), loghex(start[2]).c_str(),
+ device->address.ToStringForLogging().c_str(),
+ loghex(start[4]).c_str());
device->command_acked = false;
BtaGattQueue::WriteCharacteristic(
device->conn_id, device->audio_control_point_handle, start,
@@ -1171,12 +1172,12 @@
uint16_t len, const uint8_t* value,
void* data) {
if (status != GATT_SUCCESS) {
- LOG(ERROR) << __func__ << ": handle=" << handle << ", conn_id=" << conn_id
- << ", status=" << loghex(static_cast<uint8_t>(status));
+ LOG_ERROR("handle=%u, conn_id=%u, status=%s", handle, conn_id,
+ loghex(static_cast<uint8_t>(status)).c_str());
return;
}
if (!instance) {
- LOG(ERROR) << __func__ << ": instance is null.";
+ LOG_ERROR("instance is null");
return;
}
instance->StartAudioCtrlCallback(conn_id);
@@ -1185,10 +1186,10 @@
void StartAudioCtrlCallback(uint16_t conn_id) {
HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
if (!hearingDevice) {
- LOG(ERROR) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+ LOG_ERROR("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
return;
}
- LOG(INFO) << __func__ << ": device: " << hearingDevice->address;
+ LOG_INFO("device: %s", hearingDevice->address.ToStringForLogging().c_str());
hearingDevice->playback_started = true;
}
@@ -1203,7 +1204,7 @@
bool NeedToDropPacket(HearingDevice* target_side, HearingDevice* other_side) {
// Just drop packet if the other side does not exist.
if (!other_side) {
- VLOG(2) << __func__ << ": other side not connected to profile";
+ LOG_DEBUG("other side not connected to profile");
return true;
}
@@ -1212,14 +1213,14 @@
uint16_t target_current_credit = L2CA_GetPeerLECocCredit(
target_side->address, GAP_ConnGetL2CAPCid(target_side->gap_handle));
if (target_current_credit == L2CAP_LE_CREDIT_MAX) {
- LOG(ERROR) << __func__ << ": Get target side credit value fail.";
+ LOG_ERROR("Get target side credit value fail.");
return true;
}
uint16_t other_current_credit = L2CA_GetPeerLECocCredit(
other_side->address, GAP_ConnGetL2CAPCid(other_side->gap_handle));
if (other_current_credit == L2CAP_LE_CREDIT_MAX) {
- LOG(ERROR) << __func__ << ": Get other side credit value fail.";
+ LOG_ERROR("Get other side credit value fail.");
return true;
}
@@ -1228,24 +1229,23 @@
} else {
diff_credit = other_current_credit - target_current_credit;
}
- VLOG(2) << __func__ << ": Target(" << target_side->address
- << ") Credit: " << target_current_credit << ", Other("
- << other_side->address << ") Credit: " << other_current_credit
- << ", Init Credit: " << init_credit;
+ LOG_DEBUG("Target(%s) Credit: %u, Other(%s) Credit: %u, Init Credit: %u",
+ target_side->address.ToStringForLogging().c_str(),
+ target_current_credit,
+ other_side->address.ToStringForLogging().c_str(),
+ other_current_credit, init_credit);
return diff_credit < (init_credit / 2 - 1);
}
void OnAudioDataReady(const std::vector<uint8_t>& data) {
/* For now we assume data comes in as 16bit per sample 16kHz PCM stereo */
- DVLOG(2) << __func__;
-
bool need_drop = false;
int num_samples =
data.size() / (2 /*bytes_per_sample*/ * 2 /*number of channels*/);
// The G.722 codec accept only even number of samples for encoding
if (num_samples % 2 != 0)
- LOG(FATAL) << "num_samples is not even: " << num_samples;
+ LOG_ALWAYS_FATAL("num_samples is not even: %d", num_samples);
// TODO: we should cache left/right and current state, instad of recomputing
// it for each packet, 100 times a second.
@@ -1261,8 +1261,7 @@
}
if (left == nullptr && right == nullptr) {
- LOG(WARNING) << __func__ << ": No more (0/" << GetDeviceCount()
- << ") devices ready";
+ LOG_WARN("No more (0/%d) devices ready", GetDeviceCount());
DoDisconnectAudioStop();
return;
}
@@ -1318,13 +1317,15 @@
// Compare the two sides LE CoC credit value to confirm need to drop or
// skip audio packet.
if (NeedToDropPacket(left, right)) {
- LOG(INFO) << left->address << " triggers dropping, "
- << packets_in_chans << " packets in channel";
+ LOG_INFO("%s triggers dropping, %u packets in channel",
+ left->address.ToStringForLogging().c_str(),
+ packets_in_chans);
need_drop = true;
left->audio_stats.trigger_drop_count++;
} else {
- LOG(INFO) << left->address << " skipping " << packets_in_chans
- << " packets";
+ LOG_INFO("%s skipping %u packets",
+ left->address.ToStringForLogging().c_str(),
+ packets_in_chans);
left->audio_stats.packet_flush_count += packets_in_chans;
left->audio_stats.frame_flush_count++;
L2CA_FlushChannel(cid, 0xffff);
@@ -1350,13 +1351,15 @@
// Compare the two sides LE CoC credit value to confirm need to drop or
// skip audio packet.
if (NeedToDropPacket(right, left)) {
- LOG(INFO) << right->address << " triggers dropping, "
- << packets_in_chans << " packets in channel";
+ LOG_INFO("%s triggers dropping, %u packets in channel",
+ right->address.ToStringForLogging().c_str(),
+ packets_in_chans);
need_drop = true;
right->audio_stats.trigger_drop_count++;
} else {
- LOG(INFO) << right->address << " skipping " << packets_in_chans
- << " packets";
+ LOG_INFO("%s skipping %u packets",
+ right->address.ToStringForLogging().c_str(),
+ packets_in_chans);
right->audio_stats.packet_flush_count += packets_in_chans;
right->audio_stats.frame_flush_count++;
L2CA_FlushChannel(cid, 0xffff);
@@ -1400,10 +1403,9 @@
void SendAudio(uint8_t* encoded_data, uint16_t packet_size,
HearingDevice* hearingAid) {
if (!hearingAid->playback_started || !hearingAid->command_acked) {
- VLOG(2) << __func__
- << ": Playback stalled, device=" << hearingAid->address
- << ", cmd send=" << hearingAid->playback_started
- << ", cmd acked=" << hearingAid->command_acked;
+ LOG_DEBUG("Playback stalled, device=%s,cmd send=%i, cmd acked=%i",
+ hearingAid->address.ToStringForLogging().c_str(),
+ hearingAid->playback_started, hearingAid->command_acked);
return;
}
@@ -1413,19 +1415,20 @@
p++;
memcpy(p, encoded_data, packet_size);
- DVLOG(2) << hearingAid->address << " : " << base::HexEncode(p, packet_size);
+ LOG_DEBUG("%s : %s", hearingAid->address.ToStringForLogging().c_str(),
+ base::HexEncode(p, packet_size).c_str());
uint16_t result = GAP_ConnWriteData(hearingAid->gap_handle, audio_packet);
if (result != BT_PASS) {
- LOG(ERROR) << " Error sending data: " << loghex(result);
+ LOG_ERROR("Error sending data: %s", loghex(result).c_str());
}
}
void GapCallback(uint16_t gap_handle, uint16_t event, tGAP_CB_DATA* data) {
HearingDevice* hearingDevice = hearingDevices.FindByGapHandle(gap_handle);
if (!hearingDevice) {
- LOG(INFO) << "Skipping unknown device, gap_handle=" << gap_handle;
+ LOG_INFO("Skipping unknown device, gap_handle=%u", gap_handle);
return;
}
@@ -1437,12 +1440,13 @@
init_credit =
L2CA_GetPeerLECocCredit(address, GAP_ConnGetL2CAPCid(gap_handle));
- LOG(INFO) << "GAP_EVT_CONN_OPENED " << address << ", tx_mtu=" << tx_mtu
- << ", init_credit=" << init_credit;
+ LOG_INFO("GAP_EVT_CONN_OPENED %s, tx_mtu=%u, init_credit=%u",
+ address.ToStringForLogging().c_str(), tx_mtu, init_credit);
HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
if (!hearingDevice) {
- LOG(INFO) << "Skipping unknown device" << address;
+ LOG_INFO("Skipping unknown device %s",
+ address.ToStringForLogging().c_str());
return;
}
hearingDevice->gap_opened = true;
@@ -1453,10 +1457,11 @@
}
case GAP_EVT_CONN_CLOSED:
- LOG(INFO) << __func__
- << ": GAP_EVT_CONN_CLOSED: " << hearingDevice->address
- << ", playback_started=" << hearingDevice->playback_started
- << ", accepting_audio=" << hearingDevice->accepting_audio;
+ LOG_INFO(
+ "GAP_EVT_CONN_CLOSED: %s, playback_started=%i, "
+ "accepting_audio=%i",
+ hearingDevice->address.ToStringForLogging().c_str(),
+ hearingDevice->playback_started, hearingDevice->accepting_audio);
if (!hearingDevice->accepting_audio) {
/* Disconnect connection when data channel is not available */
BTA_GATTC_Close(hearingDevice->conn_id);
@@ -1471,7 +1476,7 @@
}
break;
case GAP_EVT_CONN_DATA_AVAIL: {
- DVLOG(2) << "GAP_EVT_CONN_DATA_AVAIL";
+ LOG_DEBUG("GAP_EVT_CONN_DATA_AVAIL");
// only data we receive back from hearing aids are some stats, not
// really important, but useful now for debugging.
@@ -1484,28 +1489,28 @@
GAP_ConnReadData(gap_handle, buffer.data(), buffer.size(), &bytes_read);
if (bytes_read < 4) {
- LOG(WARNING) << " Wrong data length";
+ LOG_WARN("Wrong data length");
return;
}
uint8_t* p = buffer.data();
- DVLOG(1) << "stats from the hearing aid:";
+ LOG_DEBUG("stats from the hearing aid:");
for (size_t i = 0; i + 4 <= buffer.size(); i += 4) {
uint16_t event_counter, frame_index;
STREAM_TO_UINT16(event_counter, p);
STREAM_TO_UINT16(frame_index, p);
- DVLOG(1) << "event_counter=" << event_counter
- << " frame_index: " << frame_index;
+ LOG_DEBUG("event_counter=%u frame_index: %u", event_counter,
+ frame_index);
}
break;
}
case GAP_EVT_TX_EMPTY:
- DVLOG(2) << "GAP_EVT_TX_EMPTY";
+ LOG_DEBUG("GAP_EVT_TX_EMPTY");
break;
case GAP_EVT_CONN_CONGESTED:
- DVLOG(2) << "GAP_EVT_CONN_CONGESTED";
+ LOG_DEBUG("GAP_EVT_CONN_CONGESTED");
// TODO: make it into function
HearingAidAudioSource::Stop();
@@ -1515,7 +1520,7 @@
// encoder_state_right = nulllptr;
break;
case GAP_EVT_CONN_UNCONGESTED:
- DVLOG(2) << "GAP_EVT_CONN_UNCONGESTED";
+ LOG_DEBUG("GAP_EVT_CONN_UNCONGESTED");
break;
}
}
@@ -1544,8 +1549,8 @@
char temptime[20];
struct tm* tstamp = localtime(&rssi_logs.timestamp.tv_sec);
if (!strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp)) {
- LOG(ERROR) << __func__ << ": strftime fails. tm_sec=" << tstamp->tm_sec << ", tm_min=" << tstamp->tm_min
- << ", tm_hour=" << tstamp->tm_hour;
+ LOG_ERROR("strftime fails. tm_sec=%d, tm_min=%d, tm_hour=%d",
+ tstamp->tm_sec, tstamp->tm_min, tstamp->tm_hour);
strlcpy(temptime, "UNKNOWN TIME", sizeof(temptime));
}
snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime, rssi_logs.timestamp.tv_nsec / 1000000);
@@ -1586,22 +1591,22 @@
dprintf(fd, "%s", stream.str().c_str());
}
- void Disconnect(const RawAddress& address) override {
- DVLOG(2) << __func__;
+ void Disconnect(const RawAddress& address) {
HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
if (!hearingDevice) {
- LOG(INFO) << "Device not connected to profile" << address;
+ LOG_INFO("Device not connected to profile %s",
+ address.ToStringForLogging().c_str());
return;
}
- VLOG(2) << __func__ << ": " << address;
+ LOG_DEBUG("%s", address.ToStringForLogging().c_str());
bool connected = hearingDevice->accepting_audio;
bool connecting_by_user = hearingDevice->connecting_actively;
- LOG(INFO) << __func__ << ": " << hearingDevice->address
- << ", playback_started=" << hearingDevice->playback_started
- << ", accepting_audio=" << hearingDevice->accepting_audio;
+ LOG_INFO("%s, playback_started=%i, accepting_audio=%i",
+ hearingDevice->address.ToStringForLogging().c_str(),
+ hearingDevice->playback_started, hearingDevice->accepting_audio);
if (hearingDevice->connecting_actively) {
// cancel pending direct connect
@@ -1634,8 +1639,7 @@
for (const auto& device : hearingDevices.devices) {
if (device.accepting_audio) return;
}
- LOG(INFO) << __func__ << ": No more (0/" << GetDeviceCount()
- << ") devices ready";
+ LOG_INFO("No more (0/%d) devices ready", GetDeviceCount());
DoDisconnectAudioStop();
}
@@ -1643,12 +1647,12 @@
RawAddress remote_bda) {
HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
if (!hearingDevice) {
- VLOG(2) << "Skipping unknown device disconnect, conn_id="
- << loghex(conn_id);
+ LOG_DEBUG("Skipping unknown device disconnect, conn_id=%s",
+ loghex(conn_id).c_str());
return;
}
- VLOG(2) << __func__ << ": conn_id=" << loghex(conn_id)
- << ", remote_bda=" << remote_bda;
+ LOG_DEBUG("conn_id=%s, remote_bda=%s", loghex(conn_id).c_str(),
+ remote_bda.ToStringForLogging().c_str());
// Inform the other side (if any) of this disconnection
std::vector<uint8_t> inform_disconn_state(
@@ -1667,16 +1671,15 @@
for (const auto& device : hearingDevices.devices) {
if (device.accepting_audio) return;
}
- LOG(INFO) << __func__ << ": No more (0/" << GetDeviceCount()
- << ") devices ready";
+ LOG_INFO("No more (0/%d) devices ready", GetDeviceCount());
DoDisconnectAudioStop();
}
void DoDisconnectCleanUp(HearingDevice* hearingDevice) {
if (hearingDevice->connection_update_status != COMPLETED) {
- LOG(INFO) << __func__ << ": connection update not completed. Current="
- << hearingDevice->connection_update_status
- << ", device=" << hearingDevice->address;
+ LOG_INFO("connection update not completed. Current=%u, device=%s",
+ hearingDevice->connection_update_status,
+ hearingDevice->address.ToStringForLogging().c_str());
if (hearingDevice->connection_update_status == STARTED) {
OnConnectionUpdateComplete(hearingDevice->conn_id, NULL);
@@ -1697,8 +1700,9 @@
}
hearingDevice->accepting_audio = false;
- LOG(INFO) << __func__ << ": device=" << hearingDevice->address
- << ", playback_started=" << hearingDevice->playback_started;
+ LOG_INFO("device=%s, playback_started=%i",
+ hearingDevice->address.ToStringForLogging().c_str(),
+ hearingDevice->playback_started);
hearingDevice->playback_started = false;
hearingDevice->command_acked = false;
}
@@ -1710,8 +1714,8 @@
current_volume = VOLUME_UNKNOWN;
}
- void SetVolume(int8_t volume) override {
- VLOG(2) << __func__ << ": " << +volume;
+ void SetVolume(int8_t volume) {
+ LOG_DEBUG("%d", volume);
current_volume = volume;
for (HearingDevice& device : hearingDevices.devices) {
if (!device.accepting_audio) continue;
@@ -1754,7 +1758,7 @@
const gatt::Service* service) {
HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
if (!hearingDevice) {
- DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+ LOG_DEBUG("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
return;
}
for (const gatt::Characteristic& charac : service->characteristics) {
@@ -1762,12 +1766,11 @@
hearingDevice->service_changed_ccc_handle =
find_ccc_handle(conn_id, charac.value_handle);
if (!hearingDevice->service_changed_ccc_handle) {
- LOG(ERROR) << __func__
- << ": cannot find service changed CCC descriptor";
+ LOG_ERROR("cannot find service changed CCC descriptor");
continue;
}
- LOG(INFO) << __func__ << " service_changed_ccc="
- << loghex(hearingDevice->service_changed_ccc_handle);
+ LOG_INFO("service_changed_ccc=%s",
+ loghex(hearingDevice->service_changed_ccc_handle).c_str());
break;
}
}
@@ -1780,7 +1783,7 @@
BTA_GATTC_GetCharacteristic(conn_id, char_handle);
if (!p_char) {
- LOG(WARNING) << __func__ << ": No such characteristic: " << char_handle;
+ LOG_WARN("No such characteristic: %u", char_handle);
return 0;
}
@@ -1795,14 +1798,14 @@
void send_state_change(HearingDevice* device, std::vector<uint8_t> payload) {
if (device->conn_id != 0) {
if (device->service_changed_rcvd) {
- LOG(INFO)
- << __func__
- << ": service discover is in progress, skip send State Change cmd.";
+ LOG_INFO(
+ "service discover is in progress, skip send State Change cmd.");
return;
}
// Send the data packet
- LOG(INFO) << __func__ << ": Send State Change. device=" << device->address
- << ", status=" << loghex(payload[1]);
+ LOG_INFO("Send State Change. device=%s, status=%s",
+ device->address.ToStringForLogging().c_str(),
+ loghex(payload[1]).c_str());
BtaGattQueue::WriteCharacteristic(
device->conn_id, device->audio_control_point_handle, payload,
GATT_WRITE_NO_RSP, nullptr, nullptr);
@@ -1825,7 +1828,7 @@
device->num_intervals_since_last_rssi_read++;
if (device->num_intervals_since_last_rssi_read >= PERIOD_TO_READ_RSSI_IN_INTERVALS) {
device->num_intervals_since_last_rssi_read = 0;
- VLOG(1) << __func__ << ": device=" << device->address;
+ LOG_DEBUG("device=%s", device->address.ToStringForLogging().c_str());
BTM_ReadRSSI(device->address, read_rssi_cb);
}
}
@@ -1843,7 +1846,7 @@
}
void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
- VLOG(2) << __func__ << " event = " << +event;
+ LOG_DEBUG("event = %u", event);
if (p_data == nullptr) return;
@@ -1874,9 +1877,8 @@
case BTA_GATTC_NOTIF_EVT:
if (!instance) return;
if (!p_data->notify.is_notify || p_data->notify.len > GATT_MAX_ATTR_LEN) {
- LOG(ERROR) << __func__ << ": rejected BTA_GATTC_NOTIF_EVT. is_notify="
- << p_data->notify.is_notify
- << ", len=" << p_data->notify.len;
+ LOG_ERROR("rejected BTA_GATTC_NOTIF_EVT. is_notify=%i, len=%u",
+ p_data->notify.is_notify, p_data->notify.len);
break;
}
instance->OnNotificationEvent(p_data->notify.conn_id,
@@ -1945,7 +1947,8 @@
void HearingAid::Initialize(
bluetooth::hearing_aid::HearingAidCallbacks* callbacks, Closure initCb) {
if (instance) {
- LOG(ERROR) << "Already initialized!";
+ LOG_ERROR("Already initialized!");
+ return;
}
audioReceiver = &audioReceiverImpl;
@@ -1955,15 +1958,42 @@
bool HearingAid::IsHearingAidRunning() { return instance; }
-HearingAid* HearingAid::Get() {
- CHECK(instance);
- return instance;
-};
+void HearingAid::Connect(const RawAddress& address) {
+ if (!instance) {
+ LOG_ERROR("Hearing Aid instance is not available");
+ return;
+ }
+ instance->Connect(address);
+}
+
+void HearingAid::Disconnect(const RawAddress& address) {
+ if (!instance) {
+ LOG_ERROR("Hearing Aid instance is not available");
+ return;
+ }
+ instance->Disconnect(address);
+}
+
+void HearingAid::AddToAcceptlist(const RawAddress& address) {
+ if (!instance) {
+ LOG_ERROR("Hearing Aid instance is not available");
+ return;
+ }
+ instance->AddToAcceptlist(address);
+}
+
+void HearingAid::SetVolume(int8_t volume) {
+ if (!instance) {
+ LOG_ERROR("Hearing Aid instance is not available");
+ return;
+ }
+ instance->SetVolume(volume);
+}
void HearingAid::AddFromStorage(const HearingDevice& dev_info,
uint16_t is_acceptlisted) {
if (!instance) {
- LOG(ERROR) << "Not initialized yet";
+ LOG_ERROR("Not initialized yet");
}
instance->AddFromStorage(dev_info, is_acceptlisted);
@@ -1971,7 +2001,7 @@
int HearingAid::GetDeviceCount() {
if (!instance) {
- LOG(INFO) << __func__ << ": Not initialized yet";
+ LOG_INFO("Not initialized yet");
return 0;
}
diff --git a/system/bta/hearing_aid/hearing_aid_audio_source.cc b/system/bta/hearing_aid/hearing_aid_audio_source.cc
index c7dc6ae..e347f87 100644
--- a/system/bta/hearing_aid/hearing_aid_audio_source.cc
+++ b/system/bta/hearing_aid/hearing_aid_audio_source.cc
@@ -18,6 +18,7 @@
#include <base/files/file_util.h>
#include <base/logging.h>
+
#include <cstdint>
#include <memory>
#include <sstream>
@@ -28,6 +29,7 @@
#include "bta/include/bta_hearing_aid_api.h"
#include "common/repeating_timer.h"
#include "common/time_util.h"
+#include "osi/include/log.h"
#include "osi/include/wakelock.h"
#include "stack/include/btu.h" // get_main_thread
#include "udrv/include/uipc.h"
@@ -98,7 +100,7 @@
bytes_per_tick);
}
- VLOG(2) << "bytes_read: " << bytes_read;
+ LOG_DEBUG("bytes_read: %u", bytes_read);
if (bytes_read < bytes_per_tick) {
stats.media_read_total_underflow_bytes += bytes_per_tick - bytes_read;
stats.media_read_total_underflow_count++;
@@ -115,14 +117,14 @@
void hearing_aid_send_ack(tHEARING_AID_CTRL_ACK status) {
uint8_t ack = status;
- DVLOG(2) << "Hearing Aid audio ctrl ack: " << status;
+ LOG_DEBUG("Hearing Aid audio ctrl ack: %u", status);
UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
}
void start_audio_ticks() {
if (data_interval_ms != HA_INTERVAL_10_MS &&
data_interval_ms != HA_INTERVAL_20_MS) {
- LOG(FATAL) << " Unsupported data interval: " << data_interval_ms;
+ LOG_ALWAYS_FATAL("Unsupported data interval: %d", data_interval_ms);
}
wakelock_acquire();
@@ -133,20 +135,20 @@
#else
base::Milliseconds(data_interval_ms));
#endif
- LOG(INFO) << __func__ << ": running with data interval: " << data_interval_ms;
+ LOG_INFO("running with data interval: %d", data_interval_ms);
}
void stop_audio_ticks() {
- LOG(INFO) << __func__ << ": stopped";
+ LOG_INFO("stopped");
audio_timer.CancelAndWait();
wakelock_release();
}
void hearing_aid_data_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
- DVLOG(2) << "Hearing Aid audio data event: " << event;
+ LOG_DEBUG("Hearing Aid audio data event: %u", event);
switch (event) {
case UIPC_OPEN_EVT:
- LOG(INFO) << __func__ << ": UIPC_OPEN_EVT";
+ LOG_INFO("UIPC_OPEN_EVT");
/*
* Read directly from media task from here on (keep callback for
* connection events.
@@ -159,12 +161,12 @@
do_in_main_thread(FROM_HERE, base::BindOnce(start_audio_ticks));
break;
case UIPC_CLOSE_EVT:
- LOG(INFO) << __func__ << ": UIPC_CLOSE_EVT";
+ LOG_INFO("UIPC_CLOSE_EVT");
hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
do_in_main_thread(FROM_HERE, base::BindOnce(stop_audio_ticks));
break;
default:
- LOG(ERROR) << "Hearing Aid audio data event not recognized:" << event;
+ LOG_ERROR("Hearing Aid audio data event not recognized: %u", event);
}
}
@@ -178,12 +180,12 @@
/* detach on ctrl channel means audioflinger process was terminated */
if (n == 0) {
- LOG(WARNING) << __func__ << "CTRL CH DETACHED";
+ LOG_WARN("CTRL CH DETACHED");
UIPC_Close(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL);
return;
}
- LOG(INFO) << __func__ << " " << audio_ha_hw_dump_ctrl_event(cmd);
+ LOG_INFO("%s", audio_ha_hw_dump_ctrl_event(cmd));
// a2dp_cmd_pending = cmd;
tHEARING_AID_CTRL_ACK ctrl_ack_status;
@@ -207,7 +209,9 @@
case HEARING_AID_CTRL_CMD_STOP:
if (!hearing_aid_on_suspend_req()) {
- LOG(INFO) << __func__ << ":HEARING_AID_CTRL_CMD_STOP: hearing_aid_on_suspend_req() errs, but ignored.";
+ LOG_INFO(
+ "HEARING_AID_CTRL_CMD_STOP: hearing_aid_on_suspend_req() errs, but "
+ "ignored.");
}
hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
break;
@@ -230,7 +234,7 @@
codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_24000;
codec_capability.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_24000;
} else {
- LOG(FATAL) << "unsupported sample rate: " << sample_rate;
+ LOG_ALWAYS_FATAL("unsupported sample rate: %d", sample_rate);
}
codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
@@ -278,15 +282,14 @@
reinterpret_cast<uint8_t*>(&codec_config.sample_rate),
sizeof(btav_a2dp_codec_sample_rate_t)) !=
sizeof(btav_a2dp_codec_sample_rate_t)) {
- LOG(ERROR) << __func__ << "Error reading sample rate from audio HAL";
+ LOG_ERROR("Error reading sample rate from audio HAL");
break;
}
if (UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL,
reinterpret_cast<uint8_t*>(&codec_config.bits_per_sample),
sizeof(btav_a2dp_codec_bits_per_sample_t)) !=
sizeof(btav_a2dp_codec_bits_per_sample_t)) {
- LOG(ERROR) << __func__
- << "Error reading bits per sample from audio HAL";
+ LOG_ERROR("Error reading bits per sample from audio HAL");
break;
}
@@ -294,29 +297,28 @@
reinterpret_cast<uint8_t*>(&codec_config.channel_mode),
sizeof(btav_a2dp_codec_channel_mode_t)) !=
sizeof(btav_a2dp_codec_channel_mode_t)) {
- LOG(ERROR) << __func__ << "Error reading channel mode from audio HAL";
+ LOG_ERROR("Error reading channel mode from audio HAL");
break;
}
- LOG(INFO) << __func__ << " HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG: "
- << "sample_rate=" << codec_config.sample_rate
- << "bits_per_sample=" << codec_config.bits_per_sample
- << "channel_mode=" << codec_config.channel_mode;
+ LOG_INFO(
+ "HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG: sample_rate=%u, "
+ "bits_per_sample=%u,channel_mode=%u",
+ codec_config.sample_rate, codec_config.bits_per_sample,
+ codec_config.channel_mode);
break;
}
default:
- LOG(ERROR) << __func__ << "UNSUPPORTED CMD: " << cmd;
+ LOG_ERROR("UNSUPPORTED CMD: %u", cmd);
hearing_aid_send_ack(HEARING_AID_CTRL_ACK_FAILURE);
break;
}
- LOG(INFO) << __func__
- << " a2dp-ctrl-cmd : " << audio_ha_hw_dump_ctrl_event(cmd)
- << " DONE";
+ LOG_INFO("a2dp-ctrl-cmd : %s DONE", audio_ha_hw_dump_ctrl_event(cmd));
}
void hearing_aid_ctrl_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
- VLOG(2) << "Hearing Aid audio ctrl event: " << event;
+ LOG_DEBUG("Hearing Aid audio ctrl event: %u", event);
switch (event) {
case UIPC_OPEN_EVT:
break;
@@ -331,14 +333,13 @@
hearing_aid_recv_ctrl_data();
break;
default:
- LOG(ERROR) << "Hearing Aid audio ctrl unrecognized event: " << event;
+ LOG_ERROR("Hearing Aid audio ctrl unrecognized event: %u", event);
}
}
bool hearing_aid_on_resume_req(bool start_media_task) {
if (localAudioReceiver == nullptr) {
- LOG(ERROR) << __func__
- << ": HEARING_AID_CTRL_CMD_START: audio receiver not started";
+ LOG_ERROR("HEARING_AID_CTRL_CMD_START: audio receiver not started");
return false;
}
bt_status_t status;
@@ -349,7 +350,7 @@
start_audio_ticks));
} else {
auto start_dummy_ticks = []() {
- LOG(INFO) << "start_audio_ticks: waiting for data path opened";
+ LOG_INFO("start_audio_ticks: waiting for data path opened");
};
status = do_in_main_thread(
FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
@@ -357,9 +358,7 @@
start_dummy_ticks));
}
if (status != BT_STATUS_SUCCESS) {
- LOG(ERROR) << __func__
- << ": HEARING_AID_CTRL_CMD_START: do_in_main_thread err="
- << status;
+ LOG_ERROR("HEARING_AID_CTRL_CMD_START: do_in_main_thread err=%u", status);
return false;
}
return true;
@@ -367,8 +366,7 @@
bool hearing_aid_on_suspend_req() {
if (localAudioReceiver == nullptr) {
- LOG(ERROR) << __func__
- << ": HEARING_AID_CTRL_CMD_SUSPEND: audio receiver not started";
+ LOG_ERROR("HEARING_AID_CTRL_CMD_SUSPEND: audio receiver not started");
return false;
}
bt_status_t status = do_in_main_thread(
@@ -376,9 +374,7 @@
base::BindOnce(&HearingAidAudioReceiver::OnAudioSuspend,
base::Unretained(localAudioReceiver), stop_audio_ticks));
if (status != BT_STATUS_SUCCESS) {
- LOG(ERROR) << __func__
- << ": HEARING_AID_CTRL_CMD_SUSPEND: do_in_main_thread err="
- << status;
+ LOG_ERROR("HEARING_AID_CTRL_CMD_SUSPEND: do_in_main_thread err=%u", status);
return false;
}
return true;
@@ -388,7 +384,7 @@
void HearingAidAudioSource::Start(const CodecConfiguration& codecConfiguration,
HearingAidAudioReceiver* audioReceiver,
uint16_t remote_delay_ms) {
- LOG(INFO) << __func__ << ": Hearing Aid Source Open";
+ LOG_INFO("Hearing Aid Source Open");
bit_rate = codecConfiguration.bit_rate;
sample_rate = codecConfiguration.sample_rate;
@@ -404,7 +400,7 @@
}
void HearingAidAudioSource::Stop() {
- LOG(INFO) << __func__ << ": Hearing Aid Source Close";
+ LOG_INFO("Hearing Aid Source Close");
localAudioReceiver = nullptr;
if (bluetooth::audio::hearing_aid::is_hal_enabled()) {
@@ -420,7 +416,7 @@
.on_suspend_ = hearing_aid_on_suspend_req,
};
if (!bluetooth::audio::hearing_aid::init(stream_cb, get_main_thread())) {
- LOG(WARNING) << __func__ << ": Using legacy HAL";
+ LOG_WARN("Using legacy HAL");
uipc_hearing_aid = UIPC_Init();
UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb, HEARING_AID_CTRL_PATH);
}
diff --git a/system/bta/hf_client/bta_hf_client_at.cc b/system/bta/hf_client/bta_hf_client_at.cc
index 7a710bf..97fcb97 100644
--- a/system/bta/hf_client/bta_hf_client_at.cc
+++ b/system/bta/hf_client/bta_hf_client_at.cc
@@ -2149,7 +2149,7 @@
at_len = snprintf(buf, sizeof(buf), "AT+BIA=");
const int32_t position = osi_property_get_int32(
- "bluetooth.headsetclient.disable_indicator.position", -1);
+ "bluetooth.headset_client.disable_indicator.position", -1);
for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) {
int sup = client_cb->at_cb.indicator_lookup[i] == -1 ? 0 : 1;
diff --git a/system/bta/hh/bta_hh_le.cc b/system/bta/hh/bta_hh_le.cc
index ffcbf7f..776a5a3 100644
--- a/system/bta/hh/bta_hh_le.cc
+++ b/system/bta/hh/bta_hh_le.cc
@@ -1015,7 +1015,8 @@
bta_hh_status_text(p_cb->status).c_str(),
btm_status_text(p_cb->btm_status).c_str());
if (!(p_cb->status == BTA_HH_ERR_SEC &&
- p_cb->btm_status == BTM_ERR_PROCESSING))
+ (p_cb->btm_status == BTM_ERR_PROCESSING ||
+ p_cb->btm_status == BTM_FAILED_ON_SECURITY)))
bta_hh_le_api_disc_act(p_cb);
}
}
diff --git a/system/bta/include/bta_gatt_api.h b/system/bta/include/bta_gatt_api.h
index d334bcc..9fd4db8 100644
--- a/system/bta/include/bta_gatt_api.h
+++ b/system/bta/include/bta_gatt_api.h
@@ -999,4 +999,7 @@
******************************************************************************/
extern void BTA_GATTS_Close(uint16_t conn_id);
+// Adds bonded device for GATT server tracking service changes
+extern void BTA_GATTS_InitBonded(void);
+
#endif /* BTA_GATT_API_H */
diff --git a/system/bta/include/bta_hearing_aid_api.h b/system/bta/include/bta_hearing_aid_api.h
index 90803c5..d1b930b 100644
--- a/system/bta/include/bta_hearing_aid_api.h
+++ b/system/bta/include/bta_hearing_aid_api.h
@@ -228,7 +228,6 @@
base::Closure initCb);
static void CleanUp();
static bool IsHearingAidRunning();
- static HearingAid* Get();
static void DebugDump(int fd);
static void AddFromStorage(const HearingDevice& dev_info,
@@ -236,10 +235,10 @@
static int GetDeviceCount();
- virtual void Connect(const RawAddress& address) = 0;
- virtual void Disconnect(const RawAddress& address) = 0;
- virtual void AddToAcceptlist(const RawAddress& address) = 0;
- virtual void SetVolume(int8_t volume) = 0;
+ static void Connect(const RawAddress& address);
+ static void Disconnect(const RawAddress& address);
+ static void AddToAcceptlist(const RawAddress& address);
+ static void SetVolume(int8_t volume);
};
/* Represents configuration of audio codec, as exchanged between hearing aid and
diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc
index c9a89bc..1d3cb3f 100644
--- a/system/bta/le_audio/client.cc
+++ b/system/bta/le_audio/client.cc
@@ -1350,15 +1350,15 @@
leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTING);
- if (acl_force_disconnect) {
- leAudioDevice->DisconnectAcl();
- return;
- }
-
BtaGattQueue::Clean(leAudioDevice->conn_id_);
BTA_GATTC_Close(leAudioDevice->conn_id_);
leAudioDevice->conn_id_ = GATT_INVALID_CONN_ID;
leAudioDevice->mtu_ = 0;
+
+ /* Remote in bad state, force ACL Disconnection. */
+ if (acl_force_disconnect) {
+ leAudioDevice->DisconnectAcl();
+ }
}
void DeregisterNotifications(LeAudioDevice* leAudioDevice) {
diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc
index 49f80f5..9b91b43 100644
--- a/system/bta/le_audio/state_machine.cc
+++ b/system/bta/le_audio/state_machine.cc
@@ -681,8 +681,6 @@
LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
const bluetooth::hci::iso_manager::cis_establish_cmpl_evt* event)
override {
- std::vector<uint8_t> value;
-
auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(event->cis_conn_hdl);
if (event->status) {
@@ -734,11 +732,17 @@
}
if (!leAudioDevice->HaveAllActiveAsesCisEst()) {
- /* More cis established event has to come */
+ /* More cis established events has to come */
return;
}
- std::vector<uint8_t> ids;
+ if (!leAudioDevice->IsReadyToCreateStream()) {
+ /* Device still remains in ready to create stream state. It means that
+ * more enabling status notifications has to come. This may only happen
+ * for reconnection scenario for bi-directional CIS.
+ */
+ return;
+ }
/* All CISes created. Send start ready for source ASE before we can go
* to streaming state.
@@ -749,21 +753,8 @@
"id: %d, cis handle 0x%04x",
leAudioDevice->address_.ToString().c_str(), event->cig_id,
event->cis_conn_hdl);
- do {
- if (ase->direction == le_audio::types::kLeAudioDirectionSource)
- ids.push_back(ase->id);
- } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
- if (ids.size() > 0) {
- le_audio::client_parser::ascs::PrepareAseCtpAudioReceiverStartReady(
- ids, value);
-
- BtaGattQueue::WriteCharacteristic(leAudioDevice->conn_id_,
- leAudioDevice->ctp_hdls_.val_hdl, value,
- GATT_WRITE_NO_RSP, NULL, NULL);
-
- return;
- }
+ PrepareAndSendReceiverStartReady(leAudioDevice, ase);
/* Cis establishment may came after setting group state to streaming, e.g.
* for autonomous scenario when ase is sink */
@@ -850,6 +841,7 @@
}
LOG_INFO("Lost all members from the group %d", group->group_id_);
+ group->cises_.clear();
RemoveCigForGroup(group);
group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
@@ -2187,6 +2179,28 @@
}
}
+ void PrepareAndSendReceiverStartReady(LeAudioDevice* leAudioDevice,
+ struct ase* ase) {
+ std::vector<uint8_t> ids;
+ std::vector<uint8_t> value;
+
+ do {
+ if (ase->direction == le_audio::types::kLeAudioDirectionSource)
+ ids.push_back(ase->id);
+ } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
+
+ if (ids.size() > 0) {
+ le_audio::client_parser::ascs::PrepareAseCtpAudioReceiverStartReady(
+ ids, value);
+
+ BtaGattQueue::WriteCharacteristic(leAudioDevice->conn_id_,
+ leAudioDevice->ctp_hdls_.val_hdl, value,
+ GATT_WRITE_NO_RSP, NULL, NULL);
+
+ return;
+ }
+ }
+
void AseStateMachineProcessEnabling(
struct le_audio::client_parser::ascs::ase_rsp_hdr& arh, struct ase* ase,
LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
@@ -2200,8 +2214,32 @@
ase->state = AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING;
if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
- /* We are here because of the reconnection of the single device. */
- CisCreateForDevice(leAudioDevice);
+ if (ase->data_path_state < AudioStreamDataPathState::CIS_PENDING) {
+ /* We are here because of the reconnection of the single device. */
+ CisCreateForDevice(leAudioDevice);
+ }
+
+ if (!leAudioDevice->HaveAllActiveAsesCisEst()) {
+ /* More cis established events has to come */
+ return;
+ }
+
+ if (!leAudioDevice->IsReadyToCreateStream()) {
+ /* Device still remains in ready to create stream state. It means
+ * that more enabling status notifications has to come.
+ */
+ return;
+ }
+
+ /* All CISes created. Send start ready for source ASE before we can go
+ * to streaming state.
+ */
+ struct ase* ase = leAudioDevice->GetFirstActiveAse();
+ ASSERT_LOG(ase != nullptr,
+ "shouldn't be called without an active ASE, device %s",
+ leAudioDevice->address_.ToString().c_str());
+ PrepareAndSendReceiverStartReady(leAudioDevice, ase);
+
return;
}
diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc
index 1cafe06..dc5cfe9 100644
--- a/system/bta/le_audio/state_machine_test.cc
+++ b/system/bta/le_audio/state_machine_test.cc
@@ -3100,6 +3100,118 @@
ASSERT_NE(ase->retrans_nb, 0);
}
+TEST_F(StateMachineTest, testAttachDeviceToTheConversationalStream) {
+ const auto context_type = kContextTypeConversational;
+ const auto leaudio_group_id = 6;
+ const auto num_devices = 2;
+
+ ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
+
+ // Prepare multiple fake connected devices in a group
+ auto* group =
+ PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
+ ASSERT_EQ(group->Size(), num_devices);
+
+ PrepareConfigureCodecHandler(group);
+ PrepareConfigureQosHandler(group);
+ PrepareEnableHandler(group);
+ PrepareReceiverStartReady(group);
+ PrepareDisableHandler(group);
+ PrepareReleaseHandler(group);
+
+ auto* leAudioDevice = group->GetFirstDevice();
+ LeAudioDevice* lastDevice;
+ LeAudioDevice* fistDevice = leAudioDevice;
+
+ auto expected_devices_written = 0;
+ while (leAudioDevice) {
+ /* Three Writes:
+ * 1: Codec Config
+ * 2: Codec QoS
+ * 3: Enabling
+ */
+ lastDevice = leAudioDevice;
+ EXPECT_CALL(gatt_queue,
+ WriteCharacteristic(leAudioDevice->conn_id_,
+ leAudioDevice->ctp_hdls_.val_hdl, _,
+ GATT_WRITE_NO_RSP, _, _))
+ .Times(AtLeast(3));
+ expected_devices_written++;
+ leAudioDevice = group->GetNextDevice(leAudioDevice);
+ }
+ ASSERT_EQ(expected_devices_written, num_devices);
+
+ EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
+ EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
+ EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4);
+
+ InjectInitialIdleNotification(group);
+
+ // Start the configuration and stream Conversational content
+ LeAudioGroupStateMachine::Get()->StartStream(
+ group, static_cast<LeAudioContextType>(context_type),
+ types::AudioContexts(context_type));
+
+ // Check if group has transitioned to a proper state
+ ASSERT_EQ(group->GetState(),
+ types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
+ testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
+
+ // Inject CIS and ACL disconnection of first device
+ InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
+ InjectAclDisconnected(group, lastDevice);
+
+ // Check if group keeps streaming
+ ASSERT_EQ(group->GetState(),
+ types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
+
+ lastDevice->conn_id_ = 3;
+ group->UpdateAudioContextTypeAvailability();
+
+ // Make sure ASE with disconnected CIS are not left in STREAMING
+ ASSERT_EQ(lastDevice->GetFirstAseWithState(
+ ::le_audio::types::kLeAudioDirectionSink,
+ types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
+ nullptr);
+ ASSERT_EQ(lastDevice->GetFirstAseWithState(
+ ::le_audio::types::kLeAudioDirectionSource,
+ types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
+ nullptr);
+
+ EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
+ lastDevice->ctp_hdls_.val_hdl, _,
+ GATT_WRITE_NO_RSP, _, _))
+ .Times(AtLeast(3));
+
+ EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
+ EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
+ LeAudioGroupStateMachine::Get()->AttachToStream(group, lastDevice);
+
+ // Check if group keeps streaming
+ ASSERT_EQ(group->GetState(),
+ types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
+
+ // Verify that the joining device receives the right CCID list
+ auto lastMeta = lastDevice->GetFirstActiveAse()->metadata;
+ bool parsedOk = false;
+ auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(),
+ lastMeta.size(), parsedOk);
+ ASSERT_TRUE(parsedOk);
+
+ auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList);
+ ASSERT_TRUE(ccids.has_value());
+ ASSERT_NE(std::find(ccids->begin(), ccids->end(), call_ccid), ccids->end());
+
+ /* Verify that ASE of first device are still good*/
+ auto ase = fistDevice->GetFirstActiveAse();
+ ASSERT_NE(ase->max_transport_latency, 0);
+ ASSERT_NE(ase->retrans_nb, 0);
+
+ // Make sure ASEs with reconnected CIS are in STREAMING state
+ ASSERT_TRUE(lastDevice->HaveAllActiveAsesSameState(
+ types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING));
+}
+
TEST_F(StateMachineTest, StartStreamAfterConfigure) {
const auto context_type = kContextTypeMedia;
const auto leaudio_group_id = 6;
@@ -3705,5 +3817,135 @@
testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
}
+
+TEST_F(StateMachineTest, StreamReconfigureAfterCisLostTwoDevices) {
+ auto context_type = kContextTypeConversational;
+ const auto leaudio_group_id = 4;
+ const auto num_devices = 2;
+
+ // Prepare multiple fake connected devices in a group
+ auto* group = PrepareSingleTestDeviceGroup(
+ leaudio_group_id, context_type, num_devices,
+ kContextTypeConversational | kContextTypeMedia);
+ ASSERT_EQ(group->Size(), num_devices);
+
+ PrepareConfigureCodecHandler(group);
+ PrepareConfigureQosHandler(group);
+ PrepareEnableHandler(group);
+ PrepareReceiverStartReady(group);
+
+ /* Prepare DisconnectCis mock to not symulate CisDisconnection */
+ ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return());
+
+ EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2);
+ EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2);
+ EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(6);
+ EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
+ EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
+ EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
+
+ InjectInitialIdleNotification(group);
+
+ auto* leAudioDevice = group->GetFirstDevice();
+ auto expected_devices_written = 0;
+ while (leAudioDevice) {
+ EXPECT_CALL(gatt_queue,
+ WriteCharacteristic(leAudioDevice->conn_id_,
+ leAudioDevice->ctp_hdls_.val_hdl, _,
+ GATT_WRITE_NO_RSP, _, _))
+ .Times(3);
+ expected_devices_written++;
+ leAudioDevice = group->GetNextDevice(leAudioDevice);
+ }
+ ASSERT_EQ(expected_devices_written, num_devices);
+
+ // Validate GroupStreamStatus
+ EXPECT_CALL(
+ mock_callbacks_,
+ StatusReportCb(leaudio_group_id,
+ bluetooth::le_audio::GroupStreamStatus::STREAMING));
+
+ // Start the configuration and stream Media content
+ context_type = kContextTypeMedia;
+ ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
+ group, static_cast<LeAudioContextType>(context_type),
+ types::AudioContexts(context_type)));
+
+ // Check if group has transitioned to a proper state
+ ASSERT_EQ(group->GetState(),
+ types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
+ ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
+ testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
+ testing::Mock::VerifyAndClearExpectations(&gatt_queue);
+ testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
+
+ // Device disconnects due to timeout of CIS
+ leAudioDevice = group->GetFirstDevice();
+ while (leAudioDevice) {
+ InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
+ // Disconnect device
+ LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected(
+ group, leAudioDevice);
+
+ leAudioDevice = group->GetNextDevice(leAudioDevice);
+ }
+
+ LOG(INFO) << "GK A1";
+ group->ReloadAudioLocations();
+ group->ReloadAudioDirections();
+ group->UpdateAudioContextTypeAvailability();
+
+ // Start conversational scenario
+ leAudioDevice = group->GetFirstDevice();
+ int device_cnt = num_devices;
+ while (leAudioDevice) {
+ LOG(INFO) << "GK A11";
+ leAudioDevice->conn_id_ = device_cnt--;
+ leAudioDevice->SetConnectionState(DeviceConnectState::CONNECTED);
+ leAudioDevice = group->GetNextDevice(leAudioDevice);
+ }
+
+ LOG(INFO) << "GK A2";
+ InjectInitialIdleNotification(group);
+
+ group->ReloadAudioLocations();
+ group->ReloadAudioDirections();
+ group->UpdateAudioContextTypeAvailability(kContextTypeConversational |
+ kContextTypeMedia);
+
+ leAudioDevice = group->GetFirstDevice();
+ expected_devices_written = 0;
+ while (leAudioDevice) {
+ EXPECT_CALL(gatt_queue,
+ WriteCharacteristic(leAudioDevice->conn_id_,
+ leAudioDevice->ctp_hdls_.val_hdl, _,
+ GATT_WRITE_NO_RSP, _, _))
+ .Times(4);
+ expected_devices_written++;
+ leAudioDevice = group->GetNextDevice(leAudioDevice);
+ }
+ ASSERT_EQ(expected_devices_written, num_devices);
+
+ // Validate GroupStreamStatus
+ EXPECT_CALL(
+ mock_callbacks_,
+ StatusReportCb(leaudio_group_id,
+ bluetooth::le_audio::GroupStreamStatus::STREAMING));
+
+ // Start the configuration and stream Conversational content
+ context_type = kContextTypeConversational;
+ ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
+ group, static_cast<LeAudioContextType>(context_type),
+ types::AudioContexts(context_type)));
+
+ // Check if group has transitioned to a proper state
+ ASSERT_EQ(group->GetState(),
+ types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
+ ASSERT_EQ(2, mock_function_count_map["alarm_cancel"]);
+ testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
+ testing::Mock::VerifyAndClearExpectations(&gatt_queue);
+ testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
+}
+
} // namespace internal
} // namespace le_audio
diff --git a/system/btif/Android.bp b/system/btif/Android.bp
index 6299237..b86486f 100644
--- a/system/btif/Android.bp
+++ b/system/btif/Android.bp
@@ -389,6 +389,124 @@
cflags: ["-DBUILDCFG"],
}
+cc_test {
+ name: "net_test_btif_hh",
+ host_supported: true,
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
+ test_suites: ["device-tests"],
+ include_dirs: [
+ "frameworks/av/media/libaaudio/include",
+ "packages/modules/Bluetooth/system",
+ "packages/modules/Bluetooth/system/bta/dm",
+ "packages/modules/Bluetooth/system/bta/include",
+ "packages/modules/Bluetooth/system/bta/sys",
+ "packages/modules/Bluetooth/system/btif/avrcp",
+ "packages/modules/Bluetooth/system/btif/co",
+ "packages/modules/Bluetooth/system/btif/include",
+ "packages/modules/Bluetooth/system/device/include",
+ "packages/modules/Bluetooth/system/embdrv/sbc/decoder/include",
+ "packages/modules/Bluetooth/system/embdrv/sbc/encoder/include",
+ "packages/modules/Bluetooth/system/gd",
+ "packages/modules/Bluetooth/system/include",
+ "packages/modules/Bluetooth/system/internal_include",
+ "packages/modules/Bluetooth/system/stack/a2dp",
+ "packages/modules/Bluetooth/system/stack/avdt",
+ "packages/modules/Bluetooth/system/stack/btm",
+ "packages/modules/Bluetooth/system/stack/include",
+ "packages/modules/Bluetooth/system/stack/l2cap",
+ "packages/modules/Bluetooth/system/udrv/include",
+ "packages/modules/Bluetooth/system/utils/include",
+ "packages/modules/Bluetooth/system/vnd/include",
+ "system/libfmq/include",
+ "system/libhwbinder/include",
+ ],
+ srcs: [
+ ":LibBluetoothSources",
+ ":TestCommonMainHandler",
+ ":TestCommonMockFunctions",
+ ":TestMockAndroidHardware",
+ ":BtaDmSources",
+ ":TestMockBtaAg",
+ ":TestMockBtaAr",
+ ":TestMockBtaAv",
+ ":TestMockBtaCsis",
+ ":TestMockBtaGatt",
+ ":TestMockBtaGroups",
+ ":TestMockBtaHas",
+ ":TestMockBtaHd",
+ ":TestMockBtaHearingAid",
+ ":TestMockBtaHf",
+ ":TestMockBtaHh",
+ ":TestMockBtaJv",
+ ":TestMockBtaLeAudio",
+ ":TestMockBtaLeAudioHalVerifier",
+ ":TestMockBtaPan",
+ ":TestMockBtaSdp",
+ ":TestMockBtaSys",
+ ":TestMockBtaVc",
+ ":TestMockBtu",
+ ":TestMockBtcore",
+ ":TestMockCommon",
+ ":TestMockFrameworks",
+ ":TestMockHci",
+ ":TestMockMainShim",
+ ":TestMockOsi",
+ ":TestMockStack",
+ ":TestMockSystemLibfmq",
+ ":TestMockUdrv",
+ ":TestMockUtils",
+ "test/btif_hh_test.cc",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedDumpsysDataSchema_h",
+ "BluetoothGeneratedPackets_h",
+ ],
+ header_libs: ["libbluetooth_headers"],
+ shared_libs: [
+ "android.hardware.bluetooth.audio@2.0",
+ "android.hardware.bluetooth.audio@2.1",
+ "libcrypto",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libtinyxml2",
+ ],
+ whole_static_libs: [
+ "libbtif",
+ ],
+ static_libs: [
+ "android.hardware.bluetooth.a2dp@1.0",
+ "avrcp-target-service",
+ "libaudio-a2dp-hw-utils",
+ "libbluetooth-types",
+ "libbt-audio-hal-interface",
+ "libbt-stack",
+ "libbtdevice",
+ "lib-bt-packets",
+ "lib-bt-packets-avrcp",
+ "lib-bt-packets-base",
+ "libc++fs",
+ "libflatbuffers-cpp",
+ "libgmock",
+ ],
+ cflags: ["-DBUILDCFG"],
+ target: {
+ android: {
+ shared_libs: [
+ "libbinder_ndk",
+ "android.hardware.bluetooth.audio-V2-ndk",
+ ],
+ },
+ },
+ sanitize: {
+ address: true,
+ cfi: true,
+ misc_undefined: ["bounds"],
+ },
+}
// Cycle stack test
cc_test {
name: "net_test_btif_stack",
diff --git a/system/btif/include/btif_sock.h b/system/btif/include/btif_sock.h
index cb0378e..494782e 100644
--- a/system/btif/include/btif_sock.h
+++ b/system/btif/include/btif_sock.h
@@ -18,11 +18,35 @@
#pragma once
-#include "btif_uid.h"
-
#include <hardware/bt_sock.h>
+#include "btif_uid.h"
+#include "types/raw_address.h"
+
+enum {
+ SOCKET_CONNECTION_STATE_UNKNOWN,
+ // Socket acts as a server waiting for connection
+ SOCKET_CONNECTION_STATE_LISTENING,
+ // Socket acts as a client trying to connect
+ SOCKET_CONNECTION_STATE_CONNECTING,
+ // Socket is connected
+ SOCKET_CONNECTION_STATE_CONNECTED,
+ // Socket tries to disconnect from remote
+ SOCKET_CONNECTION_STATE_DISCONNECTING,
+ // This socket is closed
+ SOCKET_CONNECTION_STATE_DISCONNECTED,
+};
+
+enum {
+ SOCKET_ROLE_UNKNOWN,
+ SOCKET_ROLE_LISTEN,
+ SOCKET_ROLE_CONNECTION,
+};
+
const btsock_interface_t* btif_sock_get_interface(void);
bt_status_t btif_sock_init(uid_set_t* uid_set);
void btif_sock_cleanup(void);
+
+void btif_sock_connection_logger(int state, int role, const RawAddress& addr);
+void btif_sock_dump(int fd);
diff --git a/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc
index 9a16712..9e089f7 100644
--- a/system/btif/src/bluetooth.cc
+++ b/system/btif/src/bluetooth.cc
@@ -58,6 +58,7 @@
#include "bta/include/bta_le_audio_broadcaster_api.h"
#include "bta/include/bta_vc_api.h"
#include "btif/avrcp/avrcp_service.h"
+#include "btif/include/btif_sock.h"
#include "btif/include/stack_manager.h"
#include "btif_a2dp.h"
#include "btif_activity_attribution.h"
@@ -434,6 +435,7 @@
btif_debug_av_dump(fd);
bta_debug_av_dump(fd);
stack_debug_avdtp_api_dump(fd);
+ btif_sock_dump(fd);
bluetooth::avrcp::AvrcpService::DebugDump(fd);
btif_debug_config_dump(fd);
BTA_HfClientDumpStatistics(fd);
diff --git a/system/btif/src/btif_config.cc b/system/btif/src/btif_config.cc
index 4b99365..a777ba8 100644
--- a/system/btif/src/btif_config.cc
+++ b/system/btif/src/btif_config.cc
@@ -112,7 +112,7 @@
metrics_salt.fill(0);
}
if (!AddressObfuscator::IsSaltValid(metrics_salt)) {
- LOG(INFO) << __func__ << ": Metrics salt is not invalid, creating new one";
+ LOG(INFO) << __func__ << ": Metrics salt is invalid, creating new one";
if (RAND_bytes(metrics_salt.data(), metrics_salt.size()) != 1) {
LOG(FATAL) << __func__ << "Failed to generate salt for metrics";
}
diff --git a/system/btif/src/btif_gatt.cc b/system/btif/src/btif_gatt.cc
index d8076b0..2d0944f 100644
--- a/system/btif/src/btif_gatt.cc
+++ b/system/btif/src/btif_gatt.cc
@@ -55,6 +55,7 @@
******************************************************************************/
static bt_status_t btif_gatt_init(const btgatt_callbacks_t* callbacks) {
bt_gatt_callbacks = callbacks;
+ BTA_GATTS_InitBonded();
return BT_STATUS_SUCCESS;
}
diff --git a/system/btif/src/btif_gatt_util.cc b/system/btif/src/btif_gatt_util.cc
index 290c431..55788b0 100644
--- a/system/btif/src/btif_gatt_util.cc
+++ b/system/btif/src/btif_gatt_util.cc
@@ -36,6 +36,7 @@
#include "btif_gatt.h"
#include "btif_storage.h"
#include "btif_util.h"
+#include "gd/os/system_properties.h"
#include "osi/include/allocator.h"
#include "osi/include/osi.h"
#include "stack/btm/btm_sec.h"
@@ -75,6 +76,12 @@
void btif_gatt_check_encrypted_link(RawAddress bd_addr,
tBT_TRANSPORT transport_link) {
+ static const bool check_encrypted = bluetooth::os::GetSystemPropertyBool(
+ "bluetooth.gatt.check_encrypted_link.enabled", true);
+ if (!check_encrypted) {
+ LOG_DEBUG("Check skipped due to system config");
+ return;
+ }
tBTM_LE_PENC_KEYS key;
if ((btif_storage_get_ble_bonding_key(
bd_addr, BTM_LE_KEY_PENC, (uint8_t*)&key,
diff --git a/system/btif/src/btif_hd.cc b/system/btif/src/btif_hd.cc
index 0d5b365..c41713a 100644
--- a/system/btif/src/btif_hd.cc
+++ b/system/btif/src/btif_hd.cc
@@ -32,10 +32,12 @@
#include "bt_target.h" // Must be first to define build configuration
#include "bta/include/bta_hd_api.h"
+#include "bta/sys/bta_sys.h"
#include "btif/include/btif_common.h"
#include "btif/include/btif_hd.h"
#include "btif/include/btif_storage.h"
#include "btif/include/btif_util.h"
+#include "gd/common/init_flags.h"
#include "include/hardware/bt_hd.h"
#include "osi/include/allocator.h"
#include "osi/include/compat.h"
@@ -162,6 +164,7 @@
BTIF_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
btif_hd_cb.status = BTIF_HD_DISABLED;
if (btif_hd_cb.service_dereg_active) {
+ bta_sys_deregister(BTA_ID_HD);
BTIF_TRACE_WARNING("registering hid host now");
btif_hh_service_registration(TRUE);
btif_hd_cb.service_dereg_active = FALSE;
@@ -181,6 +184,7 @@
addr = NULL;
}
+ LOG_INFO("Registering HID device app");
btif_hd_cb.app_registered = TRUE;
HAL_CBACK(bt_hd_callbacks, application_state_cb, addr,
BTHD_APP_STATE_REGISTERED);
@@ -192,7 +196,10 @@
BTHD_APP_STATE_NOT_REGISTERED);
if (btif_hd_cb.service_dereg_active) {
BTIF_TRACE_WARNING("disabling hid device service now");
- btif_hd_free_buf();
+ if (!bluetooth::common::init_flags::
+ delay_hidh_cleanup_until_hidh_ready_start_is_enabled()) {
+ btif_hd_free_buf();
+ }
BTA_HdDisable();
}
break;
diff --git a/system/btif/src/btif_hearing_aid.cc b/system/btif/src/btif_hearing_aid.cc
index 3b51ede..7820f42 100644
--- a/system/btif/src/btif_hearing_aid.cc
+++ b/system/btif/src/btif_hearing_aid.cc
@@ -85,30 +85,26 @@
void Connect(const RawAddress& address) override {
DVLOG(2) << __func__ << " address: " << address;
- do_in_main_thread(FROM_HERE, Bind(&HearingAid::Connect,
- Unretained(HearingAid::Get()), address));
+ do_in_main_thread(FROM_HERE, Bind(&HearingAid::Connect, address));
}
void Disconnect(const RawAddress& address) override {
DVLOG(2) << __func__ << " address: " << address;
- do_in_main_thread(FROM_HERE, Bind(&HearingAid::Disconnect,
- Unretained(HearingAid::Get()), address));
+ do_in_main_thread(FROM_HERE, Bind(&HearingAid::Disconnect, address));
do_in_jni_thread(FROM_HERE, Bind(&btif_storage_set_hearing_aid_acceptlist,
address, false));
}
void AddToAcceptlist(const RawAddress& address) override {
VLOG(2) << __func__ << " address: " << address;
- do_in_main_thread(FROM_HERE, Bind(&HearingAid::AddToAcceptlist,
- Unretained(HearingAid::Get()), address));
+ do_in_main_thread(FROM_HERE, Bind(&HearingAid::AddToAcceptlist, address));
do_in_jni_thread(FROM_HERE, Bind(&btif_storage_set_hearing_aid_acceptlist,
address, true));
}
void SetVolume(int8_t volume) override {
DVLOG(2) << __func__ << " volume: " << +volume;
- do_in_main_thread(FROM_HERE, Bind(&HearingAid::SetVolume,
- Unretained(HearingAid::Get()), volume));
+ do_in_main_thread(FROM_HERE, Bind(&HearingAid::SetVolume, volume));
}
void RemoveDevice(const RawAddress& address) override {
@@ -116,9 +112,7 @@
// RemoveDevice can be called on devices that don't have HA enabled
if (HearingAid::IsHearingAidRunning()) {
- do_in_main_thread(FROM_HERE,
- Bind(&HearingAid::Disconnect,
- Unretained(HearingAid::Get()), address));
+ do_in_main_thread(FROM_HERE, Bind(&HearingAid::Disconnect, address));
}
do_in_jni_thread(FROM_HERE,
diff --git a/system/btif/src/btif_hf_client.cc b/system/btif/src/btif_hf_client.cc
index 177ea7c..6ea3178 100644
--- a/system/btif/src/btif_hf_client.cc
+++ b/system/btif/src/btif_hf_client.cc
@@ -872,6 +872,7 @@
cb->state = BTHF_CLIENT_CONNECTION_STATE_CONNECTED;
cb->peer_feat = 0;
cb->chld_feat = 0;
+ cb->handle = p_data->open.handle;
} else if (cb->state == BTHF_CLIENT_CONNECTION_STATE_CONNECTING) {
cb->state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
} else {
@@ -917,6 +918,22 @@
cb->peer_bda = RawAddress::kAny;
cb->peer_feat = 0;
cb->chld_feat = 0;
+ cb->handle = 0;
+
+ /* Clean up any btif_hf_client_cb for the same disconnected bd_addr.
+ * when there is an Incoming hf_client connection is in progress and
+ * at the same time, outgoing hf_client connection is initiated then
+ * due to race condition two btif_hf_client_cb is created. This creates
+ * problem for successive connections
+ */
+ while ((cb = btif_hf_client_get_cb_by_bda(p_data->bd_addr)) != NULL) {
+ cb->state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
+ cb->peer_bda = RawAddress::kAny;
+ cb->peer_feat = 0;
+ cb->chld_feat = 0;
+ cb->handle = 0;
+ }
+
btif_queue_advance();
break;
diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc
index 3280a95..38986b9 100644
--- a/system/btif/src/btif_hh.cc
+++ b/system/btif/src/btif_hh.cc
@@ -538,6 +538,15 @@
(btif_hh_cb.status == BTIF_HH_DEV_CONNECTING)) {
btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
btif_hh_cb.pending_conn_address = RawAddress::kEmpty;
+
+ /* need to notify up-layer device is disconnected to avoid
+ * state out of sync with up-layer */
+ do_in_jni_thread(base::Bind(
+ [](RawAddress bd_addrcb) {
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, &bd_addrcb,
+ BTHH_CONN_STATE_DISCONNECTED);
+ },
+ *bd_addr));
}
return BT_STATUS_FAIL;
}
diff --git a/system/btif/src/btif_rc.cc b/system/btif/src/btif_rc.cc
index 1b68326..937cb15 100644
--- a/system/btif/src/btif_rc.cc
+++ b/system/btif/src/btif_rc.cc
@@ -1959,6 +1959,11 @@
dump_rc_notification_event_id(event_id));
std::unique_lock<std::mutex> lock(btif_rc_cb.lock);
+ if (event_id > MAX_RC_NOTIFICATIONS) {
+ BTIF_TRACE_ERROR("Invalid event id");
+ return BT_STATUS_PARM_INVALID;
+ }
+
memset(&(avrc_rsp.reg_notif), 0, sizeof(tAVRC_REG_NOTIF_RSP));
avrc_rsp.reg_notif.event_id = event_id;
diff --git a/system/btif/src/btif_sdp_server.cc b/system/btif/src/btif_sdp_server.cc
index 5bfd3e8..64dab16 100644
--- a/system/btif/src/btif_sdp_server.cc
+++ b/system/btif/src/btif_sdp_server.cc
@@ -287,6 +287,10 @@
bt_status_t remove_sdp_record(int record_id) {
int handle;
+ if (record_id >= MAX_SDP_SLOTS) {
+ return BT_STATUS_PARM_INVALID;
+ }
+
bluetooth_sdp_record* record;
bluetooth_sdp_types sdp_type = SDP_TYPE_RAW;
{
@@ -349,9 +353,9 @@
BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
const sdp_slot_t* sdp_slot = start_create_sdp(id);
tBTA_SERVICE_ID service_id = -1;
+ bluetooth_sdp_record* record;
/* In the case we are shutting down, sdp_slot is NULL */
- if (sdp_slot != NULL) {
- bluetooth_sdp_record* record = sdp_slot->record_data;
+ if (sdp_slot != nullptr && (record = sdp_slot->record_data) != nullptr) {
int handle = -1;
switch (record->hdr.type) {
case SDP_TYPE_MAP_MAS:
diff --git a/system/btif/src/btif_sock.cc b/system/btif/src/btif_sock.cc
index b945f4b..bcbce01 100644
--- a/system/btif/src/btif_sock.cc
+++ b/system/btif/src/btif_sock.cc
@@ -18,10 +18,13 @@
#define LOG_TAG "bt_btif_sock"
+#include "btif/include/btif_sock.h"
+
#include <base/logging.h>
#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_sock.h>
+#include <time.h>
#include <atomic>
@@ -60,6 +63,22 @@
static std::atomic_int thread_handle{-1};
static thread_t* thread;
+#define SOCK_LOGGER_SIZE_MAX 16
+
+struct SockConnectionEvent {
+ bool used;
+ RawAddress addr;
+ int state;
+ int role;
+ struct timespec timestamp;
+
+ void dump(const int fd);
+};
+
+static std::atomic<uint8_t> logger_index;
+
+static SockConnectionEvent connection_logger[SOCK_LOGGER_SIZE_MAX];
+
const btsock_interface_t* btif_sock_get_interface(void) {
static btsock_interface_t interface = {
sizeof(interface), btsock_listen, /* listen */
@@ -131,6 +150,88 @@
thread = NULL;
}
+void btif_sock_connection_logger(int state, int role, const RawAddress& addr) {
+ LOG_INFO("address=%s, role=%d, state=%d", addr.ToString().c_str(), state,
+ role);
+
+ uint8_t index = logger_index++ % SOCK_LOGGER_SIZE_MAX;
+
+ connection_logger[index] = {
+ .used = true,
+ .addr = addr,
+ .state = state,
+ .role = role,
+ };
+ clock_gettime(CLOCK_REALTIME, &connection_logger[index].timestamp);
+}
+
+void btif_sock_dump(int fd) {
+ dprintf(fd, "\nSocket Events: \n");
+ dprintf(fd, " Time \tAddress \tState \tRole\n");
+
+ const uint8_t head = logger_index.load() % SOCK_LOGGER_SIZE_MAX;
+
+ uint8_t index = head;
+ do {
+ connection_logger[index].dump(fd);
+
+ index++;
+ index %= SOCK_LOGGER_SIZE_MAX;
+ } while (index != head);
+ dprintf(fd, "\n");
+}
+
+void SockConnectionEvent::dump(const int fd) {
+ if (!used) {
+ return;
+ }
+
+ char eventtime[20];
+ char temptime[20];
+ struct tm* tstamp = localtime(×tamp.tv_sec);
+ strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp);
+ snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime,
+ timestamp.tv_nsec / 1000000);
+
+ const char* str_state;
+ switch (state) {
+ case SOCKET_CONNECTION_STATE_LISTENING:
+ str_state = "STATE_LISTENING";
+ break;
+ case SOCKET_CONNECTION_STATE_CONNECTING:
+ str_state = "STATE_CONNECTING";
+ break;
+ case SOCKET_CONNECTION_STATE_CONNECTED:
+ str_state = "STATE_CONNECTED";
+ break;
+ case SOCKET_CONNECTION_STATE_DISCONNECTING:
+ str_state = "STATE_DISCONNECTING";
+ break;
+ case SOCKET_CONNECTION_STATE_DISCONNECTED:
+ str_state = "STATE_DISCONNECTED";
+ break;
+ default:
+ str_state = "STATE_UNKNOWN";
+ break;
+ }
+
+ const char* str_role;
+ switch (role) {
+ case SOCKET_ROLE_LISTEN:
+ str_role = "ROLE_LISTEN";
+ break;
+ case SOCKET_ROLE_CONNECTION:
+ str_role = "ROLE_CONNECTION";
+ break;
+ default:
+ str_role = "ROLE_UNKNOWN";
+ break;
+ }
+
+ dprintf(fd, " %s\t%s\t%s \t%s\n", eventtime,
+ addr.ToString().c_str(), str_state, str_role);
+}
+
static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
const Uuid* service_uuid, int channel,
int* sock_fd, int flags, int app_uid) {
@@ -142,6 +243,8 @@
bt_status_t status = BT_STATUS_FAIL;
int original_channel = channel;
+ btif_sock_connection_logger(SOCKET_CONNECTION_STATE_LISTENING,
+ SOCKET_ROLE_LISTEN, RawAddress::kEmpty);
log_socket_connection_state(RawAddress::kEmpty, 0, type,
android::bluetooth::SocketConnectionstateEnum::
SOCKET_CONNECTION_STATE_LISTENING,
@@ -183,6 +286,8 @@
break;
}
if (status != BT_STATUS_SUCCESS) {
+ btif_sock_connection_logger(SOCKET_CONNECTION_STATE_DISCONNECTED,
+ SOCKET_ROLE_LISTEN, RawAddress::kEmpty);
log_socket_connection_state(RawAddress::kEmpty, 0, type,
android::bluetooth::SocketConnectionstateEnum::
SOCKET_CONNECTION_STATE_DISCONNECTED,
@@ -198,9 +303,13 @@
CHECK(bd_addr != NULL);
CHECK(sock_fd != NULL);
+ LOG_INFO("%s", __func__);
+
*sock_fd = INVALID_FD;
bt_status_t status = BT_STATUS_FAIL;
+ btif_sock_connection_logger(SOCKET_CONNECTION_STATE_CONNECTING,
+ SOCKET_ROLE_CONNECTION, *bd_addr);
log_socket_connection_state(*bd_addr, 0, type,
android::bluetooth::SocketConnectionstateEnum::
SOCKET_CONNECTION_STATE_CONNECTING,
@@ -245,6 +354,8 @@
break;
}
if (status != BT_STATUS_SUCCESS) {
+ btif_sock_connection_logger(SOCKET_CONNECTION_STATE_DISCONNECTED,
+ SOCKET_ROLE_CONNECTION, *bd_addr);
log_socket_connection_state(*bd_addr, 0, type,
android::bluetooth::SocketConnectionstateEnum::
SOCKET_CONNECTION_STATE_DISCONNECTED,
diff --git a/system/btif/src/btif_sock_l2cap.cc b/system/btif/src/btif_sock_l2cap.cc
index 9d5a5bd..8f42316 100644
--- a/system/btif/src/btif_sock_l2cap.cc
+++ b/system/btif/src/btif_sock_l2cap.cc
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+#include <base/logging.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -24,6 +25,7 @@
#include "bta/include/bta_jv_api.h"
#include "btif/include/btif_metrics_logging.h"
+#include "btif/include/btif_sock.h"
#include "btif/include/btif_sock_thread.h"
#include "btif/include/btif_sock_util.h"
#include "btif/include/btif_uid.h"
@@ -37,8 +39,6 @@
#include "stack/include/bt_types.h"
#include "types/raw_address.h"
-#include <base/logging.h>
-
struct packet {
struct packet *next, *prev;
uint32_t len;
@@ -206,6 +206,10 @@
if (!t) /* prever double-frees */
return;
+ btif_sock_connection_logger(
+ SOCKET_CONNECTION_STATE_DISCONNECTED,
+ sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr);
+
// Whenever a socket is freed, the connection must be dropped
log_socket_connection_state(
sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
@@ -389,6 +393,10 @@
sock->handle = p_start->handle;
+ btif_sock_connection_logger(
+ SOCKET_CONNECTION_STATE_LISTENING,
+ sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr);
+
log_socket_connection_state(
sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
android::bluetooth::SocketConnectionstateEnum::
@@ -452,6 +460,11 @@
accept_rs->id = sock->id;
sock->id = new_listen_id;
+ btif_sock_connection_logger(
+ SOCKET_CONNECTION_STATE_CONNECTED,
+ accept_rs->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+ accept_rs->addr);
+
log_socket_connection_state(
accept_rs->addr, accept_rs->id,
accept_rs->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
@@ -492,6 +505,10 @@
return;
}
+ btif_sock_connection_logger(
+ SOCKET_CONNECTION_STATE_CONNECTED,
+ sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr);
+
log_socket_connection_state(
sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
@@ -544,6 +561,10 @@
return;
}
+ btif_sock_connection_logger(
+ SOCKET_CONNECTION_STATE_DISCONNECTING,
+ sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr);
+
log_socket_connection_state(
sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTING, 0, 0,
diff --git a/system/btif/src/btif_sock_rfc.cc b/system/btif/src/btif_sock_rfc.cc
index 7452f86..0a6a26e 100644
--- a/system/btif/src/btif_sock_rfc.cc
+++ b/system/btif/src/btif_sock_rfc.cc
@@ -31,6 +31,7 @@
#include "btif/include/btif_metrics_logging.h"
/* The JV interface can have only one user, hence we need to call a few
* L2CAP functions from this file. */
+#include "btif/include/btif_sock.h"
#include "btif/include/btif_sock_l2cap.h"
#include "btif/include/btif_sock_sdp.h"
#include "btif/include/btif_sock_thread.h"
@@ -404,6 +405,10 @@
if (slot->fd != INVALID_FD) {
shutdown(slot->fd, SHUT_RDWR);
close(slot->fd);
+ btif_sock_connection_logger(
+ SOCKET_CONNECTION_STATE_DISCONNECTED,
+ slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+ slot->addr);
log_socket_connection_state(
slot->addr, slot->id, BTSOCK_RFCOMM,
android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTED,
@@ -485,6 +490,10 @@
if (p_start->status == BTA_JV_SUCCESS) {
slot->rfc_handle = p_start->handle;
+ btif_sock_connection_logger(
+ SOCKET_CONNECTION_STATE_LISTENING,
+ slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+ slot->addr);
log_socket_connection_state(
slot->addr, slot->id, BTSOCK_RFCOMM,
android::bluetooth::SocketConnectionstateEnum::
@@ -508,6 +517,10 @@
srv_rs, &p_open->rem_bda, p_open->handle, p_open->new_listen_handle);
if (!accept_rs) return 0;
+ btif_sock_connection_logger(
+ SOCKET_CONNECTION_STATE_CONNECTED,
+ accept_rs->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+ accept_rs->addr);
log_socket_connection_state(
accept_rs->addr, accept_rs->id, BTSOCK_RFCOMM,
android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
@@ -540,6 +553,9 @@
slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
slot->addr = p_open->rem_bda;
+ btif_sock_connection_logger(
+ SOCKET_CONNECTION_STATE_CONNECTED,
+ slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, slot->addr);
log_socket_connection_state(
slot->addr, slot->id, BTSOCK_RFCOMM,
android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
diff --git a/system/btif/test/btif_hh_test.cc b/system/btif/test/btif_hh_test.cc
new file mode 100644
index 0000000..9c1fc9d
--- /dev/null
+++ b/system/btif/test/btif_hh_test.cc
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#include "btif/include/btif_hh.h"
+
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <array>
+#include <future>
+#include <vector>
+
+#include "bta/hh/bta_hh_int.h"
+#include "bta/include/bta_ag_api.h"
+#include "bta/include/bta_hh_api.h"
+#include "btcore/include/module.h"
+#include "btif/include/btif_api.h"
+#include "btif/include/stack_manager.h"
+#include "include/hardware/bt_hh.h"
+#include "test/common/mock_functions.h"
+#include "test/mock/mock_osi_allocator.h"
+
+using namespace std::chrono_literals;
+
+void set_hal_cbacks(bt_callbacks_t* callbacks);
+
+uint8_t appl_trace_level = BT_TRACE_LEVEL_DEBUG;
+uint8_t btif_trace_level = BT_TRACE_LEVEL_DEBUG;
+uint8_t btu_trace_level = BT_TRACE_LEVEL_DEBUG;
+
+module_t bt_utils_module;
+module_t gd_controller_module;
+module_t gd_idle_module;
+module_t gd_shim_module;
+module_t osi_module;
+
+const tBTA_AG_RES_DATA tBTA_AG_RES_DATA::kEmpty = {};
+
+extern void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data);
+extern const bthh_interface_t* btif_hh_get_interface();
+
+namespace test {
+namespace mock {
+extern bool bluetooth_shim_is_gd_stack_started_up;
+}
+} // namespace test
+
+#if __GLIBC__
+size_t strlcpy(char* dst, const char* src, size_t siz) {
+ char* d = dst;
+ const char* s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0) {
+ while (--n != 0) {
+ if ((*d++ = *s++) == '\0') break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0) *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return (s - src - 1); /* count does not include NUL */
+}
+
+pid_t gettid(void) throw() { return syscall(SYS_gettid); }
+#endif
+
+namespace {
+std::array<uint8_t, 32> data32 = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+};
+
+const RawAddress kDeviceAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66});
+const uint16_t kHhHandle = 123;
+
+// Callback parameters grouped into a structure
+struct get_report_cb_t {
+ RawAddress raw_address;
+ bthh_status_t status;
+ std::vector<uint8_t> data;
+} get_report_cb_;
+
+// Globals allow usage within function pointers
+std::promise<bt_cb_thread_evt> g_thread_evt_promise;
+std::promise<bt_status_t> g_status_promise;
+std::promise<get_report_cb_t> g_bthh_callbacks_get_report_promise;
+
+} // namespace
+
+bt_callbacks_t bt_callbacks = {
+ .size = sizeof(bt_callbacks_t),
+ .adapter_state_changed_cb = nullptr, // adapter_state_changed_callback
+ .adapter_properties_cb = nullptr, // adapter_properties_callback
+ .remote_device_properties_cb =
+ nullptr, // remote_device_properties_callback
+ .device_found_cb = nullptr, // device_found_callback
+ .discovery_state_changed_cb = nullptr, // discovery_state_changed_callback
+ .pin_request_cb = nullptr, // pin_request_callback
+ .ssp_request_cb = nullptr, // ssp_request_callback
+ .bond_state_changed_cb = nullptr, // bond_state_changed_callback
+ .address_consolidate_cb = nullptr, // address_consolidate_callback
+ .le_address_associate_cb = nullptr, // le_address_associate_callback
+ .acl_state_changed_cb = nullptr, // acl_state_changed_callback
+ .thread_evt_cb = nullptr, // callback_thread_event
+ .dut_mode_recv_cb = nullptr, // dut_mode_recv_callback
+ .le_test_mode_cb = nullptr, // le_test_mode_callback
+ .energy_info_cb = nullptr, // energy_info_callback
+ .link_quality_report_cb = nullptr, // link_quality_report_callback
+ .generate_local_oob_data_cb = nullptr, // generate_local_oob_data_callback
+ .switch_buffer_size_cb = nullptr, // switch_buffer_size_callback
+ .switch_codec_cb = nullptr, // switch_codec_callback
+};
+
+bthh_callbacks_t bthh_callbacks = {
+ .size = sizeof(bthh_callbacks_t),
+ .connection_state_cb = nullptr, // bthh_connection_state_callback
+ .hid_info_cb = nullptr, // bthh_hid_info_callback
+ .protocol_mode_cb = nullptr, // bthh_protocol_mode_callback
+ .idle_time_cb = nullptr, // bthh_idle_time_callback
+ .get_report_cb = nullptr, // bthh_get_report_callback
+ .virtual_unplug_cb = nullptr, // bthh_virtual_unplug_callback
+ .handshake_cb = nullptr, // bthh_handshake_callback
+};
+
+class BtifHhWithMockTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ reset_mock_function_count_map();
+ test::mock::osi_allocator::osi_malloc.body = [](size_t size) {
+ return malloc(size);
+ };
+ test::mock::osi_allocator::osi_calloc.body = [](size_t size) {
+ return calloc(1UL, size);
+ };
+ test::mock::osi_allocator::osi_free.body = [](void* ptr) { free(ptr); };
+ test::mock::osi_allocator::osi_free_and_reset.body = [](void** ptr) {
+ free(*ptr);
+ *ptr = nullptr;
+ };
+ }
+
+ void TearDown() override {
+ test::mock::osi_allocator::osi_malloc = {};
+ test::mock::osi_allocator::osi_calloc = {};
+ test::mock::osi_allocator::osi_free = {};
+ test::mock::osi_allocator::osi_free_and_reset = {};
+ }
+};
+
+class BtifHhWithHalCallbacksTest : public BtifHhWithMockTest {
+ protected:
+ void SetUp() override {
+ bluetooth::common::InitFlags::SetAllForTesting();
+ BtifHhWithMockTest::SetUp();
+ g_thread_evt_promise = std::promise<bt_cb_thread_evt>();
+ auto future = g_thread_evt_promise.get_future();
+ bt_callbacks.thread_evt_cb = [](bt_cb_thread_evt evt) {
+ g_thread_evt_promise.set_value(evt);
+ };
+ set_hal_cbacks(&bt_callbacks);
+ // Start the jni callback thread
+ ASSERT_EQ(BT_STATUS_SUCCESS, btif_init_bluetooth());
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+ ASSERT_EQ(ASSOCIATE_JVM, future.get());
+
+ bt_callbacks.thread_evt_cb = [](bt_cb_thread_evt evt) {};
+ }
+
+ void TearDown() override {
+ g_thread_evt_promise = std::promise<bt_cb_thread_evt>();
+ auto future = g_thread_evt_promise.get_future();
+ bt_callbacks.thread_evt_cb = [](bt_cb_thread_evt evt) {
+ g_thread_evt_promise.set_value(evt);
+ };
+ // Shutdown the jni callback thread
+ ASSERT_EQ(BT_STATUS_SUCCESS, btif_cleanup_bluetooth());
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+ ASSERT_EQ(DISASSOCIATE_JVM, future.get());
+
+ bt_callbacks.thread_evt_cb = [](bt_cb_thread_evt evt) {};
+ BtifHhWithMockTest::TearDown();
+ }
+};
+
+class BtifHhAdapterReady : public BtifHhWithHalCallbacksTest {
+ protected:
+ void SetUp() override {
+ BtifHhWithHalCallbacksTest::SetUp();
+ test::mock::bluetooth_shim_is_gd_stack_started_up = true;
+ ASSERT_EQ(BT_STATUS_SUCCESS,
+ btif_hh_get_interface()->init(&bthh_callbacks));
+ }
+
+ void TearDown() override {
+ test::mock::bluetooth_shim_is_gd_stack_started_up = false;
+ BtifHhWithHalCallbacksTest::TearDown();
+ }
+};
+
+class BtifHhWithDevice : public BtifHhAdapterReady {
+ protected:
+ void SetUp() override {
+ BtifHhAdapterReady::SetUp();
+
+ // Short circuit a connected device
+ btif_hh_cb.devices[0].bd_addr = kDeviceAddress;
+ btif_hh_cb.devices[0].dev_status = BTHH_CONN_STATE_CONNECTED;
+ btif_hh_cb.devices[0].dev_handle = kHhHandle;
+ }
+
+ void TearDown() override { BtifHhAdapterReady::TearDown(); }
+};
+
+TEST_F(BtifHhAdapterReady, lifecycle) {}
+
+TEST_F(BtifHhWithDevice, BTA_HH_GET_RPT_EVT) {
+ tBTA_HH data = {
+ .hs_data =
+ {
+ .status = BTA_HH_OK,
+ .handle = kHhHandle,
+ .rsp_data =
+ {
+ .p_rpt_data = static_cast<BT_HDR*>(
+ osi_calloc(data32.size() + sizeof(BT_HDR))),
+ },
+ },
+ };
+
+ // Fill out the deep copy data
+ data.hs_data.rsp_data.p_rpt_data->len = static_cast<uint16_t>(data32.size());
+ std::copy(data32.begin(), data32.begin() + data32.size(),
+ reinterpret_cast<uint8_t*>((data.hs_data.rsp_data.p_rpt_data + 1)));
+
+ g_bthh_callbacks_get_report_promise = std::promise<get_report_cb_t>();
+ auto future = g_bthh_callbacks_get_report_promise.get_future();
+ bthh_callbacks.get_report_cb = [](RawAddress* bd_addr,
+ bthh_status_t hh_status, uint8_t* rpt_data,
+ int rpt_size) {
+ get_report_cb_t report = {
+ .raw_address = *bd_addr,
+ .status = hh_status,
+ .data = std::vector<uint8_t>(),
+ };
+ report.data.assign(rpt_data, rpt_data + rpt_size),
+ g_bthh_callbacks_get_report_promise.set_value(report);
+ };
+
+ bte_hh_evt(BTA_HH_GET_RPT_EVT, &data);
+ osi_free(data.hs_data.rsp_data.p_rpt_data);
+
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+ auto report = future.get();
+
+ // Verify data was delivered
+ ASSERT_STREQ(kDeviceAddress.ToString().c_str(),
+ report.raw_address.ToString().c_str());
+ ASSERT_EQ(BTHH_OK, report.status);
+ int i = 0;
+ for (const auto& data : data32) {
+ ASSERT_EQ(data, report.data[i++]);
+ }
+}
diff --git a/system/device/include/interop.h b/system/device/include/interop.h
index 0f1ff22..7b8eb1a 100644
--- a/system/device/include/interop.h
+++ b/system/device/include/interop.h
@@ -118,7 +118,14 @@
INTEROP_SLC_SKIP_BIND_COMMAND,
// Respond AVRCP profile version only 1.3 for some device.
- INTEROP_AVRCP_1_3_ONLY
+ INTEROP_AVRCP_1_3_ONLY,
+
+ // Some remote devices have LMP version in[5.0, 5.2] but do not support
+ // robust
+ // caching or correctly response with an error. We disable the
+ // database hash
+ // lookup for such devices.
+ INTEROP_DISABLE_ROBUST_CACHING,
} interop_feature_t;
// Check if a given |addr| matches a known interoperability workaround as
diff --git a/system/device/include/interop_database.h b/system/device/include/interop_database.h
index 6f127e0..e055f43 100644
--- a/system/device/include/interop_database.h
+++ b/system/device/include/interop_database.h
@@ -195,6 +195,39 @@
// BMW Carkit
{{{0x00, 0x0a, 0x08, 0, 0, 0}}, 3, INTEROP_AVRCP_1_3_ONLY},
+
+ // Eero Wi-Fi Router
+ {{{0x08, 0x9b, 0xf1, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x20, 0xbe, 0xcd, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x30, 0x34, 0x22, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x3c, 0x5c, 0xf1, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x40, 0x47, 0x5e, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x50, 0x27, 0xa9, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x64, 0x97, 0x14, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x64, 0xc2, 0x69, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x68, 0x4a, 0x76, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x6c, 0xae, 0xf6, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x78, 0x76, 0x89, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x78, 0xd6, 0xd6, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x84, 0x70, 0xd7, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x98, 0xed, 0x7e, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x9c, 0x0b, 0x05, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x9c, 0x57, 0xbc, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0x9c, 0xa5, 0x70, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xa0, 0x8e, 0x24, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xac, 0xec, 0x85, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xb4, 0x20, 0x46, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xb4, 0xb9, 0xe6, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xc0, 0x36, 0x53, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xc4, 0xf1, 0x74, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xc8, 0xb8, 0x2f, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xc8, 0xe3, 0x06, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xd4, 0x05, 0xde, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xd4, 0x3f, 0x32, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xec, 0x74, 0x27, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xf0, 0x21, 0xe0, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xf0, 0xb6, 0x61, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+ {{{0xfc, 0x3f, 0xa6, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
};
typedef struct {
diff --git a/system/device/src/interop.cc b/system/device/src/interop.cc
index 5cde30d..2024d7a 100644
--- a/system/device/src/interop.cc
+++ b/system/device/src/interop.cc
@@ -138,7 +138,8 @@
CASE_RETURN_STR(INTEROP_DISABLE_SNIFF)
CASE_RETURN_STR(INTEROP_DISABLE_AVDTP_SUSPEND)
CASE_RETURN_STR(INTEROP_SLC_SKIP_BIND_COMMAND)
- CASE_RETURN_STR(INTEROP_AVRCP_1_3_ONLY);
+ CASE_RETURN_STR(INTEROP_AVRCP_1_3_ONLY)
+ CASE_RETURN_STR(INTEROP_DISABLE_ROBUST_CACHING);
}
return "UNKNOWN";
diff --git a/system/gd/common/circular_buffer_test.cc b/system/gd/common/circular_buffer_test.cc
index dc238c2..9a2ef4e 100644
--- a/system/gd/common/circular_buffer_test.cc
+++ b/system/gd/common/circular_buffer_test.cc
@@ -68,6 +68,7 @@
}
TEST(CircularBufferTest, test_timestamps) {
+ timestamp_ = 0;
bluetooth::common::TimestampedCircularBuffer<std::string> buffer(10, std::make_unique<TestTimestamper>());
buffer.Push(std::string("One"));
diff --git a/system/gd/common/init_flags.fbs b/system/gd/common/init_flags.fbs
index b6dbe0a..0953465 100644
--- a/system/gd/common/init_flags.fbs
+++ b/system/gd/common/init_flags.fbs
@@ -16,7 +16,8 @@
btaa_hci_is_enabled:bool (privacy:"Any");
bta_dm_clear_conn_id_on_client_close_is_enabled:bool (privacy:"Any");
btm_dm_flush_discovery_queue_on_search_cancel_is_enabled:bool (privacy:"Any");
- finite_att_timeout_is_enabled:bool (privacy:"Any");
+ clear_hidd_interrupt_cid_on_disconnect_is_enabled:bool (privacy:"Any");
+ delay_hidh_cleanup_until_hidh_ready_start_is_enabled:bool (privacy:"Any");
gatt_robust_caching_client_is_enabled:bool (privacy:"Any");
gatt_robust_caching_server_is_enabled:bool (privacy:"Any");
gd_core_is_enabled:bool (privacy:"Any");
diff --git a/system/gd/common/interfaces/ILoggable.h b/system/gd/common/interfaces/ILoggable.h
new file mode 100644
index 0000000..ad2b8ab
--- /dev/null
+++ b/system/gd/common/interfaces/ILoggable.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright 2022 Google, Inc.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <string>
+
+namespace bluetooth {
+namespace common {
+
+class ILoggable {
+ public:
+ // the interface for
+ // converting an object to a string for feeding to loggers
+ // e.g.. logcat
+ virtual std::string ToStringForLogging() const = 0;
+ virtual ~ILoggable() = default;
+};
+
+class IRedactableLoggable : public ILoggable {
+ public:
+ // the interface for
+ // converting an object to a string with sensitive info redacted
+ // to avoid violating privacy
+ virtual std::string ToRedactedStringForLogging() const = 0;
+ virtual ~IRedactableLoggable() = default;
+};
+
+} // namespace common
+} // namespace bluetooth
diff --git a/system/gd/common/testing/host/log_capture_test.cc b/system/gd/common/testing/host/log_capture_test.cc
index cbd6a1c..320b4fe 100644
--- a/system/gd/common/testing/host/log_capture_test.cc
+++ b/system/gd/common/testing/host/log_capture_test.cc
@@ -62,7 +62,8 @@
ASSERT_TRUE(log_capture->Size() == 0);
}
-TEST_F(LogCaptureTest, truncate) {
+// b/260917913
+TEST_F(LogCaptureTest, DISABLED_truncate) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
CalibrateOneLine(kLogError);
@@ -76,7 +77,8 @@
ASSERT_EQ(size, log_capture->Size());
}
-TEST_F(LogCaptureTest, log_size) {
+// b/260917913
+TEST_F(LogCaptureTest, DISABLED_log_size) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
CalibrateOneLine(kEmptyLine);
@@ -101,7 +103,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find(kLogInfo));
}
-TEST_F(LogCaptureTest, typical) {
+// b/260917913
+TEST_F(LogCaptureTest, DISABLED_typical) {
bluetooth::common::InitFlags::Load(nullptr);
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
@@ -118,7 +121,8 @@
ASSERT_FALSE(log_capture->Rewind()->Find(kLogVerbose));
}
-TEST_F(LogCaptureTest, with_logging_debug_enabled_for_all) {
+// b/260917913
+TEST_F(LogCaptureTest, DISABLED_with_logging_debug_enabled_for_all) {
bluetooth::common::InitFlags::Load(test_flags);
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
@@ -136,7 +140,8 @@
bluetooth::common::InitFlags::Load(nullptr);
}
-TEST_F(LogCaptureTest, wait_until_log_contains) {
+// b/260917913
+TEST_F(LogCaptureTest, DISABLED_wait_until_log_contains) {
bluetooth::common::InitFlags::Load(test_flags);
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
diff --git a/system/gd/dumpsys/bundler/Android.bp b/system/gd/dumpsys/bundler/Android.bp
index 3754611..41f5549 100644
--- a/system/gd/dumpsys/bundler/Android.bp
+++ b/system/gd/dumpsys/bundler/Android.bp
@@ -69,9 +69,8 @@
],
}
-cc_test {
+cc_test_host {
name: "bluetooth_flatbuffer_bundler_test",
- host_supported: true,
srcs: [
":BluetoothFlatbufferBundlerTestSources",
],
diff --git a/system/gd/dumpsys/init_flags.cc b/system/gd/dumpsys/init_flags.cc
index 08d3bf9..0bf3cd0 100644
--- a/system/gd/dumpsys/init_flags.cc
+++ b/system/gd/dumpsys/init_flags.cc
@@ -39,8 +39,10 @@
initFlags::bta_dm_clear_conn_id_on_client_close_is_enabled());
builder.add_btm_dm_flush_discovery_queue_on_search_cancel_is_enabled(
initFlags::btm_dm_flush_discovery_queue_on_search_cancel_is_enabled());
- builder.add_finite_att_timeout_is_enabled(initFlags::finite_att_timeout_is_enabled());
- builder.add_gatt_robust_caching_client_is_enabled(initFlags::gatt_robust_caching_client_is_enabled());
+ builder.add_clear_hidd_interrupt_cid_on_disconnect_is_enabled(
+ initFlags::clear_hidd_interrupt_cid_on_disconnect_is_enabled());
+ builder.add_delay_hidh_cleanup_until_hidh_ready_start_is_enabled(
+ initFlags::delay_hidh_cleanup_until_hidh_ready_start_is_enabled());
builder.add_gatt_robust_caching_server_is_enabled(initFlags::gatt_robust_caching_server_is_enabled());
builder.add_gd_core_is_enabled(initFlags::gd_core_is_enabled());
builder.add_gd_l2cap_is_enabled(initFlags::gd_l2cap_is_enabled());
diff --git a/system/gd/hal/snoop_logger.cc b/system/gd/hal/snoop_logger.cc
index 1b03033..e3b585c 100644
--- a/system/gd/hal/snoop_logger.cc
+++ b/system/gd/hal/snoop_logger.cc
@@ -193,6 +193,7 @@
} // namespace
const std::string SnoopLogger::kBtSnoopLogModeDisabled = "disabled";
+const std::string SnoopLogger::kBtSnoopLogModeTruncated = "truncated";
const std::string SnoopLogger::kBtSnoopLogModeFiltered = "filtered";
const std::string SnoopLogger::kBtSnoopLogModeFull = "full";
const std::string SnoopLogger::kSoCManufacturerQualcomm = "Qualcomm";
@@ -203,6 +204,10 @@
const std::string SnoopLogger::kBtSnoopDefaultLogModeProperty = "persist.bluetooth.btsnoopdefaultmode";
const std::string SnoopLogger::kSoCManufacturerProperty = "ro.soc.manufacturer";
+// The max ACL packet size (in bytes) in truncated logging mode. All information
+// past this point is truncated from a packet.
+static constexpr uint32_t kMaxTruncatedAclPacketSize = 100;
+
SnoopLogger::SnoopLogger(
std::string snoop_log_path,
std::string snooz_log_path,
@@ -236,6 +241,15 @@
delete_btsnoop_files(get_btsnoop_log_path(snoop_log_path_, true));
// delete snooz logs
delete_btsnoop_files(snooz_log_path_);
+ } else if (btsnoop_mode == kBtSnoopLogModeTruncated) {
+ LOG_INFO("Snoop Logs truncated. Limiting to %u", kMaxTruncatedAclPacketSize);
+ is_enabled_ = true;
+ is_truncated_ = true;
+ is_filtered_ = false;
+ // delete filtered logs
+ delete_btsnoop_files(get_btsnoop_log_path(snoop_log_path_, true));
+ // delete snooz logs
+ delete_btsnoop_files(snooz_log_path_);
} else {
LOG_INFO("Snoop Logs disabled");
is_enabled_ = false;
@@ -320,6 +334,9 @@
.dropped_packets = 0,
.timestamp = htonll(timestamp_us + kBtSnoopEpochDelta),
.type = static_cast<uint8_t>(type)};
+ if (is_truncated_ && type == PacketType::ACL) {
+ header.length_captured = htonl(std::min(length, kMaxTruncatedAclPacketSize));
+ }
{
std::lock_guard<std::recursive_mutex> lock(file_mutex_);
if (!is_enabled_) {
@@ -445,9 +462,8 @@
size_t SnoopLogger::GetMaxPacketsPerBuffer() {
// We want to use at most 256 KB memory for btsnooz log for release builds
// and 512 KB memory for userdebug/eng builds
- auto is_debuggable = os::GetSystemProperty(kIsDebuggableProperty);
- size_t btsnooz_max_memory_usage_bytes =
- ((is_debuggable.has_value() && common::StringTrim(is_debuggable.value()) == "1") ? 1024 : 256) * 1024;
+ auto is_debuggable = os::GetSystemPropertyBool(kIsDebuggableProperty, false);
+ size_t btsnooz_max_memory_usage_bytes = (is_debuggable ? 1024 : 256) * 1024;
// Calculate max number of packets based on max memory usage and max packet size
return btsnooz_max_memory_usage_bytes / kDefaultBtSnoozMaxBytesPerPacket;
}
@@ -457,8 +473,8 @@
// In userdebug/eng build, it can also be overwritten by modifying the global setting
std::string default_mode = kBtSnoopLogModeDisabled;
{
- auto is_debuggable = os::GetSystemProperty(kIsDebuggableProperty);
- if (is_debuggable.has_value() && common::StringTrim(is_debuggable.value()) == "1") {
+ auto is_debuggable = os::GetSystemPropertyBool(kIsDebuggableProperty, false);
+ if (is_debuggable) {
auto default_mode_property = os::GetSystemProperty(kBtSnoopDefaultLogModeProperty);
if (default_mode_property) {
default_mode = std::move(default_mode_property.value());
diff --git a/system/gd/hal/snoop_logger.h b/system/gd/hal/snoop_logger.h
index 7fa65aa..f879798 100644
--- a/system/gd/hal/snoop_logger.h
+++ b/system/gd/hal/snoop_logger.h
@@ -38,6 +38,7 @@
static const ModuleFactory Factory;
static const std::string kBtSnoopLogModeDisabled;
+ static const std::string kBtSnoopLogModeTruncated;
static const std::string kBtSnoopLogModeFiltered;
static const std::string kBtSnoopLogModeFull;
static const std::string kSoCManufacturerQualcomm;
@@ -124,6 +125,7 @@
std::ofstream btsnoop_ostream_;
bool is_enabled_ = false;
bool is_filtered_ = false;
+ bool is_truncated_ = false;
size_t max_packets_per_file_;
common::CircularBuffer<std::string> btsnooz_buffer_;
bool qualcomm_debug_log_enabled_ = false;
diff --git a/system/gd/hci/Android.bp b/system/gd/hci/Android.bp
index ae026fc..3dad0d6 100644
--- a/system/gd/hci/Android.bp
+++ b/system/gd/hci/Android.bp
@@ -33,32 +33,25 @@
filegroup {
name: "BluetoothHciUnitTestSources",
srcs: [
- "acl_manager/le_impl_test.cc",
"acl_builder_test.cc",
+ "acl_manager_test.cc",
"acl_manager_unittest.cc",
+ "acl_manager/classic_acl_connection_test.cc",
+ "acl_manager/le_impl_test.cc",
+ "acl_manager/round_robin_scheduler_test.cc",
"address_unittest.cc",
"address_with_type_test.cc",
"class_of_device_unittest.cc",
"controller_test.cc",
"hci_layer_fake.cc",
+ "hci_layer_test.cc",
"hci_layer_unittest.cc",
"hci_packets_test.cc",
"uuid_unittest.cc",
"le_periodic_sync_manager_test.cc",
"le_scanning_manager_test.cc",
"le_advertising_manager_test.cc",
- ],
-}
-
-filegroup {
- name: "BluetoothHciTestSources",
- srcs: [
- "acl_manager/round_robin_scheduler_test.cc",
- "acl_manager_test.cc",
- "hci_layer_test.cc",
"le_address_manager_test.cc",
- "le_advertising_manager_test.cc",
- "le_scanning_manager_test.cc",
],
}
diff --git a/system/gd/hci/acl_manager/classic_acl_connection_test.cc b/system/gd/hci/acl_manager/classic_acl_connection_test.cc
new file mode 100644
index 0000000..9ba38c9
--- /dev/null
+++ b/system/gd/hci/acl_manager/classic_acl_connection_test.cc
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#include "hci/acl_manager/classic_acl_connection.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <cstdint>
+#include <future>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <vector>
+
+#include "hci/acl_connection_interface.h"
+#include "hci/acl_manager/connection_management_callbacks.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "os/thread.h"
+
+using namespace bluetooth;
+using namespace std::chrono_literals;
+
+namespace {
+constexpr char kAddress[] = "00:11:22:33:44:55";
+constexpr uint16_t kConnectionHandle = 123;
+constexpr size_t kQueueSize = 10;
+
+std::vector<hci::DisconnectReason> disconnect_reason_vector = {
+ hci::DisconnectReason::AUTHENTICATION_FAILURE,
+ hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION,
+ hci::DisconnectReason::REMOTE_DEVICE_TERMINATED_CONNECTION_LOW_RESOURCES,
+ hci::DisconnectReason::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF,
+ hci::DisconnectReason::UNSUPPORTED_REMOTE_FEATURE,
+ hci::DisconnectReason::PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED,
+ hci::DisconnectReason::UNACCEPTABLE_CONNECTION_PARAMETERS,
+};
+
+std::vector<hci::ErrorCode> error_code_vector = {
+ hci::ErrorCode::SUCCESS,
+ hci::ErrorCode::UNKNOWN_HCI_COMMAND,
+ hci::ErrorCode::UNKNOWN_CONNECTION,
+ hci::ErrorCode::HARDWARE_FAILURE,
+ hci::ErrorCode::PAGE_TIMEOUT,
+ hci::ErrorCode::AUTHENTICATION_FAILURE,
+ hci::ErrorCode::PIN_OR_KEY_MISSING,
+ hci::ErrorCode::MEMORY_CAPACITY_EXCEEDED,
+ hci::ErrorCode::CONNECTION_TIMEOUT,
+ hci::ErrorCode::CONNECTION_LIMIT_EXCEEDED,
+ hci::ErrorCode::SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED,
+ hci::ErrorCode::CONNECTION_ALREADY_EXISTS,
+ hci::ErrorCode::COMMAND_DISALLOWED,
+ hci::ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES,
+ hci::ErrorCode::CONNECTION_REJECTED_SECURITY_REASONS,
+ hci::ErrorCode::CONNECTION_REJECTED_UNACCEPTABLE_BD_ADDR,
+ hci::ErrorCode::CONNECTION_ACCEPT_TIMEOUT,
+ hci::ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE,
+ hci::ErrorCode::INVALID_HCI_COMMAND_PARAMETERS,
+ hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION,
+ hci::ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_LOW_RESOURCES,
+ hci::ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF,
+ hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST,
+ hci::ErrorCode::REPEATED_ATTEMPTS,
+ hci::ErrorCode::PAIRING_NOT_ALLOWED,
+ hci::ErrorCode::UNKNOWN_LMP_PDU,
+ hci::ErrorCode::UNSUPPORTED_REMOTE_OR_LMP_FEATURE,
+ hci::ErrorCode::SCO_OFFSET_REJECTED,
+ hci::ErrorCode::SCO_INTERVAL_REJECTED,
+ hci::ErrorCode::SCO_AIR_MODE_REJECTED,
+ hci::ErrorCode::INVALID_LMP_OR_LL_PARAMETERS,
+ hci::ErrorCode::UNSPECIFIED_ERROR,
+ hci::ErrorCode::UNSUPPORTED_LMP_OR_LL_PARAMETER,
+ hci::ErrorCode::ROLE_CHANGE_NOT_ALLOWED,
+ hci::ErrorCode::TRANSACTION_RESPONSE_TIMEOUT,
+ hci::ErrorCode::LINK_LAYER_COLLISION,
+ hci::ErrorCode::ENCRYPTION_MODE_NOT_ACCEPTABLE,
+ hci::ErrorCode::ROLE_SWITCH_FAILED,
+ hci::ErrorCode::CONTROLLER_BUSY,
+ hci::ErrorCode::ADVERTISING_TIMEOUT,
+ hci::ErrorCode::CONNECTION_FAILED_ESTABLISHMENT,
+ hci::ErrorCode::LIMIT_REACHED,
+ hci::ErrorCode::STATUS_UNKNOWN,
+};
+
+// Generic template for all commands
+template <typename T, typename U>
+T CreateCommand(U u) {
+ T command;
+ return command;
+}
+
+template <>
+hci::DisconnectView CreateCommand(std::shared_ptr<std::vector<uint8_t>> bytes) {
+ return hci::DisconnectView::Create(
+ hci::AclCommandView::Create(hci::CommandView::Create(hci::PacketView<hci::kLittleEndian>(bytes))));
+}
+
+} // namespace
+
+class TestAclConnectionInterface : public hci::AclConnectionInterface {
+ private:
+ void EnqueueCommand(
+ std::unique_ptr<hci::AclCommandBuilder> command,
+ common::ContextualOnceCallback<void(hci::CommandStatusView)> on_status) override {
+ const std::lock_guard<std::mutex> lock(command_queue_mutex_);
+ command_queue_.push(std::move(command));
+ command_status_callbacks.push_back(std::move(on_status));
+ if (command_promise_ != nullptr) {
+ std::promise<void>* prom = command_promise_.release();
+ prom->set_value();
+ delete prom;
+ }
+ }
+
+ void EnqueueCommand(
+ std::unique_ptr<hci::AclCommandBuilder> command,
+ common::ContextualOnceCallback<void(hci::CommandCompleteView)> on_complete) override {
+ const std::lock_guard<std::mutex> lock(command_queue_mutex_);
+ command_queue_.push(std::move(command));
+ command_complete_callbacks.push_back(std::move(on_complete));
+ if (command_promise_ != nullptr) {
+ std::promise<void>* prom = command_promise_.release();
+ prom->set_value();
+ delete prom;
+ }
+ }
+
+ public:
+ virtual ~TestAclConnectionInterface() = default;
+
+ std::unique_ptr<hci::CommandBuilder> DequeueCommand() {
+ const std::lock_guard<std::mutex> lock(command_queue_mutex_);
+ auto packet = std::move(command_queue_.front());
+ command_queue_.pop();
+ return std::move(packet);
+ }
+
+ std::shared_ptr<std::vector<uint8_t>> DequeueCommandBytes() {
+ auto command = DequeueCommand();
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ packet::BitInserter bi(*bytes);
+ command->Serialize(bi);
+ return bytes;
+ }
+
+ bool IsPacketQueueEmpty() const {
+ const std::lock_guard<std::mutex> lock(command_queue_mutex_);
+ return command_queue_.empty();
+ }
+
+ size_t NumberOfQueuedCommands() const {
+ const std::lock_guard<std::mutex> lock(command_queue_mutex_);
+ return command_queue_.size();
+ }
+
+ private:
+ std::list<common::ContextualOnceCallback<void(hci::CommandCompleteView)>> command_complete_callbacks;
+ std::list<common::ContextualOnceCallback<void(hci::CommandStatusView)>> command_status_callbacks;
+ std::queue<std::unique_ptr<hci::CommandBuilder>> command_queue_;
+ mutable std::mutex command_queue_mutex_;
+ std::unique_ptr<std::promise<void>> command_promise_;
+ std::unique_ptr<std::future<void>> command_future_;
+};
+
+class TestConnectionManagementCallbacks : public hci::acl_manager::ConnectionManagementCallbacks {
+ public:
+ ~TestConnectionManagementCallbacks() = default;
+ void OnConnectionPacketTypeChanged(uint16_t packet_type) override {}
+ void OnAuthenticationComplete(hci::ErrorCode hci_status) override {}
+ void OnEncryptionChange(hci::EncryptionEnabled enabled) override {}
+ void OnChangeConnectionLinkKeyComplete() override {}
+ void OnReadClockOffsetComplete(uint16_t clock_offset) override {}
+ void OnModeChange(hci::ErrorCode status, hci::Mode current_mode, uint16_t interval) override {}
+ void OnSniffSubrating(
+ hci::ErrorCode hci_status,
+ uint16_t maximum_transmit_latency,
+ uint16_t maximum_receive_latency,
+ uint16_t minimum_remote_timeout,
+ uint16_t minimum_local_timeout) override {}
+ void OnQosSetupComplete(
+ hci::ServiceType service_type,
+ uint32_t token_rate,
+ uint32_t peak_bandwidth,
+ uint32_t latency,
+ uint32_t delay_variation) override {}
+ void OnFlowSpecificationComplete(
+ hci::FlowDirection flow_direction,
+ hci::ServiceType service_type,
+ uint32_t token_rate,
+ uint32_t token_bucket_size,
+ uint32_t peak_bandwidth,
+ uint32_t access_latency) override {}
+ void OnFlushOccurred() override {}
+ void OnRoleDiscoveryComplete(hci::Role current_role) override {}
+ void OnReadLinkPolicySettingsComplete(uint16_t link_policy_settings) override {}
+ void OnReadAutomaticFlushTimeoutComplete(uint16_t flush_timeout) override {}
+ void OnReadTransmitPowerLevelComplete(uint8_t transmit_power_level) override {}
+ void OnReadLinkSupervisionTimeoutComplete(uint16_t link_supervision_timeout) override {}
+ void OnReadFailedContactCounterComplete(uint16_t failed_contact_counter) override {}
+ void OnReadLinkQualityComplete(uint8_t link_quality) override {}
+ void OnReadAfhChannelMapComplete(hci::AfhMode afh_mode, std::array<uint8_t, 10> afh_channel_map) override {}
+ void OnReadRssiComplete(uint8_t rssi) override {}
+ void OnReadClockComplete(uint32_t clock, uint16_t accuracy) override {}
+ void OnCentralLinkKeyComplete(hci::KeyFlag key_flag) override {}
+ void OnRoleChange(hci::ErrorCode hci_status, hci::Role new_role) override {}
+ void OnDisconnection(hci::ErrorCode reason) override {
+ on_disconnection_error_code_queue_.push(reason);
+ }
+ void OnReadRemoteVersionInformationComplete(
+ hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) override {}
+ void OnReadRemoteSupportedFeaturesComplete(uint64_t features) override {}
+ void OnReadRemoteExtendedFeaturesComplete(uint8_t page_number, uint8_t max_page_number, uint64_t features) override {}
+
+ std::queue<hci::ErrorCode> on_disconnection_error_code_queue_;
+};
+
+namespace bluetooth {
+namespace hci {
+namespace acl_manager {
+
+class ClassicAclConnectionTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ ASSERT_TRUE(hci::Address::FromString(kAddress, address_));
+ thread_ = new os::Thread("thread", os::Thread::Priority::NORMAL);
+ handler_ = new os::Handler(thread_);
+ queue_ = std::make_shared<hci::acl_manager::AclConnection::Queue>(kQueueSize);
+ sync_handler();
+ }
+
+ void TearDown() override {
+ handler_->Clear();
+ delete handler_;
+ delete thread_;
+ }
+
+ void sync_handler() {
+ ASSERT(handler_ != nullptr);
+
+ auto promise = std::promise<void>();
+ auto future = promise.get_future();
+ handler_->BindOnceOn(&promise, &std::promise<void>::set_value).Invoke();
+ auto status = future.wait_for(2s);
+ ASSERT_EQ(status, std::future_status::ready);
+ }
+
+ Address address_;
+ os::Handler* handler_{nullptr};
+ os::Thread* thread_{nullptr};
+ std::shared_ptr<hci::acl_manager::AclConnection::Queue> queue_;
+
+ TestAclConnectionInterface acl_connection_interface_;
+ TestConnectionManagementCallbacks callbacks_;
+};
+
+TEST_F(ClassicAclConnectionTest, simple) {
+ AclConnectionInterface* acl_connection_interface = nullptr;
+ ClassicAclConnection* connection =
+ new ClassicAclConnection(queue_, acl_connection_interface, kConnectionHandle, address_);
+ connection->RegisterCallbacks(&callbacks_, handler_);
+
+ delete connection;
+}
+
+class ClassicAclConnectionWithCallbacksTest : public ClassicAclConnectionTest {
+ protected:
+ void SetUp() override {
+ ClassicAclConnectionTest::SetUp();
+ connection_ =
+ std::make_unique<ClassicAclConnection>(queue_, &acl_connection_interface_, kConnectionHandle, address_);
+ connection_->RegisterCallbacks(&callbacks_, handler_);
+ is_callbacks_registered_ = true;
+ connection_management_callbacks_ =
+ connection_->GetEventCallbacks([this](uint16_t hci_handle) { is_callbacks_invalidated_ = true; });
+ is_callbacks_invalidated_ = false;
+ }
+
+ void TearDown() override {
+ connection_.reset();
+ ASSERT_TRUE(is_callbacks_invalidated_);
+ ClassicAclConnectionTest::TearDown();
+ }
+
+ protected:
+ std::unique_ptr<ClassicAclConnection> connection_;
+ ConnectionManagementCallbacks* connection_management_callbacks_;
+ bool is_callbacks_registered_{false};
+ bool is_callbacks_invalidated_{false};
+};
+
+TEST_F(ClassicAclConnectionWithCallbacksTest, Disconnect) {
+ for (const auto& reason : disconnect_reason_vector) {
+ ASSERT_TRUE(connection_->Disconnect(reason));
+ }
+
+ for (const auto& reason : disconnect_reason_vector) {
+ ASSERT_FALSE(acl_connection_interface_.IsPacketQueueEmpty());
+ auto command = CreateCommand<DisconnectView>(acl_connection_interface_.DequeueCommandBytes());
+ ASSERT_TRUE(command.IsValid());
+ ASSERT_EQ(reason, command.GetReason());
+ ASSERT_EQ(kConnectionHandle, command.GetConnectionHandle());
+ }
+ ASSERT_TRUE(acl_connection_interface_.IsPacketQueueEmpty());
+}
+
+TEST_F(ClassicAclConnectionWithCallbacksTest, OnDisconnection) {
+ for (const auto& error_code : error_code_vector) {
+ connection_management_callbacks_->OnDisconnection(error_code);
+ }
+
+ sync_handler();
+ ASSERT_TRUE(!callbacks_.on_disconnection_error_code_queue_.empty());
+
+ for (const auto& error_code : error_code_vector) {
+ ASSERT_EQ(error_code, callbacks_.on_disconnection_error_code_queue_.front());
+ callbacks_.on_disconnection_error_code_queue_.pop();
+ }
+}
+
+} // namespace acl_manager
+} // namespace hci
+} // namespace bluetooth
diff --git a/system/gd/hci/acl_manager/le_impl_test.cc b/system/gd/hci/acl_manager/le_impl_test.cc
index ca9d022..d84f95b 100644
--- a/system/gd/hci/acl_manager/le_impl_test.cc
+++ b/system/gd/hci/acl_manager/le_impl_test.cc
@@ -62,12 +62,14 @@
[[maybe_unused]] constexpr bool kSkipFilterAcceptList = !kAddToFilterAcceptList;
[[maybe_unused]] constexpr bool kIsDirectConnection = true;
[[maybe_unused]] constexpr bool kIsBackgroundConnection = !kIsDirectConnection;
-constexpr ::bluetooth::crypto_toolbox::Octet16 kRotationIrk = {};
+constexpr crypto_toolbox::Octet16 kRotationIrk = {};
constexpr std::chrono::milliseconds kMinimumRotationTime(14 * 1000);
constexpr std::chrono::milliseconds kMaximumRotationTime(16 * 1000);
-constexpr uint16_t kIntervalMin = 0x20;
constexpr uint16_t kIntervalMax = 0x40;
+constexpr uint16_t kIntervalMin = 0x20;
constexpr uint16_t kLatency = 0x60;
+constexpr uint16_t kLength = 0x5678;
+constexpr uint16_t kTime = 0x1234;
constexpr uint16_t kTimeout = 0x80;
constexpr std::array<uint8_t, 16> kPeerIdentityResolvingKey({
0x00,
@@ -106,11 +108,12 @@
0x8f,
});
-// Generic template for all commands
-template <typename T, typename U>
-T CreateCommand(U u) {
- T command;
- return command;
+template <typename B>
+std::shared_ptr<std::vector<uint8_t>> Serialize(std::unique_ptr<B> build) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter bi(*bytes);
+ build->Serialize(bi);
+ return bytes;
}
template <typename T>
@@ -140,20 +143,16 @@
[[maybe_unused]] hci::CommandCompleteView ReturnCommandComplete(hci::OpCode op_code, hci::ErrorCode error_code) {
std::vector<uint8_t> success_vector{static_cast<uint8_t>(error_code)};
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter bi(*bytes);
auto builder = hci::CommandCompleteBuilder::Create(uint8_t{1}, op_code, std::make_unique<RawBuilder>(success_vector));
- builder->Serialize(bi);
+ auto bytes = Serialize<hci::CommandCompleteBuilder>(std::move(builder));
return hci::CommandCompleteView::Create(hci::EventView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
}
[[maybe_unused]] hci::CommandStatusView ReturnCommandStatus(hci::OpCode op_code, hci::ErrorCode error_code) {
std::vector<uint8_t> success_vector{static_cast<uint8_t>(error_code)};
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter bi(*bytes);
auto builder = hci::CommandStatusBuilder::Create(
hci::ErrorCode::SUCCESS, uint8_t{1}, op_code, std::make_unique<RawBuilder>(success_vector));
- builder->Serialize(bi);
+ auto bytes = Serialize<hci::CommandStatusBuilder>(std::move(builder));
return hci::CommandStatusView::Create(hci::EventView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
}
@@ -256,8 +255,9 @@
command_queue_.push(std::move(command));
command_status_callbacks.push_back(std::move(on_status));
if (command_promise_ != nullptr) {
- command_promise_->set_value();
- command_promise_.reset();
+ std::promise<void>* prom = command_promise_.release();
+ prom->set_value();
+ delete prom;
}
}
@@ -268,8 +268,9 @@
command_queue_.push(std::move(command));
command_complete_callbacks.push_back(std::move(on_complete));
if (command_promise_ != nullptr) {
- command_promise_->set_value();
- command_promise_.reset();
+ std::promise<void>* prom = command_promise_.release();
+ prom->set_value();
+ delete prom;
}
}
@@ -300,7 +301,7 @@
}
void SetCommandFuture() {
- ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
+ ASSERT_EQ(command_promise_, nullptr) << "Promises, Promises, ... Only one at a time.";
command_promise_ = std::make_unique<std::promise<void>>();
command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
}
@@ -425,6 +426,7 @@
class LeImplTest : public ::testing::Test {
protected:
void SetUp() override {
+ bluetooth::common::InitFlags::SetAllForTesting();
thread_ = new Thread("thread", Thread::Priority::NORMAL);
handler_ = new Handler(thread_);
controller_ = new TestController();
@@ -449,7 +451,7 @@
void set_random_device_address_policy() {
// Set address policy
- hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
hci::Address address;
Address::FromString("D0:05:04:03:02:01", address);
hci::AddressWithType address_with_type(address, hci::AddressType::RANDOM_DEVICE_ADDRESS);
@@ -571,6 +573,7 @@
protected:
void SetUp() override {
LeImplTest::SetUp();
+ set_random_device_address_policy();
EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(_, _))
.WillOnce([&](AddressWithType addr, std::unique_ptr<LeAclConnection> conn) {
@@ -579,8 +582,6 @@
connection_->RegisterCallbacks(&connection_management_callbacks_, handler_);
});
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter bi(*bytes);
auto command = LeEnhancedConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
kHciHandle,
@@ -593,7 +594,7 @@
0x0000,
0x0011,
ClockAccuracy::PPM_30);
- command->Serialize(bi);
+ auto bytes = Serialize<LeEnhancedConnectionCompleteBuilder>(std::move(command));
auto view = CreateLeEventView<hci::LeEnhancedConnectionCompleteView>(bytes);
ASSERT_TRUE(view.IsValid());
le_impl_->on_le_event(view);
@@ -603,6 +604,7 @@
}
void TearDown() override {
+ connection_.reset();
LeImplTest::TearDown();
}
@@ -652,11 +654,11 @@
set_random_device_address_policy();
// Create connection
- hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
le_impl_->create_le_connection(
{{0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, AddressType::PUBLIC_DEVICE_ADDRESS}, true, false);
hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
- hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
hci_layer_->CommandStatusCallback(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
@@ -669,7 +671,7 @@
hci::Address remote_address;
Address::FromString("D0:05:04:03:02:01", remote_address);
hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
- EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, ::testing::_));
+ EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, _));
hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
0x0041,
@@ -691,11 +693,11 @@
controller_->AddSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION);
// Create connection
- hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
le_impl_->create_le_connection(
{{0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, AddressType::PUBLIC_DEVICE_ADDRESS}, true, false);
hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
- hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
hci_layer_->GetCommand(OpCode::LE_EXTENDED_CREATE_CONNECTION);
hci_layer_->CommandStatusCallback(LeExtendedCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
@@ -708,7 +710,7 @@
hci::Address remote_address;
Address::FromString("D0:05:04:03:02:01", remote_address);
hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
- EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, ::testing::_));
+ EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, _));
hci_layer_->IncomingLeMetaEvent(LeEnhancedConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
0x0041,
@@ -734,10 +736,10 @@
Address::FromString("D0:05:04:03:02:01", remote_address);
hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
// Create connection
- hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
le_impl_->create_le_connection(address_with_type, true, false);
hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
- hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
hci_layer_->CommandStatusCallback(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
@@ -747,7 +749,7 @@
ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);
// Receive connection complete of outgoing connection (Role::CENTRAL)
- EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, ::testing::_));
+ EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, _));
hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
0x0041,
@@ -772,10 +774,10 @@
Address::FromString("D0:05:04:03:02:01", remote_address);
hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
// Create connection
- hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
le_impl_->create_le_connection(address_with_type, true, false);
hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
- hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
hci_layer_->GetCommand(OpCode::LE_EXTENDED_CREATE_CONNECTION);
hci_layer_->CommandStatusCallback(LeExtendedCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
@@ -785,7 +787,7 @@
ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);
// Receive connection complete of outgoing connection (Role::CENTRAL)
- EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, ::testing::_));
+ EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, _));
hci_layer_->IncomingLeMetaEvent(LeEnhancedConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
0x0041,
@@ -804,8 +806,8 @@
ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_);
}
-TEST_F(LeImplTest, register_with_address_manager__AddressPolicyNotSet) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyNotSet) {
auto log_capture = std::make_unique<LogCapture>();
std::promise<void> promise;
@@ -857,8 +859,8 @@
std::move(log_capture)));
}
-TEST_F(LeImplTest, disarm_connectability_DISARMED) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_DISARMED) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
le_impl_->connectability_state_ = ConnectabilityState::DISARMED;
@@ -871,8 +873,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMED"));
}
-TEST_F(LeImplTest, disarm_connectability_DISARMED_extended) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_DISARMED_extended) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
le_impl_->connectability_state_ = ConnectabilityState::DISARMED;
@@ -886,8 +888,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMED"));
}
-TEST_F(LeImplTest, disarm_connectability_ARMING) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_ARMING) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
le_impl_->connectability_state_ = ConnectabilityState::ARMING;
@@ -899,8 +901,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("Le connection state machine armed state"));
}
-TEST_F(LeImplTest, disarm_connectability_ARMING_extended) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_ARMING_extended) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
le_impl_->connectability_state_ = ConnectabilityState::ARMING;
@@ -914,8 +916,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("Le connection state machine armed state"));
}
-TEST_F(LeImplTest, disarm_connectability_ARMED) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_ARMED) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
le_impl_->connectability_state_ = ConnectabilityState::ARMED;
@@ -928,8 +930,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("Disarming LE connection state machine with create connection"));
}
-TEST_F(LeImplTest, disarm_connectability_ARMED_extended) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_ARMED_extended) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
le_impl_->connectability_state_ = ConnectabilityState::ARMED;
@@ -943,8 +945,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("Disarming LE connection state machine with create connection"));
}
-TEST_F(LeImplTest, disarm_connectability_DISARMING) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_DISARMING) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
le_impl_->connectability_state_ = ConnectabilityState::DISARMING;
@@ -957,8 +959,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMING"));
}
-TEST_F(LeImplTest, disarm_connectability_DISARMING_extended) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_DISARMING_extended) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
le_impl_->connectability_state_ = ConnectabilityState::DISARMING;
@@ -972,8 +974,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMING"));
}
-TEST_F(LeImplTest, register_with_address_manager__AddressPolicyPublicAddress) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyPublicAddress) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
set_privacy_policy_for_initiator_address(fixed_address_, LeAddressManager::AddressPolicy::USE_PUBLIC_ADDRESS);
@@ -994,8 +996,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("Client unregistered"));
}
-TEST_F(LeImplTest, register_with_address_manager__AddressPolicyStaticAddress) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyStaticAddress) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
set_privacy_policy_for_initiator_address(fixed_address_, LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS);
@@ -1016,8 +1018,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("Client unregistered"));
}
-TEST_F(LeImplTest, register_with_address_manager__AddressPolicyNonResolvableAddress) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyNonResolvableAddress) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
set_privacy_policy_for_initiator_address(fixed_address_, LeAddressManager::AddressPolicy::USE_NON_RESOLVABLE_ADDRESS);
@@ -1038,8 +1040,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("Client unregistered"));
}
-TEST_F(LeImplTest, register_with_address_manager__AddressPolicyResolvableAddress) {
- bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyResolvableAddress) {
std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
set_privacy_policy_for_initiator_address(fixed_address_, LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS);
@@ -1060,9 +1062,8 @@
ASSERT_TRUE(log_capture->Rewind()->Find("Client unregistered"));
}
-TEST_F(LeImplTest, add_device_to_resolving_list) {
- bluetooth::common::InitFlags::SetAllForTesting();
-
+// b/260920739
+TEST_F(LeImplTest, DISABLED_add_device_to_resolving_list) {
// Some kind of privacy policy must be set for LeAddressManager to operate properly
set_privacy_policy_for_initiator_address(fixed_address_, LeAddressManager::AddressPolicy::USE_PUBLIC_ADDRESS);
// Let LeAddressManager::resume_registered_clients execute
@@ -1133,8 +1134,6 @@
}
TEST_F(LeImplTest, add_device_to_resolving_list__SupportsBlePrivacy) {
- bluetooth::common::InitFlags::SetAllForTesting();
-
controller_->supports_ble_privacy_ = true;
// Some kind of privacy policy must be set for LeAddressManager to operate properly
@@ -1228,11 +1227,8 @@
}
TEST_F(LeImplTest, on_le_event__CONNECTION_COMPLETE_CENTRAL) {
- bluetooth::common::InitFlags::SetAllForTesting();
+ EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(_, _)).Times(1);
set_random_device_address_policy();
-
- EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(::testing::_, ::testing::_)).Times(1);
-
auto command = LeConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
kHciHandle,
@@ -1243,22 +1239,15 @@
0x0000,
0x0011,
ClockAccuracy::PPM_30);
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter bi(*bytes);
- command->Serialize(bi);
+ auto bytes = Serialize<LeConnectionCompleteBuilder>(std::move(command));
auto view = CreateLeEventView<hci::LeConnectionCompleteView>(bytes);
ASSERT_TRUE(view.IsValid());
le_impl_->on_le_event(view);
}
TEST_F(LeImplTest, on_le_event__CONNECTION_COMPLETE_PERIPHERAL) {
- bluetooth::common::InitFlags::SetAllForTesting();
+ EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(_, _)).Times(1);
set_random_device_address_policy();
-
- EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(::testing::_, ::testing::_)).Times(1);
-
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter bi(*bytes);
auto command = LeConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
kHciHandle,
@@ -1269,18 +1258,15 @@
0x0000,
0x0011,
ClockAccuracy::PPM_30);
- command->Serialize(bi);
+ auto bytes = Serialize<LeConnectionCompleteBuilder>(std::move(command));
auto view = CreateLeEventView<hci::LeConnectionCompleteView>(bytes);
ASSERT_TRUE(view.IsValid());
le_impl_->on_le_event(view);
}
TEST_F(LeImplTest, on_le_event__ENHANCED_CONNECTION_COMPLETE_CENTRAL) {
- bluetooth::common::InitFlags::SetAllForTesting();
+ EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(_, _)).Times(1);
set_random_device_address_policy();
-
- EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(::testing::_, ::testing::_)).Times(1);
-
auto command = LeEnhancedConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
kHciHandle,
@@ -1293,20 +1279,15 @@
0x0000,
0x0011,
ClockAccuracy::PPM_30);
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter bi(*bytes);
- command->Serialize(bi);
+ auto bytes = Serialize<LeEnhancedConnectionCompleteBuilder>(std::move(command));
auto view = CreateLeEventView<hci::LeEnhancedConnectionCompleteView>(bytes);
ASSERT_TRUE(view.IsValid());
le_impl_->on_le_event(view);
}
TEST_F(LeImplTest, on_le_event__ENHANCED_CONNECTION_COMPLETE_PERIPHERAL) {
- EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(::testing::_, ::testing::_)).Times(1);
-
- bluetooth::common::InitFlags::SetAllForTesting();
+ EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(_, _)).Times(1);
set_random_device_address_policy();
-
auto command = LeEnhancedConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
kHciHandle,
@@ -1319,9 +1300,7 @@
0x0000,
0x0011,
ClockAccuracy::PPM_30);
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter bi(*bytes);
- command->Serialize(bi);
+ auto bytes = Serialize<LeEnhancedConnectionCompleteBuilder>(std::move(command));
auto view = CreateLeEventView<hci::LeEnhancedConnectionCompleteView>(bytes);
ASSERT_TRUE(view.IsValid());
le_impl_->on_le_event(view);
@@ -1340,11 +1319,9 @@
}
TEST_F(LeImplWithConnectionTest, on_le_event__PHY_UPDATE_COMPLETE) {
- bluetooth::common::InitFlags::SetAllForTesting();
- set_random_device_address_policy();
- hci::ErrorCode hci_status;
- hci::PhyType tx_phy;
- hci::PhyType rx_phy;
+ hci::ErrorCode hci_status{ErrorCode::STATUS_UNKNOWN};
+ hci::PhyType tx_phy{0};
+ hci::PhyType rx_phy{0};
// Send a phy update
{
@@ -1354,10 +1331,8 @@
tx_phy = static_cast<PhyType>(_tx_phy);
rx_phy = static_cast<PhyType>(_rx_phy);
});
- auto command = LePhyUpdateCompleteBuilder::Create(ErrorCode::SUCCESS, kHciHandle, 0x01, 0x01);
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter bi(*bytes);
- command->Serialize(bi);
+ auto command = LePhyUpdateCompleteBuilder::Create(ErrorCode::SUCCESS, kHciHandle, 0x01, 0x02);
+ auto bytes = Serialize<LePhyUpdateCompleteBuilder>(std::move(command));
auto view = CreateLeEventView<hci::LePhyUpdateCompleteView>(bytes);
ASSERT_TRUE(view.IsValid());
le_impl_->on_le_event(view);
@@ -1366,12 +1341,10 @@
sync_handler();
ASSERT_EQ(ErrorCode::SUCCESS, hci_status);
ASSERT_EQ(PhyType::LE_1M, tx_phy);
+ ASSERT_EQ(PhyType::LE_2M, rx_phy);
}
TEST_F(LeImplWithConnectionTest, on_le_event__DATA_LENGTH_CHANGE) {
- bluetooth::common::InitFlags::SetAllForTesting();
- set_random_device_address_policy();
-
uint16_t tx_octets{0};
uint16_t tx_time{0};
uint16_t rx_octets{0};
@@ -1387,9 +1360,7 @@
rx_time = _rx_time;
});
auto command = LeDataLengthChangeBuilder::Create(kHciHandle, 0x1234, 0x5678, 0x9abc, 0xdef0);
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter bi(*bytes);
- command->Serialize(bi);
+ auto bytes = Serialize<LeDataLengthChangeBuilder>(std::move(command));
auto view = CreateLeEventView<hci::LeDataLengthChangeView>(bytes);
ASSERT_TRUE(view.IsValid());
le_impl_->on_le_event(view);
@@ -1403,15 +1374,10 @@
}
TEST_F(LeImplWithConnectionTest, on_le_event__REMOTE_CONNECTION_PARAMETER_REQUEST) {
- bluetooth::common::InitFlags::SetAllForTesting();
- set_random_device_address_policy();
-
// Send a remote connection parameter request
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter bi(*bytes);
auto command = hci::LeRemoteConnectionParameterRequestBuilder::Create(
kHciHandle, kIntervalMin, kIntervalMax, kLatency, kTimeout);
- command->Serialize(bi);
+ auto bytes = Serialize<LeRemoteConnectionParameterRequestBuilder>(std::move(command));
{
auto view = CreateLeEventView<hci::LeRemoteConnectionParameterRequestView>(bytes);
ASSERT_TRUE(view.IsValid());
@@ -1432,6 +1398,99 @@
ASSERT_EQ(kTimeout, view.GetTimeout());
}
+// b/260920739
+TEST_F(LeImplRegisteredWithAddressManagerTest, DISABLED_clear_resolving_list) {
+ le_impl_->clear_resolving_list();
+ ASSERT_EQ(3UL, le_impl_->le_address_manager_->NumberCachedCommands());
+
+ sync_handler(); // Allow |LeAddressManager::pause_registered_clients| to complete
+ sync_handler(); // Allow |LeAddressManager::handle_next_command| to complete
+
+ ASSERT_EQ(1UL, hci_layer_->NumberOfQueuedCommands());
+ {
+ auto view = CreateLeSecurityCommandView<LeSetAddressResolutionEnableView>(hci_layer_->DequeueCommandBytes());
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(Enable::DISABLED, view.GetAddressResolutionEnable());
+ le_impl_->le_address_manager_->OnCommandComplete(
+ ReturnCommandComplete(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE, ErrorCode::SUCCESS));
+ }
+
+ sync_handler(); // Allow |LeAddressManager::check_cached_commands| to complete
+ ASSERT_EQ(1UL, hci_layer_->NumberOfQueuedCommands());
+ {
+ auto view = CreateLeSecurityCommandView<LeClearResolvingListView>(hci_layer_->DequeueCommandBytes());
+ ASSERT_TRUE(view.IsValid());
+ le_impl_->le_address_manager_->OnCommandComplete(
+ ReturnCommandComplete(OpCode::LE_CLEAR_RESOLVING_LIST, ErrorCode::SUCCESS));
+ }
+
+ sync_handler(); // Allow |LeAddressManager::handle_next_command| to complete
+ ASSERT_EQ(1UL, hci_layer_->NumberOfQueuedCommands());
+ {
+ auto view = CreateLeSecurityCommandView<LeSetAddressResolutionEnableView>(hci_layer_->DequeueCommandBytes());
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(Enable::ENABLED, view.GetAddressResolutionEnable());
+ le_impl_->le_address_manager_->OnCommandComplete(
+ ReturnCommandComplete(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE, ErrorCode::SUCCESS));
+ }
+ ASSERT_TRUE(hci_layer_->IsPacketQueueEmpty());
+}
+
+TEST_F(LeImplWithConnectionTest, HACK_get_handle) {
+ sync_handler();
+
+ ASSERT_EQ(kHciHandle, le_impl_->HACK_get_handle(remote_address_));
+}
+
+TEST_F(LeImplTest, on_le_connection_canceled_on_pause) {
+ set_random_device_address_policy();
+ le_impl_->pause_connection = true;
+ le_impl_->on_le_connection_canceled_on_pause();
+ ASSERT_TRUE(le_impl_->arm_on_resume_);
+ ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_);
+}
+
+TEST_F(LeImplTest, on_create_connection_timeout) {
+ EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT)).Times(1);
+ le_impl_->create_connection_timeout_alarms_.emplace(
+ std::piecewise_construct,
+ std::forward_as_tuple(
+ remote_public_address_with_type_.GetAddress(), remote_public_address_with_type_.GetAddressType()),
+ std::forward_as_tuple(handler_));
+ le_impl_->on_create_connection_timeout(remote_public_address_with_type_);
+ sync_handler();
+ ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty());
+}
+
+// b/260917913
+TEST_F(LeImplTest, DISABLED_on_common_le_connection_complete__NoPriorConnection) {
+ auto log_capture = std::make_unique<LogCapture>();
+ le_impl_->on_common_le_connection_complete(remote_public_address_with_type_);
+ ASSERT_TRUE(le_impl_->connecting_le_.empty());
+ ASSERT_TRUE(log_capture->Rewind()->Find("No prior connection request for"));
+}
+
+TEST_F(LeImplTest, cancel_connect) {
+ le_impl_->create_connection_timeout_alarms_.emplace(
+ std::piecewise_construct,
+ std::forward_as_tuple(
+ remote_public_address_with_type_.GetAddress(), remote_public_address_with_type_.GetAddressType()),
+ std::forward_as_tuple(handler_));
+ le_impl_->cancel_connect(remote_public_address_with_type_);
+ sync_handler();
+ ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty());
+}
+
+TEST_F(LeImplTest, set_le_suggested_default_data_parameters) {
+ le_impl_->set_le_suggested_default_data_parameters(kLength, kTime);
+ sync_handler();
+ auto view =
+ CreateLeConnectionManagementCommandView<LeWriteSuggestedDefaultDataLengthView>(hci_layer_->DequeueCommandBytes());
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(kLength, view.GetTxOctets());
+ ASSERT_EQ(kTime, view.GetTxTime());
+}
+
} // namespace acl_manager
} // namespace hci
} // namespace bluetooth
diff --git a/system/gd/hci/acl_manager/round_robin_scheduler_test.cc b/system/gd/hci/acl_manager/round_robin_scheduler_test.cc
index e27ff7c..a8bd3d7 100644
--- a/system/gd/hci/acl_manager/round_robin_scheduler_test.cc
+++ b/system/gd/hci/acl_manager/round_robin_scheduler_test.cc
@@ -35,6 +35,7 @@
namespace bluetooth {
namespace hci {
namespace acl_manager {
+namespace {
class TestController : public Controller {
public:
@@ -153,7 +154,7 @@
}
void SetPacketFuture(uint16_t count) {
- ASSERT_LOG(packet_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
+ ASSERT_EQ(packet_promise_, nullptr) << "Promises, Promises, ... Only one at a time.";
packet_count_ = count;
packet_promise_ = std::make_unique<std::promise<void>>();
packet_future_ = std::make_unique<std::future<void>>(packet_promise_->get_future());
@@ -186,7 +187,7 @@
auto connection_queue = std::make_shared<AclConnection::Queue>(10);
round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue);
- SetPacketFuture(2);
+ ASSERT_NO_FATAL_FAILURE(SetPacketFuture(2));
AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
std::vector<uint8_t> packet1 = {0x01, 0x02, 0x03};
std::vector<uint8_t> packet2 = {0x04, 0x05, 0x06};
@@ -210,7 +211,7 @@
round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue);
round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue);
- SetPacketFuture(2);
+ ASSERT_NO_FATAL_FAILURE(SetPacketFuture(2));
AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd();
std::vector<uint8_t> packet = {0x01, 0x02, 0x03};
@@ -233,7 +234,7 @@
auto connection_queue = std::make_shared<AclConnection::Queue>(15);
round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue);
- SetPacketFuture(10);
+ ASSERT_NO_FATAL_FAILURE(SetPacketFuture(10));
AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
for (uint8_t i = 0; i < 15; i++) {
std::vector<uint8_t> packet = {0x01, 0x02, 0x03, i};
@@ -247,7 +248,7 @@
}
ASSERT_EQ(round_robin_scheduler_->GetCredits(), 0);
- SetPacketFuture(5);
+ ASSERT_NO_FATAL_FAILURE(SetPacketFuture(5));
controller_->SendCompletedAclPacketsCallback(0x01, 10);
sync_handler();
packet_future_->wait();
@@ -277,7 +278,7 @@
auto le_connection_queue1 = std::make_shared<AclConnection::Queue>(10);
auto le_connection_queue2 = std::make_shared<AclConnection::Queue>(10);
- SetPacketFuture(18);
+ ASSERT_NO_FATAL_FAILURE(SetPacketFuture(18));
AclConnection::QueueUpEnd* queue_up_end1 = connection_queue1->GetUpEnd();
AclConnection::QueueUpEnd* queue_up_end2 = connection_queue2->GetUpEnd();
AclConnection::QueueUpEnd* le_queue_up_end1 = le_connection_queue1->GetUpEnd();
@@ -334,7 +335,7 @@
round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue);
round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue);
- SetPacketFuture(5);
+ ASSERT_NO_FATAL_FAILURE(SetPacketFuture(5));
AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd();
std::vector<uint8_t> packet(controller_->hci_mtu_, 0xff);
@@ -380,7 +381,8 @@
round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue);
round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue);
- SetPacketFuture(controller_->le_max_acl_packet_credits_ + controller_->max_acl_packet_credits_);
+ ASSERT_NO_FATAL_FAILURE(
+ SetPacketFuture(controller_->le_max_acl_packet_credits_ + controller_->max_acl_packet_credits_));
AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd();
std::vector<uint8_t> huge_packet(2000);
@@ -411,6 +413,7 @@
round_robin_scheduler_->Unregister(le_handle);
}
+} // namespace
} // namespace acl_manager
} // namespace hci
} // namespace bluetooth
diff --git a/system/gd/hci/acl_manager_test.cc b/system/gd/hci/acl_manager_test.cc
index 73e3228..e4cdcae 100644
--- a/system/gd/hci/acl_manager_test.cc
+++ b/system/gd/hci/acl_manager_test.cc
@@ -16,19 +16,20 @@
#include "hci/acl_manager.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
#include <algorithm>
#include <chrono>
#include <future>
#include <map>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
#include "common/bind.h"
#include "hci/address.h"
#include "hci/class_of_device.h"
#include "hci/controller.h"
#include "hci/hci_layer.h"
+#include "hci/hci_layer_fake.h"
#include "os/thread.h"
#include "packet/raw_builder.h"
@@ -43,37 +44,14 @@
using packet::PacketView;
using packet::RawBuilder;
-constexpr std::chrono::seconds kTimeout = std::chrono::seconds(2);
+constexpr auto kTimeout = std::chrono::seconds(2);
+constexpr auto kShortTimeout = std::chrono::milliseconds(100);
constexpr uint16_t kScanIntervalFast = 0x0060;
constexpr uint16_t kScanWindowFast = 0x0030;
constexpr uint16_t kScanIntervalSlow = 0x0800;
constexpr uint16_t kScanWindowSlow = 0x0030;
const AddressWithType empty_address_with_type = hci::AddressWithType();
-PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter i(*bytes);
- bytes->reserve(packet->size());
- packet->Serialize(i);
- return packet::PacketView<packet::kLittleEndian>(bytes);
-}
-
-std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle) {
- static uint32_t packet_number = 1;
- auto payload = std::make_unique<RawBuilder>();
- payload->AddOctets2(6); // L2CAP PDU size
- payload->AddOctets2(2); // L2CAP CID
- payload->AddOctets2(handle);
- payload->AddOctets4(packet_number++);
- return std::move(payload);
-}
-
-std::unique_ptr<AclBuilder> NextAclPacket(uint16_t handle) {
- PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
- BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
- return AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, NextPayload(handle));
-}
-
class TestController : public Controller {
public:
void RegisterCompletedAclPacketsCallback(
@@ -118,200 +96,6 @@
void ListDependencies(ModuleList* list) const {}
};
-class TestHciLayer : public HciLayer {
- public:
- void EnqueueCommand(
- std::unique_ptr<CommandBuilder> command,
- common::ContextualOnceCallback<void(CommandStatusView)> on_status) override {
- command_queue_.push(std::move(command));
- command_status_callbacks.push_back(std::move(on_status));
- if (command_promise_ != nullptr) {
- command_promise_->set_value();
- command_promise_.reset();
- }
- }
-
- void EnqueueCommand(
- std::unique_ptr<CommandBuilder> command,
- common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
- command_queue_.push(std::move(command));
- command_complete_callbacks.push_back(std::move(on_complete));
- if (command_promise_ != nullptr) {
- command_promise_->set_value();
- command_promise_.reset();
- }
- }
-
- void SetCommandFuture() {
- ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
- command_promise_ = std::make_unique<std::promise<void>>();
- command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
- }
-
- CommandView GetLastCommand() {
- if (command_queue_.size() == 0) {
- return CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
- }
- auto last = std::move(command_queue_.front());
- command_queue_.pop();
- return CommandView::Create(GetPacketView(std::move(last)));
- }
-
- ConnectionManagementCommandView GetCommand(OpCode op_code) {
- if (command_future_ != nullptr) {
- auto result = command_future_->wait_for(std::chrono::milliseconds(1000));
- EXPECT_NE(std::future_status::timeout, result);
- }
- if (command_queue_.empty()) {
- return ConnectionManagementCommandView::Create(AclCommandView::Create(
- CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()))));
- }
- CommandView command_packet_view = GetLastCommand();
- ConnectionManagementCommandView command =
- ConnectionManagementCommandView::Create(AclCommandView::Create(command_packet_view));
- EXPECT_TRUE(command.IsValid());
- EXPECT_EQ(command.GetOpCode(), op_code);
-
- return command;
- }
-
- ConnectionManagementCommandView GetLastCommand(OpCode op_code) {
- if (!command_queue_.empty() && command_future_ != nullptr) {
- command_future_.reset();
- command_promise_.reset();
- } else if (command_future_ != nullptr) {
- auto result = command_future_->wait_for(std::chrono::milliseconds(1000));
- EXPECT_NE(std::future_status::timeout, result);
- }
- if (command_queue_.empty()) {
- return ConnectionManagementCommandView::Create(AclCommandView::Create(
- CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()))));
- }
- CommandView command_packet_view = GetLastCommand();
- ConnectionManagementCommandView command =
- ConnectionManagementCommandView::Create(AclCommandView::Create(command_packet_view));
- EXPECT_TRUE(command.IsValid());
- EXPECT_EQ(command.GetOpCode(), op_code);
-
- return command;
- }
-
- void RegisterEventHandler(EventCode event_code, common::ContextualCallback<void(EventView)> event_handler) override {
- registered_events_[event_code] = event_handler;
- }
-
- void UnregisterEventHandler(EventCode event_code) override {
- registered_events_.erase(event_code);
- }
-
- void RegisterLeEventHandler(SubeventCode subevent_code,
- common::ContextualCallback<void(LeMetaEventView)> event_handler) override {
- registered_le_events_[subevent_code] = event_handler;
- }
-
- void UnregisterLeEventHandler(SubeventCode subevent_code) override {
- registered_le_events_.erase(subevent_code);
- }
-
- void IncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
- auto packet = GetPacketView(std::move(event_builder));
- EventView event = EventView::Create(packet);
- ASSERT_TRUE(event.IsValid());
- EventCode event_code = event.GetEventCode();
- ASSERT_NE(registered_events_.find(event_code), registered_events_.end()) << EventCodeText(event_code);
- registered_events_[event_code].Invoke(event);
- }
-
- void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
- auto packet = GetPacketView(std::move(event_builder));
- EventView event = EventView::Create(packet);
- LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
- EXPECT_TRUE(meta_event_view.IsValid());
- SubeventCode subevent_code = meta_event_view.GetSubeventCode();
- EXPECT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end());
- registered_le_events_[subevent_code].Invoke(meta_event_view);
- }
-
- void IncomingAclData(uint16_t handle) {
- os::Handler* hci_handler = GetHandler();
- auto* queue_end = acl_queue_.GetDownEnd();
- std::promise<void> promise;
- auto future = promise.get_future();
- queue_end->RegisterEnqueue(hci_handler,
- common::Bind(
- [](decltype(queue_end) queue_end, uint16_t handle, std::promise<void> promise) {
- auto packet = GetPacketView(NextAclPacket(handle));
- AclView acl2 = AclView::Create(packet);
- queue_end->UnregisterEnqueue();
- promise.set_value();
- return std::make_unique<AclView>(acl2);
- },
- queue_end, handle, common::Passed(std::move(promise))));
- auto status = future.wait_for(kTimeout);
- ASSERT_EQ(status, std::future_status::ready);
- }
-
- void AssertNoOutgoingAclData() {
- auto queue_end = acl_queue_.GetDownEnd();
- EXPECT_EQ(queue_end->TryDequeue(), nullptr);
- }
-
- void CommandCompleteCallback(EventView event) {
- CommandCompleteView complete_view = CommandCompleteView::Create(event);
- ASSERT_TRUE(complete_view.IsValid());
- std::move(command_complete_callbacks.front()).Invoke(complete_view);
- command_complete_callbacks.pop_front();
- }
-
- void CommandStatusCallback(EventView event) {
- CommandStatusView status_view = CommandStatusView::Create(event);
- ASSERT_TRUE(status_view.IsValid());
- std::move(command_status_callbacks.front()).Invoke(status_view);
- command_status_callbacks.pop_front();
- }
-
- PacketView<kLittleEndian> OutgoingAclData() {
- auto queue_end = acl_queue_.GetDownEnd();
- std::unique_ptr<AclBuilder> received;
- do {
- received = queue_end->TryDequeue();
- } while (received == nullptr);
-
- return GetPacketView(std::move(received));
- }
-
- BidiQueueEnd<AclBuilder, AclView>* GetAclQueueEnd() override {
- return acl_queue_.GetUpEnd();
- }
-
- void ListDependencies(ModuleList* list) const {}
- void Start() override {
- RegisterEventHandler(EventCode::COMMAND_COMPLETE,
- GetHandler()->BindOn(this, &TestHciLayer::CommandCompleteCallback));
- RegisterEventHandler(EventCode::COMMAND_STATUS, GetHandler()->BindOn(this, &TestHciLayer::CommandStatusCallback));
- }
- void Stop() override {}
-
- void Disconnect(uint16_t handle, ErrorCode reason) override {
- GetHandler()->Post(common::BindOnce(&TestHciLayer::do_disconnect, common::Unretained(this), handle, reason));
- }
-
- private:
- std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_;
- std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_;
- std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
- std::list<common::ContextualOnceCallback<void(CommandStatusView)>> command_status_callbacks;
- BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */};
-
- std::queue<std::unique_ptr<CommandBuilder>> command_queue_;
- std::unique_ptr<std::promise<void>> command_promise_;
- std::unique_ptr<std::future<void>> command_future_;
-
- void do_disconnect(uint16_t handle, ErrorCode reason) {
- HciLayer::Disconnect(handle, reason);
- }
-};
-
class AclManagerNoCallbacksTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -321,7 +105,6 @@
fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
ASSERT_NE(client_handler_, nullptr);
- test_hci_layer_->SetCommandFuture();
fake_registry_.Start<AclManager>(&thread_);
acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
Address::FromString("A1:A2:A3:A4:A5:A6", remote);
@@ -337,21 +120,29 @@
minimum_rotation_time,
maximum_rotation_time);
- auto set_random_address_packet = LeSetRandomAddressView::Create(
- LeAdvertisingCommandView::Create(test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS)));
+ auto set_random_address_packet =
+ LeSetRandomAddressView::Create(LeAdvertisingCommandView::Create(
+ GetConnectionManagementCommand(OpCode::LE_SET_RANDOM_ADDRESS)));
ASSERT_TRUE(set_random_address_packet.IsValid());
- my_initiating_address =
- AddressWithType(set_random_address_packet.GetRandomAddress(), AddressType::RANDOM_DEVICE_ADDRESS);
- // Verify LE Set Random Address was sent during setup
- test_hci_layer_->GetLastCommand(OpCode::LE_SET_RANDOM_ADDRESS);
+ my_initiating_address = AddressWithType(
+ set_random_address_packet.GetRandomAddress(), AddressType::RANDOM_DEVICE_ADDRESS);
test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
}
void TearDown() override {
+ // Invalid mutex exception is raised if the connections
+ // are cleared after the AclConnectionInterface is deleted
+ // through fake_registry_.
+ mock_connection_callback_.Clear();
+ mock_le_connection_callbacks_.Clear();
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
fake_registry_.StopAll();
}
+ void sync_client_handler() {
+ ASSERT(thread_.GetReactor()->WaitForIdle(std::chrono::seconds(2)));
+ }
+
TestModuleRegistry fake_registry_;
TestHciLayer* test_hci_layer_ = nullptr;
TestController* test_controller_ = nullptr;
@@ -398,6 +189,15 @@
ASSERT_EQ(status, std::future_status::ready);
}
+ ConnectionManagementCommandView GetConnectionManagementCommand(OpCode op_code) {
+ auto base_command = test_hci_layer_->GetCommand();
+ ConnectionManagementCommandView command =
+ ConnectionManagementCommandView::Create(AclCommandView::Create(base_command));
+ EXPECT_TRUE(command.IsValid());
+ EXPECT_EQ(command.GetOpCode(), op_code);
+ return command;
+ }
+
class MockConnectionCallback : public ConnectionCallbacks {
public:
void OnConnectSuccess(std::unique_ptr<ClassicAclConnection> connection) override {
@@ -408,6 +208,11 @@
connection_promise_.reset();
}
}
+
+ void Clear() {
+ connections_.clear();
+ }
+
MOCK_METHOD(void, OnConnectFail, (Address, ErrorCode reason), (override));
MOCK_METHOD(void, HACK_OnEscoConnectRequest, (Address, ClassOfDevice), (override));
@@ -426,6 +231,11 @@
le_connection_promise_.reset();
}
}
+
+ void Clear() {
+ le_connections_.clear();
+ }
+
MOCK_METHOD(void, OnLeConnectFail, (AddressWithType, ErrorCode reason), (override));
std::list<std::shared_ptr<LeAclConnection>> le_connections_;
@@ -451,9 +261,9 @@
acl_manager_->CreateConnection(remote);
// Wait for the connection request
- auto last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+ auto last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
while (!last_command.IsValid()) {
- last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+ last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
}
EXPECT_CALL(mock_connection_management_callbacks_, OnRoleChange(hci::ErrorCode::SUCCESS, Role::CENTRAL));
@@ -470,19 +280,17 @@
}
void TearDown() override {
+ // Invalid mutex exception is raised if the connection
+ // is cleared after the AclConnectionInterface is deleted
+ // through fake_registry_.
+ mock_connection_callback_.Clear();
+ mock_le_connection_callbacks_.Clear();
+ connection_.reset();
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
fake_registry_.StopAll();
}
- void sync_client_handler() {
- std::promise<void> promise;
- auto future = promise.get_future();
- client_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
- auto future_status = future.wait_for(std::chrono::seconds(1));
- EXPECT_EQ(future_status, std::future_status::ready);
- }
-
uint16_t handle_;
std::shared_ptr<ClassicAclConnection> connection_;
@@ -532,30 +340,15 @@
TEST_F(AclManagerTest, startup_teardown) {}
-TEST_F(AclManagerNoCallbacksTest, acl_connection_before_registered_callbacks) {
- ClassOfDevice class_of_device;
-
- test_hci_layer_->IncomingEvent(
- ConnectionRequestBuilder::Create(remote, class_of_device, ConnectionRequestLinkType::ACL));
- fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
- fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
- fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
- CommandView command = CommandView::Create(test_hci_layer_->GetLastCommand());
- EXPECT_TRUE(command.IsValid());
- OpCode op_code = command.GetOpCode();
- EXPECT_EQ(op_code, OpCode::REJECT_CONNECTION_REQUEST);
-}
-
TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_success) {
uint16_t handle = 1;
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateConnection(remote);
// Wait for the connection request
- auto last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+ auto last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
while (!last_command.IsValid()) {
- last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+ last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
}
auto first_connection = GetConnectionFuture();
@@ -573,13 +366,12 @@
TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_fail) {
uint16_t handle = 0x123;
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateConnection(remote);
// Wait for the connection request
- auto last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+ auto last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
while (!last_command.IsValid()) {
- last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+ last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
}
EXPECT_CALL(mock_connection_callback_, OnConnectFail(remote, ErrorCode::PAGE_TIMEOUT));
@@ -596,12 +388,10 @@
AclManagerTest::SetUp();
remote_with_type_ = AddressWithType(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateLeConnection(remote_with_type_, true);
- test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+ GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
- auto packet = test_hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
+ auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
auto le_connection_management_command_view =
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
@@ -621,7 +411,7 @@
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
handle_,
- Role::PERIPHERAL,
+ Role::CENTRAL,
AddressType::PUBLIC_DEVICE_ADDRESS,
remote,
0x0100,
@@ -629,8 +419,7 @@
0x0C80,
ClockAccuracy::PPM_30));
- test_hci_layer_->SetCommandFuture();
- test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
+ GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
auto first_connection_status = first_connection.wait_for(kTimeout);
@@ -640,19 +429,17 @@
}
void TearDown() override {
+ // Invalid mutex exception is raised if the connection
+ // is cleared after the AclConnectionInterface is deleted
+ // through fake_registry_.
+ mock_connection_callback_.Clear();
+ mock_le_connection_callbacks_.Clear();
+ connection_.reset();
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
fake_registry_.StopAll();
}
- void sync_client_handler() {
- std::promise<void> promise;
- auto future = promise.get_future();
- client_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
- auto future_status = future.wait_for(std::chrono::seconds(1));
- EXPECT_EQ(future_status, std::future_status::ready);
- }
-
uint16_t handle_ = 0x123;
std::shared_ptr<LeAclConnection> connection_;
AddressWithType remote_with_type_;
@@ -686,12 +473,10 @@
TEST_F(AclManagerTest, invoke_registered_callback_le_connection_complete_fail) {
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateLeConnection(remote_with_type, true);
- test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+ GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
- auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+ auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
auto le_connection_management_command_view =
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
@@ -707,10 +492,11 @@
EXPECT_CALL(mock_le_connection_callbacks_,
OnLeConnectFail(remote_with_type, ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES));
+
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES,
0x123,
- Role::PERIPHERAL,
+ Role::CENTRAL,
AddressType::PUBLIC_DEVICE_ADDRESS,
remote,
0x0100,
@@ -718,8 +504,7 @@
0x0011,
ClockAccuracy::PPM_30));
- test_hci_layer_->SetCommandFuture();
- packet = test_hci_layer_->GetLastCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
+ packet = GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
le_connection_management_command_view = LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
auto remove_command_view = LeRemoveDeviceFromFilterAcceptListView::Create(le_connection_management_command_view);
ASSERT_TRUE(remove_command_view.IsValid());
@@ -728,16 +513,14 @@
TEST_F(AclManagerTest, cancel_le_connection) {
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateLeConnection(remote_with_type, true);
- test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+ GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
- test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+ GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
+ test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
- test_hci_layer_->SetCommandFuture();
acl_manager_->CancelLeConnect(remote_with_type);
- auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
+ auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
auto le_connection_management_command_view =
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
auto command_view = LeCreateConnectionCancelView::Create(le_connection_management_command_view);
@@ -747,7 +530,7 @@
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
ErrorCode::UNKNOWN_CONNECTION,
0x123,
- Role::PERIPHERAL,
+ Role::CENTRAL,
AddressType::PUBLIC_DEVICE_ADDRESS,
remote,
0x0100,
@@ -755,8 +538,7 @@
0x0011,
ClockAccuracy::PPM_30));
- test_hci_layer_->SetCommandFuture();
- packet = test_hci_layer_->GetLastCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
+ packet = GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
le_connection_management_command_view = LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
auto remove_command_view = LeRemoveDeviceFromFilterAcceptListView::Create(le_connection_management_command_view);
ASSERT_TRUE(remove_command_view.IsValid());
@@ -766,31 +548,32 @@
TEST_F(AclManagerTest, create_connection_with_fast_mode) {
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateLeConnection(remote_with_type, true);
- test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
- test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
- auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+ GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+ test_hci_layer_->IncomingEvent(
+ LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+
+ auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
auto command_view =
LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(packet)));
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetLeScanInterval(), kScanIntervalFast);
ASSERT_EQ(command_view.GetLeScanWindow(), kScanWindowFast);
test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
+
auto first_connection = GetLeConnectionFuture();
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
0x00,
- Role::PERIPHERAL,
+ Role::CENTRAL,
AddressType::PUBLIC_DEVICE_ADDRESS,
remote,
0x0100,
0x0010,
0x0C80,
ClockAccuracy::PPM_30));
- test_hci_layer_->SetCommandFuture();
- test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
+
+ GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
auto first_connection_status = first_connection.wait_for(kTimeout);
ASSERT_EQ(first_connection_status, std::future_status::ready);
@@ -798,12 +581,10 @@
TEST_F(AclManagerTest, create_connection_with_slow_mode) {
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateLeConnection(remote_with_type, false);
- test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+ GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
- auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+ auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
auto command_view =
LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(packet)));
ASSERT_TRUE(command_view.IsValid());
@@ -814,15 +595,14 @@
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS,
0x00,
- Role::PERIPHERAL,
+ Role::CENTRAL,
AddressType::PUBLIC_DEVICE_ADDRESS,
remote,
0x0100,
0x0010,
0x0C80,
ClockAccuracy::PPM_30));
- test_hci_layer_->SetCommandFuture();
- test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
+ GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
auto first_connection_status = first_connection.wait_for(kTimeout);
ASSERT_EQ(first_connection_status, std::future_status::ready);
@@ -867,19 +647,25 @@
uint16_t connection_interval = (connection_interval_max + connection_interval_min) / 2;
uint16_t connection_latency = 0x0001;
uint16_t supervision_timeout = 0x0A00;
- test_hci_layer_->SetCommandFuture();
- connection_->LeConnectionUpdate(connection_interval_min, connection_interval_max, connection_latency,
- supervision_timeout, 0x10, 0x20);
- auto update_packet = test_hci_layer_->GetCommand(OpCode::LE_CONNECTION_UPDATE);
+ connection_->LeConnectionUpdate(
+ connection_interval_min,
+ connection_interval_max,
+ connection_latency,
+ supervision_timeout,
+ 0x10,
+ 0x20);
+ auto update_packet = GetConnectionManagementCommand(OpCode::LE_CONNECTION_UPDATE);
auto update_view =
LeConnectionUpdateView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(update_packet)));
ASSERT_TRUE(update_view.IsValid());
EXPECT_EQ(update_view.GetConnectionHandle(), handle_);
+ test_hci_layer_->IncomingEvent(LeConnectionUpdateStatusBuilder::Create(ErrorCode::SUCCESS, 0x1));
EXPECT_CALL(
mock_le_connection_management_callbacks_,
OnConnectionUpdate(hci_status, connection_interval, connection_latency, supervision_timeout));
test_hci_layer_->IncomingLeMetaEvent(LeConnectionUpdateCompleteBuilder::Create(
ErrorCode::SUCCESS, handle_, connection_interval, connection_latency, supervision_timeout));
+ sync_client_handler();
}
TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_disconnect) {
@@ -890,9 +676,10 @@
auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
EXPECT_CALL(mock_le_connection_management_callbacks_, OnDisconnection(reason));
test_hci_layer_->Disconnect(handle_, reason);
+ sync_client_handler();
}
-TEST_F(AclManagerWithLeConnectionTest, DISABLED_invoke_registered_callback_le_disconnect_data_race) {
+TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_disconnect_data_race) {
ASSERT_EQ(connection_->GetRemoteAddress(), remote_with_type_);
ASSERT_EQ(connection_->GetHandle(), handle_);
connection_->RegisterCallbacks(&mock_le_connection_management_callbacks_, client_handler_);
@@ -901,6 +688,7 @@
auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
EXPECT_CALL(mock_le_connection_management_callbacks_, OnDisconnection(reason));
test_hci_layer_->Disconnect(handle_, reason);
+ sync_client_handler();
}
TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_queue_disconnect) {
@@ -918,6 +706,7 @@
auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
EXPECT_CALL(mock_connection_management_callbacks_, OnDisconnection(reason));
test_hci_layer_->Disconnect(handle_, reason);
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, acl_send_data_one_connection) {
@@ -941,15 +730,15 @@
SendAclData(handle_, connection_->GetAclQueueEnd());
sent_packet = test_hci_layer_->OutgoingAclData();
- test_hci_layer_->SetCommandFuture();
auto reason = ErrorCode::AUTHENTICATION_FAILURE;
EXPECT_CALL(mock_connection_management_callbacks_, OnDisconnection(reason));
connection_->Disconnect(DisconnectReason::AUTHENTICATION_FAILURE);
- auto packet = test_hci_layer_->GetCommand(OpCode::DISCONNECT);
+ auto packet = GetConnectionManagementCommand(OpCode::DISCONNECT);
auto command_view = DisconnectView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetConnectionHandle(), handle_);
test_hci_layer_->Disconnect(handle_, reason);
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, acl_send_data_credits) {
@@ -969,12 +758,12 @@
test_controller_->CompletePackets(handle_, 1);
auto after_credits_sent_packet = test_hci_layer_->OutgoingAclData();
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_switch_role) {
- test_hci_layer_->SetCommandFuture();
acl_manager_->SwitchRole(connection_->GetAddress(), Role::PERIPHERAL);
- auto packet = test_hci_layer_->GetCommand(OpCode::SWITCH_ROLE);
+ auto packet = GetConnectionManagementCommand(OpCode::SWITCH_ROLE);
auto command_view = SwitchRoleView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetBdAddr(), connection_->GetAddress());
@@ -983,13 +772,13 @@
EXPECT_CALL(mock_connection_management_callbacks_, OnRoleChange(hci::ErrorCode::SUCCESS, Role::PERIPHERAL));
test_hci_layer_->IncomingEvent(
RoleChangeBuilder::Create(ErrorCode::SUCCESS, connection_->GetAddress(), Role::PERIPHERAL));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_write_default_link_policy_settings) {
- test_hci_layer_->SetCommandFuture();
uint16_t link_policy_settings = 0x05;
acl_manager_->WriteDefaultLinkPolicySettings(link_policy_settings);
- auto packet = test_hci_layer_->GetCommand(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS);
+ auto packet = GetConnectionManagementCommand(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS);
auto command_view = WriteDefaultLinkPolicySettingsView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetDefaultLinkPolicySettings(), 0x05);
@@ -997,49 +786,52 @@
uint8_t num_packets = 1;
test_hci_layer_->IncomingEvent(
WriteDefaultLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS));
+ sync_client_handler();
ASSERT_EQ(link_policy_settings, acl_manager_->ReadDefaultLinkPolicySettings());
}
TEST_F(AclManagerWithConnectionTest, send_authentication_requested) {
- test_hci_layer_->SetCommandFuture();
connection_->AuthenticationRequested();
- auto packet = test_hci_layer_->GetCommand(OpCode::AUTHENTICATION_REQUESTED);
+ auto packet = GetConnectionManagementCommand(OpCode::AUTHENTICATION_REQUESTED);
auto command_view = AuthenticationRequestedView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
EXPECT_CALL(mock_connection_management_callbacks_, OnAuthenticationComplete);
- test_hci_layer_->IncomingEvent(AuthenticationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_));
+ test_hci_layer_->IncomingEvent(
+ AuthenticationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_read_clock_offset) {
- test_hci_layer_->SetCommandFuture();
connection_->ReadClockOffset();
- auto packet = test_hci_layer_->GetCommand(OpCode::READ_CLOCK_OFFSET);
+ auto packet = GetConnectionManagementCommand(OpCode::READ_CLOCK_OFFSET);
auto command_view = ReadClockOffsetView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
EXPECT_CALL(mock_connection_management_callbacks_, OnReadClockOffsetComplete(0x0123));
- test_hci_layer_->IncomingEvent(ReadClockOffsetCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, 0x0123));
+ test_hci_layer_->IncomingEvent(
+ ReadClockOffsetCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, 0x0123));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_hold_mode) {
- test_hci_layer_->SetCommandFuture();
connection_->HoldMode(0x0500, 0x0020);
- auto packet = test_hci_layer_->GetCommand(OpCode::HOLD_MODE);
+ auto packet = GetConnectionManagementCommand(OpCode::HOLD_MODE);
auto command_view = HoldModeView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetHoldModeMaxInterval(), 0x0500);
ASSERT_EQ(command_view.GetHoldModeMinInterval(), 0x0020);
EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(ErrorCode::SUCCESS, Mode::HOLD, 0x0020));
- test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::HOLD, 0x0020));
+ test_hci_layer_->IncomingEvent(
+ ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::HOLD, 0x0020));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_sniff_mode) {
- test_hci_layer_->SetCommandFuture();
connection_->SniffMode(0x0500, 0x0020, 0x0040, 0x0014);
- auto packet = test_hci_layer_->GetCommand(OpCode::SNIFF_MODE);
+ auto packet = GetConnectionManagementCommand(OpCode::SNIFF_MODE);
auto command_view = SniffModeView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetSniffMaxInterval(), 0x0500);
@@ -1048,101 +840,109 @@
ASSERT_EQ(command_view.GetSniffTimeout(), 0x0014);
EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(ErrorCode::SUCCESS, Mode::SNIFF, 0x0028));
- test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::SNIFF, 0x0028));
+ test_hci_layer_->IncomingEvent(
+ ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::SNIFF, 0x0028));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_exit_sniff_mode) {
- test_hci_layer_->SetCommandFuture();
connection_->ExitSniffMode();
- auto packet = test_hci_layer_->GetCommand(OpCode::EXIT_SNIFF_MODE);
+ auto packet = GetConnectionManagementCommand(OpCode::EXIT_SNIFF_MODE);
auto command_view = ExitSniffModeView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(ErrorCode::SUCCESS, Mode::ACTIVE, 0x00));
- test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::ACTIVE, 0x00));
+ test_hci_layer_->IncomingEvent(
+ ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::ACTIVE, 0x00));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_qos_setup) {
- test_hci_layer_->SetCommandFuture();
connection_->QosSetup(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231);
- auto packet = test_hci_layer_->GetCommand(OpCode::QOS_SETUP);
+ auto packet = GetConnectionManagementCommand(OpCode::QOS_SETUP);
auto command_view = QosSetupView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetServiceType(), ServiceType::BEST_EFFORT);
- ASSERT_EQ(command_view.GetTokenRate(), 0x1234);
- ASSERT_EQ(command_view.GetPeakBandwidth(), 0x1233);
- ASSERT_EQ(command_view.GetLatency(), 0x1232);
- ASSERT_EQ(command_view.GetDelayVariation(), 0x1231);
+ ASSERT_EQ(command_view.GetTokenRate(), 0x1234u);
+ ASSERT_EQ(command_view.GetPeakBandwidth(), 0x1233u);
+ ASSERT_EQ(command_view.GetLatency(), 0x1232u);
+ ASSERT_EQ(command_view.GetDelayVariation(), 0x1231u);
EXPECT_CALL(mock_connection_management_callbacks_,
OnQosSetupComplete(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
- test_hci_layer_->IncomingEvent(QosSetupCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, ServiceType::BEST_EFFORT,
- 0x1234, 0x1233, 0x1232, 0x1231));
+ test_hci_layer_->IncomingEvent(QosSetupCompleteBuilder::Create(
+ ErrorCode::SUCCESS, handle_, ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_flow_specification) {
- test_hci_layer_->SetCommandFuture();
- connection_->FlowSpecification(FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232,
- 0x1231);
- auto packet = test_hci_layer_->GetCommand(OpCode::FLOW_SPECIFICATION);
+ connection_->FlowSpecification(
+ FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231);
+ auto packet = GetConnectionManagementCommand(OpCode::FLOW_SPECIFICATION);
auto command_view = FlowSpecificationView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetFlowDirection(), FlowDirection::OUTGOING_FLOW);
ASSERT_EQ(command_view.GetServiceType(), ServiceType::BEST_EFFORT);
- ASSERT_EQ(command_view.GetTokenRate(), 0x1234);
- ASSERT_EQ(command_view.GetTokenBucketSize(), 0x1233);
- ASSERT_EQ(command_view.GetPeakBandwidth(), 0x1232);
- ASSERT_EQ(command_view.GetAccessLatency(), 0x1231);
+ ASSERT_EQ(command_view.GetTokenRate(), 0x1234u);
+ ASSERT_EQ(command_view.GetTokenBucketSize(), 0x1233u);
+ ASSERT_EQ(command_view.GetPeakBandwidth(), 0x1232u);
+ ASSERT_EQ(command_view.GetAccessLatency(), 0x1231u);
EXPECT_CALL(mock_connection_management_callbacks_,
OnFlowSpecificationComplete(FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233,
0x1232, 0x1231));
- test_hci_layer_->IncomingEvent(
- FlowSpecificationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, FlowDirection::OUTGOING_FLOW,
- ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
+ test_hci_layer_->IncomingEvent(FlowSpecificationCompleteBuilder::Create(
+ ErrorCode::SUCCESS,
+ handle_,
+ FlowDirection::OUTGOING_FLOW,
+ ServiceType::BEST_EFFORT,
+ 0x1234,
+ 0x1233,
+ 0x1232,
+ 0x1231));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_flush) {
- test_hci_layer_->SetCommandFuture();
connection_->Flush();
- auto packet = test_hci_layer_->GetCommand(OpCode::FLUSH);
+ auto packet = GetConnectionManagementCommand(OpCode::FLUSH);
auto command_view = FlushView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
EXPECT_CALL(mock_connection_management_callbacks_, OnFlushOccurred());
test_hci_layer_->IncomingEvent(FlushOccurredBuilder::Create(handle_));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_role_discovery) {
- test_hci_layer_->SetCommandFuture();
connection_->RoleDiscovery();
- auto packet = test_hci_layer_->GetCommand(OpCode::ROLE_DISCOVERY);
+ auto packet = GetConnectionManagementCommand(OpCode::ROLE_DISCOVERY);
auto command_view = RoleDiscoveryView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
EXPECT_CALL(mock_connection_management_callbacks_, OnRoleDiscoveryComplete(Role::CENTRAL));
uint8_t num_packets = 1;
- test_hci_layer_->IncomingEvent(
- RoleDiscoveryCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, Role::CENTRAL));
+ test_hci_layer_->IncomingEvent(RoleDiscoveryCompleteBuilder::Create(
+ num_packets, ErrorCode::SUCCESS, handle_, Role::CENTRAL));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_read_link_policy_settings) {
- test_hci_layer_->SetCommandFuture();
connection_->ReadLinkPolicySettings();
- auto packet = test_hci_layer_->GetCommand(OpCode::READ_LINK_POLICY_SETTINGS);
+ auto packet = GetConnectionManagementCommand(OpCode::READ_LINK_POLICY_SETTINGS);
auto command_view = ReadLinkPolicySettingsView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkPolicySettingsComplete(0x07));
uint8_t num_packets = 1;
- test_hci_layer_->IncomingEvent(
- ReadLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+ test_hci_layer_->IncomingEvent(ReadLinkPolicySettingsCompleteBuilder::Create(
+ num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_write_link_policy_settings) {
- test_hci_layer_->SetCommandFuture();
connection_->WriteLinkPolicySettings(0x05);
- auto packet = test_hci_layer_->GetCommand(OpCode::WRITE_LINK_POLICY_SETTINGS);
+ auto packet = GetConnectionManagementCommand(OpCode::WRITE_LINK_POLICY_SETTINGS);
auto command_view = WriteLinkPolicySettingsView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetLinkPolicySettings(), 0x05);
@@ -1150,12 +950,12 @@
uint8_t num_packets = 1;
test_hci_layer_->IncomingEvent(
WriteLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_sniff_subrating) {
- test_hci_layer_->SetCommandFuture();
connection_->SniffSubrating(0x1234, 0x1235, 0x1236);
- auto packet = test_hci_layer_->GetCommand(OpCode::SNIFF_SUBRATING);
+ auto packet = GetConnectionManagementCommand(OpCode::SNIFF_SUBRATING);
auto command_view = SniffSubratingView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetMaximumLatency(), 0x1234);
@@ -1163,26 +963,27 @@
ASSERT_EQ(command_view.GetMinimumLocalTimeout(), 0x1236);
uint8_t num_packets = 1;
- test_hci_layer_->IncomingEvent(SniffSubratingCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+ test_hci_layer_->IncomingEvent(
+ SniffSubratingCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_read_automatic_flush_timeout) {
- test_hci_layer_->SetCommandFuture();
connection_->ReadAutomaticFlushTimeout();
- auto packet = test_hci_layer_->GetCommand(OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT);
+ auto packet = GetConnectionManagementCommand(OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT);
auto command_view = ReadAutomaticFlushTimeoutView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
EXPECT_CALL(mock_connection_management_callbacks_, OnReadAutomaticFlushTimeoutComplete(0x07ff));
uint8_t num_packets = 1;
- test_hci_layer_->IncomingEvent(
- ReadAutomaticFlushTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07ff));
+ test_hci_layer_->IncomingEvent(ReadAutomaticFlushTimeoutCompleteBuilder::Create(
+ num_packets, ErrorCode::SUCCESS, handle_, 0x07ff));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_write_automatic_flush_timeout) {
- test_hci_layer_->SetCommandFuture();
connection_->WriteAutomaticFlushTimeout(0x07FF);
- auto packet = test_hci_layer_->GetCommand(OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT);
+ auto packet = GetConnectionManagementCommand(OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT);
auto command_view = WriteAutomaticFlushTimeoutView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetFlushTimeout(), 0x07FF);
@@ -1190,39 +991,39 @@
uint8_t num_packets = 1;
test_hci_layer_->IncomingEvent(
WriteAutomaticFlushTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_read_transmit_power_level) {
- test_hci_layer_->SetCommandFuture();
connection_->ReadTransmitPowerLevel(TransmitPowerLevelType::CURRENT);
- auto packet = test_hci_layer_->GetCommand(OpCode::READ_TRANSMIT_POWER_LEVEL);
+ auto packet = GetConnectionManagementCommand(OpCode::READ_TRANSMIT_POWER_LEVEL);
auto command_view = ReadTransmitPowerLevelView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetTransmitPowerLevelType(), TransmitPowerLevelType::CURRENT);
EXPECT_CALL(mock_connection_management_callbacks_, OnReadTransmitPowerLevelComplete(0x07));
uint8_t num_packets = 1;
- test_hci_layer_->IncomingEvent(
- ReadTransmitPowerLevelCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+ test_hci_layer_->IncomingEvent(ReadTransmitPowerLevelCompleteBuilder::Create(
+ num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_read_link_supervision_timeout) {
- test_hci_layer_->SetCommandFuture();
connection_->ReadLinkSupervisionTimeout();
- auto packet = test_hci_layer_->GetCommand(OpCode::READ_LINK_SUPERVISION_TIMEOUT);
+ auto packet = GetConnectionManagementCommand(OpCode::READ_LINK_SUPERVISION_TIMEOUT);
auto command_view = ReadLinkSupervisionTimeoutView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkSupervisionTimeoutComplete(0x5677));
uint8_t num_packets = 1;
- test_hci_layer_->IncomingEvent(
- ReadLinkSupervisionTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x5677));
+ test_hci_layer_->IncomingEvent(ReadLinkSupervisionTimeoutCompleteBuilder::Create(
+ num_packets, ErrorCode::SUCCESS, handle_, 0x5677));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_write_link_supervision_timeout) {
- test_hci_layer_->SetCommandFuture();
connection_->WriteLinkSupervisionTimeout(0x5678);
- auto packet = test_hci_layer_->GetCommand(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT);
+ auto packet = GetConnectionManagementCommand(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT);
auto command_view = WriteLinkSupervisionTimeoutView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetLinkSupervisionTimeout(), 0x5678);
@@ -1230,37 +1031,37 @@
uint8_t num_packets = 1;
test_hci_layer_->IncomingEvent(
WriteLinkSupervisionTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_read_failed_contact_counter) {
- test_hci_layer_->SetCommandFuture();
connection_->ReadFailedContactCounter();
- auto packet = test_hci_layer_->GetCommand(OpCode::READ_FAILED_CONTACT_COUNTER);
+ auto packet = GetConnectionManagementCommand(OpCode::READ_FAILED_CONTACT_COUNTER);
auto command_view = ReadFailedContactCounterView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
EXPECT_CALL(mock_connection_management_callbacks_, OnReadFailedContactCounterComplete(0x00));
uint8_t num_packets = 1;
- test_hci_layer_->IncomingEvent(
- ReadFailedContactCounterCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+ test_hci_layer_->IncomingEvent(ReadFailedContactCounterCompleteBuilder::Create(
+ num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_reset_failed_contact_counter) {
- test_hci_layer_->SetCommandFuture();
connection_->ResetFailedContactCounter();
- auto packet = test_hci_layer_->GetCommand(OpCode::RESET_FAILED_CONTACT_COUNTER);
+ auto packet = GetConnectionManagementCommand(OpCode::RESET_FAILED_CONTACT_COUNTER);
auto command_view = ResetFailedContactCounterView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
uint8_t num_packets = 1;
test_hci_layer_->IncomingEvent(
ResetFailedContactCounterCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_read_link_quality) {
- test_hci_layer_->SetCommandFuture();
connection_->ReadLinkQuality();
- auto packet = test_hci_layer_->GetCommand(OpCode::READ_LINK_QUALITY);
+ auto packet = GetConnectionManagementCommand(OpCode::READ_LINK_QUALITY);
auto command_view = ReadLinkQualityView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
@@ -1268,12 +1069,12 @@
uint8_t num_packets = 1;
test_hci_layer_->IncomingEvent(
ReadLinkQualityCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0xa9));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_read_afh_channel_map) {
- test_hci_layer_->SetCommandFuture();
connection_->ReadAfhChannelMap();
- auto packet = test_hci_layer_->GetCommand(OpCode::READ_AFH_CHANNEL_MAP);
+ auto packet = GetConnectionManagementCommand(OpCode::READ_AFH_CHANNEL_MAP);
auto command_view = ReadAfhChannelMapView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
std::array<uint8_t, 10> afh_channel_map = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
@@ -1281,34 +1082,36 @@
EXPECT_CALL(mock_connection_management_callbacks_,
OnReadAfhChannelMapComplete(AfhMode::AFH_ENABLED, afh_channel_map));
uint8_t num_packets = 1;
- test_hci_layer_->IncomingEvent(ReadAfhChannelMapCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_,
- AfhMode::AFH_ENABLED, afh_channel_map));
+ test_hci_layer_->IncomingEvent(ReadAfhChannelMapCompleteBuilder::Create(
+ num_packets, ErrorCode::SUCCESS, handle_, AfhMode::AFH_ENABLED, afh_channel_map));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_read_rssi) {
- test_hci_layer_->SetCommandFuture();
connection_->ReadRssi();
- auto packet = test_hci_layer_->GetCommand(OpCode::READ_RSSI);
+ auto packet = GetConnectionManagementCommand(OpCode::READ_RSSI);
auto command_view = ReadRssiView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
sync_client_handler();
EXPECT_CALL(mock_connection_management_callbacks_, OnReadRssiComplete(0x00));
uint8_t num_packets = 1;
- test_hci_layer_->IncomingEvent(ReadRssiCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+ test_hci_layer_->IncomingEvent(
+ ReadRssiCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+ sync_client_handler();
}
TEST_F(AclManagerWithConnectionTest, send_read_clock) {
- test_hci_layer_->SetCommandFuture();
connection_->ReadClock(WhichClock::LOCAL);
- auto packet = test_hci_layer_->GetCommand(OpCode::READ_CLOCK);
+ auto packet = GetConnectionManagementCommand(OpCode::READ_CLOCK);
auto command_view = ReadClockView::Create(packet);
ASSERT_TRUE(command_view.IsValid());
ASSERT_EQ(command_view.GetWhichClock(), WhichClock::LOCAL);
EXPECT_CALL(mock_connection_management_callbacks_, OnReadClockComplete(0x00002e6a, 0x0000));
uint8_t num_packets = 1;
- test_hci_layer_->IncomingEvent(
- ReadClockCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00002e6a, 0x0000));
+ test_hci_layer_->IncomingEvent(ReadClockCompleteBuilder::Create(
+ num_packets, ErrorCode::SUCCESS, handle_, 0x00002e6a, 0x0000));
+ sync_client_handler();
}
class AclManagerWithResolvableAddressTest : public AclManagerNoCallbacksTest {
@@ -1320,7 +1123,6 @@
fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
ASSERT_NE(client_handler_, nullptr);
- test_hci_layer_->SetCommandFuture();
fake_registry_.Start<AclManager>(&thread_);
acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
Address::FromString("A1:A2:A3:A4:A5:A6", remote);
@@ -1338,28 +1140,22 @@
minimum_rotation_time,
maximum_rotation_time);
- test_hci_layer_->GetLastCommand(OpCode::LE_SET_RANDOM_ADDRESS);
+ GetConnectionManagementCommand(OpCode::LE_SET_RANDOM_ADDRESS);
test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
}
};
TEST_F(AclManagerWithResolvableAddressTest, create_connection_cancel_fail) {
auto remote_with_type_ = AddressWithType(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateLeConnection(remote_with_type_, true);
- // Set random address
- test_hci_layer_->GetLastCommand(OpCode::LE_SET_RANDOM_ADDRESS);
- test_hci_layer_->SetCommandFuture();
- test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
-
// Add device to connect list
- test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
- test_hci_layer_->SetCommandFuture();
- test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+ test_hci_layer_->IncomingEvent(
+ LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
// send create connection command
- test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+ GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
@@ -1370,11 +1166,10 @@
auto remote_with_type2 = AddressWithType(remote2, AddressType::PUBLIC_DEVICE_ADDRESS);
// create another connection
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateLeConnection(remote_with_type2, true);
// cancel previous connection
- test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
+ GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
// receive connection complete of first device
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
@@ -1389,13 +1184,14 @@
ClockAccuracy::PPM_30));
// receive create connection cancel complete with ErrorCode::CONNECTION_ALREADY_EXISTS
- test_hci_layer_->SetCommandFuture();
test_hci_layer_->IncomingEvent(
LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::CONNECTION_ALREADY_EXISTS));
// Add another device to connect list
- test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+ GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+
+ // Sync events.
}
class AclManagerLifeCycleTest : public AclManagerNoCallbacksTest {
@@ -1412,9 +1208,8 @@
TEST_F(AclManagerLifeCycleTest, unregister_classic_after_create_connection) {
// Inject create connection
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateConnection(remote);
- auto connection_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+ auto connection_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
// Unregister callbacks after sending connection request
auto promise = std::promise<void>();
@@ -1426,38 +1221,19 @@
auto connection_future = GetConnectionFuture();
test_hci_layer_->IncomingEvent(
ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, remote, LinkType::ACL, Enable::DISABLED));
- auto connection_future_status = connection_future.wait_for(kTimeout);
+
+ sync_client_handler();
+ auto connection_future_status = connection_future.wait_for(kShortTimeout);
ASSERT_NE(connection_future_status, std::future_status::ready);
}
-TEST_F(AclManagerLifeCycleTest, unregister_classic_before_connection_request) {
- ClassOfDevice class_of_device;
-
- // Unregister callbacks before receiving connection request
- auto promise = std::promise<void>();
- auto future = promise.get_future();
- acl_manager_->UnregisterCallbacks(&mock_connection_callback_, std::move(promise));
- future.get();
-
- // Inject peer sending connection request
- auto connection_future = GetConnectionFuture();
- test_hci_layer_->IncomingEvent(
- ConnectionRequestBuilder::Create(remote, class_of_device, ConnectionRequestLinkType::ACL));
- auto connection_future_status = connection_future.wait_for(kTimeout);
- ASSERT_NE(connection_future_status, std::future_status::ready);
-
- test_hci_layer_->GetLastCommand(OpCode::REJECT_CONNECTION_REQUEST);
-}
-
TEST_F(AclManagerLifeCycleTest, unregister_le_before_connection_complete) {
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateLeConnection(remote_with_type, true);
- test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+ GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
- auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+ auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
auto le_connection_management_command_view =
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
@@ -1487,19 +1263,18 @@
0x0500,
ClockAccuracy::PPM_30));
- auto connection_future_status = connection_future.wait_for(kTimeout);
+ sync_client_handler();
+ auto connection_future_status = connection_future.wait_for(kShortTimeout);
ASSERT_NE(connection_future_status, std::future_status::ready);
}
TEST_F(AclManagerLifeCycleTest, unregister_le_before_enhanced_connection_complete) {
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
- test_hci_layer_->SetCommandFuture();
acl_manager_->CreateLeConnection(remote_with_type, true);
- test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+ GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
- auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+ auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
auto le_connection_management_command_view =
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
@@ -1531,7 +1306,8 @@
0x0500,
ClockAccuracy::PPM_30));
- auto connection_future_status = connection_future.wait_for(kTimeout);
+ sync_client_handler();
+ auto connection_future_status = connection_future.wait_for(kShortTimeout);
ASSERT_NE(connection_future_status, std::future_status::ready);
}
diff --git a/system/gd/hci/acl_manager_unittest.cc b/system/gd/hci/acl_manager_unittest.cc
index 37d96db..31c71eb 100644
--- a/system/gd/hci/acl_manager_unittest.cc
+++ b/system/gd/hci/acl_manager_unittest.cc
@@ -21,11 +21,15 @@
#include <algorithm>
#include <chrono>
+#include <deque>
#include <future>
+#include <list>
#include <map>
#include "common/bind.h"
+#include "common/init_flags.h"
#include "hci/address.h"
+#include "hci/address_with_type.h"
#include "hci/class_of_device.h"
#include "hci/controller.h"
#include "hci/hci_layer.h"
@@ -45,9 +49,28 @@
using packet::PacketView;
using packet::RawBuilder;
-constexpr std::chrono::seconds kTimeout = std::chrono::seconds(2);
+namespace {
+constexpr char kLocalRandomAddressString[] = "D0:05:04:03:02:01";
+constexpr char kRemotePublicDeviceStringA[] = "11:A2:A3:A4:A5:A6";
+constexpr char kRemotePublicDeviceStringB[] = "11:B2:B3:B4:B5:B6";
+constexpr uint16_t kHciHandleA = 123;
+constexpr uint16_t kHciHandleB = 456;
+
+constexpr auto kMinimumRotationTime = std::chrono::milliseconds(7 * 60 * 1000);
+constexpr auto kMaximumRotationTime = std::chrono::milliseconds(15 * 60 * 1000);
+
const AddressWithType empty_address_with_type = hci::AddressWithType();
+struct {
+ Address address;
+ ClassOfDevice class_of_device;
+ const uint16_t handle;
+} remote_device[2] = {
+ {.address = {}, .class_of_device = {}, .handle = kHciHandleA},
+ {.address = {}, .class_of_device = {}, .handle = kHciHandleB},
+};
+} // namespace
+
PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
auto bytes = std::make_shared<std::vector<uint8_t>>();
BitInserter i(*bytes);
@@ -74,15 +97,6 @@
class TestController : public Controller {
public:
- void RegisterCompletedAclPacketsCallback(
- common::ContextualCallback<void(uint16_t /* handle */, uint16_t /* packets */)> cb) override {
- acl_cb_ = cb;
- }
-
- void UnregisterCompletedAclPacketsCallback() override {
- acl_cb_ = {};
- }
-
uint16_t GetAclPacketLength() const override {
return acl_buffer_length_;
}
@@ -102,18 +116,15 @@
return le_buffer_size;
}
- void CompletePackets(uint16_t handle, uint16_t packets) {
- acl_cb_.Invoke(handle, packets);
- }
-
- uint16_t acl_buffer_length_ = 1024;
- uint16_t total_acl_buffers_ = 2;
- common::ContextualCallback<void(uint16_t /* handle */, uint16_t /* packets */)> acl_cb_;
-
protected:
void Start() override {}
void Stop() override {}
void ListDependencies(ModuleList* list) const {}
+
+ private:
+ uint16_t acl_buffer_length_ = 1024;
+ uint16_t total_acl_buffers_ = 2;
+ common::ContextualCallback<void(uint16_t /* handle */, uint16_t /* packets */)> acl_cb_;
};
class TestHciLayer : public HciLayer {
@@ -123,10 +134,7 @@
common::ContextualOnceCallback<void(CommandStatusView)> on_status) override {
command_queue_.push(std::move(command));
command_status_callbacks.push_back(std::move(on_status));
- if (command_promise_ != nullptr) {
- command_promise_->set_value();
- command_promise_.reset();
- }
+ Notify();
}
void EnqueueCommand(
@@ -134,16 +142,18 @@
common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
command_queue_.push(std::move(command));
command_complete_callbacks.push_back(std::move(on_complete));
- if (command_promise_ != nullptr) {
- command_promise_->set_value();
- command_promise_.reset();
- }
+ Notify();
}
void SetCommandFuture() {
- ASSERT_TRUE(command_promise_ == nullptr) << "Promises, Promises, ... Only one at a time.";
- command_promise_ = std::make_unique<std::promise<void>>();
- command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
+ ASSERT_EQ(hci_command_promise_, nullptr) << "Promises, Promises, ... Only one at a time.";
+ hci_command_promise_ = std::make_unique<std::promise<void>>();
+ command_future_ = std::make_unique<std::future<void>>(hci_command_promise_->get_future());
+ }
+
+ std::future<void> GetOutgoingCommandFuture() {
+ hci_command_promise_ = std::make_unique<std::promise<void>>();
+ return hci_command_promise_->get_future();
}
CommandView GetLastCommand() {
@@ -173,9 +183,10 @@
ConnectionManagementCommandView GetLastCommand(OpCode op_code) {
if (!command_queue_.empty() && command_future_ != nullptr) {
command_future_.reset();
- command_promise_.reset();
+ hci_command_promise_.reset();
} else if (command_future_ != nullptr) {
command_future_->wait_for(std::chrono::milliseconds(1000));
+ hci_command_promise_.reset();
}
if (command_queue_.empty()) {
return ConnectionManagementCommandView::Create(AclCommandView::Create(
@@ -188,6 +199,19 @@
return command;
}
+ ConnectionManagementCommandView GetLastOutgoingCommand() {
+ if (command_queue_.empty()) {
+ // An empty packet will force a failure on |IsValid()| required by all packets before usage
+ return ConnectionManagementCommandView::Create(AclCommandView::Create(
+ CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()))));
+ } else {
+ CommandView command_packet_view = GetLastCommand();
+ ConnectionManagementCommandView command =
+ ConnectionManagementCommandView::Create(AclCommandView::Create(command_packet_view));
+ return command;
+ }
+ }
+
void RegisterEventHandler(EventCode event_code, common::ContextualCallback<void(EventView)> event_handler) override {
registered_events_[event_code] = event_handler;
}
@@ -205,7 +229,7 @@
registered_le_events_.erase(subevent_code);
}
- void IncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
+ void SendIncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
auto packet = GetPacketView(std::move(event_builder));
EventView event = EventView::Create(packet);
ASSERT_TRUE(event.IsValid());
@@ -242,7 +266,7 @@
queue_end,
handle,
common::Passed(std::move(promise))));
- auto status = future.wait_for(kTimeout);
+ auto status = future.wait_for(2s);
ASSERT_EQ(status, std::future_status::ready);
}
@@ -291,7 +315,17 @@
GetHandler()->Post(common::BindOnce(&TestHciLayer::do_disconnect, common::Unretained(this), handle, reason));
}
+ std::unique_ptr<std::promise<void>> hci_command_promise_;
+
private:
+ void Notify() {
+ if (hci_command_promise_ != nullptr) {
+ std::promise<void>* prom = hci_command_promise_.release();
+ prom->set_value();
+ delete prom;
+ }
+ }
+
std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_;
std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_;
std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
@@ -299,7 +333,6 @@
BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */};
std::queue<std::unique_ptr<CommandBuilder>> command_queue_;
- std::unique_ptr<std::promise<void>> command_promise_;
std::unique_ptr<std::future<void>> command_future_;
void do_disconnect(uint16_t handle, ErrorCode reason) {
@@ -307,90 +340,122 @@
}
};
-class AclManagerNoCallbacksTest : public ::testing::Test {
+class MockConnectionCallback : public ConnectionCallbacks {
+ public:
+ void OnConnectSuccess(std::unique_ptr<ClassicAclConnection> connection) override {
+ // Convert to std::shared_ptr during push_back()
+ connections_.push_back(std::move(connection));
+ if (is_promise_set_) {
+ is_promise_set_ = false;
+ connection_promise_.set_value(connections_.back());
+ }
+ }
+ MOCK_METHOD(void, OnConnectFail, (Address, ErrorCode reason), (override));
+
+ MOCK_METHOD(void, HACK_OnEscoConnectRequest, (Address, ClassOfDevice), (override));
+ MOCK_METHOD(void, HACK_OnScoConnectRequest, (Address, ClassOfDevice), (override));
+
+ size_t NumberOfConnections() const {
+ return connections_.size();
+ }
+
+ private:
+ friend class AclManagerWithCallbacksTest;
+ friend class AclManagerNoCallbacksTest;
+
+ std::deque<std::shared_ptr<ClassicAclConnection>> connections_;
+ std::promise<std::shared_ptr<ClassicAclConnection>> connection_promise_;
+ bool is_promise_set_{false};
+};
+
+class MockLeConnectionCallbacks : public LeConnectionCallbacks {
+ public:
+ void OnLeConnectSuccess(AddressWithType address_with_type, std::unique_ptr<LeAclConnection> connection) override {
+ le_connections_.push_back(std::move(connection));
+ if (le_connection_promise_ != nullptr) {
+ std::promise<void>* prom = le_connection_promise_.release();
+ prom->set_value();
+ delete prom;
+ }
+ }
+ MOCK_METHOD(void, OnLeConnectFail, (AddressWithType, ErrorCode reason), (override));
+
+ std::deque<std::shared_ptr<LeAclConnection>> le_connections_;
+ std::unique_ptr<std::promise<void>> le_connection_promise_;
+};
+
+class AclManagerBaseTest : public ::testing::Test {
protected:
void SetUp() override {
+ common::InitFlags::SetAllForTesting();
test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry
+ ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
test_controller_ = new TestController;
fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
ASSERT_NE(client_handler_, nullptr);
- test_hci_layer_->SetCommandFuture();
fake_registry_.Start<AclManager>(&thread_);
- acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
- Address::FromString("A1:A2:A3:A4:A5:A6", remote);
-
- hci::Address address;
- Address::FromString("D0:05:04:03:02:01", address);
- hci::AddressWithType address_with_type(address, hci::AddressType::RANDOM_DEVICE_ADDRESS);
- auto minimum_rotation_time = std::chrono::milliseconds(7 * 60 * 1000);
- auto maximum_rotation_time = std::chrono::milliseconds(15 * 60 * 1000);
- acl_manager_->SetPrivacyPolicyForInitiatorAddress(
- LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS,
- address_with_type,
- minimum_rotation_time,
- maximum_rotation_time);
-
- auto set_random_address_packet = LeSetRandomAddressView::Create(
- LeAdvertisingCommandView::Create(test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS)));
- ASSERT_TRUE(set_random_address_packet.IsValid());
- my_initiating_address =
- AddressWithType(set_random_address_packet.GetRandomAddress(), AddressType::RANDOM_DEVICE_ADDRESS);
- // Verify LE Set Random Address was sent during setup
- test_hci_layer_->GetLastCommand(OpCode::LE_SET_RANDOM_ADDRESS);
- test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
}
void TearDown() override {
- mock_connection_callbacks_.connections_.clear();
- mock_le_connection_callbacks_.le_connections_.clear();
-
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
fake_registry_.StopAll();
}
- TestModuleRegistry fake_registry_;
+ void sync_client_handler() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ client_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ auto future_status = future.wait_for(std::chrono::seconds(1));
+ ASSERT_EQ(future_status, std::future_status::ready);
+ }
+
TestHciLayer* test_hci_layer_ = nullptr;
TestController* test_controller_ = nullptr;
+
+ TestModuleRegistry fake_registry_;
os::Thread& thread_ = fake_registry_.GetTestThread();
AclManager* acl_manager_ = nullptr;
os::Handler* client_handler_ = nullptr;
- Address remote;
- AddressWithType my_initiating_address;
+};
+
+class AclManagerNoCallbacksTest : public AclManagerBaseTest {
+ protected:
+ void SetUp() override {
+ AclManagerBaseTest::SetUp();
+ ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
+
+ acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
+
+ local_address_with_type_ = AddressWithType(
+ Address::FromString(kLocalRandomAddressString).value(), hci::AddressType::RANDOM_DEVICE_ADDRESS);
+
+ ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
+ auto future = test_hci_layer_->GetOutgoingCommandFuture();
+
+ acl_manager_->SetPrivacyPolicyForInitiatorAddress(
+ LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS,
+ local_address_with_type_,
+ kMinimumRotationTime,
+ kMaximumRotationTime);
+
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+ sync_client_handler();
+ ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
+ auto command = test_hci_layer_->GetLastOutgoingCommand();
+ ASSERT_TRUE(command.IsValid());
+ ASSERT_EQ(OpCode::LE_SET_RANDOM_ADDRESS, command.GetOpCode());
+ }
+
+ void TearDown() override {
+ AclManagerBaseTest::TearDown();
+ }
+
+ AddressWithType local_address_with_type_;
const bool use_connect_list_ = true; // gd currently only supports connect list
- void check_connection_promise_not_null() {
- ASSERT_TRUE(mock_connection_callbacks_.connection_promise_ == nullptr)
- << "Promises promises ... Only one at a time";
- }
-
- std::future<void> GetConnectionFuture() {
- check_connection_promise_not_null();
- mock_connection_callbacks_.connection_promise_ = std::make_unique<std::promise<void>>();
- return mock_connection_callbacks_.connection_promise_->get_future();
- }
-
- std::future<void> GetLeConnectionFuture() {
- check_connection_promise_not_null();
- mock_le_connection_callbacks_.le_connection_promise_ = std::make_unique<std::promise<void>>();
- return mock_le_connection_callbacks_.le_connection_promise_->get_future();
- }
-
- void check_connections_not_empty() {
- ASSERT_TRUE(!mock_connection_callbacks_.connections_.empty()) << "There are no classic ACL connections";
- }
-
- std::shared_ptr<ClassicAclConnection> GetLastConnection() {
- check_connections_not_empty();
- return mock_connection_callbacks_.connections_.back();
- }
-
- std::shared_ptr<LeAclConnection> GetLastLeConnection() {
- check_connections_not_empty();
- return mock_le_connection_callbacks_.le_connections_.back();
- }
-
void SendAclData(uint16_t handle, AclConnection::QueueUpEnd* queue_end) {
std::promise<void> promise;
auto future = promise.get_future();
@@ -405,51 +470,18 @@
queue_end,
handle,
common::Passed(std::move(promise))));
- auto status = future.wait_for(kTimeout);
+ auto status = future.wait_for(2s);
ASSERT_EQ(status, std::future_status::ready);
}
-
- class MockConnectionCallback : public ConnectionCallbacks {
- public:
- void OnConnectSuccess(std::unique_ptr<ClassicAclConnection> connection) override {
- // Convert to std::shared_ptr during push_back()
- connections_.push_back(std::move(connection));
- if (connection_promise_ != nullptr) {
- connection_promise_->set_value();
- connection_promise_.reset();
- }
- }
- MOCK_METHOD(void, OnConnectFail, (Address, ErrorCode reason), (override));
-
- MOCK_METHOD(void, HACK_OnEscoConnectRequest, (Address, ClassOfDevice), (override));
- MOCK_METHOD(void, HACK_OnScoConnectRequest, (Address, ClassOfDevice), (override));
-
- std::list<std::shared_ptr<ClassicAclConnection>> connections_;
- std::unique_ptr<std::promise<void>> connection_promise_;
- } mock_connection_callbacks_;
-
- class MockLeConnectionCallbacks : public LeConnectionCallbacks {
- public:
- void OnLeConnectSuccess(AddressWithType address_with_type, std::unique_ptr<LeAclConnection> connection) override {
- le_connections_.push_back(std::move(connection));
- if (le_connection_promise_ != nullptr) {
- le_connection_promise_->set_value();
- le_connection_promise_.reset();
- }
- }
- MOCK_METHOD(void, OnLeConnectFail, (AddressWithType, ErrorCode reason), (override));
-
- std::list<std::shared_ptr<LeAclConnection>> le_connections_;
- std::unique_ptr<std::promise<void>> le_connection_promise_;
- } mock_le_connection_callbacks_;
};
-class AclManagerTest : public AclManagerNoCallbacksTest {
+class AclManagerWithCallbacksTest : public AclManagerNoCallbacksTest {
protected:
void SetUp() override {
AclManagerNoCallbacksTest::SetUp();
acl_manager_->RegisterCallbacks(&mock_connection_callbacks_, client_handler_);
acl_manager_->RegisterLeCallbacks(&mock_le_connection_callbacks_, client_handler_);
+ ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
}
void TearDown() override {
@@ -468,16 +500,53 @@
acl_manager_->UnregisterCallbacks(&mock_connection_callbacks_, std::move(promise));
future.wait_for(2s);
}
+
+ mock_connection_callbacks_.connections_.clear();
+ mock_le_connection_callbacks_.le_connections_.clear();
+
AclManagerNoCallbacksTest::TearDown();
}
+
+ std::future<std::shared_ptr<ClassicAclConnection>> GetConnectionFuture() {
+ // Run on main thread
+ mock_connection_callbacks_.connection_promise_ = std::promise<std::shared_ptr<ClassicAclConnection>>();
+ mock_connection_callbacks_.is_promise_set_ = true;
+ return mock_connection_callbacks_.connection_promise_.get_future();
+ }
+
+ std::future<void> GetLeConnectionFuture() {
+ mock_le_connection_callbacks_.le_connection_promise_ = std::make_unique<std::promise<void>>();
+ return mock_le_connection_callbacks_.le_connection_promise_->get_future();
+ }
+
+ std::shared_ptr<ClassicAclConnection> GetLastConnection() {
+ return mock_connection_callbacks_.connections_.back();
+ }
+
+ size_t NumberOfConnections() {
+ return mock_connection_callbacks_.connections_.size();
+ }
+
+ std::shared_ptr<LeAclConnection> GetLastLeConnection() {
+ return mock_le_connection_callbacks_.le_connections_.back();
+ }
+
+ size_t NumberOfLeConnections() {
+ return mock_le_connection_callbacks_.le_connections_.size();
+ }
+
+ MockConnectionCallback mock_connection_callbacks_;
+ MockLeConnectionCallbacks mock_le_connection_callbacks_;
};
-class AclManagerWithConnectionTest : public AclManagerTest {
+class AclManagerWithConnectionTest : public AclManagerWithCallbacksTest {
protected:
void SetUp() override {
- AclManagerTest::SetUp();
+ AclManagerWithCallbacksTest::SetUp();
handle_ = 0x123;
+ Address::FromString("A1:A2:A3:A4:A5:A6", remote);
+
acl_manager_->CreateConnection(remote);
// Wait for the connection request
@@ -489,10 +558,10 @@
EXPECT_CALL(mock_connection_management_callbacks_, OnRoleChange(hci::ErrorCode::SUCCESS, Role::CENTRAL));
auto first_connection = GetConnectionFuture();
- test_hci_layer_->IncomingEvent(
+ test_hci_layer_->SendIncomingEvent(
ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, remote, LinkType::ACL, Enable::DISABLED));
- auto first_connection_status = first_connection.wait_for(kTimeout);
+ auto first_connection_status = first_connection.wait_for(2s);
ASSERT_EQ(first_connection_status, std::future_status::ready);
connection_ = GetLastConnection();
@@ -505,15 +574,8 @@
fake_registry_.StopAll();
}
- void sync_client_handler() {
- std::promise<void> promise;
- auto future = promise.get_future();
- client_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
- auto future_status = future.wait_for(std::chrono::seconds(1));
- ASSERT_EQ(future_status, std::future_status::ready);
- }
-
uint16_t handle_;
+ Address remote;
std::shared_ptr<ClassicAclConnection> connection_;
class MockConnectionManagementCallbacks : public ConnectionManagementCallbacks {
@@ -572,19 +634,20 @@
} mock_connection_management_callbacks_;
};
-TEST_F(AclManagerTest, startup_teardown) {}
+TEST_F(AclManagerWithCallbacksTest, startup_teardown) {}
-class AclManagerWithLeConnectionTest : public AclManagerTest {
+class AclManagerWithLeConnectionTest : public AclManagerWithCallbacksTest {
protected:
void SetUp() override {
- AclManagerTest::SetUp();
+ AclManagerWithCallbacksTest::SetUp();
- remote_with_type_ = AddressWithType(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
- test_hci_layer_->SetCommandFuture();
+ Address remote_public_address = Address::FromString(kRemotePublicDeviceStringA).value();
+ remote_with_type_ = AddressWithType(remote_public_address, AddressType::PUBLIC_DEVICE_ADDRESS);
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
acl_manager_->CreateLeConnection(remote_with_type_, true);
test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
- test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
+ test_hci_layer_->SendIncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
auto packet = test_hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
auto le_connection_management_command_view =
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
@@ -594,11 +657,11 @@
ASSERT_EQ(command_view.GetPeerAddress(), empty_address_with_type.GetAddress());
ASSERT_EQ(command_view.GetPeerAddressType(), empty_address_with_type.GetAddressType());
} else {
- ASSERT_EQ(command_view.GetPeerAddress(), remote);
+ ASSERT_EQ(command_view.GetPeerAddress(), remote_public_address);
ASSERT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);
}
- test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
+ test_hci_layer_->SendIncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
auto first_connection = GetLeConnectionFuture();
@@ -607,17 +670,18 @@
handle_,
Role::PERIPHERAL,
AddressType::PUBLIC_DEVICE_ADDRESS,
- remote,
+ remote_public_address,
0x0100,
0x0010,
0x0C80,
ClockAccuracy::PPM_30));
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
- test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ test_hci_layer_->SendIncomingEvent(
+ LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- auto first_connection_status = first_connection.wait_for(kTimeout);
+ auto first_connection_status = first_connection.wait_for(2s);
ASSERT_EQ(first_connection_status, std::future_status::ready);
connection_ = GetLastLeConnection();
@@ -661,7 +725,7 @@
} mock_le_connection_management_callbacks_;
};
-class AclManagerWithResolvableAddressTest : public AclManagerNoCallbacksTest {
+class AclManagerWithResolvableAddressTest : public AclManagerWithCallbacksTest {
protected:
void SetUp() override {
test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry
@@ -670,11 +734,9 @@
fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
ASSERT_NE(client_handler_, nullptr);
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
fake_registry_.Start<AclManager>(&thread_);
acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
- Address::FromString("A1:A2:A3:A4:A5:A6", remote);
-
hci::Address address;
Address::FromString("D0:05:04:03:02:01", address);
hci::AddressWithType address_with_type(address, hci::AddressType::RANDOM_DEVICE_ADDRESS);
@@ -689,25 +751,17 @@
maximum_rotation_time);
test_hci_layer_->GetLastCommand(OpCode::LE_SET_RANDOM_ADDRESS);
- test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ test_hci_layer_->SendIncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
}
};
-class AclManagerLifeCycleTest : public AclManagerNoCallbacksTest {
- protected:
- void SetUp() override {
- AclManagerNoCallbacksTest::SetUp();
- acl_manager_->RegisterCallbacks(&mock_connection_callbacks_, client_handler_);
- acl_manager_->RegisterLeCallbacks(&mock_le_connection_callbacks_, client_handler_);
- }
-
- AddressWithType remote_with_type_;
- uint16_t handle_{0x123};
-};
-
-TEST_F(AclManagerLifeCycleTest, unregister_classic_before_connection_request) {
+TEST_F(AclManagerNoCallbacksTest, unregister_classic_before_connection_request) {
ClassOfDevice class_of_device;
+ MockConnectionCallback mock_connection_callbacks_;
+
+ acl_manager_->RegisterCallbacks(&mock_connection_callbacks_, client_handler_);
+
// Unregister callbacks before receiving connection request
auto promise = std::promise<void>();
auto future = promise.get_future();
@@ -715,103 +769,126 @@
future.get();
// Inject peer sending connection request
- auto connection_future = GetConnectionFuture();
- test_hci_layer_->IncomingEvent(
- ConnectionRequestBuilder::Create(remote, class_of_device, ConnectionRequestLinkType::ACL));
- auto connection_future_status = connection_future.wait_for(kTimeout);
- ASSERT_NE(connection_future_status, std::future_status::ready);
+ test_hci_layer_->SendIncomingEvent(ConnectionRequestBuilder::Create(
+ local_address_with_type_.GetAddress(), class_of_device, ConnectionRequestLinkType::ACL));
+ sync_client_handler();
- test_hci_layer_->GetLastCommand(OpCode::REJECT_CONNECTION_REQUEST);
+ // There should be no connections
+ ASSERT_EQ(0UL, mock_connection_callbacks_.NumberOfConnections());
+
+ auto command = test_hci_layer_->GetLastOutgoingCommand();
+ ASSERT_TRUE(command.IsValid());
+ ASSERT_EQ(OpCode::REJECT_CONNECTION_REQUEST, command.GetOpCode());
}
-TEST_F(AclManagerTest, two_remote_connection_requests_ABAB) {
- struct {
- Address address;
- ClassOfDevice class_of_device;
- const uint16_t handle;
- } remote[2] = {
- {
- .address = {},
- .class_of_device = {},
- .handle = 123,
- },
- {.address = {}, .class_of_device = {}, .handle = 456},
- };
- Address::FromString("A1:A2:A3:A4:A5:A6", remote[0].address);
- Address::FromString("B1:B2:B3:B4:B5:B6", remote[1].address);
-
- test_hci_layer_->SetCommandFuture();
- test_hci_layer_->IncomingEvent(
- ConnectionRequestBuilder::Create(remote[0].address, remote[0].class_of_device, ConnectionRequestLinkType::ACL));
- test_hci_layer_->GetLastCommand(OpCode::ACCEPT_CONNECTION_REQUEST);
-
- test_hci_layer_->SetCommandFuture();
- test_hci_layer_->IncomingEvent(
- ConnectionRequestBuilder::Create(remote[1].address, remote[1].class_of_device, ConnectionRequestLinkType::ACL));
- test_hci_layer_->GetLastCommand(OpCode::ACCEPT_CONNECTION_REQUEST);
+TEST_F(AclManagerWithCallbacksTest, two_remote_connection_requests_ABAB) {
+ Address::FromString(kRemotePublicDeviceStringA, remote_device[0].address);
+ Address::FromString(kRemotePublicDeviceStringB, remote_device[1].address);
{
- auto first_connection = GetConnectionFuture();
- test_hci_layer_->IncomingEvent(ConnectionCompleteBuilder::Create(
- ErrorCode::SUCCESS, remote[0].handle, remote[0].address, LinkType::ACL, Enable::DISABLED));
- auto first_connection_status = first_connection.wait_for(kTimeout);
- ASSERT_EQ(first_connection_status, std::future_status::ready);
+ // Device A sends connection request
+ auto future = test_hci_layer_->GetOutgoingCommandFuture();
+ test_hci_layer_->SendIncomingEvent(ConnectionRequestBuilder::Create(
+ remote_device[0].address, remote_device[0].class_of_device, ConnectionRequestLinkType::ACL));
+ sync_client_handler();
+ // Verify we accept this connection
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+ auto command = test_hci_layer_->GetLastOutgoingCommand();
+ ASSERT_TRUE(command.IsValid());
+ ASSERT_EQ(OpCode::ACCEPT_CONNECTION_REQUEST, command.GetOpCode());
}
- ASSERT_EQ(GetLastConnection()->GetAddress(), remote[0].address);
{
- auto first_connection = GetConnectionFuture();
- test_hci_layer_->IncomingEvent(ConnectionCompleteBuilder::Create(
- ErrorCode::SUCCESS, remote[1].handle, remote[1].address, LinkType::ACL, Enable::DISABLED));
- auto first_connection_status = first_connection.wait_for(2s);
- ASSERT_EQ(first_connection_status, std::future_status::ready);
+ // Device B sends connection request
+ auto future = test_hci_layer_->GetOutgoingCommandFuture();
+ test_hci_layer_->SendIncomingEvent(ConnectionRequestBuilder::Create(
+ remote_device[1].address, remote_device[1].class_of_device, ConnectionRequestLinkType::ACL));
+ sync_client_handler();
+ // Verify we accept this connection
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+ auto command = test_hci_layer_->GetLastOutgoingCommand();
+ ASSERT_TRUE(command.IsValid());
+ ASSERT_EQ(OpCode::ACCEPT_CONNECTION_REQUEST, command.GetOpCode());
}
- ASSERT_EQ(GetLastConnection()->GetAddress(), remote[1].address);
+
+ ASSERT_EQ(0UL, NumberOfConnections());
+
+ {
+ // Device A completes first connection
+ auto future = GetConnectionFuture();
+ test_hci_layer_->SendIncomingEvent(ConnectionCompleteBuilder::Create(
+ ErrorCode::SUCCESS, remote_device[0].handle, remote_device[0].address, LinkType::ACL, Enable::DISABLED));
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s)) << "Timeout waiting for first connection complete";
+ ASSERT_EQ(1UL, NumberOfConnections());
+ auto connection = future.get();
+ ASSERT_EQ(connection->GetAddress(), remote_device[0].address) << "First connection remote address mismatch";
+ }
+
+ {
+ // Device B completes second connection
+ auto future = GetConnectionFuture();
+ test_hci_layer_->SendIncomingEvent(ConnectionCompleteBuilder::Create(
+ ErrorCode::SUCCESS, remote_device[1].handle, remote_device[1].address, LinkType::ACL, Enable::DISABLED));
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s)) << "Timeout waiting for second connection complete";
+ ASSERT_EQ(2UL, NumberOfConnections());
+ auto connection = future.get();
+ ASSERT_EQ(connection->GetAddress(), remote_device[1].address) << "Second connection remote address mismatch";
+ }
}
-TEST_F(AclManagerTest, two_remote_connection_requests_ABBA) {
- struct {
- Address address;
- ClassOfDevice class_of_device;
- const uint16_t handle;
- } remote[2] = {
- {
- .address = {},
- .class_of_device = {},
- .handle = 123,
- },
- {.address = {}, .class_of_device = {}, .handle = 456},
- };
- Address::FromString("A1:A2:A3:A4:A5:A6", remote[0].address);
- Address::FromString("B1:B2:B3:B4:B5:B6", remote[1].address);
-
- test_hci_layer_->SetCommandFuture();
- test_hci_layer_->IncomingEvent(
- ConnectionRequestBuilder::Create(remote[0].address, remote[0].class_of_device, ConnectionRequestLinkType::ACL));
- test_hci_layer_->GetLastCommand(OpCode::ACCEPT_CONNECTION_REQUEST);
-
- test_hci_layer_->SetCommandFuture();
- test_hci_layer_->IncomingEvent(
- ConnectionRequestBuilder::Create(remote[1].address, remote[1].class_of_device, ConnectionRequestLinkType::ACL));
- test_hci_layer_->GetLastCommand(OpCode::ACCEPT_CONNECTION_REQUEST);
+TEST_F(AclManagerWithCallbacksTest, two_remote_connection_requests_ABBA) {
+ Address::FromString(kRemotePublicDeviceStringA, remote_device[0].address);
+ Address::FromString(kRemotePublicDeviceStringB, remote_device[1].address);
{
- auto first_connection = GetConnectionFuture();
- test_hci_layer_->IncomingEvent(ConnectionCompleteBuilder::Create(
- ErrorCode::SUCCESS, remote[1].handle, remote[1].address, LinkType::ACL, Enable::DISABLED));
- auto first_connection_status = first_connection.wait_for(2s);
- ASSERT_EQ(first_connection_status, std::future_status::ready);
+ // Device A sends connection request
+ auto future = test_hci_layer_->GetOutgoingCommandFuture();
+ test_hci_layer_->SendIncomingEvent(ConnectionRequestBuilder::Create(
+ remote_device[0].address, remote_device[0].class_of_device, ConnectionRequestLinkType::ACL));
+ sync_client_handler();
+ // Verify we accept this connection
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+ auto command = test_hci_layer_->GetLastOutgoingCommand();
+ ASSERT_TRUE(command.IsValid());
+ ASSERT_EQ(OpCode::ACCEPT_CONNECTION_REQUEST, command.GetOpCode());
}
- ASSERT_EQ(GetLastConnection()->GetAddress(), remote[1].address);
{
- auto first_connection = GetConnectionFuture();
- test_hci_layer_->IncomingEvent(ConnectionCompleteBuilder::Create(
- ErrorCode::SUCCESS, remote[0].handle, remote[0].address, LinkType::ACL, Enable::DISABLED));
- auto first_connection_status = first_connection.wait_for(kTimeout);
- ASSERT_EQ(first_connection_status, std::future_status::ready);
+ // Device B sends connection request
+ auto future = test_hci_layer_->GetOutgoingCommandFuture();
+ test_hci_layer_->SendIncomingEvent(ConnectionRequestBuilder::Create(
+ remote_device[1].address, remote_device[1].class_of_device, ConnectionRequestLinkType::ACL));
+ sync_client_handler();
+ // Verify we accept this connection
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+ auto command = test_hci_layer_->GetLastOutgoingCommand();
+ ASSERT_TRUE(command.IsValid());
+ ASSERT_EQ(OpCode::ACCEPT_CONNECTION_REQUEST, command.GetOpCode());
}
- ASSERT_EQ(GetLastConnection()->GetAddress(), remote[0].address);
+
+ ASSERT_EQ(0UL, NumberOfConnections());
+
+ {
+ // Device B completes first connection
+ auto future = GetConnectionFuture();
+ test_hci_layer_->SendIncomingEvent(ConnectionCompleteBuilder::Create(
+ ErrorCode::SUCCESS, remote_device[1].handle, remote_device[1].address, LinkType::ACL, Enable::DISABLED));
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s)) << "Timeout waiting for first connection complete";
+ ASSERT_EQ(1UL, NumberOfConnections());
+ auto connection = future.get();
+ ASSERT_EQ(connection->GetAddress(), remote_device[1].address) << "First connection remote address mismatch";
+ }
+
+ {
+ // Device A completes second connection
+ auto future = GetConnectionFuture();
+ test_hci_layer_->SendIncomingEvent(ConnectionCompleteBuilder::Create(
+ ErrorCode::SUCCESS, remote_device[0].handle, remote_device[0].address, LinkType::ACL, Enable::DISABLED));
+ ASSERT_EQ(std::future_status::ready, future.wait_for(2s)) << "Timeout waiting for second connection complete";
+ ASSERT_EQ(2UL, NumberOfConnections());
+ auto connection = future.get();
+ ASSERT_EQ(connection->GetAddress(), remote_device[0].address) << "Second connection remote address mismatch";
+ }
}
} // namespace
diff --git a/system/gd/hci/address.cc b/system/gd/hci/address.cc
index 3dc013f..7409418 100644
--- a/system/gd/hci/address.cc
+++ b/system/gd/hci/address.cc
@@ -42,10 +42,15 @@
std::copy(l.begin(), std::min(l.begin() + kLength, l.end()), data());
}
-std::string Address::ToString() const {
+std::string Address::_ToMaskedColonSepHexString(int bytes_to_mask) const {
std::stringstream ss;
+ int count = 0;
for (auto it = address.rbegin(); it != address.rend(); it++) {
- ss << std::nouppercase << std::hex << std::setw(2) << std::setfill('0') << +*it;
+ if (count++ < bytes_to_mask) {
+ ss << "xx";
+ } else {
+ ss << std::nouppercase << std::hex << std::setw(2) << std::setfill('0') << +*it;
+ }
if (std::next(it) != address.rend()) {
ss << ':';
}
@@ -53,6 +58,22 @@
return ss.str();
}
+std::string Address::ToString() const {
+ return _ToMaskedColonSepHexString(0);
+}
+
+std::string Address::ToColonSepHexString() const {
+ return _ToMaskedColonSepHexString(0);
+}
+
+std::string Address::ToStringForLogging() const {
+ return _ToMaskedColonSepHexString(0);
+}
+
+std::string Address::ToRedactedStringForLogging() const {
+ return _ToMaskedColonSepHexString(4);
+}
+
std::string Address::ToLegacyConfigString() const {
return ToString();
}
diff --git a/system/gd/hci/address.h b/system/gd/hci/address.h
index c5e43d4..2c1dfff 100644
--- a/system/gd/hci/address.h
+++ b/system/gd/hci/address.h
@@ -25,13 +25,16 @@
#include <ostream>
#include <string>
+#include "common/interfaces/ILoggable.h"
#include "packet/custom_field_fixed_size_interface.h"
#include "storage/serializable.h"
namespace bluetooth {
namespace hci {
-class Address final : public packet::CustomFieldFixedSizeInterface<Address>, public storage::Serializable<Address> {
+class Address final : public packet::CustomFieldFixedSizeInterface<Address>,
+ public storage::Serializable<Address>,
+ public bluetooth::common::IRedactableLoggable {
public:
static constexpr size_t kLength = 6;
@@ -51,6 +54,10 @@
// storage::Serializable methods
std::string ToString() const override;
+ std::string ToColonSepHexString() const;
+ std::string ToStringForLogging() const override;
+ std::string ToRedactedStringForLogging() const override;
+
static std::optional<Address> FromString(const std::string& from);
std::string ToLegacyConfigString() const override;
static std::optional<Address> FromLegacyConfigString(const std::string& str);
@@ -91,8 +98,12 @@
static const Address kEmpty; // 00:00:00:00:00:00
static const Address kAny; // FF:FF:FF:FF:FF:FF
+ private:
+ std::string _ToMaskedColonSepHexString(int bytes_to_mask) const;
};
+// TODO: to fine-tune this.
+// we need an interface between the logger and ILoggable
inline std::ostream& operator<<(std::ostream& os, const Address& a) {
os << a.ToString();
return os;
diff --git a/system/gd/hci/address_unittest.cc b/system/gd/hci/address_unittest.cc
index ae2c2e7..a675682 100644
--- a/system/gd/hci/address_unittest.cc
+++ b/system/gd/hci/address_unittest.cc
@@ -16,12 +16,14 @@
*
******************************************************************************/
-#include <unordered_map>
+#include "hci/address.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "hci/address.h"
+#include <cstdint>
+#include <string>
+#include <unordered_map>
using bluetooth::hci::Address;
@@ -233,3 +235,14 @@
struct std::hash<Address> hasher;
ASSERT_NE(hasher(Address::kEmpty), hasher(Address::kAny));
}
+
+TEST(AddressTest, ToStringForLoggingTestOutputUnderDebuggablePropAndInitFlag) {
+ Address addr{{0xab, 0x55, 0x44, 0x33, 0x22, 0x11}};
+ const std::string redacted_loggable_str = "xx:xx:xx:xx:55:ab";
+ const std::string loggable_str = "11:22:33:44:55:ab";
+
+ std::string ret1 = addr.ToStringForLogging();
+ ASSERT_STREQ(ret1.c_str(), loggable_str.c_str());
+ std::string ret2 = addr.ToRedactedStringForLogging();
+ ASSERT_STREQ(ret2.c_str(), redacted_loggable_str.c_str());
+}
diff --git a/system/gd/hci/address_with_type.h b/system/gd/hci/address_with_type.h
index ec4d40c..75a0b3c 100644
--- a/system/gd/hci/address_with_type.h
+++ b/system/gd/hci/address_with_type.h
@@ -22,6 +22,7 @@
#include <string>
#include <utility>
+#include "common/interfaces/ILoggable.h"
#include "crypto_toolbox/crypto_toolbox.h"
#include "hci/address.h"
#include "hci/hci_packets.h"
@@ -29,7 +30,7 @@
namespace bluetooth {
namespace hci {
-class AddressWithType final {
+class AddressWithType final : public bluetooth::common::IRedactableLoggable {
public:
AddressWithType(Address address, AddressType address_type)
: address_(std::move(address)), address_type_(address_type) {}
@@ -119,6 +120,14 @@
return ss.str();
}
+ std::string ToStringForLogging() const override {
+ return address_.ToStringForLogging() + "[" + AddressTypeText(address_type_) + "]";
+ }
+
+ std::string ToRedactedStringForLogging() const override {
+ return address_.ToStringForLogging() + "[" + AddressTypeText(address_type_) + "]";
+ }
+
private:
Address address_;
AddressType address_type_;
diff --git a/system/gd/hci/controller.cc b/system/gd/hci/controller.cc
index 3c8b69d..9dac2b6 100644
--- a/system/gd/hci/controller.cc
+++ b/system/gd/hci/controller.cc
@@ -870,27 +870,27 @@
CompletedAclPacketsCallback acl_credits_callback_{};
CompletedAclPacketsCallback acl_monitor_credits_callback_{};
- LocalVersionInformation local_version_information_;
- std::array<uint8_t, 64> local_supported_commands_;
- std::vector<uint64_t> extended_lmp_features_array_;
- uint16_t acl_buffer_length_ = 0;
- uint16_t acl_buffers_ = 0;
- uint8_t sco_buffer_length_ = 0;
- uint16_t sco_buffers_ = 0;
- Address mac_address_;
- std::string local_name_;
- LeBufferSize le_buffer_size_;
- LeBufferSize iso_buffer_size_;
- uint64_t le_local_supported_features_;
- uint64_t le_supported_states_;
- uint8_t le_connect_list_size_;
- uint8_t le_resolving_list_size_;
- LeMaximumDataLength le_maximum_data_length_;
- uint16_t le_maximum_advertising_data_length_;
- uint16_t le_suggested_default_data_length_;
- uint8_t le_number_supported_advertising_sets_;
- uint8_t le_periodic_advertiser_list_size_;
- VendorCapabilities vendor_capabilities_;
+ LocalVersionInformation local_version_information_{};
+ std::array<uint8_t, 64> local_supported_commands_{};
+ std::vector<uint64_t> extended_lmp_features_array_{};
+ uint16_t acl_buffer_length_{};
+ uint16_t acl_buffers_{};
+ uint8_t sco_buffer_length_{};
+ uint16_t sco_buffers_{};
+ Address mac_address_{};
+ std::string local_name_{};
+ LeBufferSize le_buffer_size_{};
+ LeBufferSize iso_buffer_size_{};
+ uint64_t le_local_supported_features_{};
+ uint64_t le_supported_states_{};
+ uint8_t le_connect_list_size_{};
+ uint8_t le_resolving_list_size_{};
+ LeMaximumDataLength le_maximum_data_length_{};
+ uint16_t le_maximum_advertising_data_length_{};
+ uint16_t le_suggested_default_data_length_{};
+ uint8_t le_number_supported_advertising_sets_{};
+ uint8_t le_periodic_advertiser_list_size_{};
+ VendorCapabilities vendor_capabilities_{};
}; // namespace hci
Controller::Controller() : impl_(std::make_unique<impl>(*this)) {}
diff --git a/system/gd/hci/controller_test.cc b/system/gd/hci/controller_test.cc
index dacdef7..6353482 100644
--- a/system/gd/hci/controller_test.cc
+++ b/system/gd/hci/controller_test.cc
@@ -54,7 +54,6 @@
uint16_t feature_spec_version = 55;
constexpr char title[] = "hci_controller_test";
-
PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
auto bytes = std::make_shared<std::vector<uint8_t>>();
BitInserter i(*bytes);
@@ -65,6 +64,8 @@
} // namespace
+namespace {
+
class TestHciLayer : public HciLayer {
public:
void EnqueueCommand(
@@ -281,9 +282,11 @@
std::condition_variable not_empty_;
};
+} // namespace
class ControllerTest : public ::testing::Test {
protected:
void SetUp() override {
+ feature_spec_version = feature_spec_version_;
bluetooth::common::InitFlags::SetAllForTesting();
test_hci_layer_ = new TestHciLayer;
fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
@@ -301,6 +304,31 @@
os::Thread& thread_ = fake_registry_.GetTestThread();
Controller* controller_ = nullptr;
os::Handler* client_handler_ = nullptr;
+ uint16_t feature_spec_version_ = 98;
+};
+
+class Controller055Test : public ControllerTest {
+ protected:
+ void SetUp() override {
+ feature_spec_version_ = 55;
+ ControllerTest::SetUp();
+ }
+};
+
+class Controller095Test : public ControllerTest {
+ protected:
+ void SetUp() override {
+ feature_spec_version_ = 95;
+ ControllerTest::SetUp();
+ }
+};
+
+class Controller096Test : public ControllerTest {
+ protected:
+ void SetUp() override {
+ feature_spec_version_ = 96;
+ ControllerTest::SetUp();
+ }
};
TEST_F(ControllerTest, startup_teardown) {}
@@ -407,28 +435,25 @@
ASSERT_FALSE(controller_->IsSupported(OpCode::LE_SET_PERIODIC_ADVERTISING_PARAM));
}
-TEST_F(ControllerTest, feature_spec_version_055_test) {
+TEST_F(Controller055Test, feature_spec_version_055_test) {
ASSERT_EQ(controller_->GetVendorCapabilities().version_supported_, 55);
ASSERT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
- feature_spec_version = 95;
}
-TEST_F(ControllerTest, feature_spec_version_095_test) {
+TEST_F(Controller095Test, feature_spec_version_095_test) {
ASSERT_EQ(controller_->GetVendorCapabilities().version_supported_, 95);
ASSERT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
- feature_spec_version = 96;
}
-TEST_F(ControllerTest, feature_spec_version_096_test) {
+TEST_F(Controller096Test, feature_spec_version_096_test) {
ASSERT_EQ(controller_->GetVendorCapabilities().version_supported_, 96);
ASSERT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
- feature_spec_version = 98;
}
TEST_F(ControllerTest, feature_spec_version_098_test) {
@@ -436,7 +461,6 @@
ASSERT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
ASSERT_TRUE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
- feature_spec_version = 55;
}
std::promise<void> credits1_set;
diff --git a/system/gd/hci/hci_layer_fake.cc b/system/gd/hci/hci_layer_fake.cc
index 65ef988..3000c56 100644
--- a/system/gd/hci/hci_layer_fake.cc
+++ b/system/gd/hci/hci_layer_fake.cc
@@ -25,6 +25,8 @@
namespace bluetooth {
namespace hci {
+using common::BidiQueue;
+using common::BidiQueueEnd;
using packet::kLittleEndian;
using packet::PacketView;
using packet::RawBuilder;
@@ -37,6 +39,22 @@
return packet::PacketView<packet::kLittleEndian>(bytes);
}
+std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle) {
+ static uint32_t packet_number = 1;
+ auto payload = std::make_unique<RawBuilder>();
+ payload->AddOctets2(6); // L2CAP PDU size
+ payload->AddOctets2(2); // L2CAP CID
+ payload->AddOctets2(handle);
+ payload->AddOctets4(packet_number++);
+ return std::move(payload);
+}
+
+static std::unique_ptr<AclBuilder> NextAclPacket(uint16_t handle) {
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+ BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
+ return AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, NextPayload(handle));
+}
+
void TestHciLayer::EnqueueCommand(
std::unique_ptr<CommandBuilder> command, common::ContextualOnceCallback<void(CommandStatusView)> on_status) {
std::lock_guard<std::mutex> lock(mutex_);
@@ -150,10 +168,59 @@
ASSERT_TRUE(empty_command_view_.IsValid());
}
+void TestHciLayer::IncomingAclData(uint16_t handle) {
+ os::Handler* hci_handler = GetHandler();
+ auto* queue_end = acl_queue_.GetDownEnd();
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ queue_end->RegisterEnqueue(
+ hci_handler,
+ common::Bind(
+ [](decltype(queue_end) queue_end, uint16_t handle, std::promise<void> promise) {
+ auto packet = GetPacketView(NextAclPacket(handle));
+ AclView acl2 = AclView::Create(packet);
+ queue_end->UnregisterEnqueue();
+ promise.set_value();
+ return std::make_unique<AclView>(acl2);
+ },
+ queue_end,
+ handle,
+ common::Passed(std::move(promise))));
+ auto status = future.wait_for(std::chrono::milliseconds(1000));
+ ASSERT_EQ(status, std::future_status::ready);
+}
+
+void TestHciLayer::AssertNoOutgoingAclData() {
+ auto queue_end = acl_queue_.GetDownEnd();
+ EXPECT_EQ(queue_end->TryDequeue(), nullptr);
+}
+
+PacketView<kLittleEndian> TestHciLayer::OutgoingAclData() {
+ auto queue_end = acl_queue_.GetDownEnd();
+ std::unique_ptr<AclBuilder> received;
+ do {
+ received = queue_end->TryDequeue();
+ } while (received == nullptr);
+
+ return GetPacketView(std::move(received));
+}
+
+BidiQueueEnd<AclBuilder, AclView>* TestHciLayer::GetAclQueueEnd() {
+ return acl_queue_.GetUpEnd();
+}
+
+void TestHciLayer::Disconnect(uint16_t handle, ErrorCode reason) {
+ GetHandler()->Post(
+ common::BindOnce(&TestHciLayer::do_disconnect, common::Unretained(this), handle, reason));
+}
+
+void TestHciLayer::do_disconnect(uint16_t handle, ErrorCode reason) {
+ HciLayer::Disconnect(handle, reason);
+}
+
void TestHciLayer::ListDependencies(ModuleList* list) const {}
void TestHciLayer::Start() {
std::lock_guard<std::mutex> lock(mutex_);
-
InitEmptyCommand();
}
void TestHciLayer::Stop() {}
diff --git a/system/gd/hci/hci_layer_fake.h b/system/gd/hci/hci_layer_fake.h
index a944286..a2c3ea1 100644
--- a/system/gd/hci/hci_layer_fake.h
+++ b/system/gd/hci/hci_layer_fake.h
@@ -25,10 +25,10 @@
namespace bluetooth {
namespace hci {
-using packet::kLittleEndian;
-using packet::PacketView;
+packet::PacketView<packet::kLittleEndian> GetPacketView(
+ std::unique_ptr<packet::BasePacketBuilder> packet);
-PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet);
+std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle);
class TestHciLayer : public HciLayer {
public:
@@ -59,6 +59,16 @@
void CommandStatusCallback(EventView event);
+ void IncomingAclData(uint16_t handle);
+
+ void AssertNoOutgoingAclData();
+
+ packet::PacketView<packet::kLittleEndian> OutgoingAclData();
+
+ common::BidiQueueEnd<AclBuilder, AclView>* GetAclQueueEnd() override;
+
+ void Disconnect(uint16_t handle, ErrorCode reason) override;
+
protected:
void ListDependencies(ModuleList* list) const override;
void Start() override;
@@ -66,6 +76,7 @@
private:
void InitEmptyCommand();
+ void do_disconnect(uint16_t handle, ErrorCode reason);
// Handler-only state. Mutexes are not needed when accessing these fields.
std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
@@ -73,9 +84,12 @@
std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_;
std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_;
- // Most operations must acquire this mutex before manipulating shared state. The ONLY exception is blocking on a
- // promise, IF your thread is the only one mutating it. Note that SETTING a promise REQUIRES a lock, since another
- // thread may replace the promise while you are doing so.
+ // thread-safe
+ common::BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */};
+
+ // Most operations must acquire this mutex before manipulating shared state. The ONLY exception
+ // is blocking on a promise, IF your thread is the only one mutating it. Note that SETTING a
+ // promise REQUIRES a lock, since another thread may replace the promise while you are doing so.
mutable std::mutex mutex_{};
// Shared state between the test and stack threads
@@ -83,13 +97,14 @@
// We start with Consumed=Set, Command=Unset.
// When a command is enqueued, we set Command=set
- // When a command is popped, we block until Command=Set, then (if the queue is now empty) we reset Command=Unset and
- // set Consumed=Set. This way we emulate a blocking queue.
- std::promise<void> command_promise_{}; // Set when at least one command is in the queue
- std::future<void> command_future_ = command_promise_.get_future(); // GetCommand() blocks until this is fulfilled
+ // When a command is popped, we block until Command=Set, then (if the queue is now empty) we
+ // reset Command=Unset and set Consumed=Set. This way we emulate a blocking queue.
+ std::promise<void> command_promise_{}; // Set when at least one command is in the queue
+ std::future<void> command_future_ =
+ command_promise_.get_future(); // GetCommand() blocks until this is fulfilled
- CommandView empty_command_view_ =
- CommandView::Create(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
+ CommandView empty_command_view_ = CommandView::Create(
+ PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
};
} // namespace hci
diff --git a/system/gd/hci/hci_layer_test.cc b/system/gd/hci/hci_layer_test.cc
index b0aaeaa..8735dcb 100644
--- a/system/gd/hci/hci_layer_test.cc
+++ b/system/gd/hci/hci_layer_test.cc
@@ -60,6 +60,7 @@
namespace bluetooth {
namespace hci {
+namespace {
constexpr std::chrono::milliseconds kTimeout = HciLayer::kHciTimeoutMs / 2;
constexpr std::chrono::milliseconds kAclTimeout = std::chrono::milliseconds(1000);
@@ -83,18 +84,18 @@
void sendHciCommand(hal::HciPacket command) override {
outgoing_commands_.push_back(std::move(command));
if (sent_command_promise_ != nullptr) {
- auto promise = std::move(sent_command_promise_);
- sent_command_promise_.reset();
- promise->set_value();
+ std::promise<void>* prom = sent_command_promise_.release();
+ prom->set_value();
+ delete prom;
}
}
void sendAclData(hal::HciPacket data) override {
outgoing_acl_.push_back(std::move(data));
if (sent_acl_promise_ != nullptr) {
- auto promise = std::move(sent_acl_promise_);
- sent_acl_promise_.reset();
- promise->set_value();
+ std::promise<void>* prom = sent_acl_promise_.release();
+ prom->set_value();
+ delete prom;
}
}
@@ -105,9 +106,9 @@
void sendIsoData(hal::HciPacket data) override {
outgoing_iso_.push_back(std::move(data));
if (sent_iso_promise_ != nullptr) {
- auto promise = std::move(sent_iso_promise_);
- sent_iso_promise_.reset();
- promise->set_value();
+ std::promise<void>* prom = sent_iso_promise_.release();
+ prom->set_value();
+ delete prom;
}
}
@@ -290,7 +291,7 @@
hci_->GetIsoQueueEnd()->UnregisterDequeue();
}
- void ListDependencies(ModuleList* list) {
+ void ListDependencies(ModuleList* list) const {
list->add<HciLayer>();
}
@@ -390,14 +391,14 @@
ASSERT_EQ(reset_sent_status, std::future_status::ready);
// Verify that reset was received
- ASSERT_EQ(1, hal->GetNumSentCommands());
+ ASSERT_EQ(1u, hal->GetNumSentCommands());
auto sent_command = hal->GetSentCommand();
auto reset_view = ResetView::Create(CommandView::Create(sent_command));
ASSERT_TRUE(reset_view.IsValid());
// Verify that only one was sent
- ASSERT_EQ(0, hal->GetNumSentCommands());
+ ASSERT_EQ(0u, hal->GetNumSentCommands());
// Send the response event
uint8_t num_packets = 1;
@@ -457,7 +458,7 @@
ASSERT_TRUE(LeConnectionCompleteView::Create(LeMetaEventView::Create(EventView::Create(event))).IsValid());
}
-TEST_F(HciTest, hciTimeOut) {
+TEST_F(HciTest, DISABLED_hciTimeOut) {
auto event_future = upper->GetReceivedEventFuture();
auto reset_command_future = hal->GetSentCommandFuture();
upper->SendHciCommandExpectingComplete(ResetBuilder::Create());
@@ -478,7 +479,7 @@
}
TEST_F(HciTest, noOpCredits) {
- ASSERT_EQ(0, hal->GetNumSentCommands());
+ ASSERT_EQ(0u, hal->GetNumSentCommands());
// Send 0 credits
uint8_t num_packets = 0;
@@ -488,7 +489,7 @@
upper->SendHciCommandExpectingComplete(ReadLocalVersionInformationBuilder::Create());
// Verify that nothing was sent
- ASSERT_EQ(0, hal->GetNumSentCommands());
+ ASSERT_EQ(0u, hal->GetNumSentCommands());
num_packets = 1;
hal->callbacks->hciEventReceived(GetPacketBytes(NoCommandCompleteBuilder::Create(num_packets)));
@@ -497,7 +498,7 @@
ASSERT_EQ(command_sent_status, std::future_status::ready);
// Verify that one was sent
- ASSERT_EQ(1, hal->GetNumSentCommands());
+ ASSERT_EQ(1u, hal->GetNumSentCommands());
auto event_future = upper->GetReceivedEventFuture();
@@ -522,7 +523,7 @@
}
TEST_F(HciTest, creditsTest) {
- ASSERT_EQ(0, hal->GetNumSentCommands());
+ ASSERT_EQ(0u, hal->GetNumSentCommands());
auto command_future = hal->GetSentCommandFuture();
@@ -535,14 +536,14 @@
ASSERT_EQ(command_sent_status, std::future_status::ready);
// Verify that the first one is sent
- ASSERT_EQ(1, hal->GetNumSentCommands());
+ ASSERT_EQ(1u, hal->GetNumSentCommands());
auto sent_command = hal->GetSentCommand();
auto version_view = ReadLocalVersionInformationView::Create(CommandView::Create(sent_command));
ASSERT_TRUE(version_view.IsValid());
// Verify that only one was sent
- ASSERT_EQ(0, hal->GetNumSentCommands());
+ ASSERT_EQ(0u, hal->GetNumSentCommands());
// Get a new future
auto event_future = upper->GetReceivedEventFuture();
@@ -570,14 +571,14 @@
// Verify that the second one is sent
command_sent_status = command_future.wait_for(kTimeout);
ASSERT_EQ(command_sent_status, std::future_status::ready);
- ASSERT_EQ(1, hal->GetNumSentCommands());
+ ASSERT_EQ(1u, hal->GetNumSentCommands());
sent_command = hal->GetSentCommand();
auto supported_commands_view = ReadLocalSupportedCommandsView::Create(CommandView::Create(sent_command));
ASSERT_TRUE(supported_commands_view.IsValid());
// Verify that only one was sent
- ASSERT_EQ(0, hal->GetNumSentCommands());
+ ASSERT_EQ(0u, hal->GetNumSentCommands());
event_future = upper->GetReceivedEventFuture();
command_future = hal->GetSentCommandFuture();
@@ -598,14 +599,14 @@
// Verify that the third one is sent
command_sent_status = command_future.wait_for(kTimeout);
ASSERT_EQ(command_sent_status, std::future_status::ready);
- ASSERT_EQ(1, hal->GetNumSentCommands());
+ ASSERT_EQ(1u, hal->GetNumSentCommands());
sent_command = hal->GetSentCommand();
auto supported_features_view = ReadLocalSupportedFeaturesView::Create(CommandView::Create(sent_command));
ASSERT_TRUE(supported_features_view.IsValid());
// Verify that only one was sent
- ASSERT_EQ(0, hal->GetNumSentCommands());
+ ASSERT_EQ(0u, hal->GetNumSentCommands());
event_future = upper->GetReceivedEventFuture();
// Send the response event
@@ -631,7 +632,7 @@
// Check the command
auto sent_command = hal->GetSentCommand();
- ASSERT_LT(0, sent_command.size());
+ ASSERT_LT(0u, sent_command.size());
LeRandView view = LeRandView::Create(LeSecurityCommandView::Create(CommandView::Create(sent_command)));
ASSERT_TRUE(view.IsValid());
@@ -662,7 +663,7 @@
// Check the command
auto sent_command = hal->GetSentCommand();
- ASSERT_LT(0, sent_command.size());
+ ASSERT_LT(0u, sent_command.size());
auto view = WriteSimplePairingModeView::Create(SecurityCommandView::Create(CommandView::Create(sent_command)));
ASSERT_TRUE(view.IsValid());
@@ -699,7 +700,7 @@
// Check the command
auto sent_command = hal->GetSentCommand();
- ASSERT_LT(0, sent_command.size());
+ ASSERT_LT(0u, sent_command.size());
CreateConnectionView view = CreateConnectionView::Create(
ConnectionManagementCommandView::Create(AclCommandView::Create(CommandView::Create(sent_command))));
ASSERT_TRUE(view.IsValid());
@@ -776,7 +777,7 @@
auto sent_acl_status = sent_acl_future.wait_for(kAclTimeout);
ASSERT_EQ(sent_acl_status, std::future_status::ready);
auto sent_acl = hal->GetSentAcl();
- ASSERT_LT(0, sent_acl.size());
+ ASSERT_LT(0u, sent_acl.size());
AclView sent_acl_view = AclView::Create(sent_acl);
ASSERT_TRUE(sent_acl_view.IsValid());
ASSERT_EQ(bd_addr.length() + sizeof(handle), sent_acl_view.GetPayload().size());
@@ -904,5 +905,7 @@
ASSERT_EQ(handle, itr.extract<uint16_t>());
ASSERT_EQ(received_packets, itr.extract<uint16_t>());
}
+
+} // namespace
} // namespace hci
} // namespace bluetooth
diff --git a/system/gd/hci/hci_layer_unittest.cc b/system/gd/hci/hci_layer_unittest.cc
index 3d88f06..d4c2423 100644
--- a/system/gd/hci/hci_layer_unittest.cc
+++ b/system/gd/hci/hci_layer_unittest.cc
@@ -168,11 +168,13 @@
TEST_F(HciLayerTest, setup_teardown) {}
-TEST_F(HciLayerTest, reset_command_sent_on_start) {
+// b/260915548
+TEST_F(HciLayerTest, DISABLED_reset_command_sent_on_start) {
FailIfResetNotSent();
}
-TEST_F(HciLayerTest, controller_debug_info_requested_on_hci_timeout) {
+// b/260915548
+TEST_F(HciLayerTest, DISABLED_controller_debug_info_requested_on_hci_timeout) {
FailIfResetNotSent();
FakeTimerAdvance(HciLayer::kHciTimeoutMs.count());
@@ -183,7 +185,8 @@
ASSERT_TRUE(debug_info_view.IsValid());
}
-TEST_F(HciLayerTest, abort_after_hci_restart_timeout) {
+// b/260915548
+TEST_F(HciLayerTest, DISABLED_abort_after_hci_restart_timeout) {
FailIfResetNotSent();
FakeTimerAdvance(HciLayer::kHciTimeoutMs.count());
@@ -202,7 +205,8 @@
"");
}
-TEST_F(HciLayerTest, abort_on_root_inflammation_event) {
+// b/260915548
+TEST_F(HciLayerTest, DISABLED_abort_on_root_inflammation_event) {
FailIfResetNotSent();
auto payload = CreatePayload({'0'});
diff --git a/system/gd/hci/le_address_manager_test.cc b/system/gd/hci/le_address_manager_test.cc
index 5008db5..7f698f0 100644
--- a/system/gd/hci/le_address_manager_test.cc
+++ b/system/gd/hci/le_address_manager_test.cc
@@ -26,22 +26,28 @@
using ::bluetooth::os::Handler;
using ::bluetooth::os::Thread;
-namespace bluetooth {
-namespace hci {
-
namespace {
-using packet::kLittleEndian;
-using packet::PacketView;
-using packet::RawBuilder;
-PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+using namespace bluetooth;
+
+packet::PacketView<packet::kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter i(*bytes);
+ packet::BitInserter i(*bytes);
bytes->reserve(packet->size());
packet->Serialize(i);
return packet::PacketView<packet::kLittleEndian>(bytes);
}
+} // namespace
+
+namespace bluetooth {
+namespace hci {
+namespace {
+
+using packet::kLittleEndian;
+using packet::PacketView;
+using packet::RawBuilder;
+
class TestHciLayer : public HciLayer {
public:
void EnqueueCommand(
@@ -51,13 +57,14 @@
command_queue_.push(std::move(command));
command_complete_callbacks.push_back(std::move(on_complete));
if (command_promise_ != nullptr) {
- command_promise_->set_value();
- command_promise_.reset();
+ std::promise<void>* prom = command_promise_.release();
+ prom->set_value();
+ delete prom;
}
}
void SetCommandFuture() {
- ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
+ ASSERT_EQ(command_promise_, nullptr) << "Promises, Promises, ... Only one at a time.";
command_promise_ = std::make_unique<std::promise<void>>();
command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
}
@@ -130,8 +137,9 @@
paused = false;
le_address_manager_->AckResume(this);
if (resume_promise_ != nullptr) {
- resume_promise_->set_value();
- resume_promise_.reset();
+ std::promise<void>* prom = resume_promise_.release();
+ prom->set_value();
+ delete prom;
}
}
@@ -217,10 +225,11 @@
LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS,
remote_address,
irk,
+ false,
minimum_rotation_time,
maximum_rotation_time);
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->Register(clients[0].get());
sync_handler(handler_);
test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS);
@@ -239,10 +248,11 @@
LeAddressManager::AddressPolicy::USE_NON_RESOLVABLE_ADDRESS,
remote_address,
irk,
+ false,
minimum_rotation_time,
maximum_rotation_time);
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->Register(clients[0].get());
sync_handler(handler_);
test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS);
@@ -263,6 +273,7 @@
LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS,
remote_address,
irk,
+ false,
minimum_rotation_time,
maximum_rotation_time);
le_address_manager_->Register(clients[0].get());
@@ -300,10 +311,11 @@
LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS,
remote_address,
irk,
+ false,
minimum_rotation_time,
maximum_rotation_time);
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->Register(clients[0].get());
sync_handler(handler_);
test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS);
@@ -330,7 +342,7 @@
TEST_F(LeAddressManagerWithSingleClientTest, add_device_to_connect_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->AddDeviceToFilterAcceptList(FilterAcceptListAddressType::RANDOM, address);
auto packet = test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
auto packet_view = LeAddDeviceToFilterAcceptListView::Create(
@@ -346,12 +358,12 @@
TEST_F(LeAddressManagerWithSingleClientTest, remove_device_from_connect_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->AddDeviceToFilterAcceptList(FilterAcceptListAddressType::RANDOM, address);
test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->RemoveDeviceFromFilterAcceptList(FilterAcceptListAddressType::RANDOM, address);
auto packet = test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
auto packet_view = LeRemoveDeviceFromFilterAcceptListView::Create(
@@ -366,84 +378,154 @@
TEST_F(LeAddressManagerWithSingleClientTest, clear_connect_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->AddDeviceToFilterAcceptList(FilterAcceptListAddressType::RANDOM, address);
test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->ClearFilterAcceptList();
test_hci_layer_->GetCommand(OpCode::LE_CLEAR_FILTER_ACCEPT_LIST);
test_hci_layer_->IncomingEvent(LeClearFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
clients[0].get()->WaitForResume();
}
-TEST_F(LeAddressManagerWithSingleClientTest, add_device_to_resolving_list) {
+// b/260916288
+TEST_F(LeAddressManagerWithSingleClientTest, DISABLED_add_device_to_resolving_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
Octet16 peer_irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
Octet16 local_irk = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
- test_hci_layer_->SetCommandFuture();
+
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->AddDeviceToResolvingList(
PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address, peer_irk, local_irk);
- auto packet = test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST);
- auto packet_view = LeAddDeviceToResolvingListView::Create(LeSecurityCommandView::Create(packet));
- ASSERT_TRUE(packet_view.IsValid());
- ASSERT_EQ(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, packet_view.GetPeerIdentityAddressType());
- ASSERT_EQ(address, packet_view.GetPeerIdentityAddress());
- ASSERT_EQ(peer_irk, packet_view.GetPeerIrk());
- ASSERT_EQ(local_irk, packet_view.GetLocalIrk());
-
- test_hci_layer_->IncomingEvent(LeAddDeviceToResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ {
+ auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+ auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+ ASSERT_TRUE(packet_view.IsValid());
+ ASSERT_EQ(Enable::DISABLED, packet_view.GetAddressResolutionEnable());
+ test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ }
+ {
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+ auto packet = test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST);
+ auto packet_view = LeAddDeviceToResolvingListView::Create(LeSecurityCommandView::Create(packet));
+ ASSERT_TRUE(packet_view.IsValid());
+ ASSERT_EQ(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, packet_view.GetPeerIdentityAddressType());
+ ASSERT_EQ(address, packet_view.GetPeerIdentityAddress());
+ ASSERT_EQ(peer_irk, packet_view.GetPeerIrk());
+ ASSERT_EQ(local_irk, packet_view.GetLocalIrk());
+ test_hci_layer_->IncomingEvent(LeAddDeviceToResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ }
+ {
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+ auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+ auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+ ASSERT_TRUE(packet_view.IsValid());
+ ASSERT_EQ(Enable::ENABLED, packet_view.GetAddressResolutionEnable());
+ test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ }
clients[0].get()->WaitForResume();
}
-TEST_F(LeAddressManagerWithSingleClientTest, remove_device_from_resolving_list) {
+// b/260916288
+TEST_F(LeAddressManagerWithSingleClientTest, DISABLED_remove_device_from_resolving_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
Octet16 peer_irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
Octet16 local_irk = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->AddDeviceToResolvingList(
PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address, peer_irk, local_irk);
+ test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+ test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+ test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+ test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->RemoveDeviceFromResolvingList(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address);
- auto packet = test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST);
- auto packet_view = LeRemoveDeviceFromResolvingListView::Create(LeSecurityCommandView::Create(packet));
- ASSERT_TRUE(packet_view.IsValid());
- ASSERT_EQ(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, packet_view.GetPeerIdentityAddressType());
- ASSERT_EQ(address, packet_view.GetPeerIdentityAddress());
- test_hci_layer_->IncomingEvent(LeRemoveDeviceFromResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ {
+ auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+ auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+ ASSERT_TRUE(packet_view.IsValid());
+ ASSERT_EQ(Enable::DISABLED, packet_view.GetAddressResolutionEnable());
+ test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ }
+ {
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+ auto packet = test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST);
+ auto packet_view = LeRemoveDeviceFromResolvingListView::Create(LeSecurityCommandView::Create(packet));
+ ASSERT_TRUE(packet_view.IsValid());
+ ASSERT_EQ(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, packet_view.GetPeerIdentityAddressType());
+ ASSERT_EQ(address, packet_view.GetPeerIdentityAddress());
+ test_hci_layer_->IncomingEvent(LeRemoveDeviceFromResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ }
+ {
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+ auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+ auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+ ASSERT_TRUE(packet_view.IsValid());
+ ASSERT_EQ(Enable::ENABLED, packet_view.GetAddressResolutionEnable());
+ test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ }
clients[0].get()->WaitForResume();
}
-TEST_F(LeAddressManagerWithSingleClientTest, clear_resolving_list) {
+// b/260916288
+TEST_F(LeAddressManagerWithSingleClientTest, DISABLED_clear_resolving_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
Octet16 peer_irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
Octet16 local_irk = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->AddDeviceToResolvingList(
PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address, peer_irk, local_irk);
+ test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+ test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+ test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+ test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->ClearResolvingList();
- auto packet = test_hci_layer_->GetCommand(OpCode::LE_CLEAR_RESOLVING_LIST);
- auto packet_view = LeClearResolvingListView::Create(LeSecurityCommandView::Create(packet));
- ASSERT_TRUE(packet_view.IsValid());
- test_hci_layer_->IncomingEvent(LeClearResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ {
+ auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+ auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+ ASSERT_TRUE(packet_view.IsValid());
+ ASSERT_EQ(Enable::DISABLED, packet_view.GetAddressResolutionEnable());
+ test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ }
+ {
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+ auto packet = test_hci_layer_->GetCommand(OpCode::LE_CLEAR_RESOLVING_LIST);
+ auto packet_view = LeClearResolvingListView::Create(LeSecurityCommandView::Create(packet));
+ ASSERT_TRUE(packet_view.IsValid());
+ test_hci_layer_->IncomingEvent(LeClearResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ }
+ {
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+ auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+ auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+ ASSERT_TRUE(packet_view.IsValid());
+ ASSERT_EQ(Enable::ENABLED, packet_view.GetAddressResolutionEnable());
+ test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ }
+
clients[0].get()->WaitForResume();
}
TEST_F(LeAddressManagerWithSingleClientTest, register_during_command_complete) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->AddDeviceToFilterAcceptList(FilterAcceptListAddressType::RANDOM, address);
auto packet = test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
auto packet_view = LeAddDeviceToFilterAcceptListView::Create(
@@ -454,7 +536,7 @@
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
AllocateClients(1);
- test_hci_layer_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
le_address_manager_->Register(clients[1].get());
clients[0].get()->WaitForResume();
clients[1].get()->WaitForResume();
diff --git a/system/gd/hci/le_periodic_sync_manager_test.cc b/system/gd/hci/le_periodic_sync_manager_test.cc
index 3bb9e42..da77d18 100644
--- a/system/gd/hci/le_periodic_sync_manager_test.cc
+++ b/system/gd/hci/le_periodic_sync_manager_test.cc
@@ -45,8 +45,9 @@
command_queue_.push(std::move(command));
command_complete_callbacks.push_back(std::move(on_complete));
if (command_promise_ != nullptr) {
- command_promise_->set_value();
- command_promise_.reset();
+ std::promise<void>* prom = command_promise_.release();
+ prom->set_value();
+ delete prom;
}
}
@@ -56,13 +57,14 @@
command_queue_.push(std::move(command));
command_status_callbacks.push_back(std::move(on_status));
if (command_promise_ != nullptr) {
- command_promise_->set_value();
- command_promise_.reset();
+ std::promise<void>* prom = command_promise_.release();
+ prom->set_value();
+ delete prom;
}
}
void SetCommandFuture() {
- ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
+ ASSERT_EQ(command_promise_, nullptr) << "Promises, Promises, ... Only one at a time.";
command_promise_ = std::make_unique<std::promise<void>>();
command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
}
@@ -224,7 +226,7 @@
};
uint16_t skip = 0x04;
uint16_t sync_timeout = 0x0A;
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->StartSync(request, skip, sync_timeout);
auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
auto packet_view = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -251,7 +253,7 @@
.sync_handle = sync_handle,
.sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
};
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
auto temp_view = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -293,7 +295,7 @@
.sync_handle = sync_handle,
.sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
};
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
auto temp_view = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -335,7 +337,7 @@
.sync_handle = sync_handle,
.sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
};
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
auto temp_veiw = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -362,7 +364,7 @@
periodic_sync_manager_->HandleLePeriodicAdvertisingSyncEstablished(event_view);
// StopSync
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->StopSync(sync_handle);
packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_TERMINATE_SYNC);
auto packet_view = LePeriodicAdvertisingTerminateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -385,7 +387,7 @@
.sync_handle = sync_handle,
.sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
};
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
auto temp_veiw = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -396,7 +398,7 @@
LePeriodicAdvertisingCreateSyncStatusBuilder::Create(ErrorCode::SUCCESS, 0x00));
// Cancel crate sync
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->CancelCreateSync(advertiser_sid, address_with_type.GetAddress());
packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL);
auto packet_view = LePeriodicAdvertisingCreateSyncCancelView::Create(LeScanningCommandView::Create(packet));
@@ -411,7 +413,7 @@
uint16_t sync_handle = 0x11;
uint16_t connection_handle = 0x12;
int pa_source = 0x01;
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->TransferSync(address, service_data, sync_handle, pa_source, connection_handle);
auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_SYNC_TRANSFER);
auto packet_view = LePeriodicAdvertisingSyncTransferView::Create(LeScanningCommandView::Create(packet));
@@ -436,7 +438,7 @@
uint16_t advertising_handle = 0x11;
uint16_t connection_handle = 0x12;
int pa_source = 0x01;
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->SyncSetInfo(address, service_data, advertising_handle, pa_source, connection_handle);
auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER);
auto packet_view = LePeriodicAdvertisingSetInfoTransferView::Create(LeScanningCommandView::Create(packet));
@@ -461,7 +463,7 @@
uint16_t skip = 0x11;
uint16_t timout = 0x12;
int reg_id = 0x01;
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->SyncTxParameters(address, mode, skip, timout, reg_id);
auto packet =
test_le_scanning_interface_->GetCommand(OpCode::LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS);
@@ -490,7 +492,7 @@
.sync_handle = sync_handle,
.sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
};
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
auto temp_veiw = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -542,7 +544,7 @@
.sync_handle = sync_handle,
.sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
};
- test_le_scanning_interface_->SetCommandFuture();
+ ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
auto temp_veiw = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
diff --git a/system/gd/hci/le_scanning_manager_test.cc b/system/gd/hci/le_scanning_manager_test.cc
index 88eb3be..e59c725 100644
--- a/system/gd/hci/le_scanning_manager_test.cc
+++ b/system/gd/hci/le_scanning_manager_test.cc
@@ -29,6 +29,7 @@
#include <queue>
#include <vector>
+#include "hci/hci_layer_fake.h"
#include "common/bind.h"
#include "hci/acl_manager.h"
#include "hci/address.h"
@@ -109,14 +110,6 @@
namespace hci {
namespace {
-PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
- auto bytes = std::make_shared<std::vector<uint8_t>>();
- BitInserter i(*bytes);
- bytes->reserve(packet->size());
- packet->Serialize(i);
- return packet::PacketView<packet::kLittleEndian>(bytes);
-}
-
class TestController : public Controller {
public:
bool IsSupported(OpCode op_code) const override {
@@ -127,6 +120,14 @@
supported_opcodes_.insert(op_code);
}
+ bool SupportsBleExtendedAdvertising() const override {
+ return support_ble_extended_advertising_;
+ }
+
+ void SetBleExtendedAdvertisingSupport(bool support) {
+ support_ble_extended_advertising_ = support;
+ }
+
protected:
void Start() override {}
void Stop() override {}
@@ -134,156 +135,7 @@
private:
std::set<OpCode> supported_opcodes_{};
-};
-
-class TestHciLayer : public HciLayer {
- public:
- void EnqueueCommand(
- std::unique_ptr<CommandBuilder> command,
- common::ContextualOnceCallback<void(CommandStatusView)> on_status) override {
- std::lock_guard<std::mutex> lock(mutex_);
- command_queue_.push(std::move(command));
- command_status_callbacks.push_back(std::move(on_status));
- command_count_--;
- if (command_promise_ != nullptr && command_count_ == 0) {
- command_promise_->set_value();
- command_promise_.reset();
- }
- }
-
- void EnqueueCommand(
- std::unique_ptr<CommandBuilder> command,
- common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
- std::lock_guard<std::mutex> lock(mutex_);
- command_queue_.push(std::move(command));
- command_complete_callbacks.push_back(std::move(on_complete));
- command_count_--;
- if (command_promise_ != nullptr && command_count_ == 0) {
- command_promise_->set_value();
- command_promise_.reset();
- }
- }
-
- // Set command future for 'num_command' commands are expected
- void SetCommandFuture(uint16_t num_command = 1) {
- ASSERT_TRUE(command_promise_ == nullptr) << "Promises, Promises, ... Only one at a time.";
- command_count_ = num_command;
- command_promise_ = std::make_unique<std::promise<void>>();
- command_future_ = command_promise_->get_future();
- }
-
- CommandView GetCommand() {
- // Wait for EnqueueCommand if command_queue_ is empty
- if (command_promise_ != nullptr) {
- if (command_queue_.empty()) {
- LOG_ERROR("Waiting for command queue to fill ");
- command_future_.wait_for(1s);
- }
- command_promise_.reset();
- }
-
- std::lock_guard<std::mutex> lock(mutex_);
- if (command_queue_.empty()) {
- LOG_ERROR("Command queue is empty");
- return empty_command_view_;
- }
-
- auto last = std::move(command_queue_.front());
- command_queue_.pop();
- CommandView command_packet_view = CommandView::Create(GetPacketView(std::move(last)));
- if (!command_packet_view.IsValid()) {
- LOG_ERROR("Got invalid command");
- return empty_command_view_;
- }
- return command_packet_view;
- }
-
- void RegisterEventHandler(EventCode event_code, common::ContextualCallback<void(EventView)> event_handler) override {
- registered_events_[event_code] = event_handler;
- }
-
- void UnregisterEventHandler(EventCode event_code) override {
- registered_events_.erase(event_code);
- }
-
- void RegisterLeEventHandler(
- SubeventCode subevent_code, common::ContextualCallback<void(LeMetaEventView)> event_handler) override {
- registered_le_events_[subevent_code] = event_handler;
- }
-
- void UnregisterLeEventHandler(SubeventCode subevent_code) override {
- registered_le_events_.erase(subevent_code);
- }
-
- void IncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
- auto packet = GetPacketView(std::move(event_builder));
- EventView event = EventView::Create(packet);
- ASSERT_TRUE(event.IsValid());
- EventCode event_code = event.GetEventCode();
- ASSERT_NE(registered_events_.find(event_code), registered_events_.end()) << EventCodeText(event_code);
- registered_events_[event_code].Invoke(event);
- }
-
- void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
- auto packet = GetPacketView(std::move(event_builder));
- EventView event = EventView::Create(packet);
- LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
- ASSERT_TRUE(meta_event_view.IsValid());
- SubeventCode subevent_code = meta_event_view.GetSubeventCode();
- ASSERT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end());
- registered_le_events_[subevent_code].Invoke(meta_event_view);
- }
-
- void CommandCompleteCallback(EventView event) {
- CommandCompleteView complete_view = CommandCompleteView::Create(event);
- ASSERT_TRUE(complete_view.IsValid());
- ASSERT_TRUE(!command_complete_callbacks.empty());
- std::move(command_complete_callbacks.front()).Invoke(complete_view);
- command_complete_callbacks.pop_front();
- }
-
- void CommandStatusCallback(EventView event) {
- CommandStatusView status_view = CommandStatusView::Create(event);
- ASSERT_TRUE(status_view.IsValid());
- std::move(command_status_callbacks.front()).Invoke(status_view);
- command_status_callbacks.pop_front();
- }
-
- void InitEmptyCommand() {
- auto payload = std::make_unique<bluetooth::packet::RawBuilder>();
- auto command_builder = CommandBuilder::Create(OpCode::NONE, std::move(payload));
- empty_command_view_ = CommandView::Create(GetPacketView(std::move(command_builder)));
- ASSERT_TRUE(empty_command_view_.IsValid());
- }
-
- void ListDependencies(ModuleList* list) const {}
- void Start() override {
- InitEmptyCommand();
- RegisterEventHandler(
- EventCode::COMMAND_COMPLETE, GetHandler()->BindOn(this, &TestHciLayer::CommandCompleteCallback));
- RegisterEventHandler(EventCode::COMMAND_STATUS, GetHandler()->BindOn(this, &TestHciLayer::CommandStatusCallback));
- }
- void Stop() override {
- UnregisterEventHandler(EventCode::COMMAND_STATUS);
- UnregisterEventHandler(EventCode::COMMAND_COMPLETE);
- }
-
- size_t CommandQueueSize() const {
- return command_queue_.size();
- }
-
- private:
- std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_;
- std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_;
- std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
- std::list<common::ContextualOnceCallback<void(CommandStatusView)>> command_status_callbacks;
- std::queue<std::unique_ptr<CommandBuilder>> command_queue_;
- std::unique_ptr<std::promise<void>> command_promise_;
- std::future<void> command_future_;
- mutable std::mutex mutex_;
- uint16_t command_count_ = 0;
- CommandView empty_command_view_ =
- CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
+ bool support_ble_extended_advertising_ = false;
};
class TestLeAddressManager : public LeAddressManager {
@@ -438,11 +290,7 @@
}
void sync_client_handler() {
- std::promise<void> promise;
- auto future = promise.get_future();
- client_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
- auto future_status = future.wait_for(std::chrono::seconds(1));
- ASSERT_EQ(future_status, std::future_status::ready);
+ ASSERT(thread_.GetReactor()->WaitForIdle(std::chrono::seconds(2)));
}
TestModuleRegistry fake_registry_;
@@ -466,10 +314,13 @@
start_le_scanning_manager();
ASSERT_TRUE(fake_registry_.IsStarted(&HciLayer::Factory));
- test_hci_layer_->SetCommandFuture();
ASSERT_EQ(OpCode::LE_ADV_FILTER, test_hci_layer_->GetCommand().GetOpCode());
- ASSERT_EQ(0UL, test_hci_layer_->CommandQueueSize());
test_hci_layer_->IncomingEvent(LeAdvFilterReadExtendedFeaturesCompleteBuilder::Create(1, ErrorCode::SUCCESS, 0x01));
+
+ // Get the command a second time as the configure_scan is called twice in le_scanning_manager.cc
+ // Fixed on aosp/2242078 but not present on older branches
+ EXPECT_EQ(OpCode::LE_EXTENDED_SCAN_PARAMS, test_hci_layer_->GetCommand().GetOpCode());
+ test_hci_layer_->IncomingEvent(LeExtendedScanParamsCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
}
void TearDown() override {
@@ -483,7 +334,12 @@
LeScanningManagerTest::SetUp();
test_controller_->AddSupported(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS);
test_controller_->AddSupported(OpCode::LE_SET_EXTENDED_SCAN_ENABLE);
+ test_controller_->SetBleExtendedAdvertisingSupport(true);
start_le_scanning_manager();
+ // Get the command a second time as the configure_scan is called twice in le_scanning_manager.cc
+ // Fixed on aosp/2242078 but not present on older branches
+ EXPECT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
+ test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
}
};
@@ -492,12 +348,17 @@
TEST_F(LeScanningManagerTest, start_scan_test) {
start_le_scanning_manager();
- test_hci_layer_->SetCommandFuture(2);
+ // Get the command a second time as the configure_scan is called twice in le_scanning_manager.cc
+ // Fixed on aosp/2242078 but not present on older branches
+ EXPECT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
+ test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+
// Enable scan
le_scanning_manager->Scan(true);
- ASSERT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
+ EXPECT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
- ASSERT_EQ(OpCode::LE_SET_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode());
+
+ EXPECT_EQ(OpCode::LE_SET_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode());
test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
LeAdvertisingResponse report = make_advertising_report();
@@ -515,7 +376,7 @@
TEST_F(LeScanningManagerTest, scan_filter_add_ad_type_not_supported_test) {
start_le_scanning_manager();
ASSERT_TRUE(fake_registry_.IsStarted(&HciLayer::Factory));
- test_hci_layer_->SetCommandFuture();
+
std::vector<AdvertisingPacketContentFilterCommand> filters = {};
filters.push_back(make_filter(hci::ApcfFilterType::AD_TYPE));
le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -524,7 +385,6 @@
TEST_F(LeScanningManagerAndroidHciTest, startup_teardown) {}
TEST_F(LeScanningManagerAndroidHciTest, start_scan_test) {
- test_hci_layer_->SetCommandFuture(2);
// Enable scan
le_scanning_manager->Scan(true);
ASSERT_EQ(OpCode::LE_EXTENDED_SCAN_PARAMS, test_hci_layer_->GetCommand().GetOpCode());
@@ -545,14 +405,16 @@
TEST_F(LeScanningManagerAndroidHciTest, scan_filter_enable_test) {
le_scanning_manager->ScanFilterEnable(true);
+ sync_client_handler();
EXPECT_CALL(mock_callbacks_, OnFilterEnable);
test_hci_layer_->IncomingEvent(
LeAdvFilterEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, Enable::ENABLED));
+ sync_client_handler();
}
TEST_F(LeScanningManagerAndroidHciTest, scan_filter_parameter_test) {
- test_hci_layer_->SetCommandFuture();
+
AdvertisingFilterParameter advertising_filter_parameter{};
advertising_filter_parameter.delivery_mode = DeliveryMode::IMMEDIATE;
le_scanning_manager->ScanFilterParameterSetup(ApcfAction::ADD, 0x01, advertising_filter_parameter);
@@ -566,10 +428,11 @@
EXPECT_CALL(mock_callbacks_, OnFilterParamSetup);
test_hci_layer_->IncomingEvent(
LeAdvFilterSetFilteringParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a));
+ sync_client_handler();
}
TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_broadcaster_address_test) {
- test_hci_layer_->SetCommandFuture();
+
std::vector<AdvertisingPacketContentFilterCommand> filters = {};
filters.push_back(make_filter(ApcfFilterType::BROADCASTER_ADDRESS));
le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -586,7 +449,7 @@
}
TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_service_uuid_test) {
- test_hci_layer_->SetCommandFuture();
+
std::vector<AdvertisingPacketContentFilterCommand> filters = {};
filters.push_back(make_filter(ApcfFilterType::SERVICE_UUID));
le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -603,7 +466,7 @@
}
TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_local_name_test) {
- test_hci_layer_->SetCommandFuture();
+
std::vector<AdvertisingPacketContentFilterCommand> filters = {};
filters.push_back(make_filter(ApcfFilterType::LOCAL_NAME));
le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -620,7 +483,7 @@
}
TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_manufacturer_data_test) {
- test_hci_layer_->SetCommandFuture();
+
std::vector<AdvertisingPacketContentFilterCommand> filters = {};
filters.push_back(make_filter(ApcfFilterType::MANUFACTURER_DATA));
le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -637,7 +500,7 @@
}
TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_service_data_test) {
- test_hci_layer_->SetCommandFuture();
+
std::vector<AdvertisingPacketContentFilterCommand> filters = {};
filters.push_back(make_filter(hci::ApcfFilterType::SERVICE_DATA));
le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -680,20 +543,20 @@
LeBatchScanSetStorageParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
// Enable batch scan
- test_hci_layer_->SetCommandFuture();
+
le_scanning_manager->BatchScanEnable(BatchScanMode::FULL, 2400, 2400, BatchScanDiscardRule::OLDEST);
ASSERT_EQ(OpCode::LE_BATCH_SCAN, test_hci_layer_->GetCommand().GetOpCode());
test_hci_layer_->IncomingEvent(LeBatchScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
// Read batch scan data
- test_hci_layer_->SetCommandFuture();
+
le_scanning_manager->BatchScanReadReport(0x01, BatchScanMode::FULL);
ASSERT_EQ(OpCode::LE_BATCH_SCAN, test_hci_layer_->GetCommand().GetOpCode());
// We will send read command while num_of_record != 0
std::vector<uint8_t> raw_data = {0x5c, 0x1f, 0xa2, 0xc3, 0x63, 0x5d, 0x01, 0xf5, 0xb3, 0x5e, 0x00, 0x0c, 0x02,
0x01, 0x02, 0x05, 0x09, 0x6d, 0x76, 0x38, 0x76, 0x02, 0x0a, 0xf5, 0x00};
- test_hci_layer_->SetCommandFuture();
+
test_hci_layer_->IncomingEvent(LeBatchScanReadResultParametersCompleteRawBuilder::Create(
uint8_t{1}, ErrorCode::SUCCESS, BatchScanDataRead::FULL_MODE_DATA, 1, raw_data));
ASSERT_EQ(OpCode::LE_BATCH_SCAN, test_hci_layer_->GetCommand().GetOpCode());
@@ -708,7 +571,6 @@
TEST_F(LeScanningManagerExtendedTest, start_scan_test) {
// Enable scan
- test_hci_layer_->SetCommandFuture(2);
le_scanning_manager->Scan(true);
ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
@@ -742,7 +604,6 @@
test_le_address_manager->ignore_unregister_for_testing = true;
// Register LeAddressManager
- test_hci_layer_->SetCommandFuture(2);
le_scanning_manager->Scan(true);
ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
@@ -751,7 +612,6 @@
sync_client_handler();
// Unregister LeAddressManager
- test_hci_layer_->SetCommandFuture(1);
le_scanning_manager->Scan(false);
ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode());
test_hci_layer_->IncomingEvent(LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
@@ -768,7 +628,6 @@
TEST_F(LeScanningManagerExtendedTest, drop_insignificant_bytes_test) {
// Enable scan
- test_hci_layer_->SetCommandFuture(2);
le_scanning_manager->Scan(true);
ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
diff --git a/system/gd/os/Android.bp b/system/gd/os/Android.bp
index 7431f15..292da06 100644
--- a/system/gd/os/Android.bp
+++ b/system/gd/os/Android.bp
@@ -17,6 +17,7 @@
filegroup {
name: "BluetoothOsSources_android",
srcs: [
+ "system_properties_common.cc",
"android/metrics.cc",
"android/parameter_provider.cc",
"android/system_properties.cc",
@@ -35,6 +36,7 @@
filegroup {
name: "BluetoothOsSources_host",
srcs: [
+ "system_properties_common.cc",
"host/metrics.cc",
"host/parameter_provider.cc",
"host/system_properties.cc",
diff --git a/system/gd/os/BUILD.gn b/system/gd/os/BUILD.gn
index 48337e1..7204ccd 100644
--- a/system/gd/os/BUILD.gn
+++ b/system/gd/os/BUILD.gn
@@ -18,6 +18,7 @@
"linux/parameter_provider.cc",
"linux/system_properties.cc",
"linux/wakelock_native.cc",
+ "system_properties_common.cc",
"syslog.cc",
]
diff --git a/system/gd/os/android/metrics.cc b/system/gd/os/android/metrics.cc
index db42fc5a..eacaa72 100644
--- a/system/gd/os/android/metrics.cc
+++ b/system/gd/os/android/metrics.cc
@@ -236,7 +236,7 @@
}
void LogMetricSmpPairingEvent(
- const Address& address, uint8_t smp_cmd, android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {
+ const Address& address, uint16_t smp_cmd, android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) {
int metric_id = 0;
if (!address.IsEmpty()) {
metric_id = MetricIdManager::GetInstance().AllocateId(address);
diff --git a/system/gd/os/android/wakelock_native_test.cc b/system/gd/os/android/wakelock_native_test.cc
index 66be722..36f8af8 100644
--- a/system/gd/os/android/wakelock_native_test.cc
+++ b/system/gd/os/android/wakelock_native_test.cc
@@ -53,8 +53,9 @@
static void FulfilPromise(std::unique_ptr<std::promise<void>>& promise) {
std::lock_guard<std::recursive_mutex> lock_guard(mutex);
if (promise != nullptr) {
- promise->set_value();
- promise = nullptr;
+ std::promise<void>* prom = promise.release();
+ prom->set_value();
+ delete prom;
}
}
diff --git a/system/gd/os/host/metrics.cc b/system/gd/os/host/metrics.cc
index 955d22e..2e85e73 100644
--- a/system/gd/os/host/metrics.cc
+++ b/system/gd/os/host/metrics.cc
@@ -96,7 +96,7 @@
const char* attribute_value) {}
void LogMetricSmpPairingEvent(
- const Address& address, uint8_t smp_cmd, android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {}
+ const Address& address, uint16_t smp_cmd, android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) {}
void LogMetricA2dpPlaybackEvent(const Address& address, int playback_state, int audio_coding_mode) {}
diff --git a/system/gd/os/linux/metrics.cc b/system/gd/os/linux/metrics.cc
index 65fb181..3941f77 100644
--- a/system/gd/os/linux/metrics.cc
+++ b/system/gd/os/linux/metrics.cc
@@ -96,7 +96,7 @@
const char* attribute_value) {}
void LogMetricSmpPairingEvent(
- const Address& address, uint8_t smp_cmd, android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {}
+ const Address& address, uint16_t smp_cmd, android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) {}
void LogMetricA2dpPlaybackEvent(const Address& address, int playback_state, int audio_coding_mode) {}
diff --git a/system/gd/os/linux_generic/queue_unittest.cc b/system/gd/os/linux_generic/queue_unittest.cc
index 7994aba..706fcd2 100644
--- a/system/gd/os/linux_generic/queue_unittest.cc
+++ b/system/gd/os/linux_generic/queue_unittest.cc
@@ -19,6 +19,7 @@
#include <sys/eventfd.h>
#include <atomic>
+#include <chrono>
#include <future>
#include <unordered_map>
@@ -26,6 +27,8 @@
#include "gtest/gtest.h"
#include "os/reactor.h"
+using namespace std::chrono_literals;
+
namespace bluetooth {
namespace os {
namespace {
@@ -60,6 +63,11 @@
Handler* enqueue_handler_;
Thread* dequeue_thread_;
Handler* dequeue_handler_;
+
+ void sync_enqueue_handler() {
+ ASSERT(enqueue_thread_ != nullptr);
+ ASSERT(enqueue_thread_->GetReactor()->WaitForIdle(2s));
+ }
};
class TestEnqueueEnd {
@@ -338,6 +346,7 @@
test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
enqueue_future.wait();
EXPECT_EQ(enqueue_future.get(), 0);
+ sync_enqueue_handler();
}
// Enqueue end level : 1
diff --git a/system/gd/os/metrics.h b/system/gd/os/metrics.h
index 339a2cf..cb35d68 100644
--- a/system/gd/os/metrics.h
+++ b/system/gd/os/metrics.h
@@ -166,7 +166,10 @@
* @param smp_fail_reason SMP pairing failure reason code from SMP spec
*/
void LogMetricSmpPairingEvent(
- const hci::Address& address, uint8_t smp_cmd, android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason);
+ const hci::Address& address,
+ uint16_t smp_cmd,
+ android::bluetooth::DirectionEnum direction,
+ uint16_t smp_fail_reason);
/**
* Logs there is an event related Bluetooth classic pairing
diff --git a/system/gd/os/system_properties.h b/system/gd/os/system_properties.h
index f5a82b8..42ea4e7 100644
--- a/system/gd/os/system_properties.h
+++ b/system/gd/os/system_properties.h
@@ -26,6 +26,21 @@
// or if the platform does not support system property
std::optional<std::string> GetSystemProperty(const std::string& property);
+// Get |property| keyed system property as uint32_t from supported platform, return |default_value| if the property
+// does not exist or if the platform does not support system property
+uint32_t GetSystemPropertyUint32(const std::string& property, uint32_t default_value);
+
+// Get |property| keyed system property as uint32_t from supported platform, return |default_value|
+// if the property does not exist or if the platform does not support system property if property is
+// found it will call stoul with |base|
+uint32_t GetSystemPropertyUint32Base(
+ const std::string& property, uint32_t default_value, int base = 0);
+
+// Get |property| keyed property as bool from supported platform, return
+// |default_value| if the property does not exist or if the platform
+// does not support system property
+bool GetSystemPropertyBool(const std::string& property, bool default_value);
+
// Set |property| keyed system property to |value|, return true if the set was successful and false if the set failed
// Replace existing value if property already exists
bool SetSystemProperty(const std::string& property, const std::string& value);
diff --git a/system/gd/os/system_properties_common.cc b/system/gd/os/system_properties_common.cc
new file mode 100644
index 0000000..f59560c
--- /dev/null
+++ b/system/gd/os/system_properties_common.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#include <string>
+
+#include "common/strings.h"
+#include "os/system_properties.h"
+
+namespace bluetooth {
+namespace os {
+
+uint32_t GetSystemPropertyUint32(const std::string& property, uint32_t default_value) {
+ return GetSystemPropertyUint32Base(property, default_value, 10);
+}
+
+uint32_t GetSystemPropertyUint32Base(
+ const std::string& property, uint32_t default_value, int base) {
+ std::optional<std::string> result = GetSystemProperty(property);
+ if (result.has_value()) {
+ return static_cast<uint32_t>(std::stoul(*result, nullptr, base));
+ }
+ return default_value;
+}
+
+bool GetSystemPropertyBool(const std::string& property, bool default_value) {
+ std::optional<std::string> result = GetSystemProperty(property);
+ if (result.has_value()) {
+ std::string trimmed_val = common::StringTrim(result.value());
+ if (trimmed_val == "true" || trimmed_val == "1") {
+ return true;
+ }
+ if (trimmed_val == "false" || trimmed_val == "0") {
+ return false;
+ }
+ }
+ return default_value;
+}
+
+} // namespace os
+} // namespace bluetooth
diff --git a/system/gd/rust/common/src/init_flags.rs b/system/gd/rust/common/src/init_flags.rs
index 8e06df7..2beb2b5 100644
--- a/system/gd/rust/common/src/init_flags.rs
+++ b/system/gd/rust/common/src/init_flags.rs
@@ -209,6 +209,8 @@
btaa_hci = true,
bta_dm_clear_conn_id_on_client_close = true,
btm_dm_flush_discovery_queue_on_search_cancel,
+ clear_hidd_interrupt_cid_on_disconnect = true,
+ delay_hidh_cleanup_until_hidh_ready_start = true,
finite_att_timeout = true,
gatt_robust_caching_client = true,
gatt_robust_caching_server,
diff --git a/system/gd/rust/shim/src/init_flags.rs b/system/gd/rust/shim/src/init_flags.rs
index 46c379f..5c1e29d 100644
--- a/system/gd/rust/shim/src/init_flags.rs
+++ b/system/gd/rust/shim/src/init_flags.rs
@@ -8,6 +8,8 @@
fn btaa_hci_is_enabled() -> bool;
fn bta_dm_clear_conn_id_on_client_close_is_enabled() -> bool;
fn btm_dm_flush_discovery_queue_on_search_cancel_is_enabled() -> bool;
+ fn delay_hidh_cleanup_until_hidh_ready_start_is_enabled() -> bool;
+ fn clear_hidd_interrupt_cid_on_disconnect_is_enabled() -> bool;
fn finite_att_timeout_is_enabled() -> bool;
fn gatt_robust_caching_client_is_enabled() -> bool;
fn gatt_robust_caching_server_is_enabled() -> bool;
diff --git a/system/gd/stack_manager_unittest.cc b/system/gd/stack_manager_unittest.cc
index 824675e..51645ea 100644
--- a/system/gd/stack_manager_unittest.cc
+++ b/system/gd/stack_manager_unittest.cc
@@ -22,7 +22,7 @@
namespace bluetooth {
namespace {
-TEST(StackManagerTest, start_and_shutdown_no_module) {
+TEST(StackManagerTest, DISABLED_start_and_shutdown_no_module) {
StackManager stack_manager;
ModuleList module_list;
os::Thread thread{"test_thread", os::Thread::Priority::NORMAL};
@@ -45,7 +45,7 @@
const ModuleFactory TestModuleNoDependency::Factory = ModuleFactory([]() { return new TestModuleNoDependency(); });
-TEST(StackManagerTest, get_module_instance) {
+TEST(StackManagerTest, DISABLED_get_module_instance) {
StackManager stack_manager;
ModuleList module_list;
module_list.add<TestModuleNoDependency>();
diff --git a/system/hci/Android.bp b/system/hci/Android.bp
index d9f9542..1553c25 100644
--- a/system/hci/Android.bp
+++ b/system/hci/Android.bp
@@ -91,28 +91,6 @@
],
}
-// HCI native unit tests for target
-cc_test {
- name: "net_test_hci_native",
- test_suites: ["device-tests"],
- defaults: [
- "fluoride_unit_test_defaults",
- "mts_defaults",
- ],
- local_include_dirs: [
- "include",
- ],
- include_dirs: [
- "packages/modules/Bluetooth/system",
- "packages/modules/Bluetooth/system/gd",
- "packages/modules/Bluetooth/system/stack/include",
- ],
- srcs: [
- "test/hci_layer_test.cc",
- "test/other_stack_stub.cc",
- ],
-}
-
cc_test {
name: "net_test_hci_fragmenter_native",
test_suites: ["device-tests"],
diff --git a/system/hci/test/hci_layer_test.cc b/system/hci/test/hci_layer_test.cc
deleted file mode 100644
index e69de29..0000000
--- a/system/hci/test/hci_layer_test.cc
+++ /dev/null
diff --git a/system/hci/test/other_stack_stub.cc b/system/hci/test/other_stack_stub.cc
deleted file mode 100644
index e69de29..0000000
--- a/system/hci/test/other_stack_stub.cc
+++ /dev/null
diff --git a/system/internal_include/bt_target.h b/system/internal_include/bt_target.h
index 98787a3..89478dc 100644
--- a/system/internal_include/bt_target.h
+++ b/system/internal_include/bt_target.h
@@ -1026,12 +1026,4 @@
#include "bt_trace.h"
-#ifndef BTM_DELAY_AUTH_MS
-#define BTM_DELAY_AUTH_MS 0
-#endif
-
-#ifndef BTM_DISABLE_CONCURRENT_PEER_AUTH
-#define BTM_DISABLE_CONCURRENT_PEER_AUTH FALSE
-#endif
-
#endif /* BT_TARGET_H */
diff --git a/system/main/shim/metrics_api.cc b/system/main/shim/metrics_api.cc
index 99832be..82ad3c1 100644
--- a/system/main/shim/metrics_api.cc
+++ b/system/main/shim/metrics_api.cc
@@ -89,9 +89,9 @@
transmit_power_level);
}
-void LogMetricSmpPairingEvent(const RawAddress& raw_address, uint8_t smp_cmd,
+void LogMetricSmpPairingEvent(const RawAddress& raw_address, uint16_t smp_cmd,
android::bluetooth::DirectionEnum direction,
- uint8_t smp_fail_reason) {
+ uint16_t smp_fail_reason) {
Address address = bluetooth::ToGdAddress(raw_address);
bluetooth::os::LogMetricSmpPairingEvent(address, smp_cmd, direction,
smp_fail_reason);
diff --git a/system/main/shim/metrics_api.h b/system/main/shim/metrics_api.h
index ce13876..f838908 100644
--- a/system/main/shim/metrics_api.h
+++ b/system/main/shim/metrics_api.h
@@ -134,9 +134,9 @@
* @param direction direction of this SMP command
* @param smp_fail_reason SMP pairing failure reason code from SMP spec
*/
-void LogMetricSmpPairingEvent(const RawAddress& address, uint8_t smp_cmd,
+void LogMetricSmpPairingEvent(const RawAddress& address, uint16_t smp_cmd,
android::bluetooth::DirectionEnum direction,
- uint8_t smp_fail_reason);
+ uint16_t smp_fail_reason);
/**
* Logs there is an event related Bluetooth classic pairing
diff --git a/system/stack/Android.bp b/system/stack/Android.bp
index b9eaeeb..e5e7b1c 100644
--- a/system/stack/Android.bp
+++ b/system/stack/Android.bp
@@ -235,6 +235,7 @@
srcs: [
"test/stack_a2dp_test.cc",
"test/stack_avrcp_test.cc",
+ "test/gatt/gatt_api_test.cc",
],
shared_libs: [
"android.hardware.bluetooth@1.0",
@@ -481,8 +482,12 @@
// Bluetooth stack connection multiplexing
cc_test {
name: "net_test_gatt_conn_multiplexing",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
host_supported: true,
+ test_suites: ["general-tests"],
local_include_dirs: [
"include",
"btm",
@@ -998,9 +1003,14 @@
"libprotobuf-cpp-lite",
],
sanitize: {
- hwaddress: true,
- integer_overflow: true,
- scs: true,
+ address: true,
+ all_undefined: true,
+ cfi: true,
+ integer_overflow: true,
+ scs: true,
+ diag: {
+ undefined : true
+ },
},
}
diff --git a/system/stack/acl/btm_acl.cc b/system/stack/acl/btm_acl.cc
index c6264dd..eb74e90 100644
--- a/system/stack/acl/btm_acl.cc
+++ b/system/stack/acl/btm_acl.cc
@@ -50,6 +50,7 @@
#include "main/shim/dumpsys.h"
#include "main/shim/l2c_api.h"
#include "main/shim/shim.h"
+#include "os/parameter_provider.h"
#include "osi/include/allocator.h"
#include "osi/include/log.h"
#include "osi/include/osi.h" // UNUSED_ATTR
@@ -339,6 +340,11 @@
uint8_t sca;
uint8_t status;
+ if (len < 4) {
+ LOG_WARN("Malformatted packet, not containing enough data");
+ return;
+ }
+
STREAM_TO_UINT8(status, data);
if (status != HCI_SUCCESS) {
@@ -630,6 +636,23 @@
return;
}
+ /* Common Criteria mode only: if we are trying to drop encryption on an
+ * encrypted connection, drop the connection */
+ if (bluetooth::os::ParameterProvider::IsCommonCriteriaMode()) {
+ if (p->is_encrypted && !encr_enable) {
+ LOG(ERROR)
+ << __func__
+ << " attempting to decrypt encrypted connection, disconnecting. "
+ "handle: "
+ << loghex(handle);
+
+ acl_disconnect_from_handle(handle, HCI_ERR_HOST_REJECT_SECURITY,
+ "stack::btu::btu_hcif::read_drop_encryption "
+ "Connection Already Encrypted");
+ return;
+ }
+ }
+
p->is_encrypted = encr_enable;
/* Process Role Switch if active */
diff --git a/system/stack/btm/btm_ble_batchscan.cc b/system/stack/btm/btm_ble_batchscan.cc
index 2278880..bdce367 100644
--- a/system/stack/btm/btm_ble_batchscan.cc
+++ b/system/stack/btm/btm_ble_batchscan.cc
@@ -60,12 +60,15 @@
/* VSE callback for batch scan, filter, and tracking events */
void btm_ble_batchscan_filter_track_adv_vse_cback(uint8_t len,
const uint8_t* p) {
- tBTM_BLE_TRACK_ADV_DATA adv_data;
-
+ tBTM_BLE_TRACK_ADV_DATA adv_data{};
uint8_t sub_event = 0;
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
- if (len == 0) return;
+
+ if (len < 1)
+ goto err_out;
+
STREAM_TO_UINT8(sub_event, p);
+ len -= 1;
BTM_TRACE_EVENT(
"btm_ble_batchscan_filter_track_adv_vse_cback called with event:%x",
@@ -78,30 +81,45 @@
if (HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT == sub_event &&
NULL != ble_advtrack_cb.p_track_cback) {
- if (len < 10) return;
- memset(&adv_data, 0, sizeof(tBTM_BLE_TRACK_ADV_DATA));
BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
adv_data.client_if = (uint8_t)ble_advtrack_cb.ref_value;
if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) {
+ if (len < 10) {
+ goto err_out;
+ }
+
STREAM_TO_UINT8(adv_data.filt_index, p);
STREAM_TO_UINT8(adv_data.advertiser_state, p);
STREAM_TO_UINT8(adv_data.advertiser_info_present, p);
STREAM_TO_BDADDR(adv_data.bd_addr, p);
STREAM_TO_UINT8(adv_data.addr_type, p);
+ len -= 10;
+
/* Extract the adv info details */
if (ADV_INFO_PRESENT == adv_data.advertiser_info_present) {
- if (len < 15) return;
+
+ if (len < 5) {
+ goto err_out;
+ }
+
STREAM_TO_UINT8(adv_data.tx_power, p);
STREAM_TO_UINT8(adv_data.rssi_value, p);
STREAM_TO_UINT16(adv_data.time_stamp, p);
-
STREAM_TO_UINT8(adv_data.adv_pkt_len, p);
+
+ len -= 5;
+
if (adv_data.adv_pkt_len > 0) {
adv_data.p_adv_pkt_data =
static_cast<uint8_t*>(osi_malloc(adv_data.adv_pkt_len));
+ if (adv_data.p_adv_pkt_data == nullptr || \
+ len < adv_data.adv_pkt_len) {
+ goto err_out;
+ }
memcpy(adv_data.p_adv_pkt_data, p, adv_data.adv_pkt_len);
+ len -= adv_data.adv_pkt_len;
p += adv_data.adv_pkt_len;
}
@@ -109,11 +127,19 @@
if (adv_data.scan_rsp_len > 0) {
adv_data.p_scan_rsp_data =
static_cast<uint8_t*>(osi_malloc(adv_data.scan_rsp_len));
+
+ if (adv_data.p_scan_rsp_data == nullptr || len < adv_data.scan_rsp_len) {
+ goto err_out;
+ }
memcpy(adv_data.p_scan_rsp_data, p, adv_data.scan_rsp_len);
}
}
} else {
/* Based on L-release version */
+ if (len < 9) {
+ goto err_out;
+ }
+
STREAM_TO_UINT8(adv_data.filt_index, p);
STREAM_TO_UINT8(adv_data.addr_type, p);
STREAM_TO_BDADDR(adv_data.bd_addr, p);
@@ -129,8 +155,15 @@
to_ble_addr_type(adv_data.addr_type));
ble_advtrack_cb.p_track_cback(&adv_data);
- return;
}
+
+ return;
+
+err_out:
+ BTM_TRACE_ERROR("malformatted packet detected");
+
+ osi_free_and_reset((void **) &adv_data.p_adv_pkt_data);
+ osi_free_and_reset((void **) &adv_data.p_scan_rsp_data);
}
void feat_enable_cb(uint8_t* p, uint16_t len) {
diff --git a/system/stack/btm/btm_ble_gap.cc b/system/stack/btm/btm_ble_gap.cc
index 5aa30e7..57192f8 100644
--- a/system/stack/btm/btm_ble_gap.cc
+++ b/system/stack/btm/btm_ble_gap.cc
@@ -1436,7 +1436,7 @@
******************************************************************************/
void btm_ble_periodic_adv_sync_tx_rcvd(uint8_t* p, uint16_t param_len) {
LOG_DEBUG("[PAST]: PAST received, param_len=%u", param_len);
- if (param_len == 0) {
+ if (param_len < 19) {
LOG_ERROR("%s", "Insufficient data");
return;
}
@@ -2438,7 +2438,8 @@
data.size() - (p_service_data - data.data()) - service_data_len,
BTM_BLE_AD_TYPE_SERVICE_DATA_TYPE, &service_data_len))) {
uint16_t uuid;
- STREAM_TO_UINT16(uuid, p_service_data);
+ const uint8_t* p_uuid = p_service_data;
+ STREAM_TO_UINT16(uuid, p_uuid);
if (uuid == 0x184E /* Audio Stream Control service */ ||
uuid == 0x184F /* Broadcast Audio Scan service */ ||
diff --git a/system/stack/btm/btm_dev.cc b/system/stack/btm/btm_dev.cc
index 5904115..10c19d4 100644
--- a/system/stack/btm/btm_dev.cc
+++ b/system/stack/btm/btm_dev.cc
@@ -375,7 +375,7 @@
static bool has_lenc_and_address_is_equal(void* data, void* context) {
tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
- if (!(p_dev_rec->ble.key_type & BTM_LE_KEY_LENC)) return false;
+ if (!(p_dev_rec->ble.key_type & BTM_LE_KEY_LENC)) return true;
return is_address_equal(data, context);
}
@@ -650,3 +650,25 @@
p_dev_rec->bond_type = bond_type;
return true;
}
+
+/*******************************************************************************
+ *
+ * Function btm_get_sec_dev_rec
+ *
+ * Description Get security device records satisfying given filter
+ *
+ * Returns A vector containing pointers of security device records
+ *
+ ******************************************************************************/
+std::vector<tBTM_SEC_DEV_REC*> btm_get_sec_dev_rec() {
+ std::vector<tBTM_SEC_DEV_REC*> result{};
+
+ list_node_t* end = list_end(btm_cb.sec_dev_rec);
+ for (list_node_t* node = list_begin(btm_cb.sec_dev_rec); node != end;
+ node = list_next(node)) {
+ tBTM_SEC_DEV_REC* p_dev_rec =
+ static_cast<tBTM_SEC_DEV_REC*>(list_node(node));
+ result.push_back(p_dev_rec);
+ }
+ return result;
+}
diff --git a/system/stack/btm/btm_dev.h b/system/stack/btm/btm_dev.h
index 7591129..84d73e7 100644
--- a/system/stack/btm/btm_dev.h
+++ b/system/stack/btm/btm_dev.h
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <functional>
+
#include "osi/include/log.h"
#include "stack/btm/btm_ble_int.h"
#include "stack/btm/security_device_record.h"
@@ -197,3 +199,14 @@
******************************************************************************/
bool btm_set_bond_type_dev(const RawAddress& bd_addr,
tBTM_SEC_DEV_REC::tBTM_BOND_TYPE bond_type);
+
+/*******************************************************************************
+ *
+ * Function btm_get_sec_dev_rec
+ *
+ * Description Get security device records satisfying given filter
+ *
+ * Returns A vector containing pointers of security device records
+ *
+ ******************************************************************************/
+std::vector<tBTM_SEC_DEV_REC*> btm_get_sec_dev_rec();
diff --git a/system/stack/btm/btm_iso_impl.h b/system/stack/btm/btm_iso_impl.h
index 0abe21f..9559e1d 100644
--- a/system/stack/btm/btm_iso_impl.h
+++ b/system/stack/btm/btm_iso_impl.h
@@ -367,6 +367,10 @@
uint8_t status;
uint16_t conn_handle;
+ if (len < 3) {
+ LOG(WARNING) << __func__ << "Malformatted packet received";
+ return;
+ }
STREAM_TO_UINT8(status, stream);
STREAM_TO_UINT16(conn_handle, stream);
diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc
index 8df08bb..df9b6cc 100644
--- a/system/stack/btm/btm_sec.cc
+++ b/system/stack/btm/btm_sec.cc
@@ -44,6 +44,7 @@
#include "osi/include/compat.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
+#include "osi/include/properties.h"
#include "stack/btm/btm_dev.h"
#include "stack/btm/security_device_record.h"
#include "stack/eatt/eatt.h"
@@ -153,6 +154,14 @@
}
}
+static bool concurrentPeerAuthIsEnabled() {
+ // Was previously named BTM_DISABLE_CONCURRENT_PEER_AUTH.
+ // Renamed to ENABLED for homogeneity with system properties
+ static const bool sCONCURRENT_PEER_AUTH_IS_ENABLED = osi_property_get_bool(
+ "bluetooth.btm.sec.concurrent_peer_auth.enabled", true);
+ return sCONCURRENT_PEER_AUTH_IS_ENABLED;
+}
+
void NotifyBondingCanceled(tBTM_STATUS btm_status) {
if (btm_cb.api.p_bond_cancel_cmpl_callback) {
btm_cb.api.p_bond_cancel_cmpl_callback(BTM_SUCCESS);
@@ -3406,11 +3415,9 @@
__func__, p_dev_rec, p_dev_rec->p_callback);
p_dev_rec->p_callback = NULL;
l2cu_resubmit_pending_sec_req(&p_dev_rec->bd_addr);
-#ifdef BTM_DISABLE_CONCURRENT_PEER_AUTH
- } else if (BTM_DISABLE_CONCURRENT_PEER_AUTH &&
+ } else if (!concurrentPeerAuthIsEnabled() &&
p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
-#endif
}
return;
}
@@ -4035,10 +4042,9 @@
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
VLOG(2) << __func__ << " bda: " << bda;
-#if (defined(BTM_DISABLE_CONCURRENT_PEER_AUTH) && \
- (BTM_DISABLE_CONCURRENT_PEER_AUTH == TRUE))
- p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
-#endif
+ if (!concurrentPeerAuthIsEnabled()) {
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ }
if ((btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) &&
(btm_cb.collision_start_time != 0) &&
@@ -4498,12 +4504,16 @@
static void btm_sec_wait_and_start_authentication(tBTM_SEC_DEV_REC* p_dev_rec) {
p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
auto addr = new RawAddress(p_dev_rec->bd_addr);
+
+ static const int32_t delay_auth =
+ osi_property_get_int32("bluetooth.btm.sec.delay_auth_ms.value", 0);
+
bt_status_t status = do_in_main_thread_delayed(
FROM_HERE, base::Bind(&btm_sec_auth_timer_timeout, addr),
#if BASE_VER < 931007
- base::TimeDelta::FromMilliseconds(BTM_DELAY_AUTH_MS));
+ base::TimeDelta::FromMilliseconds(delay_auth));
#else
- base::Milliseconds(BTM_DELAY_AUTH_MS));
+ base::Milliseconds(delay_auth));
#endif
if (status != BT_STATUS_SUCCESS) {
LOG(ERROR) << __func__
diff --git a/system/stack/btu/btu_hcif.cc b/system/stack/btu/btu_hcif.cc
index 552b174..ec05df2 100644
--- a/system/stack/btu/btu_hcif.cc
+++ b/system/stack/btu/btu_hcif.cc
@@ -93,7 +93,7 @@
static void btu_hcif_io_cap_request_evt(const uint8_t* p);
static void btu_ble_ll_conn_param_upd_evt(uint8_t* p, uint16_t evt_len);
-static void btu_ble_proc_ltk_req(uint8_t* p);
+static void btu_ble_proc_ltk_req(uint8_t* p, uint16_t evt_len);
static void btu_hcif_encryption_key_refresh_cmpl_evt(uint8_t* p);
static void btu_ble_data_length_change_evt(uint8_t* p, uint16_t evt_len);
static void btu_ble_rc_param_req_evt(uint8_t* p, uint8_t len);
@@ -346,7 +346,7 @@
btm_ble_read_remote_features_complete(p, ble_evt_len);
break;
case HCI_BLE_LTK_REQ_EVT: /* received only at peripheral device */
- btu_ble_proc_ltk_req(p);
+ btu_ble_proc_ltk_req(p, ble_evt_len);
break;
case HCI_BLE_RC_PARAM_REQ_EVT:
btu_ble_rc_param_req_evt(p, ble_evt_len);
@@ -1660,10 +1660,22 @@
interval, latency, timeout);
}
-static void btu_ble_proc_ltk_req(uint8_t* p) {
+static void btu_ble_proc_ltk_req(uint8_t* p, uint16_t evt_len) {
uint16_t ediv, handle;
uint8_t* pp;
+ // following the spec in Core_v5.3/Vol 4/Part E
+ // / 7.7.65.5 LE Long Term Key Request event
+ // A BLE Long Term Key Request event contains:
+ // - 1-byte subevent (already consumed in btu_hcif_process_event)
+ // - 2-byte connection handler
+ // - 8-byte random number
+ // - 2 byte Encrypted_Diversifier
+ if (evt_len < 2 + 8 + 2) {
+ LOG_ERROR("Event packet too short");
+ return;
+ }
+
STREAM_TO_UINT16(handle, p);
pp = p + 8;
STREAM_TO_UINT16(ediv, pp);
diff --git a/system/stack/eatt/eatt_impl.h b/system/stack/eatt/eatt_impl.h
index f0d8254..998fc10 100644
--- a/system/stack/eatt/eatt_impl.h
+++ b/system/stack/eatt/eatt_impl.h
@@ -153,7 +153,8 @@
tL2CAP_LE_CFG_INFO local_coc_cfg = {
.mtu = eatt_dev->rx_mtu_,
.mps = eatt_dev->rx_mps_ < max_mps ? eatt_dev->rx_mps_ : max_mps,
- .credits = L2CAP_LE_CREDIT_DEFAULT};
+ .credits = L2CA_LeCreditDefault(),
+ };
if (!L2CA_ConnectCreditBasedRsp(bda, identifier, lcids, L2CAP_CONN_OK,
&local_coc_cfg))
@@ -584,7 +585,7 @@
tL2CAP_LE_CFG_INFO local_coc_cfg = {
.mtu = eatt_dev->rx_mtu_,
.mps = eatt_dev->rx_mps_,
- .credits = L2CAP_LE_CREDIT_DEFAULT,
+ .credits = L2CA_LeCreditDefault(),
.number_of_channels = num_of_channels,
};
diff --git a/system/stack/gap/gap_conn.cc b/system/stack/gap/gap_conn.cc
index d1b8219..23d9589 100644
--- a/system/stack/gap/gap_conn.cc
+++ b/system/stack/gap/gap_conn.cc
@@ -207,7 +207,7 @@
/* Configure L2CAP COC, if transport is LE */
if (transport == BT_TRANSPORT_LE) {
- p_ccb->local_coc_cfg.credits = L2CAP_LE_CREDIT_DEFAULT;
+ p_ccb->local_coc_cfg.credits = L2CA_LeCreditDefault();
p_ccb->local_coc_cfg.mtu = p_cfg->mtu;
uint16_t max_mps = controller_get_interface()->get_acl_data_size_ble();
diff --git a/system/stack/gatt/gatt_api.cc b/system/stack/gatt/gatt_api.cc
index 3861016..9a1152b 100644
--- a/system/stack/gatt/gatt_api.cc
+++ b/system/stack/gatt/gatt_api.cc
@@ -21,7 +21,7 @@
* this file contains GATT interface functions
*
******************************************************************************/
-#include "gatt_api.h"
+#include "stack/include/gatt_api.h"
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
@@ -31,13 +31,16 @@
#include "bt_target.h"
#include "device/include/controller.h"
-#include "gatt_int.h"
+#include "gd/os/system_properties.h"
#include "internal_include/stack_config.h"
#include "l2c_api.h"
#include "main/shim/dumpsys.h"
#include "osi/include/allocator.h"
+#include "osi/include/list.h"
#include "osi/include/log.h"
+#include "stack/btm/btm_dev.h"
#include "stack/gatt/connection_manager.h"
+#include "stack/gatt/gatt_int.h"
#include "stack/include/bt_hdr.h"
#include "types/bluetooth/uuid.h"
#include "types/bt_transport.h"
@@ -304,7 +307,7 @@
elem.type = list.asgn_range.is_primary ? GATT_UUID_PRI_SERVICE
: GATT_UUID_SEC_SERVICE;
- if (elem.type == GATT_UUID_PRI_SERVICE) {
+ if (elem.type == GATT_UUID_PRI_SERVICE && gatt_cb.over_br_enabled) {
Uuid* p_uuid = gatts_get_service_uuid(elem.p_db);
if (*p_uuid != Uuid::From16Bit(UUID_SERVCLASS_GMCS_SERVER) &&
*p_uuid != Uuid::From16Bit(UUID_SERVCLASS_GTBS_SERVER)) {
@@ -1479,3 +1482,48 @@
LOG_DEBUG("status=%d", status);
return status;
}
+
+static void gatt_bonded_check_add_address(const RawAddress& bda) {
+ if (!gatt_is_bda_in_the_srv_chg_clt_list(bda)) {
+ gatt_add_a_bonded_dev_for_srv_chg(bda);
+ }
+}
+
+std::optional<bool> OVERRIDE_GATT_LOAD_BONDED = std::nullopt;
+
+static bool gatt_load_bonded_is_enabled() {
+ static const bool sGATT_LOAD_BONDED = bluetooth::os::GetSystemPropertyBool(
+ "bluetooth.gatt.load_bonded.enabled", false);
+ if (OVERRIDE_GATT_LOAD_BONDED.has_value()) {
+ return OVERRIDE_GATT_LOAD_BONDED.value();
+ }
+ return sGATT_LOAD_BONDED;
+}
+
+/* Initialize GATTS list of bonded device service change updates.
+ *
+ * Addresses for bonded devices (publict for BR/EDR or pseudo for BLE) are added
+ * to GATTS service change control list so that updates are sent to bonded
+ * devices on next connect after any handles for GATTS services change due to
+ * services added/removed.
+ */
+void gatt_load_bonded(void) {
+ const bool load_bonded = gatt_load_bonded_is_enabled();
+ LOG_INFO("load bonded: %s", load_bonded ? "True" : "False");
+ if (!load_bonded) {
+ return;
+ }
+ for (tBTM_SEC_DEV_REC* p_dev_rec : btm_get_sec_dev_rec()) {
+ if (p_dev_rec->is_link_key_known()) {
+ LOG_VERBOSE("Add bonded BR/EDR transport %s",
+ PRIVATE_ADDRESS(p_dev_rec->bd_addr));
+ gatt_bonded_check_add_address(p_dev_rec->bd_addr);
+ }
+ if (p_dev_rec->is_le_link_key_known()) {
+ VLOG(1) << " add bonded BLE " << p_dev_rec->ble.pseudo_addr;
+ LOG_VERBOSE("Add bonded BLE %s",
+ PRIVATE_ADDRESS(p_dev_rec->ble.pseudo_addr));
+ gatt_bonded_check_add_address(p_dev_rec->ble.pseudo_addr);
+ }
+ }
+}
diff --git a/system/stack/gatt/gatt_int.h b/system/stack/gatt/gatt_int.h
index a05c27c..fa173f5 100644
--- a/system/stack/gatt/gatt_int.h
+++ b/system/stack/gatt/gatt_int.h
@@ -259,6 +259,8 @@
}
#undef CASE_RETURN_TEXT
+// If you change these values make sure to look at b/262219144 before.
+// Some platform rely on this to never changes
#define GATT_GATT_START_HANDLE 1
#define GATT_GAP_START_HANDLE 20
#define GATT_GMCS_START_HANDLE 40
@@ -266,14 +268,6 @@
#define GATT_TMAS_START_HANDLE 130
#define GATT_APP_START_HANDLE 134
-#ifndef GATT_DEFAULT_START_HANDLE
-#define GATT_DEFAULT_START_HANDLE GATT_GATT_START_HANDLE
-#endif
-
-#ifndef GATT_LAST_HANDLE
-#define GATT_LAST_HANDLE 0xFFFF
-#endif
-
typedef struct hdl_cfg {
uint16_t gatt_start_hdl;
uint16_t gap_start_hdl;
@@ -452,6 +446,7 @@
tGATT_APPL_INFO cb_info;
tGATT_HDL_CFG hdl_cfg;
+ bool over_br_enabled;
} tGATT_CB;
#define GATT_SIZE_OF_SRV_CHG_HNDL_RANGE 4
diff --git a/system/stack/gatt/gatt_main.cc b/system/stack/gatt/gatt_main.cc
index 09eccb6..b9d1120 100644
--- a/system/stack/gatt/gatt_main.cc
+++ b/system/stack/gatt/gatt_main.cc
@@ -123,10 +123,10 @@
L2CA_RegisterFixedChannel(L2CAP_ATT_CID, &fixed_reg);
- bool gatt_over_br_is_disabled =
- osi_property_get_bool("bluetooth.gatt_over_bredr.disabled", false);
+ gatt_cb.over_br_enabled =
+ osi_property_get_bool("bluetooth.gatt.over_bredr.enabled", true);
/* Now, register with L2CAP for ATT PSM over BR/EDR */
- if (!gatt_over_br_is_disabled &&
+ if (gatt_cb.over_br_enabled &&
!L2CA_Register2(BT_PSM_ATT, dyn_info, false /* enable_snoop */, nullptr,
GATT_MAX_MTU_SIZE, 0, BTM_SEC_NONE)) {
LOG(ERROR) << "ATT Dynamic Registration failed";
@@ -909,6 +909,13 @@
/** This function is called to send a service chnaged indication to the
* specified bd address */
void gatt_send_srv_chg_ind(const RawAddress& peer_bda) {
+ static const uint16_t sGATT_DEFAULT_START_HANDLE =
+ (uint16_t)osi_property_get_int32(
+ "bluetooth.gatt.default_start_handle_for_srvc_change.value",
+ GATT_GATT_START_HANDLE);
+ static const uint16_t sGATT_LAST_HANDLE = (uint16_t)osi_property_get_int32(
+ "bluetooth.gatt.last_handle_for_srvc_change.value", 0xFFFF);
+
VLOG(1) << __func__;
if (!gatt_cb.handle_of_h_r) return;
@@ -921,8 +928,8 @@
uint8_t handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE];
uint8_t* p = handle_range;
- UINT16_TO_STREAM(p, GATT_DEFAULT_START_HANDLE);
- UINT16_TO_STREAM(p, GATT_LAST_HANDLE);
+ UINT16_TO_STREAM(p, sGATT_DEFAULT_START_HANDLE);
+ UINT16_TO_STREAM(p, sGATT_LAST_HANDLE);
GATTS_HandleValueIndication(conn_id, gatt_cb.handle_of_h_r,
GATT_SIZE_OF_SRV_CHG_HNDL_RANGE, handle_range);
}
diff --git a/system/stack/gatt/gatt_utils.cc b/system/stack/gatt/gatt_utils.cc
index 38f91a0..d65b6d6 100644
--- a/system/stack/gatt/gatt_utils.cc
+++ b/system/stack/gatt/gatt_utils.cc
@@ -1715,10 +1715,12 @@
pseduo_op_code_idx = 0x15; /* just an index to op_code_name */
}
- if (pseduo_op_code_idx <= GATT_OP_CODE_MAX)
+ #define ARR_SIZE(a) (sizeof(a)/sizeof(a[0]))
+ if (pseduo_op_code_idx < ARR_SIZE(op_code_name))
return (uint8_t*)op_code_name[pseduo_op_code_idx];
else
return (uint8_t*)"Op Code Exceed Max";
+ #undef ARR_SIZE
}
/** Remove the application interface for the specified background device */
diff --git a/system/stack/hid/hidd_conn.cc b/system/stack/hid/hidd_conn.cc
index da78d40..fc0a245 100644
--- a/system/stack/hid/hidd_conn.cc
+++ b/system/stack/hid/hidd_conn.cc
@@ -27,6 +27,7 @@
#include "bta/include/bta_api.h"
#include "btif/include/btif_hd.h"
+#include "gd/common/init_flags.h"
#include "osi/include/allocator.h"
#include "stack/hid/hidd_int.h"
#include "stack/include/bt_hdr.h"
@@ -347,7 +348,6 @@
static void hidd_l2cif_disconnect(uint16_t cid) {
L2CA_DisconnectReq(cid);
-
HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
tHID_CONN* p_hcon = &hd_cb.device.conn;
@@ -365,6 +365,10 @@
// now disconnect CTRL
L2CA_DisconnectReq(p_hcon->ctrl_cid);
+ if (bluetooth::common::init_flags::
+ clear_hidd_interrupt_cid_on_disconnect_is_enabled()) {
+ p_hcon->ctrl_cid = 0;
+ }
}
if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
diff --git a/system/stack/include/gatt_api.h b/system/stack/include/gatt_api.h
index 05d4115..eb37910 100644
--- a/system/stack/include/gatt_api.h
+++ b/system/stack/include/gatt_api.h
@@ -1190,4 +1190,7 @@
* true, as there is no need to wipe controller acceptlist in this case. */
extern void gatt_reset_bgdev_list(bool after_reset);
+// Initialize GATTS list of bonded device service change updates.
+extern void gatt_load_bonded(void);
+
#endif /* GATT_API_H */
diff --git a/system/stack/include/l2c_api.h b/system/stack/include/l2c_api.h
index d62da3c..c4e452f 100644
--- a/system/stack/include/l2c_api.h
+++ b/system/stack/include/l2c_api.h
@@ -180,14 +180,11 @@
// This is initial amout of credits we send, and amount to which we increase
// credits once they fall below threshold
-constexpr uint16_t L2CAP_LE_CREDIT_DEFAULT = 0xffff;
+uint16_t L2CA_LeCreditDefault();
// If credit count on remote fall below this value, we send back credits to
// reach default value.
-constexpr uint16_t L2CAP_LE_CREDIT_THRESHOLD = 0x0040;
-
-static_assert(L2CAP_LE_CREDIT_THRESHOLD < L2CAP_LE_CREDIT_DEFAULT,
- "Threshold must be smaller than default credits");
+uint16_t L2CA_LeCreditThreshold();
// Max number of CIDs in the L2CAP CREDIT BASED CONNECTION REQUEST
constexpr uint16_t L2CAP_CREDIT_BASED_MAX_CIDS = 5;
@@ -199,7 +196,7 @@
uint16_t result; /* Only used in confirm messages */
uint16_t mtu = 100;
uint16_t mps = 100;
- uint16_t credits = L2CAP_LE_CREDIT_DEFAULT;
+ uint16_t credits = L2CA_LeCreditDefault();
uint8_t number_of_channels = L2CAP_CREDIT_BASED_MAX_CIDS;
};
diff --git a/system/stack/include/stack_metrics_logging.h b/system/stack/include/stack_metrics_logging.h
index 158c98f..58d869f 100644
--- a/system/stack/include/stack_metrics_logging.h
+++ b/system/stack/include/stack_metrics_logging.h
@@ -34,9 +34,9 @@
uint32_t hci_cmd, uint16_t hci_event, uint16_t hci_ble_event,
uint16_t cmd_status, uint16_t reason_code);
-void log_smp_pairing_event(const RawAddress& address, uint8_t smp_cmd,
+void log_smp_pairing_event(const RawAddress& address, uint16_t smp_cmd,
android::bluetooth::DirectionEnum direction,
- uint8_t smp_fail_reason);
+ uint16_t smp_fail_reason);
void log_sdp_attribute(const RawAddress& address, uint16_t protocol_uuid,
uint16_t attribute_id, size_t attribute_size,
diff --git a/system/stack/l2cap/l2c_api.cc b/system/stack/l2cap/l2c_api.cc
index 5464cb4..2a7efd8 100644
--- a/system/stack/l2cap/l2c_api.cc
+++ b/system/stack/l2cap/l2c_api.cc
@@ -34,6 +34,7 @@
#include "device/include/controller.h" // TODO Remove
#include "gd/common/init_flags.h"
+#include "gd/os/system_properties.h"
#include "main/shim/shim.h"
#include "osi/include/allocator.h"
#include "osi/include/log.h"
@@ -65,6 +66,29 @@
return ret;
}
+uint16_t L2CA_LeCreditDefault() {
+ static const uint16_t sL2CAP_LE_CREDIT_DEFAULT =
+ bluetooth::os::GetSystemPropertyUint32Base(
+ "bluetooth.l2cap.le.credit_default.value", 0xffff);
+ return sL2CAP_LE_CREDIT_DEFAULT;
+}
+
+uint16_t L2CA_LeCreditThreshold() {
+ static const uint16_t sL2CAP_LE_CREDIT_THRESHOLD =
+ bluetooth::os::GetSystemPropertyUint32Base(
+ "bluetooth.l2cap.le.credit_threshold.value", 0x0040);
+ return sL2CAP_LE_CREDIT_THRESHOLD;
+}
+
+static bool check_l2cap_credit() {
+ CHECK(L2CA_LeCreditThreshold() < L2CA_LeCreditDefault())
+ << "Threshold must be smaller than default credits";
+ return true;
+}
+
+// Replace static assert with startup assert depending of the config
+static const bool enforce_assert = check_l2cap_credit();
+
/*******************************************************************************
*
* Function L2CA_Register
diff --git a/system/stack/l2cap/l2c_ble.cc b/system/stack/l2cap/l2c_ble.cc
index a17ba28..890304d 100755
--- a/system/stack/l2cap/l2c_ble.cc
+++ b/system/stack/l2cap/l2c_ble.cc
@@ -990,7 +990,7 @@
p_ccb->local_conn_cfg.mtu = L2CAP_SDU_LENGTH_LE_MAX;
p_ccb->local_conn_cfg.mps =
controller_get_interface()->get_acl_data_size_ble();
- p_ccb->local_conn_cfg.credits = L2CAP_LE_CREDIT_DEFAULT,
+ p_ccb->local_conn_cfg.credits = L2CA_LeCreditDefault(),
p_ccb->peer_conn_cfg.mtu = mtu;
p_ccb->peer_conn_cfg.mps = mps;
diff --git a/system/stack/l2cap/l2c_fcr.cc b/system/stack/l2cap/l2c_fcr.cc
index 9c76005..d6d06d9 100644
--- a/system/stack/l2cap/l2c_fcr.cc
+++ b/system/stack/l2cap/l2c_fcr.cc
@@ -734,6 +734,10 @@
} else {
p_data = p_ccb->ble_sdu;
+ if (p_data == NULL) {
+ osi_free(p_buf);
+ return;
+ }
if (p_buf->len > (p_ccb->ble_sdu_length - p_data->len)) {
L2CAP_TRACE_ERROR("%s: buffer length=%d too big. max=%d. Dropped",
__func__, p_data->len,
diff --git a/system/stack/l2cap/l2c_main.cc b/system/stack/l2cap/l2c_main.cc
index 06714cb..1d412f7 100644
--- a/system/stack/l2cap/l2c_main.cc
+++ b/system/stack/l2cap/l2c_main.cc
@@ -221,9 +221,9 @@
--p_ccb->remote_credit_count;
/* If the credits left on the remote device are getting low, send some */
- if (p_ccb->remote_credit_count <= L2CAP_LE_CREDIT_THRESHOLD) {
- uint16_t credits = L2CAP_LE_CREDIT_DEFAULT - p_ccb->remote_credit_count;
- p_ccb->remote_credit_count = L2CAP_LE_CREDIT_DEFAULT;
+ if (p_ccb->remote_credit_count <= L2CA_LeCreditThreshold()) {
+ uint16_t credits = L2CA_LeCreditDefault() - p_ccb->remote_credit_count;
+ p_ccb->remote_credit_count = L2CA_LeCreditDefault();
/* Return back credits */
l2c_csm_execute(p_ccb, L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT, &credits);
diff --git a/system/stack/metrics/stack_metrics_logging.cc b/system/stack/metrics/stack_metrics_logging.cc
index 4e23bd2..d69d54e 100644
--- a/system/stack/metrics/stack_metrics_logging.cc
+++ b/system/stack/metrics/stack_metrics_logging.cc
@@ -42,9 +42,9 @@
hci_ble_event, cmd_status, reason_code);
}
-void log_smp_pairing_event(const RawAddress& address, uint8_t smp_cmd,
+void log_smp_pairing_event(const RawAddress& address, uint16_t smp_cmd,
android::bluetooth::DirectionEnum direction,
- uint8_t smp_fail_reason) {
+ uint16_t smp_fail_reason) {
bluetooth::shim::LogMetricSmpPairingEvent(address, smp_cmd, direction,
smp_fail_reason);
}
diff --git a/system/stack/smp/smp_int.h b/system/stack/smp/smp_int.h
index c4ddf3e..52b5c2b 100644
--- a/system/stack/smp/smp_int.h
+++ b/system/stack/smp/smp_int.h
@@ -32,6 +32,15 @@
#include "stack/include/bt_octets.h"
#include "types/raw_address.h"
+typedef enum : uint16_t {
+ SMP_METRIC_COMMAND_LE_FLAG = 0x0000,
+ SMP_METRIC_COMMAND_BR_FLAG = 0x0100,
+ SMP_METRIC_COMMAND_LE_PAIRING_CMPL = 0xFF00,
+ SMP_METRIC_COMMAND_BR_PAIRING_CMPL = 0xFF01,
+} tSMP_METRIC_COMMAND;
+
+constexpr uint16_t SMP_METRIC_STATUS_INTERNAL_FLAG = 0x0100;
+
typedef enum : uint8_t {
/* Legacy mode */
SMP_MODEL_ENCRYPTION_ONLY = 0, /* Just Works model */
@@ -414,7 +423,8 @@
/* smp_util.cc */
extern void smp_log_metrics(const RawAddress& bd_addr, bool is_outgoing,
- const uint8_t* p_buf, size_t buf_len);
+ const uint8_t* p_buf, size_t buf_len,
+ bool is_over_br);
extern bool smp_send_cmd(uint8_t cmd_code, tSMP_CB* p_cb);
extern void smp_cb_cleanup(tSMP_CB* p_cb);
extern void smp_reset_control_value(tSMP_CB* p_cb);
diff --git a/system/stack/smp/smp_l2c.cc b/system/stack/smp/smp_l2c.cc
index 6a13e8a..264cdc3 100644
--- a/system/stack/smp/smp_l2c.cc
+++ b/system/stack/smp/smp_l2c.cc
@@ -195,7 +195,8 @@
smp_rsp_timeout, NULL);
smp_log_metrics(p_cb->pairing_bda, false /* incoming */,
- p_buf->data + p_buf->offset, p_buf->len);
+ p_buf->data + p_buf->offset, p_buf->len,
+ false /* is_over_br */);
if (cmd == SMP_OPCODE_CONFIRM) {
SMP_TRACE_DEBUG(
@@ -334,7 +335,8 @@
smp_rsp_timeout, NULL);
smp_log_metrics(p_cb->pairing_bda, false /* incoming */,
- p_buf->data + p_buf->offset, p_buf->len);
+ p_buf->data + p_buf->offset, p_buf->len,
+ true /* is_over_br */);
p_cb->rcvd_cmd_code = cmd;
p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
diff --git a/system/stack/smp/smp_utils.cc b/system/stack/smp/smp_utils.cc
index 71fa55d..f2aba5e 100644
--- a/system/stack/smp/smp_utils.cc
+++ b/system/stack/smp/smp_utils.cc
@@ -316,22 +316,26 @@
* @param buf_len length available to read for p_buf
*/
void smp_log_metrics(const RawAddress& bd_addr, bool is_outgoing,
- const uint8_t* p_buf, size_t buf_len) {
+ const uint8_t* p_buf, size_t buf_len, bool is_over_br) {
if (buf_len < 1) {
LOG(WARNING) << __func__ << ": buffer is too small, size is " << buf_len;
return;
}
- uint8_t cmd;
- STREAM_TO_UINT8(cmd, p_buf);
+ uint8_t raw_cmd;
+ STREAM_TO_UINT8(raw_cmd, p_buf);
buf_len--;
uint8_t failure_reason = 0;
- if (cmd == SMP_OPCODE_PAIRING_FAILED && buf_len >= 1) {
+ if (raw_cmd == SMP_OPCODE_PAIRING_FAILED && buf_len >= 1) {
STREAM_TO_UINT8(failure_reason, p_buf);
}
+ uint16_t metric_cmd =
+ is_over_br ? SMP_METRIC_COMMAND_BR_FLAG : SMP_METRIC_COMMAND_LE_FLAG;
+ metric_cmd |= static_cast<uint16_t>(raw_cmd);
android::bluetooth::DirectionEnum direction =
is_outgoing ? android::bluetooth::DirectionEnum::DIRECTION_OUTGOING
: android::bluetooth::DirectionEnum::DIRECTION_INCOMING;
- log_smp_pairing_event(bd_addr, cmd, direction, failure_reason);
+ log_smp_pairing_event(bd_addr, metric_cmd, direction,
+ static_cast<uint16_t>(failure_reason));
}
/*******************************************************************************
@@ -352,7 +356,8 @@
SMP_TRACE_EVENT("%s", __func__);
smp_log_metrics(rem_bda, true /* outgoing */,
- p_toL2CAP->data + p_toL2CAP->offset, p_toL2CAP->len);
+ p_toL2CAP->data + p_toL2CAP->offset, p_toL2CAP->len,
+ smp_cb.smp_over_br /* is_over_br */);
l2cap_ret = L2CA_SendFixedChnlData(fixed_cid, rem_bda, p_toL2CAP);
if (l2cap_ret == L2CAP_DW_FAILED) {
@@ -980,6 +985,23 @@
smp_status_text(evt_data.cmplt.reason).c_str()));
}
+ // Log pairing complete event
+ {
+ auto direction =
+ p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD
+ ? android::bluetooth::DirectionEnum::DIRECTION_OUTGOING
+ : android::bluetooth::DirectionEnum::DIRECTION_INCOMING;
+ uint16_t metric_cmd = p_cb->smp_over_br
+ ? SMP_METRIC_COMMAND_BR_PAIRING_CMPL
+ : SMP_METRIC_COMMAND_LE_PAIRING_CMPL;
+ uint16_t metric_status = p_cb->status;
+ if (metric_status > SMP_MAX_FAIL_RSN_PER_SPEC) {
+ metric_status |= SMP_METRIC_STATUS_INTERNAL_FLAG;
+ }
+ log_smp_pairing_event(p_cb->pairing_bda, metric_cmd, direction,
+ metric_status);
+ }
+
if (p_cb->status == SMP_SUCCESS && p_cb->smp_over_br) {
btm_dev_consolidate_existing_connections(pairing_bda);
}
diff --git a/system/stack/test/common/mock_l2cap_layer.cc b/system/stack/test/common/mock_l2cap_layer.cc
index 2892759..d03d143 100644
--- a/system/stack/test/common/mock_l2cap_layer.cc
+++ b/system/stack/test/common/mock_l2cap_layer.cc
@@ -94,3 +94,8 @@
tL2CAP_LE_CFG_INFO* peer_cfg) {
return l2cap_interface->ReconfigCreditBasedConnsReq(bd_addr, lcids, peer_cfg);
}
+uint16_t L2CA_LeCreditDefault() { return l2cap_interface->LeCreditDefault(); }
+
+uint16_t L2CA_LeCreditThreshold() {
+ return l2cap_interface->LeCreditThreshold();
+}
diff --git a/system/stack/test/common/mock_l2cap_layer.h b/system/stack/test/common/mock_l2cap_layer.h
index edb662b..cb2b36d 100644
--- a/system/stack/test/common/mock_l2cap_layer.h
+++ b/system/stack/test/common/mock_l2cap_layer.h
@@ -51,6 +51,8 @@
tL2CAP_LE_CFG_INFO* p_cfg) = 0;
virtual bool ReconfigCreditBasedConnsReq(const RawAddress& bd_addr, std::vector<uint16_t> &lcids,
tL2CAP_LE_CFG_INFO* peer_cfg) = 0;
+ virtual uint16_t LeCreditDefault() = 0;
+ virtual uint16_t LeCreditThreshold() = 0;
virtual ~L2capInterface() = default;
};
@@ -84,6 +86,8 @@
tL2CAP_LE_CFG_INFO* p_cfg));
MOCK_METHOD3(ReconfigCreditBasedConnsReq,
bool(const RawAddress& p_bd_addr, std::vector<uint16_t> &lcids, tL2CAP_LE_CFG_INFO* peer_cfg));
+ MOCK_METHOD(uint16_t, LeCreditDefault, ());
+ MOCK_METHOD(uint16_t, LeCreditThreshold, ());
};
/**
diff --git a/system/stack/test/gatt/gatt_api_test.cc b/system/stack/test/gatt/gatt_api_test.cc
new file mode 100644
index 0000000..7900b77
--- /dev/null
+++ b/system/stack/test/gatt/gatt_api_test.cc
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#include "gatt_api.h"
+
+#include <base/logging.h>
+#include <gtest/gtest.h>
+
+#include "btm/btm_dev.h"
+#include "gatt/gatt_int.h"
+
+extern tBTM_CB btm_cb;
+
+static const size_t QUEUE_SIZE_MAX = 10;
+
+static tBTM_SEC_DEV_REC* make_bonded_ble_device(const RawAddress& bda,
+ const RawAddress& rra) {
+ tBTM_SEC_DEV_REC* dev = btm_sec_allocate_dev_rec();
+ dev->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN;
+ dev->bd_addr = bda;
+ dev->ble.pseudo_addr = rra;
+ dev->ble.key_type = BTM_LE_KEY_PID | BTM_LE_KEY_PENC | BTM_LE_KEY_LENC;
+ return dev;
+}
+
+static tBTM_SEC_DEV_REC* make_bonded_dual_device(const RawAddress& bda,
+ const RawAddress& rra) {
+ tBTM_SEC_DEV_REC* dev = make_bonded_ble_device(bda, rra);
+ dev->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+ return dev;
+}
+
+extern std::optional<bool> OVERRIDE_GATT_LOAD_BONDED;
+
+class GattApiTest : public ::testing::Test {
+ protected:
+ GattApiTest() = default;
+
+ virtual ~GattApiTest() = default;
+
+ void SetUp() override {
+ btm_cb.sec_dev_rec = list_new(osi_free);
+ gatt_cb.srv_chg_clt_q = fixed_queue_new(QUEUE_SIZE_MAX);
+ logging::SetMinLogLevel(-2);
+ }
+
+ void TearDown() override { list_free(btm_cb.sec_dev_rec); }
+};
+
+static const RawAddress SAMPLE_PUBLIC_BDA = {
+ {0x00, 0x00, 0x11, 0x22, 0x33, 0x44}};
+
+static const RawAddress SAMPLE_RRA_BDA = {{0xAA, 0xAA, 0x11, 0x22, 0x33, 0x44}};
+
+TEST_F(GattApiTest, test_gatt_load_bonded_ble_only) {
+ OVERRIDE_GATT_LOAD_BONDED = std::optional{true};
+ make_bonded_ble_device(SAMPLE_PUBLIC_BDA, SAMPLE_RRA_BDA);
+
+ gatt_load_bonded();
+
+ ASSERT_TRUE(gatt_is_bda_in_the_srv_chg_clt_list(SAMPLE_RRA_BDA));
+ ASSERT_FALSE(gatt_is_bda_in_the_srv_chg_clt_list(SAMPLE_PUBLIC_BDA));
+ OVERRIDE_GATT_LOAD_BONDED.reset();
+}
+
+TEST_F(GattApiTest, test_gatt_load_bonded_dual) {
+ OVERRIDE_GATT_LOAD_BONDED = std::optional{true};
+ make_bonded_dual_device(SAMPLE_PUBLIC_BDA, SAMPLE_RRA_BDA);
+
+ gatt_load_bonded();
+
+ ASSERT_TRUE(gatt_is_bda_in_the_srv_chg_clt_list(SAMPLE_RRA_BDA));
+ ASSERT_TRUE(gatt_is_bda_in_the_srv_chg_clt_list(SAMPLE_PUBLIC_BDA));
+ OVERRIDE_GATT_LOAD_BONDED.reset();
+}
diff --git a/system/stack/test/stack_l2cap_test.cc b/system/stack/test/stack_l2cap_test.cc
index 2418772..e8a6f1a 100644
--- a/system/stack/test/stack_l2cap_test.cc
+++ b/system/stack/test/stack_l2cap_test.cc
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include "common/init_flags.h"
+#include "device/include/controller.h"
#include "internal_include/bt_trace.h"
#include "stack/btm/btm_int_types.h"
#include "stack/include/l2cap_hci_link_interface.h"
@@ -26,24 +27,38 @@
tBTM_CB btm_cb;
extern tL2C_CB l2cb;
+void l2c_link_send_to_lower_br_edr(tL2C_LCB* p_lcb, BT_HDR* p_buf);
+void l2c_link_send_to_lower_ble(tL2C_LCB* p_lcb, BT_HDR* p_buf);
+
// Global trace level referred in the code under test
uint8_t appl_trace_level = BT_TRACE_LEVEL_VERBOSE;
extern "C" void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}
-const char* test_flags[] = {
- "INIT_logging_debug_enabled_for_all=true",
- nullptr,
-};
+namespace {
+constexpr uint16_t kAclBufferCountClassic = 123;
+constexpr uint8_t kAclBufferCountBle = 45;
+
+} // namespace
class StackL2capTest : public ::testing::Test {
protected:
void SetUp() override {
- bluetooth::common::InitFlags::Load(test_flags);
- l2cb = {}; // TODO Use proper init/free APIs
+ bluetooth::common::InitFlags::SetAllForTesting();
+ controller_.get_acl_buffer_count_classic = []() {
+ return kAclBufferCountClassic;
+ };
+ controller_.get_acl_buffer_count_ble = []() { return kAclBufferCountBle; };
+ controller_.supports_ble = []() -> bool { return true; };
+ l2c_init();
}
- void TearDown() override {}
+ void TearDown() override {
+ l2c_free();
+ controller_ = {};
+ }
+
+ controller_t controller_;
};
TEST_F(StackL2capTest, l2cble_process_data_length_change_event) {
@@ -65,3 +80,117 @@
l2cble_process_data_length_change_event(0x1234, 0x001b, 0x001b);
ASSERT_EQ(0x001b, l2cb.lcb_pool[0].tx_data_len);
}
+
+class StackL2capChannelTest : public StackL2capTest {
+ protected:
+ void SetUp() override { StackL2capTest::SetUp(); }
+
+ void TearDown() override { StackL2capTest::TearDown(); }
+
+ tL2C_CCB ccb_ = {
+ .in_use = true,
+ .chnl_state = CST_OPEN, // tL2C_CHNL_STATE
+ .local_conn_cfg =
+ {
+ // tL2CAP_LE_CFG_INFO
+ .result = 0,
+ .mtu = 100,
+ .mps = 100,
+ .credits = L2CA_LeCreditDefault(),
+ .number_of_channels = L2CAP_CREDIT_BASED_MAX_CIDS,
+ },
+ .peer_conn_cfg =
+ {
+ // tL2CAP_LE_CFG_INFO
+ .result = 0,
+ .mtu = 100,
+ .mps = 100,
+ .credits = L2CA_LeCreditDefault(),
+ .number_of_channels = L2CAP_CREDIT_BASED_MAX_CIDS,
+ },
+ .is_first_seg = false,
+ .ble_sdu = nullptr, // BT_HDR*; Buffer for storing unassembled sdu
+ .ble_sdu_length = 0, /* Length of unassembled sdu length*/
+ .p_next_ccb = nullptr, // struct t_l2c_ccb* Next CCB in the chain
+ .p_prev_ccb = nullptr, // struct t_l2c_ccb* Previous CCB in the chain
+ .p_lcb = nullptr, // struct t_l2c_linkcb* Link this CCB is assigned to
+ .local_cid = 40,
+ .remote_cid = 80,
+ .l2c_ccb_timer = nullptr, // alarm_t* CCB Timer Entry
+ .p_rcb = nullptr, // tL2C_RCB* Registration CB for this Channel
+ .config_done = 0, // Configuration flag word
+ .remote_config_rsp_result = 0, // The config rsp result from remote
+ .local_id = 12, // Transaction ID for local trans
+ .remote_id = 22, // Transaction ID for local
+ .flags = 0,
+ .connection_initiator = false,
+ .our_cfg = {}, // tL2CAP_CFG_INFO Our saved configuration options
+ .peer_cfg = {}, // tL2CAP_CFG_INFO Peer's saved configuration options
+ .xmit_hold_q = nullptr, // fixed_queue_t* Transmit data hold queue
+ .cong_sent = false,
+ .buff_quota = 0,
+
+ .ccb_priority =
+ L2CAP_CHNL_PRIORITY_HIGH, // tL2CAP_CHNL_PRIORITY Channel priority
+ .tx_data_rate = 0, // tL2CAP_CHNL_PRIORITY Channel Tx data rate
+ .rx_data_rate = 0, // tL2CAP_CHNL_PRIORITY Channel Rx data rate
+
+ .ertm_info =
+ {
+ // .tL2CAP_ERTM_INFO
+ .preferred_mode = 0,
+ },
+ .fcrb =
+ {
+ // tL2C_FCRB
+ .next_tx_seq = 0,
+ .last_rx_ack = 0,
+ .next_seq_expected = 0,
+ .last_ack_sent = 0,
+ .num_tries = 0,
+ .max_held_acks = 0,
+ .remote_busy = false,
+ .rej_sent = false,
+ .srej_sent = false,
+ .wait_ack = false,
+ .rej_after_srej = false,
+ .send_f_rsp = false,
+ .rx_sdu_len = 0,
+ .p_rx_sdu =
+ nullptr, // BT_HDR* Buffer holding the SDU being received
+ .waiting_for_ack_q = nullptr, // fixed_queue_t*
+ .srej_rcv_hold_q = nullptr, // fixed_queue_t*
+ .retrans_q = nullptr, // fixed_queue_t*
+ .ack_timer = nullptr, // alarm_t*
+ .mon_retrans_timer = nullptr, // alarm_t*
+ },
+ .tx_mps = 0,
+ .max_rx_mtu = 0,
+ .fcr_cfg_tries = 0,
+ .peer_cfg_already_rejected = false,
+ .out_cfg_fcr_present = false,
+ .is_flushable = false,
+ .fixed_chnl_idle_tout = 0,
+ .tx_data_len = 0,
+ .remote_credit_count = 0,
+ .ecoc = false,
+ .reconfig_started = false,
+ .metrics = {},
+ };
+};
+
+TEST_F(StackL2capChannelTest, l2c_lcc_proc_pdu__FirstSegment) {
+ ccb_.is_first_seg = true;
+
+ BT_HDR* p_buf = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + 32);
+ p_buf->len = 32;
+
+ l2c_lcc_proc_pdu(&ccb_, p_buf);
+}
+
+TEST_F(StackL2capChannelTest, l2c_lcc_proc_pdu__NextSegment) {
+ BT_HDR* p_buf = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + 32);
+ p_buf->len = 32;
+
+ l2c_lcc_proc_pdu(&ccb_, p_buf);
+}
diff --git a/system/test/mock/mock_bta_hearing_aid.cc b/system/test/mock/mock_bta_hearing_aid.cc
index eabcd09..200df2d 100644
--- a/system/test/mock/mock_bta_hearing_aid.cc
+++ b/system/test/mock/mock_bta_hearing_aid.cc
@@ -52,22 +52,39 @@
mock_function_count_map[__func__]++;
return 0;
}
+
void HearingAid::AddFromStorage(const HearingDevice& dev_info,
uint16_t is_acceptlisted) {
mock_function_count_map[__func__]++;
}
+
void HearingAid::DebugDump(int fd) { mock_function_count_map[__func__]++; }
-HearingAid* HearingAid::Get() {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
+
bool HearingAid::IsHearingAidRunning() {
mock_function_count_map[__func__]++;
return false;
}
+
void HearingAid::CleanUp() { mock_function_count_map[__func__]++; }
+
void HearingAid::Initialize(
bluetooth::hearing_aid::HearingAidCallbacks* callbacks,
base::Closure initCb) {
mock_function_count_map[__func__]++;
}
+
+void HearingAid::Connect(const RawAddress& address) {
+ mock_function_count_map[__func__]++;
+}
+
+void HearingAid::Disconnect(const RawAddress& address) {
+ mock_function_count_map[__func__]++;
+}
+
+void HearingAid::AddToAcceptlist(const RawAddress& address) {
+ mock_function_count_map[__func__]++;
+}
+
+void HearingAid::SetVolume(int8_t volume) {
+ mock_function_count_map[__func__]++;
+}
diff --git a/system/test/mock/mock_main_shim.cc b/system/test/mock/mock_main_shim.cc
index 69cd8df..1e997ce 100644
--- a/system/test/mock/mock_main_shim.cc
+++ b/system/test/mock/mock_main_shim.cc
@@ -25,6 +25,7 @@
extern std::map<std::string, int> mock_function_count_map;
#define LOG_TAG "bt_shim"
+
#include "gd/common/init_flags.h"
#include "main/shim/entry.h"
#include "main/shim/shim.h"
@@ -45,9 +46,14 @@
mock_function_count_map[__func__]++;
return false;
}
+namespace test {
+namespace mock {
+bool bluetooth_shim_is_gd_stack_started_up = false;
+}
+} // namespace test
bool bluetooth::shim::is_gd_stack_started_up() {
mock_function_count_map[__func__]++;
- return false;
+ return test::mock::bluetooth_shim_is_gd_stack_started_up;
}
bool bluetooth::shim::is_gd_link_policy_enabled() {
mock_function_count_map[__func__]++;
diff --git a/system/test/mock/mock_main_shim_metrics_api.cc b/system/test/mock/mock_main_shim_metrics_api.cc
index 30aeeb1..8330b85 100644
--- a/system/test/mock/mock_main_shim_metrics_api.cc
+++ b/system/test/mock/mock_main_shim_metrics_api.cc
@@ -128,8 +128,8 @@
raw_address, handle, cmd_status, transmit_power_level);
}
void bluetooth::shim::LogMetricSmpPairingEvent(
- const RawAddress& raw_address, uint8_t smp_cmd,
- android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {
+ const RawAddress& raw_address, uint16_t smp_cmd,
+ android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) {
mock_function_count_map[__func__]++;
test::mock::main_shim_metrics_api::LogMetricSmpPairingEvent(
raw_address, smp_cmd, direction, smp_fail_reason);
diff --git a/system/test/mock/mock_main_shim_metrics_api.h b/system/test/mock/mock_main_shim_metrics_api.h
index b42529f..d85088f 100644
--- a/system/test/mock/mock_main_shim_metrics_api.h
+++ b/system/test/mock/mock_main_shim_metrics_api.h
@@ -171,19 +171,19 @@
};
extern struct LogMetricReadTxPowerLevelResult LogMetricReadTxPowerLevelResult;
// Name: LogMetricSmpPairingEvent
-// Params: const RawAddress& raw_address, uint8_t smp_cmd,
+// Params: const RawAddress& raw_address, uint16_t smp_cmd,
// android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason Returns:
// void
struct LogMetricSmpPairingEvent {
- std::function<void(const RawAddress& raw_address, uint8_t smp_cmd,
+ std::function<void(const RawAddress& raw_address, uint16_t smp_cmd,
android::bluetooth::DirectionEnum direction,
- uint8_t smp_fail_reason)>
- body{[](const RawAddress& raw_address, uint8_t smp_cmd,
+ uint16_t smp_fail_reason)>
+ body{[](const RawAddress& raw_address, uint16_t smp_cmd,
android::bluetooth::DirectionEnum direction,
- uint8_t smp_fail_reason) {}};
- void operator()(const RawAddress& raw_address, uint8_t smp_cmd,
+ uint16_t smp_fail_reason) {}};
+ void operator()(const RawAddress& raw_address, uint16_t smp_cmd,
android::bluetooth::DirectionEnum direction,
- uint8_t smp_fail_reason) {
+ uint16_t smp_fail_reason) {
body(raw_address, smp_cmd, direction, smp_fail_reason);
};
};
diff --git a/system/test/mock/mock_stack_btm_dev.cc b/system/test/mock/mock_stack_btm_dev.cc
index bfd3081..cc959d3 100644
--- a/system/test/mock/mock_stack_btm_dev.cc
+++ b/system/test/mock/mock_stack_btm_dev.cc
@@ -118,3 +118,7 @@
void BTM_SecDumpDev(const RawAddress& bd_addr) {
mock_function_count_map[__func__]++;
}
+std::vector<tBTM_SEC_DEV_REC*> btm_get_sec_dev_rec() {
+ mock_function_count_map[__func__]++;
+ return {};
+}
diff --git a/system/test/mock/mock_stack_l2cap_api.cc b/system/test/mock/mock_stack_l2cap_api.cc
index 27cd1e3..7311b3b 100644
--- a/system/test/mock/mock_stack_l2cap_api.cc
+++ b/system/test/mock/mock_stack_l2cap_api.cc
@@ -99,6 +99,8 @@
struct L2CA_SetChnlFlushability L2CA_SetChnlFlushability;
struct L2CA_FlushChannel L2CA_FlushChannel;
struct L2CA_IsLinkEstablished L2CA_IsLinkEstablished;
+struct L2CA_LeCreditDefault L2CA_LeCreditDefault;
+struct L2CA_LeCreditThreshold L2CA_LeCreditThreshold;
} // namespace stack_l2cap_api
} // namespace mock
@@ -287,5 +289,13 @@
return test::mock::stack_l2cap_api::L2CA_IsLinkEstablished(bd_addr,
transport);
}
+uint16_t L2CA_LeCreditDefault() {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_LeCreditDefault();
+}
+uint16_t L2CA_LeCreditThreshold() {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_LeCreditThreshold();
+}
// END mockcify generation
diff --git a/system/test/mock/mock_stack_l2cap_api.h b/system/test/mock/mock_stack_l2cap_api.h
index 4488101..592485c 100644
--- a/system/test/mock/mock_stack_l2cap_api.h
+++ b/system/test/mock/mock_stack_l2cap_api.h
@@ -485,6 +485,22 @@
};
};
extern struct L2CA_IsLinkEstablished L2CA_IsLinkEstablished;
+// Name: L2CA_LeCreditDefault
+// Params:
+// Returns: uint16_t
+struct L2CA_LeCreditDefault {
+ std::function<uint16_t()> body{[]() { return 0; }};
+ uint16_t operator()() { return body(); };
+};
+extern struct L2CA_LeCreditDefault L2CA_LeCreditDefault;
+// Name: L2CA_LeCreditThreshold
+// Params:
+// Returns: uint16_t
+struct L2CA_LeCreditThreshold {
+ std::function<uint16_t()> body{[]() { return 0; }};
+ uint16_t operator()() { return body(); };
+};
+extern struct L2CA_LeCreditThreshold L2CA_LeCreditThreshold;
} // namespace stack_l2cap_api
} // namespace mock
diff --git a/system/test/mock/mock_stack_metrics_logging.cc b/system/test/mock/mock_stack_metrics_logging.cc
index 1f51191..028636d 100644
--- a/system/test/mock/mock_stack_metrics_logging.cc
+++ b/system/test/mock/mock_stack_metrics_logging.cc
@@ -86,9 +86,9 @@
address, connection_handle, direction, link_type, hci_cmd, hci_event,
hci_ble_event, cmd_status, reason_code);
}
-void log_smp_pairing_event(const RawAddress& address, uint8_t smp_cmd,
+void log_smp_pairing_event(const RawAddress& address, uint16_t smp_cmd,
android::bluetooth::DirectionEnum direction,
- uint8_t smp_fail_reason) {
+ uint16_t smp_fail_reason) {
mock_function_count_map[__func__]++;
test::mock::stack_metrics_logging::log_smp_pairing_event(
address, smp_cmd, direction, smp_fail_reason);
diff --git a/system/test/mock/mock_stack_metrics_logging.h b/system/test/mock/mock_stack_metrics_logging.h
index 967b2f8..8b695f4 100644
--- a/system/test/mock/mock_stack_metrics_logging.h
+++ b/system/test/mock/mock_stack_metrics_logging.h
@@ -96,19 +96,19 @@
};
extern struct log_link_layer_connection_event log_link_layer_connection_event;
// Name: log_smp_pairing_event
-// Params: const RawAddress& address, uint8_t smp_cmd,
+// Params: const RawAddress& address, uint16_t smp_cmd,
// android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason Returns:
// void
struct log_smp_pairing_event {
- std::function<void(const RawAddress& address, uint8_t smp_cmd,
+ std::function<void(const RawAddress& address, uint16_t smp_cmd,
android::bluetooth::DirectionEnum direction,
- uint8_t smp_fail_reason)>
- body{[](const RawAddress& address, uint8_t smp_cmd,
+ uint16_t smp_fail_reason)>
+ body{[](const RawAddress& address, uint16_t smp_cmd,
android::bluetooth::DirectionEnum direction,
- uint8_t smp_fail_reason) {}};
- void operator()(const RawAddress& address, uint8_t smp_cmd,
+ uint16_t smp_fail_reason) {}};
+ void operator()(const RawAddress& address, uint16_t smp_cmd,
android::bluetooth::DirectionEnum direction,
- uint8_t smp_fail_reason) {
+ uint16_t smp_fail_reason) {
body(address, smp_cmd, direction, smp_fail_reason);
};
};
diff --git a/system/types/ble_address_with_type.h b/system/types/ble_address_with_type.h
index 38a52cc..250072d 100644
--- a/system/types/ble_address_with_type.h
+++ b/system/types/ble_address_with_type.h
@@ -116,9 +116,19 @@
return (other & ~kBleAddressIdentityBit) ==
(type & ~kBleAddressIdentityBit);
}
+
std::string ToString() const {
return std::string(bda.ToString() + "[" + AddressTypeText(type) + "]");
}
+
+ std::string ToStringForLogging() const {
+ return bda.ToStringForLogging() + "[" + AddressTypeText(type) + "]";
+ }
+
+ std::string ToRedactedStringForLogging() const {
+ return bda.ToRedactedStringForLogging() + "[" + AddressTypeText(type) + "]";
+ }
+
bool operator==(const tBLE_BD_ADDR rhs) const {
return rhs.type == type && rhs.bda == bda;
}
diff --git a/system/types/raw_address.cc b/system/types/raw_address.cc
index afaf4ef..0cd9de0 100644
--- a/system/types/raw_address.cc
+++ b/system/types/raw_address.cc
@@ -38,12 +38,22 @@
std::copy(mac.begin(), mac.end(), address);
}
-std::string RawAddress::ToString() const {
+std::string RawAddress::ToString() const { return ToColonSepHexString(); }
+
+std::string RawAddress::ToColonSepHexString() const {
return base::StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x", address[0],
address[1], address[2], address[3], address[4],
address[5]);
}
+std::string RawAddress::ToStringForLogging() const {
+ return ToColonSepHexString();
+}
+
+std::string RawAddress::ToRedactedStringForLogging() const {
+ return base::StringPrintf("xx:xx:xx:xx:%02x:%02x", address[4], address[5]);
+}
+
std::array<uint8_t, RawAddress::kLength> RawAddress::ToArray() const {
std::array<uint8_t, kLength> mac;
std::copy(std::begin(address), std::end(address), std::begin(mac));
diff --git a/system/types/raw_address.h b/system/types/raw_address.h
index b3e7530..d623b9f 100644
--- a/system/types/raw_address.h
+++ b/system/types/raw_address.h
@@ -46,8 +46,22 @@
bool IsEmpty() const { return *this == kEmpty; }
+ // TODO (b/258090765): remove it and
+ // replace its usage with ToColonSepHexString
std::string ToString() const;
+ // Return a string representation in the form of
+ // hexadecimal string separated by colon (:), e.g.,
+ // "12:34:56:ab:cd:ef"
+ std::string ToColonSepHexString() const;
+ // same as ToColonSepHexString
+ std::string ToStringForLogging() const;
+
+ // Similar with ToColonHexString, ToRedactedStringForLogging returns a
+ // colon separated hexadecimal reprentation of the address but, with the
+ // leftmost 4 bytes masked with "xx", e.g., "xx:xx:xx:xx:ab:cd".
+ std::string ToRedactedStringForLogging() const;
+
// Converts |string| to RawAddress and places it in |to|. If |from| does
// not represent a Bluetooth address, |to| is not modified and this function
// returns false. Otherwise, it returns true.
diff --git a/system/types/test/raw_address_unittest.cc b/system/types/test/raw_address_unittest.cc
index 3a34295..513c8b7 100644
--- a/system/types/test/raw_address_unittest.cc
+++ b/system/types/test/raw_address_unittest.cc
@@ -198,3 +198,14 @@
std::array<uint8_t, 6> mac2 = bdaddr.ToArray();
ASSERT_EQ(mac, mac2);
}
+
+TEST(RawAddress, ToStringForLoggingTest) {
+ std::array<uint8_t, 6> addr_bytes = {0x11, 0x22, 0x33, 0x44, 0x55, 0xab};
+ RawAddress addr(addr_bytes);
+ const std::string redacted_loggable_str = "xx:xx:xx:xx:55:ab";
+ const std::string loggbable_str = "11:22:33:44:55:ab";
+ std::string ret1 = addr.ToStringForLogging();
+ ASSERT_STREQ(ret1.c_str(), loggbable_str.c_str());
+ std::string ret2 = addr.ToRedactedStringForLogging();
+ ASSERT_STREQ(ret2.c_str(), redacted_loggable_str.c_str());
+}