Merge "Import translations. DO NOT MERGE ANYWHERE" into tm-dev
diff --git a/android/app/jni/com_android_bluetooth_le_audio.cpp b/android/app/jni/com_android_bluetooth_le_audio.cpp
index 726385b..b97385f 100644
--- a/android/app/jni/com_android_bluetooth_le_audio.cpp
+++ b/android/app/jni/com_android_bluetooth_le_audio.cpp
@@ -39,6 +39,7 @@
using bluetooth::le_audio::LeAudioClientInterface;
namespace android {
+static jmethodID method_onInitialized;
static jmethodID method_onConnectionStateChanged;
static jmethodID method_onGroupStatus;
static jmethodID method_onGroupNodeStatus;
@@ -125,6 +126,14 @@
public:
~LeAudioClientCallbacksImpl() = default;
+ void OnInitialized(void) override {
+ LOG(INFO) << __func__;
+ std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
+ CallbackEnv sCallbackEnv(__func__);
+ if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInitialized);
+ }
+
void OnConnectionState(ConnectionState state,
const RawAddress& bd_addr) override {
LOG(INFO) << __func__ << ", state:" << int(state);
@@ -280,6 +289,7 @@
method_onAudioConf = env->GetMethodID(clazz, "onAudioConf", "(IIIII)V");
method_onSinkAudioLocationAvailable =
env->GetMethodID(clazz, "onSinkAudioLocationAvailable", "([BI)V");
+ method_onInitialized = env->GetMethodID(clazz, "onInitialized", "()V");
method_onConnectionStateChanged =
env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");
method_onAudioLocalCodecCapabilities =
@@ -512,6 +522,17 @@
group_id, input_codec_config, output_codec_config);
}
+static void setCcidInformationNative(JNIEnv* env, jobject object, jint ccid,
+ jint contextType) {
+ std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
+ if (!sLeAudioClientInterface) {
+ LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
+ return;
+ }
+
+ sLeAudioClientInterface->SetCcidInformation(ccid, contextType);
+}
+
static JNINativeMethod sMethods[] = {
{"classInitNative", "()V", (void*)classInitNative},
{"initNative", "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V",
@@ -526,6 +547,7 @@
"(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;Landroid/bluetooth/"
"BluetoothLeAudioCodecConfig;)V",
(void*)setCodecConfigPreferenceNative},
+ {"setCcidInformationNative", "(II)V", (void*)setCcidInformationNative},
};
/* Le Audio Broadcaster */
diff --git a/android/app/src/com/android/bluetooth/audio_util/MediaPlayerWrapper.java b/android/app/src/com/android/bluetooth/audio_util/MediaPlayerWrapper.java
index 9e5ed27..07855ae 100644
--- a/android/app/src/com/android/bluetooth/audio_util/MediaPlayerWrapper.java
+++ b/android/app/src/com/android/bluetooth/audio_util/MediaPlayerWrapper.java
@@ -252,6 +252,14 @@
Log.d(TAG, " └ Current queueItem: " + qitem);
Log.d(TAG, " └ Current metadata : " + mdata);
}
+
+ // Some player do not provide full song info in queue item, allow case
+ // that only title and artist match.
+ if (Objects.equals(qitem.title, mdata.title)
+ && Objects.equals(qitem.artist, mdata.artist)) {
+ Log.d(TAG, mPackageName + " Only Title and Artist info sync for metadata");
+ return true;
+ }
return false;
}
}
diff --git a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorStateMachine.java b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorStateMachine.java
index 7abd137..5945180 100644
--- a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorStateMachine.java
+++ b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorStateMachine.java
@@ -57,7 +57,6 @@
private Disconnecting mDisconnecting;
private Connected mConnected;
private int mLastConnectionState = -1;
- private int mNumReceivers = 0;
private CsipSetCoordinatorService mService;
private CsipSetCoordinatorNativeInterface mNativeInterface;
@@ -513,14 +512,6 @@
}
}
- public void setNumReceivers(int numReceivers) {
- mNumReceivers = numReceivers;
- }
-
- public int getNumReceivers() {
- return mNumReceivers;
- }
-
// This method does not check for error condition (newState == prevState)
private void csipConnectionState(int newState, int prevState) {
log("Connection state " + mDevice + ": " + profileStateToString(prevState) + "->"
diff --git a/android/app/src/com/android/bluetooth/le_audio/ContentControlIdKeeper.java b/android/app/src/com/android/bluetooth/le_audio/ContentControlIdKeeper.java
index 1673318..1d2770e 100644
--- a/android/app/src/com/android/bluetooth/le_audio/ContentControlIdKeeper.java
+++ b/android/app/src/com/android/bluetooth/le_audio/ContentControlIdKeeper.java
@@ -17,6 +17,15 @@
package com.android.bluetooth.le_audio;
+import android.bluetooth.BluetoothLeAudio;
+import android.os.ParcelUuid;
+import android.util.Pair;
+
+import com.android.bluetooth.btservice.ServiceFactory;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
@@ -30,8 +39,19 @@
public static final int CCID_MAX = 0xFF;
private static SortedSet<Integer> sAssignedCcidList = new TreeSet();
+ private static HashMap<ParcelUuid, Pair<Integer, Integer>> sUserMap = new HashMap();
+ private static ServiceFactory sServiceFactory = null;
- public static synchronized int acquireCcid() {
+ /**
+ * Functions is used to acquire Content Control ID (Ccid). Ccid is connected
+ * with a context type and the user uuid. In most of cases user uuid is the GATT service
+ * UUID which makes use of Ccid
+ *
+ * @param userUuid user identifier (GATT service)
+ * @param contextType the context types as defined in {@link BluetoothLeAudio}
+ * @return ccid to be used in the Gatt service Ccid characteristic.
+ */
+ public static synchronized int acquireCcid(ParcelUuid userUuid, int contextType) {
int ccid = CCID_INVALID;
if (sAssignedCcidList.size() == 0) {
@@ -51,11 +71,38 @@
}
}
- if (ccid != CCID_INVALID) sAssignedCcidList.add(ccid);
+ if (ccid != CCID_INVALID) {
+ sAssignedCcidList.add(ccid);
+ sUserMap.put(userUuid, new Pair(ccid, contextType));
+
+ if (sServiceFactory == null) {
+ sServiceFactory = new ServiceFactory();
+ }
+ /* Notify LeAudioService about new ccid */
+ LeAudioService service = sServiceFactory.getLeAudioService();
+ if (service != null) {
+ service.setCcidInformation(userUuid, ccid, contextType);
+ }
+ }
return ccid;
}
+ /**
+ * Release the acquired Ccid
+ *
+ * @param value Ccid value to release
+ */
public static synchronized void releaseCcid(int value) {
sAssignedCcidList.remove(value);
+ sUserMap.entrySet().removeIf(entry -> entry.getValue().first.equals(value));
+ }
+
+ /**
+ * Get Ccid information.
+ *
+ * @return Map of acquired ccids along with the user information.
+ */
+ public static synchronized Map<ParcelUuid, Pair<Integer, Integer>> getUserCcidMap() {
+ return Collections.unmodifiableMap(sUserMap);
}
}
diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioNativeInterface.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioNativeInterface.java
index a32b6c4..d696dc8 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioNativeInterface.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioNativeInterface.java
@@ -90,6 +90,16 @@
// Callbacks from the native stack back into the Java framework.
// All callbacks are routed via the Service which will disambiguate which
// state machine the message should be routed to.
+ private void onInitialized() {
+ LeAudioStackEvent event =
+ new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_NATIVE_INITIALIZED);
+
+ if (DBG) {
+ Log.d(TAG, "onInitialized: " + event);
+ }
+ sendMessageToService(event);
+ }
+
private void onConnectionStateChanged(int state, byte[] address) {
LeAudioStackEvent event =
new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
@@ -265,6 +275,18 @@
setCodecConfigPreferenceNative(groupId, inputCodecConfig, outputCodecConfig);
}
+ /**
+ * Set content control id (Ccid) along with context type.
+ * @param ccid content control id
+ * @param contextType assigned contextType
+ */
+ public void setCcidInformation(int ccid, int contextType) {
+ if (DBG) {
+ Log.d(TAG, "setCcidInformation ccid: " + ccid + " context type: " + contextType);
+ }
+ setCcidInformationNative(ccid, contextType);
+ }
+
// Native methods that call into the JNI interface
private static native void classInitNative();
private native void initNative(BluetoothLeAudioCodecConfig[] codecConfigOffloading);
@@ -277,4 +299,5 @@
private native void setCodecConfigPreferenceNative(int groupId,
BluetoothLeAudioCodecConfig inputCodecConfig,
BluetoothLeAudioCodecConfig outputCodecConfig);
+ private native void setCcidInformationNative(int ccid, int contextType);
}
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 edb3f17..42c4c5a 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
@@ -52,6 +52,7 @@
import android.os.RemoteException;
import android.sysprop.BluetoothProperties;
import android.util.Log;
+import android.util.Pair;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
@@ -59,6 +60,7 @@
import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.mcp.McpService;
+import com.android.bluetooth.tbs.TbsGatt;
import com.android.bluetooth.vc.VolumeControlService;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -119,6 +121,7 @@
ServiceFactory mServiceFactory = new ServiceFactory();
LeAudioNativeInterface mLeAudioNativeInterface;
+ boolean mLeAudioNativeIsInitialized = false;
LeAudioBroadcasterNativeInterface mLeAudioBroadcasterNativeInterface = null;
@VisibleForTesting
AudioManager mAudioManager;
@@ -328,6 +331,7 @@
// Cleanup native interfaces
mLeAudioNativeInterface.cleanup();
mLeAudioNativeInterface = null;
+ mLeAudioNativeIsInitialized = false;
// Set the service and BLE devices as inactive
setLeAudioService(null);
@@ -553,6 +557,10 @@
* @return true on success, otherwise false
*/
boolean groupAddNode(int groupId, BluetoothDevice device) {
+ if (!mLeAudioNativeIsInitialized) {
+ Log.e(TAG, "Le Audio not initialized properly.");
+ return false;
+ }
return mLeAudioNativeInterface.groupAddNode(groupId, device);
}
@@ -563,6 +571,10 @@
* @return true on success, otherwise false
*/
boolean groupRemoveNode(int groupId, BluetoothDevice device) {
+ if (!mLeAudioNativeIsInitialized) {
+ Log.e(TAG, "Le Audio not initialized properly.");
+ return false;
+ }
return mLeAudioNativeInterface.groupRemoveNode(groupId, device);
}
@@ -952,6 +964,10 @@
return;
}
+ if (!mLeAudioNativeIsInitialized) {
+ Log.e(TAG, "Le Audio not initialized properly.");
+ return;
+ }
mLeAudioNativeInterface.groupSetActive(groupId);
}
@@ -1346,6 +1362,14 @@
mBroadcastMetadataList.put(broadcastId, stackEvent.broadcastMetadata);
notifyBroadcastMetadataChanged(broadcastId, stackEvent.broadcastMetadata);
}
+ } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_NATIVE_INITIALIZED) {
+ mLeAudioNativeIsInitialized = true;
+ for (Map.Entry<ParcelUuid, Pair<Integer, Integer>> entry :
+ ContentControlIdKeeper.getUserCcidMap().entrySet()) {
+ ParcelUuid userUuid = entry.getKey();
+ Pair<Integer, Integer> ccidInformation = entry.getValue();
+ setCcidInformation(userUuid, ccidInformation.first, ccidInformation.second);
+ }
}
if (intent != null) {
@@ -1695,6 +1719,25 @@
}
/**
+ * Set the user application ccid along with used context type
+ * @param userUuid user uuid
+ * @param ccid content control id
+ * @param contextType context type
+ */
+ public void setCcidInformation(ParcelUuid userUuid, int ccid, int contextType) {
+ /* for the moment we care only for GMCS and GTBS */
+ if (userUuid != BluetoothUuid.GENERIC_MEDIA_CONTROL
+ && userUuid.getUuid() != TbsGatt.UUID_GTBS) {
+ return;
+ }
+ if (!mLeAudioNativeIsInitialized) {
+ Log.e(TAG, "Le Audio not initialized properly.");
+ return;
+ }
+ mLeAudioNativeInterface.setCcidInformation(ccid, contextType);
+ }
+
+ /**
* Set volume for streaming devices
* @param volume volume to set
*/
@@ -1987,6 +2030,11 @@
return;
}
+ if (!mLeAudioNativeIsInitialized) {
+ Log.e(TAG, "Le Audio not initialized properly.");
+ return;
+ }
+
mLeAudioNativeInterface.setCodecConfigPreference(groupId,
inputCodecConfig, outputCodecConfig);
}
@@ -2225,6 +2273,27 @@
}
@Override
+ public void setCcidInformation(ParcelUuid userUuid, int ccid, int contextType,
+ AttributionSource source,
+ SynchronousResultReceiver receiver) {
+ try {
+ Objects.requireNonNull(userUuid, "userUuid cannot be null");
+ Objects.requireNonNull(source, "source cannot be null");
+ Objects.requireNonNull(receiver, "receiver cannot be null");
+
+ LeAudioService service = getService(source);
+ if (service == null) {
+ throw new IllegalStateException("service is null");
+ }
+ enforceBluetoothPrivilegedPermission(service);
+ service.setCcidInformation(userUuid, ccid, contextType);
+ receiver.send(null);
+ } catch (RuntimeException e) {
+ receiver.propagateException(e);
+ }
+ }
+
+ @Override
public void getGroupId(BluetoothDevice device, AttributionSource source,
SynchronousResultReceiver receiver) {
try {
diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioStackEvent.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioStackEvent.java
index edfc9e9..6ec7483 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioStackEvent.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioStackEvent.java
@@ -36,8 +36,9 @@
public static final int EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE = 5;
public static final int EVENT_TYPE_AUDIO_LOCAL_CODEC_CONFIG_CAPA_CHANGED = 6;
public static final int EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED = 7;
+ public static final int EVENT_TYPE_NATIVE_INITIALIZED = 8;
// -------- DO NOT PUT ANY NEW UNICAST EVENTS BELOW THIS LINE-------------
- public static final int EVENT_TYPE_UNICAST_MAX = 8;
+ public static final int EVENT_TYPE_UNICAST_MAX = 9;
// Broadcast related events
public static final int EVENT_TYPE_BROADCAST_CREATED = EVENT_TYPE_UNICAST_MAX + 1;
@@ -136,6 +137,8 @@
return "EVENT_TYPE_AUDIO_LOCAL_CODEC_CONFIG_CAPA_CHANGED";
case EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED:
return "EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED";
+ case EVENT_TYPE_NATIVE_INITIALIZED:
+ return "EVENT_TYPE_NATIVE_INITIALIZED";
default:
return "EVENT_TYPE_UNKNOWN:" + type;
}
diff --git a/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java b/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java
index f3e5fc0..827b949 100644
--- a/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java
+++ b/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -675,7 +676,8 @@
}
// Instantiate a Service Instance and it's state machine
- int ccid = ContentControlIdKeeper.acquireCcid();
+ int ccid = ContentControlIdKeeper.acquireCcid(BluetoothUuid.GENERIC_MEDIA_CONTROL,
+ BluetoothLeAudio.CONTEXT_TYPE_MEDIA);
if (ccid == ContentControlIdKeeper.CCID_INVALID) {
Log.e(TAG, "Unable to acquire valid CCID!");
return;
diff --git a/android/app/src/com/android/bluetooth/tbs/TbsGatt.java b/android/app/src/com/android/bluetooth/tbs/TbsGatt.java
index 5ad083e..7c3f9fc 100644
--- a/android/app/src/com/android/bluetooth/tbs/TbsGatt.java
+++ b/android/app/src/com/android/bluetooth/tbs/TbsGatt.java
@@ -23,17 +23,14 @@
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
-import android.bluetooth.BluetoothLeCall;
+import android.content.Context;
import android.os.Handler;
import android.os.Looper;
-import android.content.Context;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import java.io.ByteArrayOutputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -52,7 +49,7 @@
@VisibleForTesting
static final UUID UUID_TBS = makeUuid("184B");
@VisibleForTesting
- static final UUID UUID_GTBS = makeUuid("184C");
+ public static final UUID UUID_GTBS = makeUuid("184C");
@VisibleForTesting
static final UUID UUID_BEARER_PROVIDER_NAME = makeUuid("2BB3");
@VisibleForTesting
diff --git a/android/app/src/com/android/bluetooth/tbs/TbsGeneric.java b/android/app/src/com/android/bluetooth/tbs/TbsGeneric.java
index 2a281ab..b8dbbff 100644
--- a/android/app/src/com/android/bluetooth/tbs/TbsGeneric.java
+++ b/android/app/src/com/android/bluetooth/tbs/TbsGeneric.java
@@ -18,6 +18,7 @@
package com.android.bluetooth.tbs;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothLeCall;
import android.bluetooth.BluetoothLeCallControl;
import android.bluetooth.IBluetoothLeCallControlCallback;
@@ -151,7 +152,8 @@
}
mTbsGatt = tbsGatt;
- int ccid = ContentControlIdKeeper.acquireCcid();
+ int ccid = ContentControlIdKeeper.acquireCcid(new ParcelUuid(TbsGatt.UUID_GTBS),
+ BluetoothLeAudio.CONTEXT_TYPE_COMMUNICATION);
if (!isCcidValid(ccid)) {
Log.e(TAG, " CCID is not valid");
cleanup();
@@ -273,7 +275,8 @@
// Acquire CCID for TbsObject. The CCID is released on remove()
Bearer bearer = new Bearer(token, callback, uci, uriSchemes, capabilities, providerName,
- technology, ContentControlIdKeeper.acquireCcid());
+ technology, ContentControlIdKeeper.acquireCcid(new ParcelUuid(UUID.randomUUID()),
+ BluetoothLeAudio.CONTEXT_TYPE_COMMUNICATION));
if (isCcidValid(bearer.ccid)) {
mBearerList.add(bearer);
diff --git a/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java b/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java
index dd6431c..2313ff0 100644
--- a/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java
+++ b/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java
@@ -103,6 +103,7 @@
private BluetoothCall mOldHeldCall = null;
private boolean mHeadsetUpdatedRecently = false;
private boolean mIsDisconnectedTonePlaying = false;
+ private boolean mIsTerminatedByClient = false;
private static final Object LOCK = new Object();
private BluetoothHeadsetProxy mBluetoothHeadset;
@@ -1287,6 +1288,10 @@
case DisconnectCause.REJECTED:
return BluetoothLeCallControl.TERMINATION_REASON_REMOTE_HANGUP;
case DisconnectCause.LOCAL:
+ if (mIsTerminatedByClient) {
+ mIsTerminatedByClient = false;
+ return BluetoothLeCallControl.TERMINATION_REASON_CLIENT_HANGUP;
+ }
return BluetoothLeCallControl.TERMINATION_REASON_SERVER_HANGUP;
case DisconnectCause.ERROR:
return BluetoothLeCallControl.TERMINATION_REASON_NETWORK_CONGESTION;
@@ -1413,6 +1418,7 @@
if (mCallInfo.isNullCall(call)) {
result = BluetoothLeCallControl.RESULT_ERROR_UNKNOWN_CALL_ID;
} else {
+ mIsTerminatedByClient = true;
call.disconnect();
}
mBluetoothLeCallControl.requestResult(requestId, result);
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 a72010a..8a8901e 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
@@ -174,6 +174,11 @@
mService.mLeAudioNativeInterface = mNativeInterface;
mService.mAudioManager = mAudioManager;
+ LeAudioStackEvent stackEvent =
+ new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_NATIVE_INITIALIZED);
+ mService.messageFromNative(stackEvent);
+ assertThat(mService.mLeAudioNativeIsInitialized).isTrue();
+
// Override the timeout value to speed up the test
LeAudioStateMachine.sConnectTimeoutMs = TIMEOUT_MS; // 1s
diff --git a/system/audio_a2dp_hw/Android.bp b/system/audio_a2dp_hw/Android.bp
index 55587a9..7d77480 100644
--- a/system/audio_a2dp_hw/Android.bp
+++ b/system/audio_a2dp_hw/Android.bp
@@ -52,7 +52,10 @@
cc_test {
name: "net_test_audio_a2dp_hw",
test_suites: ["device-tests"],
- defaults: ["audio_a2dp_hw_defaults"],
+ defaults: [
+ "audio_a2dp_hw_defaults",
+ "mts_defaults",
+ ],
srcs: [
"test/audio_a2dp_hw_test.cc",
],
diff --git a/system/audio_hearing_aid_hw/Android.bp b/system/audio_hearing_aid_hw/Android.bp
index 7ca723e..cb5f110 100644
--- a/system/audio_hearing_aid_hw/Android.bp
+++ b/system/audio_hearing_aid_hw/Android.bp
@@ -40,7 +40,10 @@
cc_test {
name: "net_test_audio_hearing_aid_hw",
test_suites: ["device-tests"],
- defaults: ["audio_hearing_aid_hw_defaults"],
+ defaults: [
+ "audio_hearing_aid_hw_defaults",
+ "mts_defaults",
+ ],
srcs: [
"test/audio_hearing_aid_hw_test.cc",
],
diff --git a/system/binder/android/bluetooth/IBluetoothLeAudio.aidl b/system/binder/android/bluetooth/IBluetoothLeAudio.aidl
index 7a3a05a..4e6e345 100644
--- a/system/binder/android/bluetooth/IBluetoothLeAudio.aidl
+++ b/system/binder/android/bluetooth/IBluetoothLeAudio.aidl
@@ -26,6 +26,8 @@
import com.android.modules.utils.SynchronousResultReceiver;
+import android.os.ParcelUuid;
+
/**
* APIs for Bluetooth LE Audio service
*
@@ -61,6 +63,8 @@
void registerCallback(in IBluetoothLeAudioCallback callback, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
void unregisterCallback(in IBluetoothLeAudioCallback callback, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
+ void setCcidInformation(in ParcelUuid userUuid, in int ccid, in int contextType, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
/* Same value as bluetooth::groups::kGroupUnknown */
const int LE_AUDIO_GROUP_ID_INVALID = -1;
diff --git a/system/blueberry/facade/hci/le_acl_manager_facade.proto b/system/blueberry/facade/hci/le_acl_manager_facade.proto
index 8eac08a..844f21a 100644
--- a/system/blueberry/facade/hci/le_acl_manager_facade.proto
+++ b/system/blueberry/facade/hci/le_acl_manager_facade.proto
@@ -6,15 +6,14 @@
import "blueberry/facade/common.proto";
service LeAclManagerFacade {
- rpc CreateConnection(blueberry.facade.BluetoothAddressWithType) returns (stream LeConnectionEvent) {}
- rpc CreateBackgroundAndDirectConnection(blueberry.facade.BluetoothAddressWithType)
- returns (stream LeConnectionEvent) {}
+ rpc CreateConnection(CreateConnectionMsg) returns (stream LeConnectionEvent) {}
rpc CancelConnection(blueberry.facade.BluetoothAddressWithType) returns (google.protobuf.Empty) {}
rpc Disconnect(LeHandleMsg) returns (google.protobuf.Empty) {}
rpc ConnectionCommand(LeConnectionCommandMsg) returns (google.protobuf.Empty) {}
rpc SendAclData(LeAclData) returns (google.protobuf.Empty) {}
rpc FetchAclData(LeHandleMsg) returns (stream LeAclData) {}
rpc FetchIncomingConnection(google.protobuf.Empty) returns (stream LeConnectionEvent) {}
+ rpc AddDeviceToResolvingList(IrkMsg) returns (google.protobuf.Empty) {}
}
message LeHandleMsg {
@@ -34,3 +33,14 @@
bytes payload = 2;
}
+message CreateConnectionMsg {
+ blueberry.facade.BluetoothAddressWithType peer_address = 1;
+ bool is_direct = 2;
+}
+
+message IrkMsg {
+ blueberry.facade.BluetoothAddressWithType peer = 1;
+ bytes peer_irk = 2;
+ bytes local_irk = 3;
+}
+
diff --git a/system/blueberry/tests/gd/cert/py_hci.py b/system/blueberry/tests/gd/cert/py_hci.py
index 682c528..f87ecff 100644
--- a/system/blueberry/tests/gd/cert/py_hci.py
+++ b/system/blueberry/tests/gd/cert/py_hci.py
@@ -13,6 +13,7 @@
# 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.
+from datetime import timedelta
from google.protobuf import empty_pb2 as empty_proto
from blueberry.tests.gd.cert.event_stream import EventStream
@@ -70,6 +71,43 @@
return self.our_acl_stream.get_event_queue()
+class PyHciLeAclConnection(IEventStream):
+
+ def __init__(self, handle, acl_stream, device, peer, peer_type, peer_resolvable, local_resolvable):
+ self.handle = int(handle)
+ self.device = device
+ self.peer = peer
+ self.peer_type = peer_type
+ self.peer_resolvable = peer_resolvable
+ self.local_resolvable = local_resolvable
+ # todo, handle we got is 0, so doesn't match - fix before enabling filtering
+ self.our_acl_stream = FilteringEventStream(acl_stream, None)
+
+ def send(self, pb_flag, b_flag, data):
+ acl = AclBuilder(self.handle, pb_flag, b_flag, RawBuilder(data))
+ self.device.hci.SendAcl(common.Data(payload=bytes(acl.Serialize())))
+
+ def send_first(self, data):
+ self.send(hci_packets.PacketBoundaryFlag.FIRST_AUTOMATICALLY_FLUSHABLE,
+ hci_packets.BroadcastFlag.POINT_TO_POINT, bytes(data))
+
+ def send_continuing(self, data):
+ self.send(hci_packets.PacketBoundaryFlag.CONTINUING_FRAGMENT, hci_packets.BroadcastFlag.POINT_TO_POINT,
+ bytes(data))
+
+ def get_event_queue(self):
+ return self.our_acl_stream.get_event_queue()
+
+ def local_resolvable_address(self):
+ return self.local_resolvable
+
+ def peer_resolvable_address(self):
+ return self.peer_resolvable
+
+ def peer_address(self):
+ return self.peer
+
+
class PyHciAdvertisement(object):
def __init__(self, handle, py_hci):
@@ -79,7 +117,7 @@
def set_data(self, complete_name):
data = GapData()
data.data_type = GapDataType.COMPLETE_LOCAL_NAME
- data.data = list(bytes(complete_name))
+ data.data = list(complete_name)
self.py_hci.send_command(
LeSetExtendedAdvertisingDataBuilder(self.handle, Operation.COMPLETE_ADVERTISEMENT,
FragmentPreference.CONTROLLER_SHOULD_NOT, [data]))
@@ -87,7 +125,7 @@
def set_scan_response(self, shortened_name):
data = GapData()
data.data_type = GapDataType.SHORTENED_LOCAL_NAME
- data.data = list(bytes(shortened_name))
+ data.data = list(shortened_name)
self.py_hci.send_command(
LeSetExtendedAdvertisingScanResponseBuilder(self.handle, Operation.COMPLETE_ADVERTISEMENT,
FragmentPreference.CONTROLLER_SHOULD_NOT, [data]))
@@ -121,6 +159,7 @@
self.register_for_events(hci_packets.EventCode.ROLE_CHANGE, hci_packets.EventCode.CONNECTION_REQUEST,
hci_packets.EventCode.CONNECTION_COMPLETE,
hci_packets.EventCode.CONNECTION_PACKET_TYPE_CHANGED)
+ self.register_for_le_events(hci_packets.SubeventCode.ENHANCED_CONNECTION_COMPLETE)
self.acl_stream = EventStream(self.device.hci.StreamAcl(empty_proto.Empty()))
def close(self):
@@ -187,6 +226,48 @@
raise Exception("Please construct '%s' with acl_streaming=True!" % self.__class__.__name__)
return PyHciAclConnection(handle, self.acl_stream, self.device)
+ def set_random_le_address(self, addr):
+ self.send_command(hci_packets.LeSetRandomAddressBuilder(addr))
+ assertThat(self.event_stream).emits(HciMatchers.CommandComplete(OpCode.LE_SET_RANDOM_ADDRESS))
+
+ def initiate_le_connection(self, remote_addr):
+ phy_scan_params = hci_packets.LeCreateConnPhyScanParameters()
+ phy_scan_params.scan_interval = 0x60
+ phy_scan_params.scan_window = 0x30
+ phy_scan_params.conn_interval_min = 0x18
+ phy_scan_params.conn_interval_max = 0x28
+ phy_scan_params.conn_latency = 0
+ phy_scan_params.supervision_timeout = 0x1f4
+ phy_scan_params.min_ce_length = 0
+ phy_scan_params.max_ce_length = 0
+ self.send_command(
+ hci_packets.LeExtendedCreateConnectionBuilder(
+ hci_packets.InitiatorFilterPolicy.USE_PEER_ADDRESS, hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
+ hci_packets.AddressType.RANDOM_DEVICE_ADDRESS, remote_addr, 1, [phy_scan_params]))
+ assertThat(self.event_stream).emits(HciMatchers.CommandStatus(OpCode.LE_EXTENDED_CREATE_CONNECTION))
+
+ def incoming_le_connection(self):
+ connection_complete = HciCaptures.LeConnectionCompleteCapture()
+ assertThat(self.le_event_stream).emits(connection_complete)
+
+ handle = connection_complete.get().GetConnectionHandle()
+ peer = connection_complete.get().GetPeerAddress()
+ peer_type = connection_complete.get().GetPeerAddressType()
+ local_resolvable = connection_complete.get().GetLocalResolvablePrivateAddress()
+ peer_resolvable = connection_complete.get().GetPeerResolvablePrivateAddress()
+ if self.acl_stream is None:
+ raise Exception("Please construct '%s' with acl_streaming=True!" % self.__class__.__name__)
+ return PyHciLeAclConnection(handle, self.acl_stream, self.device, peer, peer_type, peer_resolvable,
+ local_resolvable)
+
+ def incoming_le_connection_fails(self):
+ connection_complete = HciCaptures.LeConnectionCompleteCapture()
+ assertThat(self.le_event_stream).emitsNone(connection_complete, timeout=timedelta(seconds=5))
+
+ def add_device_to_resolving_list(self, peer_address_type, peer_address, peer_irk, local_irk):
+ self.send_command(
+ hci_packets.LeAddDeviceToResolvingListBuilder(peer_address_type, peer_address, peer_irk, local_irk))
+
def create_advertisement(self,
handle,
own_address,
diff --git a/system/blueberry/tests/gd/cert/py_le_acl_manager.py b/system/blueberry/tests/gd/cert/py_le_acl_manager.py
index 914ec84..1cb0cbe 100644
--- a/system/blueberry/tests/gd/cert/py_le_acl_manager.py
+++ b/system/blueberry/tests/gd/cert/py_le_acl_manager.py
@@ -29,12 +29,13 @@
class PyLeAclManagerAclConnection(IEventStream, Closable):
- def __init__(self, le_acl_manager, address, remote_addr, handle, event_stream):
+ def __init__(self, le_acl_manager, address, remote_addr, remote_addr_type, handle, event_stream):
"""
An abstract representation for an LE ACL connection in GD certification test
:param le_acl_manager: The LeAclManager from this GD device
:param address: The local device address
:param remote_addr: Remote device address
+ :param remote_addr_type: Remote device address type
:param handle: Connection handle
:param event_stream: The connection event stream for this connection
"""
@@ -46,6 +47,7 @@
self.acl_stream = EventStream(
self.le_acl_manager.FetchAclData(le_acl_manager_facade.LeHandleMsg(handle=self.handle)))
self.remote_address = remote_addr
+ self.remote_address_type = remote_addr_type
self.own_address = address
self.disconnect_reason = None
@@ -113,18 +115,11 @@
safeClose(pair[0])
self.le_acl_manager.CancelConnection(pair[1])
- def initiate_connection(self, remote_addr):
+ def initiate_connection(self, remote_addr, is_direct=True):
assertThat(self.next_token in self.outgoing_connection_event_streams).isFalse()
+ create_connection_msg = le_acl_manager_facade.CreateConnectionMsg(peer_address=remote_addr, is_direct=is_direct)
self.outgoing_connection_event_streams[self.next_token] = EventStream(
- self.le_acl_manager.CreateConnection(remote_addr)), remote_addr
- token = self.next_token
- self.next_token += 1
- return token
-
- def initiate_background_and_direct_connection(self, remote_addr):
- assertThat(self.next_token in self.outgoing_connection_event_streams).isFalse()
- self.outgoing_connection_event_streams[self.next_token] = EventStream(
- self.le_acl_manager.CreateBackgroundAndDirectConnection(remote_addr)), remote_addr
+ self.le_acl_manager.CreateConnection(create_connection_msg)), remote_addr
token = self.next_token
self.next_token += 1
return token
@@ -135,11 +130,13 @@
complete = connection_complete.get()
handle = complete.GetConnectionHandle()
remote = complete.GetPeerAddress()
+ remote_address_type = complete.GetPeerAddressType()
if complete.GetSubeventCode() == hci_packets.SubeventCode.ENHANCED_CONNECTION_COMPLETE:
address = complete.GetLocalResolvablePrivateAddress()
else:
address = None
- connection = PyLeAclManagerAclConnection(self.le_acl_manager, address, remote, handle, event_stream)
+ connection = PyLeAclManagerAclConnection(self.le_acl_manager, address, remote, remote_address_type, handle,
+ event_stream)
self.active_connections.append(connection)
return connection
diff --git a/system/blueberry/tests/gd/hci/direct_hci_test.py b/system/blueberry/tests/gd/hci/direct_hci_test.py
index 23f1b93..c0dbdc4 100644
--- a/system/blueberry/tests/gd/hci/direct_hci_test.py
+++ b/system/blueberry/tests/gd/hci/direct_hci_test.py
@@ -205,7 +205,6 @@
def test_le_connection_dut_advertises(self):
self.dut_hci.register_for_le_events(SubeventCode.CONNECTION_COMPLETE, SubeventCode.ADVERTISING_SET_TERMINATED,
- SubeventCode.ENHANCED_CONNECTION_COMPLETE,
SubeventCode.READ_REMOTE_FEATURES_COMPLETE)
# Cert Connects
self.cert_hal.unmask_event(EventCode.LE_META_EVENT)
@@ -239,7 +238,6 @@
lambda packet: logging.debug(packet.payload) or b'SomeMoreAclData' in packet.payload)
def test_le_filter_accept_list_connection_cert_advertises(self):
- self.dut_hci.register_for_le_events(SubeventCode.CONNECTION_COMPLETE, SubeventCode.ENHANCED_CONNECTION_COMPLETE)
# DUT Connects
self.dut_hci.send_command(LeSetRandomAddressBuilder('0D:05:04:03:02:01'))
self.dut_hci.send_command(
diff --git a/system/blueberry/tests/gd/hci/le_acl_manager_test.py b/system/blueberry/tests/gd/hci/le_acl_manager_test.py
index 34ef228..5bdf758 100644
--- a/system/blueberry/tests/gd/hci/le_acl_manager_test.py
+++ b/system/blueberry/tests/gd/hci/le_acl_manager_test.py
@@ -16,16 +16,14 @@
from blueberry.tests.gd.cert import gd_base_test
from blueberry.tests.gd.cert.closable import safeClose
-from blueberry.tests.gd.cert.event_stream import EventStream
from blueberry.tests.gd.cert.truth import assertThat
+from blueberry.tests.gd.cert.py_hci import PyHci, PyHciAdvertisement
from blueberry.tests.gd.cert.py_le_acl_manager import PyLeAclManager
-from google.protobuf import empty_pb2 as empty_proto
from blueberry.facade import common_pb2 as common
from blueberry.facade.hci import le_acl_manager_facade_pb2 as le_acl_manager_facade
from blueberry.facade.hci import le_advertising_manager_facade_pb2 as le_advertising_facade
from blueberry.facade.hci import le_initiator_address_facade_pb2 as le_initiator_address_facade
from blueberry.facade.hci import hci_facade_pb2 as hci_facade
-import bluetooth_packets_python3 as bt_packets
from bluetooth_packets_python3 import hci_packets
from bluetooth_packets_python3 import RawBuilder
from mobly import test_runner
@@ -38,22 +36,24 @@
def setup_test(self):
gd_base_test.GdBaseTestClass.setup_test(self)
+ self.cert_hci = PyHci(self.cert, acl_streaming=True)
self.dut_le_acl_manager = PyLeAclManager(self.dut)
- self.cert_hci_le_event_stream = EventStream(self.cert.hci.StreamLeSubevents(empty_proto.Empty()))
- self.cert_acl_data_stream = EventStream(self.cert.hci.StreamAcl(empty_proto.Empty()))
+ self.cert_public_address = self.cert_hci.read_own_address()
+ self.dut_public_address = self.dut.hci_controller.GetMacAddressSimple().decode("utf-8")
+ self.dut_random_address = 'd0:05:04:03:02:01'
+ self.cert_random_address = 'c0:05:04:03:02:01'
def teardown_test(self):
- safeClose(self.cert_hci_le_event_stream)
- safeClose(self.cert_acl_data_stream)
safeClose(self.dut_le_acl_manager)
+ self.cert_hci.close()
gd_base_test.GdBaseTestClass.teardown_test(self)
def set_privacy_policy_static(self):
- self.dut_address = b'd0:05:04:03:02:01'
private_policy = le_initiator_address_facade.PrivacyPolicy(
address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
address_with_type=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(self.dut_address)), type=common.RANDOM_DEVICE_ADDRESS))
+ address=common.BluetoothAddress(address=bytes(self.dut_random_address, "utf-8")),
+ type=common.RANDOM_DEVICE_ADDRESS))
self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(private_policy)
def register_for_event(self, event_code):
@@ -73,104 +73,91 @@
acl = hci_packets.AclBuilder(handle, pb_flag, b_flag, RawBuilder(data))
self.cert.hci.SendAcl(common.Data(payload=bytes(acl.Serialize())))
- def dut_connects(self, check_address):
- self.register_for_le_event(hci_packets.SubeventCode.CONNECTION_COMPLETE)
- self.register_for_le_event(hci_packets.SubeventCode.ENHANCED_CONNECTION_COMPLETE)
+ def dut_connects(self):
+ # Cert Advertises
+ advertising_handle = 0
+ py_hci_adv = PyHciAdvertisement(advertising_handle, self.cert_hci)
+
+ self.cert_hci.create_advertisement(
+ advertising_handle,
+ self.cert_random_address,
+ hci_packets.LegacyAdvertisingProperties.ADV_IND,
+ )
+
+ py_hci_adv.set_data(b'Im_A_Cert')
+ py_hci_adv.set_scan_response(b'Im_A_C')
+ py_hci_adv.start()
+
+ dut_le_acl = self.dut_le_acl_manager.connect_to_remote(
+ remote_addr=common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(self.cert_random_address, 'utf8')),
+ type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)))
+
+ cert_le_acl = self.cert_hci.incoming_le_connection()
+ return dut_le_acl, cert_le_acl
+
+ def cert_advertises_resolvable(self):
+ self.cert_hci.add_device_to_resolving_list(hci_packets.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
+ self.dut_public_address,
+ b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f',
+ b'\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f')
# Cert Advertises
advertising_handle = 0
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingLegacyParametersBuilder(
- advertising_handle,
- hci_packets.LegacyAdvertisingProperties.ADV_IND,
- 400,
- 450,
- 7,
- hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- hci_packets.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
- '00:00:00:00:00:00',
- hci_packets.AdvertisingFilterPolicy.ALL_DEVICES,
- 0xF8,
- 1, #SID
- hci_packets.Enable.DISABLED # Scan request notification
+ py_hci_adv = PyHciAdvertisement(advertising_handle, self.cert_hci)
+
+ self.cert_hci.create_advertisement(
+ advertising_handle,
+ self.cert_random_address,
+ hci_packets.LegacyAdvertisingProperties.ADV_IND,
+ own_address_type=hci_packets.OwnAddressType.RESOLVABLE_OR_PUBLIC_ADDRESS,
+ peer_address=self.dut_public_address,
+ peer_address_type=hci_packets.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS)
+
+ py_hci_adv.set_data(b'Im_A_Cert')
+ py_hci_adv.set_scan_response(b'Im_A_C')
+ py_hci_adv.start()
+
+ def dut_connects_cert_resolvable(self):
+ self.dut.hci_le_acl_manager.AddDeviceToResolvingList(
+ le_acl_manager_facade.IrkMsg(
+ peer=common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(self.cert_public_address, "utf-8")),
+ type=int(hci_packets.AddressType.PUBLIC_DEVICE_ADDRESS)),
+ peer_irk=b'\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f',
+ local_irk=b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f',
))
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingRandomAddressBuilder(advertising_handle, '0C:05:04:03:02:01'))
-
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_A_Cert'))
-
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingDataBuilder(
- advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT,
- hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_name]))
-
- gap_short_name = hci_packets.GapData()
- gap_short_name.data_type = hci_packets.GapDataType.SHORTENED_LOCAL_NAME
- gap_short_name.data = list(bytes(b'Im_A_C'))
-
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingScanResponseBuilder(
- advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT,
- hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_short_name]))
-
- enabled_set = hci_packets.EnabledSet()
- enabled_set.advertising_handle = advertising_handle
- enabled_set.duration = 0
- enabled_set.max_extended_advertising_events = 0
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingEnableBuilder(hci_packets.Enable.ENABLED, [enabled_set]))
-
- self.dut_le_acl = self.dut_le_acl_manager.connect_to_remote(
+ dut_le_acl = self.dut_le_acl_manager.connect_to_remote(
remote_addr=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:01', 'utf8')),
- type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)))
+ address=common.BluetoothAddress(address=bytes(self.cert_public_address, "utf-8")),
+ type=int(hci_packets.AddressType.PUBLIC_DEVICE_ADDRESS)))
- # Cert gets ConnectionComplete with a handle and sends ACL data
- handle = 0xfff
- address = hci_packets.Address()
+ cert_le_acl = self.cert_hci.incoming_le_connection()
+ return dut_le_acl, cert_le_acl
- def get_handle(packet):
- packet_bytes = packet.payload
- nonlocal handle
- nonlocal address
- if b'\x3e\x13\x01\x00' in packet_bytes:
- cc_view = hci_packets.LeConnectionCompleteView(
- hci_packets.LeMetaEventView(
- hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
- handle = cc_view.GetConnectionHandle()
- address = cc_view.GetPeerAddress()
- return True
- if b'\x3e\x1f\x0A\x00' in packet_bytes:
- cc_view = hci_packets.LeEnhancedConnectionCompleteView(
- hci_packets.LeMetaEventView(
- hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
- handle = cc_view.GetConnectionHandle()
- address = cc_view.GetPeerAddress()
- return True
- return False
-
- self.cert_hci_le_event_stream.assert_event_occurs(get_handle)
- self.cert_handle = handle
- dut_address_from_complete = address
- if check_address:
- assertThat(dut_address_from_complete).isEqualTo(self.dut_address.decode())
-
- def send_receive_and_check(self):
- self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
+ def send_receive_and_check(self, dut_le_acl, cert_le_acl):
+ self.enqueue_acl_data(cert_le_acl.handle, hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
hci_packets.BroadcastFlag.POINT_TO_POINT,
bytes(b'\x19\x00\x07\x00SomeAclData from the Cert'))
- self.dut_le_acl.send(b'\x1C\x00\x07\x00SomeMoreAclData from the DUT')
- self.cert_acl_data_stream.assert_event_occurs(lambda packet: b'SomeMoreAclData' in packet.payload)
- assertThat(self.dut_le_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
+ dut_le_acl.send(b'\x1C\x00\x07\x00SomeMoreAclData from the DUT')
+ assertThat(cert_le_acl.our_acl_stream).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
+ assertThat(dut_le_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
def test_dut_connects(self):
self.set_privacy_policy_static()
- self.dut_connects(check_address=True)
- self.send_receive_and_check()
+ dut_le_acl, cert_le_acl = self.dut_connects()
+
+ assertThat(cert_le_acl.handle).isNotNone()
+ assertThat(cert_le_acl.peer).isEqualTo(self.dut_random_address)
+ assertThat(cert_le_acl.peer_type).isEqualTo(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)
+
+ assertThat(dut_le_acl.handle).isNotNone()
+ assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
+ assertThat(dut_le_acl.remote_address_type).isEqualTo(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)
+
+ self.send_receive_and_check(dut_le_acl, cert_le_acl)
def test_dut_connects_resolvable_address(self):
privacy_policy = le_initiator_address_facade.PrivacyPolicy(
@@ -179,8 +166,39 @@
minimum_rotation_time=7 * 60 * 1000,
maximum_rotation_time=15 * 60 * 1000)
self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
- self.dut_connects(check_address=False)
- self.send_receive_and_check()
+ dut_le_acl, cert_le_acl = self.dut_connects()
+
+ assertThat(cert_le_acl.handle).isNotNone()
+ assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_public_address)
+ assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_random_address)
+ assertThat(cert_le_acl.peer_type).isEqualTo(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)
+
+ assertThat(dut_le_acl.handle).isNotNone()
+ assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
+ assertThat(dut_le_acl.remote_address_type).isEqualTo(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)
+
+ self.send_receive_and_check(dut_le_acl, cert_le_acl)
+
+ def test_dut_connects_resolvable_address_public(self):
+ privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_RESOLVABLE_ADDRESS,
+ rotation_irk=b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f',
+ minimum_rotation_time=7 * 60 * 1000,
+ maximum_rotation_time=15 * 60 * 1000)
+ self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
+ self.cert_advertises_resolvable()
+ dut_le_acl, cert_le_acl = self.dut_connects_cert_resolvable()
+
+ assertThat(cert_le_acl.handle).isNotNone()
+ assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_public_address)
+ assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_random_address)
+ assertThat(cert_le_acl.peer_type).isEqualTo(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)
+
+ assertThat(dut_le_acl.handle).isNotNone()
+ assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_public_address)
+ assertThat(dut_le_acl.remote_address_type).isEqualTo(hci_packets.AddressType.PUBLIC_DEVICE_ADDRESS)
+
+ self.send_receive_and_check(dut_le_acl, cert_le_acl)
def test_dut_connects_non_resolvable_address(self):
privacy_policy = le_initiator_address_facade.PrivacyPolicy(
@@ -189,28 +207,54 @@
minimum_rotation_time=8 * 60 * 1000,
maximum_rotation_time=14 * 60 * 1000)
self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
- self.dut_connects(check_address=False)
- self.send_receive_and_check()
+ dut_le_acl, cert_le_acl = self.dut_connects()
+
+ assertThat(cert_le_acl.handle).isNotNone()
+ assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_public_address)
+ assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_random_address)
+ assertThat(cert_le_acl.peer_type).isEqualTo(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)
+
+ assertThat(dut_le_acl.handle).isNotNone()
+ assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
+ assertThat(dut_le_acl.remote_address_type).isEqualTo(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)
+
+ self.send_receive_and_check(dut_le_acl, cert_le_acl)
def test_dut_connects_public_address(self):
self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(
le_initiator_address_facade.PrivacyPolicy(
address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS))
- self.dut_connects(check_address=False)
- self.send_receive_and_check()
+ dut_le_acl, cert_le_acl = self.dut_connects()
+
+ assertThat(cert_le_acl.handle).isNotNone()
+ assertThat(cert_le_acl.peer).isEqualTo(self.dut_public_address)
+ assertThat(cert_le_acl.peer_type).isEqualTo(hci_packets.AddressType.PUBLIC_DEVICE_ADDRESS)
+
+ assertThat(dut_le_acl.handle).isNotNone()
+ assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
+ assertThat(dut_le_acl.remote_address_type).isEqualTo(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)
+
+ self.send_receive_and_check(dut_le_acl, cert_le_acl)
def test_dut_connects_public_address_cancelled(self):
+ # TODO (Add cancel)
self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(
le_initiator_address_facade.PrivacyPolicy(
address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS))
- self.dut_connects(check_address=False)
- self.send_receive_and_check()
+ dut_le_acl, cert_le_acl = self.dut_connects()
+
+ assertThat(cert_le_acl.handle).isNotNone()
+ assertThat(cert_le_acl.peer).isEqualTo(self.dut_public_address)
+ assertThat(cert_le_acl.peer_type).isEqualTo(hci_packets.AddressType.PUBLIC_DEVICE_ADDRESS)
+
+ assertThat(dut_le_acl.handle).isNotNone()
+ assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
+ assertThat(dut_le_acl.remote_address_type).isEqualTo(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)
+
+ self.send_receive_and_check(dut_le_acl, cert_le_acl)
def test_cert_connects(self):
self.set_privacy_policy_static()
- self.register_for_le_event(hci_packets.SubeventCode.CONNECTION_COMPLETE)
- self.register_for_le_event(hci_packets.SubeventCode.ENHANCED_CONNECTION_COMPLETE)
-
self.dut_le_acl_manager.listen_for_incoming_connections()
# DUT Advertises
@@ -233,127 +277,130 @@
self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
# Cert Connects
- self.enqueue_hci_command(hci_packets.LeSetRandomAddressBuilder('0C:05:04:03:02:01'))
- phy_scan_params = hci_packets.LeCreateConnPhyScanParameters()
- phy_scan_params.scan_interval = 0x60
- phy_scan_params.scan_window = 0x30
- phy_scan_params.conn_interval_min = 0x18
- phy_scan_params.conn_interval_max = 0x28
- phy_scan_params.conn_latency = 0
- phy_scan_params.supervision_timeout = 0x1f4
- phy_scan_params.min_ce_length = 0
- phy_scan_params.max_ce_length = 0
- self.enqueue_hci_command(
- hci_packets.LeExtendedCreateConnectionBuilder(hci_packets.InitiatorFilterPolicy.USE_PEER_ADDRESS,
- hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- hci_packets.AddressType.RANDOM_DEVICE_ADDRESS,
- self.dut_address.decode(), 1, [phy_scan_params]))
+ self.cert_hci.set_random_le_address(self.cert_random_address)
+ self.cert_hci.initiate_le_connection(self.dut_random_address)
# Cert gets ConnectionComplete with a handle and sends ACL data
- handle = 0xfff
+ cert_le_acl = self.cert_hci.incoming_le_connection()
- def get_handle(packet):
- packet_bytes = packet.payload
- nonlocal handle
- if b'\x3e\x13\x01\x00' in packet_bytes:
- cc_view = hci_packets.LeConnectionCompleteView(
- hci_packets.LeMetaEventView(
- hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
- handle = cc_view.GetConnectionHandle()
- return True
- if b'\x3e\x1f\x0A\x00' in packet_bytes:
- cc_view = hci_packets.LeEnhancedConnectionCompleteView(
- hci_packets.LeMetaEventView(
- hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
- handle = cc_view.GetConnectionHandle()
- return True
- return False
-
- self.cert_hci_le_event_stream.assert_event_occurs(get_handle)
- self.cert_handle = handle
-
- self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
- hci_packets.BroadcastFlag.POINT_TO_POINT,
- bytes(b'\x19\x00\x07\x00SomeAclData from the Cert'))
+ cert_le_acl.send(hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
+ hci_packets.BroadcastFlag.POINT_TO_POINT, b'\x19\x00\x07\x00SomeAclData from the Cert')
# DUT gets a connection complete event and sends and receives
- handle = 0xfff
- self.dut_le_acl = self.dut_le_acl_manager.complete_incoming_connection()
+ dut_le_acl = self.dut_le_acl_manager.complete_incoming_connection()
+ assertThat(cert_le_acl.handle).isNotNone()
+ assertThat(cert_le_acl.peer).isEqualTo(self.dut_random_address)
+ assertThat(cert_le_acl.peer_type).isEqualTo(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)
- self.send_receive_and_check()
+ assertThat(dut_le_acl.handle).isNotNone()
+ assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
+ assertThat(dut_le_acl.remote_address_type).isEqualTo(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)
+
+ self.send_receive_and_check(dut_le_acl, cert_le_acl)
def test_recombination_l2cap_packet(self):
self.set_privacy_policy_static()
- self.dut_connects(check_address=True)
-
- self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
+ dut_le_acl, cert_le_acl = self.dut_connects()
+ cert_handle = cert_le_acl.handle
+ self.enqueue_acl_data(cert_handle, hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
hci_packets.BroadcastFlag.POINT_TO_POINT, bytes(b'\x06\x00\x07\x00Hello'))
- self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.CONTINUING_FRAGMENT,
+ self.enqueue_acl_data(cert_handle, hci_packets.PacketBoundaryFlag.CONTINUING_FRAGMENT,
hci_packets.BroadcastFlag.POINT_TO_POINT, bytes(b'!'))
- assertThat(self.dut_le_acl).emits(lambda packet: b'Hello!' in packet.payload)
+ assertThat(dut_le_acl).emits(lambda packet: b'Hello!' in packet.payload)
def test_background_connection(self):
- self.register_for_le_event(hci_packets.SubeventCode.CONNECTION_COMPLETE)
- self.register_for_le_event(hci_packets.SubeventCode.ENHANCED_CONNECTION_COMPLETE)
self.set_privacy_policy_static()
# Start background and direct connection
- token = self.dut_le_acl_manager.initiate_background_and_direct_connection(
+ token_direct = self.dut_le_acl_manager.initiate_connection(
remote_addr=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:01', 'utf8')),
+ address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:02', 'utf8')),
type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)))
+ token_background = self.dut_le_acl_manager.initiate_connection(
+ remote_addr=common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(self.cert_random_address, 'utf8')),
+ type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)),
+ is_direct=False)
+
# Wait for direct connection timeout
- self.dut_le_acl_manager.wait_for_connection_fail(token)
+ self.dut_le_acl_manager.wait_for_connection_fail(token_direct)
# Cert Advertises
advertising_handle = 0
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingLegacyParametersBuilder(
- advertising_handle,
- hci_packets.LegacyAdvertisingProperties.ADV_IND,
- 155, # 100ms = 160 * .625ms "LOW_LATENCY"
- 165,
- 7,
- hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- hci_packets.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
- '00:00:00:00:00:00',
- hci_packets.AdvertisingFilterPolicy.ALL_DEVICES,
- 0xF8,
- 1, #SID
- hci_packets.Enable.DISABLED # Scan request notification
- ))
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingRandomAddressBuilder(advertising_handle, '0C:05:04:03:02:01'))
+ py_hci_adv = self.cert_hci.create_advertisement(advertising_handle, self.cert_random_address,
+ hci_packets.LegacyAdvertisingProperties.ADV_IND, 155, 165)
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_A_Cert'))
-
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingDataBuilder(
- advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT,
- hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_name]))
-
- gap_short_name = hci_packets.GapData()
- gap_short_name.data_type = hci_packets.GapDataType.SHORTENED_LOCAL_NAME
- gap_short_name.data = list(bytes(b'Im_A_C'))
-
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingScanResponseBuilder(
- advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT,
- hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_short_name]))
-
- enabled_set = hci_packets.EnabledSet()
- enabled_set.advertising_handle = advertising_handle
- enabled_set.duration = 0
- enabled_set.max_extended_advertising_events = 0
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingEnableBuilder(hci_packets.Enable.ENABLED, [enabled_set]))
+ py_hci_adv.set_data(b'Im_A_Cert')
+ py_hci_adv.set_scan_response(b'Im_A_C')
+ py_hci_adv.start()
# Check background connection complete
+ self.dut_le_acl_manager.complete_outgoing_connection(token_background)
+
+ def skip_flaky_test_multiple_background_connections(self):
+ self.set_privacy_policy_static()
+
+ # Start two background connections
+ token_1 = self.dut_le_acl_manager.initiate_connection(
+ remote_addr=common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(self.cert_random_address, 'utf8')),
+ type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)),
+ is_direct=False)
+
+ token_2 = self.dut_le_acl_manager.initiate_connection(
+ remote_addr=common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:02', 'utf8')),
+ type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)),
+ is_direct=False)
+
+ # Cert Advertises
+ advertising_handle = 0
+
+ py_hci_adv = self.cert_hci.create_advertisement(advertising_handle, self.cert_random_address,
+ hci_packets.LegacyAdvertisingProperties.ADV_IND, 155, 165)
+
+ py_hci_adv.set_data(b'Im_A_Cert')
+ py_hci_adv.set_scan_response(b'Im_A_C')
+ py_hci_adv.start()
+
+ # First background connection completes
+ connection = self.dut_le_acl_manager.complete_outgoing_connection(token_1)
+ connection.close()
+
+ # Cert Advertises again
+ advertising_handle = 0
+
+ py_hci_adv = self.cert_hci.create_advertisement(advertising_handle, '0C:05:04:03:02:02',
+ hci_packets.LegacyAdvertisingProperties.ADV_IND, 155, 165)
+
+ py_hci_adv.set_data(b'Im_A_Cert')
+ py_hci_adv.set_scan_response(b'Im_A_C')
+ py_hci_adv.start()
+
+ # Second background connection completes
+ connection = self.dut_le_acl_manager.complete_outgoing_connection(token_2)
+ connection.close()
+
+ def test_direct_connection(self):
+ self.set_privacy_policy_static()
+
+ advertising_handle = 0
+ py_hci_adv = self.cert_hci.create_advertisement(advertising_handle, self.cert_random_address,
+ hci_packets.LegacyAdvertisingProperties.ADV_IND, 155, 165)
+
+ py_hci_adv.set_data(b'Im_A_Cert')
+ py_hci_adv.set_scan_response(b'Im_A_C')
+ py_hci_adv.start()
+
+ # Start direct connection
+ token = self.dut_le_acl_manager.initiate_connection(
+ remote_addr=common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(self.cert_random_address, 'utf8')),
+ type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)),
+ is_direct=True)
self.dut_le_acl_manager.complete_outgoing_connection(token)
diff --git a/system/bta/Android.bp b/system/bta/Android.bp
index 020a06d..e42d452 100644
--- a/system/bta/Android.bp
+++ b/system/bta/Android.bp
@@ -153,7 +153,10 @@
// bta unit tests for target
cc_test {
name: "net_test_bta",
- defaults: ["fluoride_bta_defaults"],
+ defaults: [
+ "fluoride_bta_defaults",
+ "mts_defaults"
+ ],
test_suites: ["device-tests"],
srcs: [
":TestMockStackBtm",
@@ -192,7 +195,10 @@
cc_test {
name: "bt_host_test_bta",
- defaults: ["fluoride_bta_defaults"],
+ defaults: [
+ "fluoride_bta_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
host_supported: true,
include_dirs: [
@@ -266,7 +272,10 @@
// bta hf client add record tests for target
cc_test {
name: "net_test_hf_client_add_record",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
include_dirs: [
"packages/modules/Bluetooth/system",
@@ -300,6 +309,7 @@
defaults: [
"fluoride_bta_defaults",
"clang_coverage_bin",
+ "mts_defaults",
],
host_supported: true,
include_dirs: [
@@ -353,6 +363,7 @@
defaults: [
"fluoride_bta_defaults",
"clang_coverage_bin",
+ "mts_defaults",
],
host_supported: true,
include_dirs: [
@@ -394,6 +405,7 @@
defaults: [
"fluoride_bta_defaults",
"clang_coverage_bin",
+ "mts_defaults",
],
host_supported: true,
include_dirs: [
@@ -512,6 +524,7 @@
defaults: [
"fluoride_defaults",
"clang_coverage_bin",
+ "mts_defaults",
],
host_supported: true,
target: {
@@ -591,6 +604,7 @@
defaults: [
"fluoride_bta_defaults",
"clang_coverage_bin",
+ "mts_defaults",
],
host_supported: true,
include_dirs: [
@@ -677,6 +691,7 @@
defaults: [
"fluoride_bta_defaults",
"clang_coverage_bin",
+ "mts_defaults",
],
host_supported: true,
include_dirs: [
@@ -724,6 +739,7 @@
defaults: [
"fluoride_bta_defaults",
"clang_coverage_bin",
+ "mts_defaults",
],
host_supported: true,
include_dirs: [
@@ -791,6 +807,7 @@
defaults: [
"fluoride_bta_defaults",
"clang_coverage_bin",
+ "mts_defaults",
],
host_supported: true,
include_dirs: [
diff --git a/system/bta/include/bta_le_audio_api.h b/system/bta/include/bta_le_audio_api.h
index b22bde7..2d44f9b 100644
--- a/system/bta/include/bta_le_audio_api.h
+++ b/system/bta/include/bta_le_audio_api.h
@@ -65,6 +65,7 @@
int group_id,
bluetooth::le_audio::btle_audio_codec_config_t input_codec_config,
bluetooth::le_audio::btle_audio_codec_config_t output_codec_config) = 0;
+ virtual void SetCcidInformation(int ccid, int context_type) = 0;
virtual std::vector<RawAddress> GetGroupDevices(const int group_id) = 0;
static void AddFromStorage(const RawAddress& addr, bool autoconnect);
static bool IsLeAudioClientRunning();
diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc
index 8158f61..287a9ac 100644
--- a/system/bta/le_audio/client.cc
+++ b/system/bta/le_audio/client.cc
@@ -307,6 +307,14 @@
group_remove_node(group, address);
}
+ int GetCcid(le_audio::types::LeAudioContextType context_type) {
+ if (ccids_.count(context_type) == 0) {
+ return -1;
+ }
+
+ return ccids_[context_type];
+ }
+
/* This callback happens if kLeAudioDeviceSetStateTimeoutMs timeout happens
* during transition from origin to target state
*/
@@ -612,7 +620,8 @@
}
bool result = groupStateMachine_->StartStream(
- group, static_cast<LeAudioContextType>(final_context_type));
+ group, static_cast<LeAudioContextType>(final_context_type),
+ GetCcid(static_cast<LeAudioContextType>(final_context_type)));
if (result)
stream_setup_start_timestamp_ =
bluetooth::common::time_get_os_boottime_us();
@@ -701,6 +710,21 @@
// TODO Implement
}
+ void SetCcidInformation(int ccid, int context_type) override {
+ LOG_DEBUG("Ccid: %d, context type %d", ccid, context_type);
+
+ std::bitset<16> test{static_cast<uint16_t>(context_type)};
+ auto ctx_type =
+ static_cast<le_audio::types::LeAudioContextType>(context_type);
+ if (test.count() > 1 ||
+ ctx_type >= le_audio::types::LeAudioContextType::RFU) {
+ LOG_ERROR("Unknownd context type %d", context_type);
+ return;
+ }
+
+ ccids_[ctx_type] = ccid;
+ }
+
void StartAudioSession(LeAudioDeviceGroup* group,
LeAudioCodecConfiguration* source_config,
LeAudioCodecConfiguration* sink_config) {
@@ -3446,8 +3470,9 @@
stream_setup_start_timestamp_ = 0;
if (group && group->IsPendingConfiguration()) {
SuspendedForReconfiguration();
- if (groupStateMachine_->ConfigureStream(group,
- current_context_type_)) {
+ if (groupStateMachine_->ConfigureStream(
+ group, current_context_type_,
+ GetCcid(current_context_type_))) {
/* If configuration succeed wait for new status. */
return;
}
@@ -3489,6 +3514,10 @@
/* Speaker(s) */
AudioState audio_sender_state_;
+ /* Ccid informations */
+ std::map<le_audio::types::LeAudioContextType /* context */, int /*ccid */>
+ ccids_;
+
/* Current stream configuration */
LeAudioCodecConfiguration current_source_codec_config;
LeAudioCodecConfiguration current_sink_codec_config;
@@ -3782,6 +3811,8 @@
IsoManager::GetInstance()->RegisterCigCallbacks(stateMachineHciCallbacks);
CodecManager::GetInstance()->Start(offloading_preference);
+
+ callbacks_->OnInitialized();
}
void LeAudioClient::DebugDump(int fd) {
diff --git a/system/bta/le_audio/client_linux.cc b/system/bta/le_audio/client_linux.cc
index 87469ca..bde6996 100644
--- a/system/bta/le_audio/client_linux.cc
+++ b/system/bta/le_audio/client_linux.cc
@@ -38,6 +38,7 @@
bluetooth::le_audio::btle_audio_codec_config_t input_codec_config,
bluetooth::le_audio::btle_audio_codec_config_t output_codec_config)
override {}
+ void SetCcidInformation(int ccid, int context_type) override {}
std::vector<RawAddress> GetGroupDevices(const int group_id) override {
return {};
}
diff --git a/system/bta/le_audio/devices.cc b/system/bta/le_audio/devices.cc
index 86b2895..ba7f462 100644
--- a/system/bta/le_audio/devices.cc
+++ b/system/bta/le_audio/devices.cc
@@ -964,7 +964,8 @@
types::LeAudioContextType context_type,
uint8_t* number_of_already_active_group_ase,
types::AudioLocations& group_snk_audio_locations,
- types::AudioLocations& group_src_audio_locations, bool reuse_cis_id) {
+ types::AudioLocations& group_src_audio_locations, bool reuse_cis_id,
+ int ccid) {
struct ase* ase = GetFirstInactiveAse(ent.direction, reuse_cis_id);
if (!ase) return false;
@@ -1019,7 +1020,7 @@
ase->retrans_nb = ent.qos.retransmission_number;
ase->max_transport_latency = ent.qos.max_transport_latency;
- ase->metadata = GetMetadata(context_type);
+ ase->metadata = GetMetadata(context_type, ccid);
DLOG(INFO) << __func__ << " device=" << address_
<< ", activated ASE id=" << +ase->id
@@ -1040,7 +1041,7 @@
*/
bool LeAudioDeviceGroup::ConfigureAses(
const set_configurations::AudioSetConfiguration* audio_set_conf,
- types::LeAudioContextType context_type) {
+ types::LeAudioContextType context_type, int ccid) {
if (!set_configurations::check_if_may_cover_scenario(
audio_set_conf, NumOfConnected(context_type)))
return false;
@@ -1086,7 +1087,7 @@
if (!device->ConfigureAses(ent, context_type, &active_ase_num,
group_snk_audio_locations,
- group_src_audio_locations, reuse_cis_id))
+ group_src_audio_locations, reuse_cis_id, ccid))
continue;
required_device_cnt--;
@@ -1174,10 +1175,10 @@
}
bool LeAudioDeviceGroup::IsMetadataChanged(
- types::LeAudioContextType context_type) {
+ types::LeAudioContextType context_type, int ccid) {
for (auto* leAudioDevice = GetFirstActiveDevice(); leAudioDevice;
leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
- if (leAudioDevice->IsMetadataChanged(context_type)) return true;
+ if (leAudioDevice->IsMetadataChanged(context_type, ccid)) return true;
}
return false;
@@ -1226,7 +1227,7 @@
/* This method should choose aproperiate ASEs to be active and set a cached
* configuration for codec and qos.
*/
-bool LeAudioDeviceGroup::Configure(LeAudioContextType context_type) {
+bool LeAudioDeviceGroup::Configure(LeAudioContextType context_type, int ccid) {
const set_configurations::AudioSetConfiguration* conf =
active_context_to_configuration_map[context_type];
@@ -1241,7 +1242,7 @@
DLOG(INFO) << __func__ << " setting context type: " << int(context_type);
- if (!ConfigureAses(conf, context_type)) {
+ if (!ConfigureAses(conf, context_type, ccid)) {
LOG(ERROR) << __func__ << ", requested pick ASE config context type: "
<< loghex(static_cast<uint16_t>(context_type))
<< ", is in mismatch with cached active contexts";
@@ -1776,20 +1777,21 @@
}
}
-std::vector<uint8_t> LeAudioDevice::GetMetadata(
- LeAudioContextType context_type) {
+std::vector<uint8_t> LeAudioDevice::GetMetadata(LeAudioContextType context_type,
+ int ccid) {
std::vector<uint8_t> metadata;
AppendMetadataLtvEntryForStreamingContext(metadata, context_type);
- AppendMetadataLtvEntryForCcidList(metadata, context_type);
+ AppendMetadataLtvEntryForCcidList(metadata, ccid);
return std::move(metadata);
}
-bool LeAudioDevice::IsMetadataChanged(types::LeAudioContextType context_type) {
+bool LeAudioDevice::IsMetadataChanged(types::LeAudioContextType context_type,
+ int ccid) {
for (auto* ase = this->GetFirstActiveAse(); ase;
ase = this->GetNextActiveAse(ase)) {
- if (this->GetMetadata(context_type) != ase->metadata) return true;
+ if (this->GetMetadata(context_type, ccid) != ase->metadata) return true;
}
return false;
diff --git a/system/bta/le_audio/devices.h b/system/bta/le_audio/devices.h
index 523e59f..30e4bbc 100644
--- a/system/bta/le_audio/devices.h
+++ b/system/bta/le_audio/devices.h
@@ -134,7 +134,7 @@
uint8_t* number_of_already_active_group_ase,
types::AudioLocations& group_snk_audio_locations,
types::AudioLocations& group_src_audio_locations,
- bool reconnect = false);
+ bool reconnect = false, int ccid = -1);
void SetSupportedContexts(types::AudioContexts snk_contexts,
types::AudioContexts src_contexts);
types::AudioContexts GetAvailableContexts(void);
@@ -144,8 +144,9 @@
void ActivateConfiguredAses(void);
void Dump(int fd);
void DisconnectAcl(void);
- std::vector<uint8_t> GetMetadata(types::LeAudioContextType context_type);
- bool IsMetadataChanged(types::LeAudioContextType context_type);
+ std::vector<uint8_t> GetMetadata(types::LeAudioContextType context_type,
+ int ccid);
+ bool IsMetadataChanged(types::LeAudioContextType context_type, int ccid);
private:
types::AudioContexts avail_snk_contexts_;
@@ -230,7 +231,7 @@
bool IsGroupStreamReady(void);
bool HaveAllActiveDevicesCisDisc(void);
uint8_t GetFirstFreeCisId(void);
- bool Configure(types::LeAudioContextType context_type);
+ bool Configure(types::LeAudioContextType context_type, int ccid = 1);
bool SetContextType(types::LeAudioContextType context_type);
types::LeAudioContextType GetContextType(void);
uint32_t GetSduInterval(uint8_t direction);
@@ -256,7 +257,8 @@
std::optional<LeAudioCodecConfiguration> GetCodecConfigurationByDirection(
types::LeAudioContextType group_context_type, uint8_t direction);
bool IsContextSupported(types::LeAudioContextType group_context_type);
- bool IsMetadataChanged(types::LeAudioContextType group_context_type);
+ bool IsMetadataChanged(types::LeAudioContextType group_context_type,
+ int ccid);
inline types::AseState GetState(void) const { return current_state_; }
void SetState(types::AseState state) {
@@ -293,7 +295,7 @@
FindFirstSupportedConfiguration(types::LeAudioContextType context_type);
bool ConfigureAses(
const set_configurations::AudioSetConfiguration* audio_set_conf,
- types::LeAudioContextType context_type);
+ types::LeAudioContextType context_type, int ccid = 1);
bool IsConfigurationSupported(
const set_configurations::AudioSetConfiguration* audio_set_configuration,
types::LeAudioContextType context_type);
diff --git a/system/bta/le_audio/le_audio_client_test.cc b/system/bta/le_audio/le_audio_client_test.cc
index ad1bc82..f2983dc 100644
--- a/system/bta/le_audio/le_audio_client_test.cc
+++ b/system/bta/le_audio/le_audio_client_test.cc
@@ -123,6 +123,7 @@
class MockLeAudioClientCallbacks
: public bluetooth::le_audio::LeAudioClientCallbacks {
public:
+ MOCK_METHOD((void), OnInitialized, (), (override));
MOCK_METHOD((void), OnConnectionState,
(ConnectionState state, const RawAddress& address), (override));
MOCK_METHOD((void), OnGroupStatus, (int group_id, GroupStatus group_status),
@@ -548,9 +549,10 @@
ON_CALL(mock_state_machine_, Initialize(_))
.WillByDefault(SaveArg<0>(&state_machine_callbacks_));
- ON_CALL(mock_state_machine_, ConfigureStream(_, _))
+ ON_CALL(mock_state_machine_, ConfigureStream(_, _, _))
.WillByDefault([this](LeAudioDeviceGroup* group,
- types::LeAudioContextType context_type) {
+ types::LeAudioContextType context_type,
+ int ccid) {
bool isReconfiguration = group->IsPendingConfiguration();
/* This shall be called only for user reconfiguration */
@@ -620,9 +622,10 @@
return true;
});
- ON_CALL(mock_state_machine_, StartStream(_, _))
+ ON_CALL(mock_state_machine_, StartStream(_, _, _))
.WillByDefault([this](LeAudioDeviceGroup* group,
- types::LeAudioContextType context_type) {
+ types::LeAudioContextType context_type,
+ int ccid) {
if (group->GetState() ==
types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
if (group->GetContextType() != context_type) {
@@ -2528,12 +2531,17 @@
uint8_t cis_count_out = 1;
uint8_t cis_count_in = 0;
+ int gmcs_ccid = 1;
+ int gtbs_ccid = 2;
+
// Audio sessions are started only when device gets active
EXPECT_CALL(*mock_unicast_audio_source_, Start(_, _)).Times(1);
EXPECT_CALL(*mock_audio_sink_, Start(_, _)).Times(1);
+ LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */);
+ LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */);
LeAudioClient::Get()->GroupSetActive(group_id);
- EXPECT_CALL(mock_state_machine_, StartStream(_, _)).Times(1);
+ EXPECT_CALL(mock_state_machine_, StartStream(_, _, gmcs_ccid)).Times(1);
StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id);
@@ -2789,7 +2797,7 @@
// Start streaming with reconfiguration from default media stream setup
EXPECT_CALL(
mock_state_machine_,
- StartStream(_, le_audio::types::LeAudioContextType::NOTIFICATIONS))
+ StartStream(_, le_audio::types::LeAudioContextType::NOTIFICATIONS, _))
.Times(1);
StartStreaming(AUDIO_USAGE_NOTIFICATION, AUDIO_CONTENT_TYPE_UNKNOWN,
@@ -2804,7 +2812,7 @@
EXPECT_CALL(*mock_unicast_audio_source_, Stop).Times(0);
EXPECT_CALL(*mock_unicast_audio_source_, Start).Times(0);
EXPECT_CALL(mock_state_machine_,
- StartStream(_, le_audio::types::LeAudioContextType::ALERTS))
+ StartStream(_, le_audio::types::LeAudioContextType::ALERTS, _))
.Times(1);
UpdateMetadata(AUDIO_USAGE_ALARM, AUDIO_CONTENT_TYPE_UNKNOWN);
Mock::VerifyAndClearExpectations(&mock_client_callbacks_);
@@ -2817,7 +2825,7 @@
EXPECT_CALL(
mock_state_machine_,
- StartStream(_, le_audio::types::LeAudioContextType::EMERGENCYALARM))
+ StartStream(_, le_audio::types::LeAudioContextType::EMERGENCYALARM, _))
.Times(1);
UpdateMetadata(AUDIO_USAGE_EMERGENCY, AUDIO_CONTENT_TYPE_UNKNOWN);
Mock::VerifyAndClearExpectations(mock_unicast_audio_source_);
@@ -2849,11 +2857,17 @@
codec_spec_conf::kLeAudioLocationFrontRight, group_size,
group_id, 2 /* rank*/, true /*connect_through_csis*/);
+ int gmcs_ccid = 1;
+ int gtbs_ccid = 2;
+
// Start streaming MEDIA
EXPECT_CALL(*mock_unicast_audio_source_, Start(_, _)).Times(1);
EXPECT_CALL(*mock_audio_sink_, Start(_, _)).Times(1);
+ LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */);
+ LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */);
LeAudioClient::Get()->GroupSetActive(group_id);
+ EXPECT_CALL(mock_state_machine_, StartStream(_, _, gmcs_ccid)).Times(1);
StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id);
Mock::VerifyAndClearExpectations(&mock_client_callbacks_);
@@ -2871,6 +2885,7 @@
fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
Mock::VerifyAndClearExpectations(&mock_client_callbacks_);
+ EXPECT_CALL(mock_state_machine_, StartStream(_, _, gtbs_ccid)).Times(1);
StartStreaming(AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_CONTENT_TYPE_SPEECH,
group_id);
@@ -3113,7 +3128,7 @@
EXPECT_CALL(
mock_state_machine_,
- StartStream(_, le_audio::types::LeAudioContextType::VOICEASSISTANTS))
+ StartStream(_, le_audio::types::LeAudioContextType::VOICEASSISTANTS, _))
.Times(1);
Mock::VerifyAndClearExpectations(&mock_client_callbacks_);
Mock::VerifyAndClearExpectations(mock_unicast_audio_source_);
diff --git a/system/bta/le_audio/le_audio_types.cc b/system/bta/le_audio/le_audio_types.cc
index ca33dc2..44d581b 100644
--- a/system/bta/le_audio/le_audio_types.cc
+++ b/system/bta/le_audio/le_audio_types.cc
@@ -392,34 +392,18 @@
} // namespace types
void AppendMetadataLtvEntryForCcidList(std::vector<uint8_t>& metadata,
- LeAudioContextType context_type) {
+ int ccid) {
+ if (ccid < 0) return;
+
std::vector<uint8_t> ccid_ltv_entry;
- /* TODO: Get CCID values from Service */
- std::vector<uint8_t> ccid_conversational = {0x12};
- std::vector<uint8_t> ccid_media = {0x56};
+ std::vector<uint8_t> ccid_value = {static_cast<uint8_t>(ccid)};
- std::vector<uint8_t>* ccid_value = nullptr;
-
- /* CCID list */
- switch (context_type) {
- case LeAudioContextType::CONVERSATIONAL:
- ccid_value = &ccid_conversational;
- break;
- case LeAudioContextType::MEDIA:
- ccid_value = &ccid_media;
- break;
- default:
- break;
- }
-
- if (!ccid_value) return;
-
- ccid_ltv_entry.push_back(static_cast<uint8_t>(types::kLeAudioMetadataTypeLen +
- ccid_value->size()));
+ ccid_ltv_entry.push_back(
+ static_cast<uint8_t>(types::kLeAudioMetadataTypeLen + ccid_value.size()));
ccid_ltv_entry.push_back(
static_cast<uint8_t>(types::kLeAudioMetadataTypeCcidList));
- ccid_ltv_entry.insert(ccid_ltv_entry.end(), ccid_value->begin(),
- ccid_value->end());
+ ccid_ltv_entry.insert(ccid_ltv_entry.end(), ccid_value.begin(),
+ ccid_value.end());
metadata.insert(metadata.end(), ccid_ltv_entry.begin(), ccid_ltv_entry.end());
}
diff --git a/system/bta/le_audio/le_audio_types.h b/system/bta/le_audio/le_audio_types.h
index b5067d4..7960359 100644
--- a/system/bta/le_audio/le_audio_types.h
+++ b/system/bta/le_audio/le_audio_types.h
@@ -687,7 +687,7 @@
};
void AppendMetadataLtvEntryForCcidList(std::vector<uint8_t>& metadata,
- types::LeAudioContextType context_type);
+ int ccid);
void AppendMetadataLtvEntryForStreamingContext(
std::vector<uint8_t>& metadata, types::LeAudioContextType context_type);
uint8_t GetMaxCodecFramesPerSduFromPac(const types::acs_ac_record* pac_record);
diff --git a/system/bta/le_audio/mock_state_machine.h b/system/bta/le_audio/mock_state_machine.h
index 017d710..63e850b 100644
--- a/system/bta/le_audio/mock_state_machine.h
+++ b/system/bta/le_audio/mock_state_machine.h
@@ -25,7 +25,7 @@
public:
MOCK_METHOD((bool), StartStream,
(le_audio::LeAudioDeviceGroup * group,
- le_audio::types::LeAudioContextType context_type),
+ le_audio::types::LeAudioContextType context_type, int ccid),
(override));
MOCK_METHOD((bool), AttachToStream,
(le_audio::LeAudioDeviceGroup * group,
@@ -35,7 +35,7 @@
(override));
MOCK_METHOD((bool), ConfigureStream,
(le_audio::LeAudioDeviceGroup * group,
- le_audio::types::LeAudioContextType context_type),
+ le_audio::types::LeAudioContextType context_type, int ccid),
(override));
MOCK_METHOD((void), StopStream, (le_audio::LeAudioDeviceGroup * group),
(override));
diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc
index 33b4b44..bb6f8f0 100644
--- a/system/bta/le_audio/state_machine.cc
+++ b/system/bta/le_audio/state_machine.cc
@@ -146,7 +146,8 @@
}
bool StartStream(LeAudioDeviceGroup* group,
- le_audio::types::LeAudioContextType context_type) override {
+ le_audio::types::LeAudioContextType context_type,
+ int ccid) override {
LOG_INFO(" current state: %s", ToString(group->GetState()).c_str());
switch (group->GetState()) {
@@ -161,7 +162,7 @@
/* If configuration is needed */
FALLTHROUGH;
case AseState::BTA_LE_AUDIO_ASE_STATE_IDLE:
- if (!group->Configure(context_type)) {
+ if (!group->Configure(context_type, ccid)) {
LOG(ERROR) << __func__ << ", failed to set ASE configuration";
return false;
}
@@ -189,7 +190,7 @@
/* This case just updates the metadata for the stream, in case
* stream configuration is satisfied
*/
- if (!group->IsMetadataChanged(context_type)) return true;
+ if (!group->IsMetadataChanged(context_type, ccid)) return true;
LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice();
if (!leAudioDevice) {
@@ -197,7 +198,7 @@
return false;
}
- PrepareAndSendUpdateMetadata(group, leAudioDevice, context_type);
+ PrepareAndSendUpdateMetadata(group, leAudioDevice, context_type, ccid);
break;
}
@@ -210,9 +211,9 @@
return true;
}
- bool ConfigureStream(
- LeAudioDeviceGroup* group,
- le_audio::types::LeAudioContextType context_type) override {
+ bool ConfigureStream(LeAudioDeviceGroup* group,
+ le_audio::types::LeAudioContextType context_type,
+ int ccid) override {
if (group->GetState() > AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) {
LOG_ERROR(
"Stream should be stopped or in configured stream. Current state: %s",
@@ -220,7 +221,7 @@
return false;
}
- if (!group->Configure(context_type)) {
+ if (!group->Configure(context_type, ccid)) {
LOG_ERROR("Could not configure ASEs for group %d content type %d",
group->group_id_, int(context_type));
@@ -1678,15 +1679,15 @@
void PrepareAndSendUpdateMetadata(
LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
- le_audio::types::LeAudioContextType context_type) {
+ le_audio::types::LeAudioContextType context_type, int ccid) {
std::vector<struct le_audio::client_parser::ascs::ctp_update_metadata>
confs;
for (; leAudioDevice;
leAudioDevice = group->GetNextActiveDevice(leAudioDevice)) {
- if (!leAudioDevice->IsMetadataChanged(context_type)) continue;
+ if (!leAudioDevice->IsMetadataChanged(context_type, ccid)) continue;
- auto new_metadata = leAudioDevice->GetMetadata(context_type);
+ auto new_metadata = leAudioDevice->GetMetadata(context_type, ccid);
/* Request server to update ASEs with new metadata */
for (struct ase* ase = leAudioDevice->GetFirstActiveAse(); ase != nullptr;
@@ -1854,13 +1855,10 @@
/* Cache current set up metadata values for for further possible
* reconfiguration
*/
- for (struct ase* ase = leAudioDevice->GetFirstActiveAse();
- ase != nullptr; ase = leAudioDevice->GetNextActiveAse(ase)) {
+ if (!rsp.metadata.empty()) {
ase->metadata = rsp.metadata;
}
- PrepareAndSendUpdateMetadata(group, leAudioDevice,
- group->GetContextType());
break;
}
default:
diff --git a/system/bta/le_audio/state_machine.h b/system/bta/le_audio/state_machine.h
index 1f440e2..06b63fb 100644
--- a/system/bta/le_audio/state_machine.h
+++ b/system/bta/le_audio/state_machine.h
@@ -48,11 +48,12 @@
virtual bool AttachToStream(LeAudioDeviceGroup* group,
LeAudioDevice* leAudioDevice) = 0;
virtual bool StartStream(LeAudioDeviceGroup* group,
- types::LeAudioContextType context_type) = 0;
+ types::LeAudioContextType context_type,
+ int ccid = -1) = 0;
virtual void SuspendStream(LeAudioDeviceGroup* group) = 0;
- virtual bool ConfigureStream(
- LeAudioDeviceGroup* group,
- le_audio::types::LeAudioContextType context_type) = 0;
+ virtual bool ConfigureStream(LeAudioDeviceGroup* group,
+ le_audio::types::LeAudioContextType context_type,
+ int ccid = -1) = 0;
virtual void StopStream(LeAudioDeviceGroup* group) = 0;
virtual void ProcessGattNotifEvent(uint8_t* value, uint16_t len,
struct types::ase* ase,
diff --git a/system/btcore/Android.bp b/system/btcore/Android.bp
index 5a81793..82ca35b 100644
--- a/system/btcore/Android.bp
+++ b/system/btcore/Android.bp
@@ -64,7 +64,10 @@
cc_test {
name: "net_test_btcore",
test_suites: ["device-tests"],
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
local_include_dirs: ["include"],
include_dirs: ["packages/modules/Bluetooth/system"],
srcs: [
diff --git a/system/btif/Android.bp b/system/btif/Android.bp
index 8fdcf037..4e016e6 100644
--- a/system/btif/Android.bp
+++ b/system/btif/Android.bp
@@ -196,7 +196,10 @@
// btif unit tests for target
cc_test {
name: "net_test_btif",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
include_dirs: btifCommonIncludes,
srcs: [
@@ -259,7 +262,10 @@
// btif profile queue unit tests for target
cc_test {
name: "net_test_btif_profile_queue",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
include_dirs: btifCommonIncludes,
srcs: [
@@ -286,7 +292,10 @@
// btif rc unit tests for target
cc_test {
name: "net_test_btif_rc",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
host_supported: true,
test_options: {
@@ -321,7 +330,10 @@
// btif config cache unit tests for target
cc_test {
name: "net_test_btif_config_cache",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
host_supported: true,
test_options: {
@@ -358,7 +370,10 @@
// btif hf client service tests for target
cc_test {
name: "net_test_btif_hf_client_service",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
include_dirs: btifCommonIncludes,
srcs: [
@@ -380,7 +395,10 @@
cc_test {
name: "net_test_btif_stack",
host_supported: true,
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
include_dirs: [
"frameworks/av/media/libaaudio/include",
diff --git a/system/btif/src/btif_le_audio.cc b/system/btif/src/btif_le_audio.cc
index ba004f3..b6d79b4 100644
--- a/system/btif/src/btif_le_audio.cc
+++ b/system/btif/src/btif_le_audio.cc
@@ -43,6 +43,11 @@
public LeAudioClientCallbacks {
~LeAudioClientInterfaceImpl() = default;
+ void OnInitialized(void) {
+ do_in_jni_thread(FROM_HERE, Bind(&LeAudioClientCallbacks::OnInitialized,
+ Unretained(callbacks)));
+ }
+
void OnConnectionState(ConnectionState state,
const RawAddress& address) override {
do_in_jni_thread(FROM_HERE, Bind(&LeAudioClientCallbacks::OnConnectionState,
@@ -186,6 +191,14 @@
input_codec_config, output_codec_config));
}
+ void SetCcidInformation(int ccid, int context_type) {
+ DVLOG(2) << __func__ << " ccid: " << ccid << " context_type"
+ << context_type;
+ do_in_main_thread(
+ FROM_HERE, Bind(&LeAudioClient::SetCcidInformation,
+ Unretained(LeAudioClient::Get()), ccid, context_type));
+ }
+
private:
LeAudioClientCallbacks* callbacks;
};
diff --git a/system/common/Android.bp b/system/common/Android.bp
index 8007573..64c9ce3 100644
--- a/system/common/Android.bp
+++ b/system/common/Android.bp
@@ -47,6 +47,7 @@
defaults: [
"fluoride_defaults",
"clang_coverage_bin",
+ "mts_defaults",
],
host_supported: true,
test_options: {
@@ -92,7 +93,10 @@
cc_test {
name: "net_test_performance",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
include_dirs: ["packages/modules/Bluetooth/system"],
host_supported: true,
diff --git a/system/device/Android.bp b/system/device/Android.bp
index 774f946..105dbe5 100644
--- a/system/device/Android.bp
+++ b/system/device/Android.bp
@@ -33,7 +33,10 @@
cc_test {
name: "net_test_device",
test_suites: ["device-tests"],
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
include_dirs: ["packages/modules/Bluetooth/system"],
srcs: [
"test/interop_test.cc",
diff --git a/system/gd/Android.bp b/system/gd/Android.bp
index 386585d..ca4c2b0 100644
--- a/system/gd/Android.bp
+++ b/system/gd/Android.bp
@@ -317,6 +317,7 @@
"gd_defaults",
"gd_clang_coverage_bin",
"libchrome_support_defaults",
+ "mts_defaults",
],
host_supported: true,
test_options: {
@@ -406,6 +407,7 @@
"gd_defaults",
"gd_clang_coverage_bin",
"libchrome_support_defaults",
+ "mts_defaults",
],
include_dirs: ["packages/modules/Bluetooth/system/gd"],
host_supported: true,
@@ -612,7 +614,10 @@
rust_test_host {
name: "libbt_packets_test",
- defaults: ["gd_rust_defaults"],
+ defaults: [
+ "gd_rust_defaults",
+ "mts_defaults",
+ ],
srcs: ["rust/packets/lib.rs", ":BluetoothGeneratedPackets_rust"],
test_suites: ["general-tests"],
edition: "2018",
@@ -642,7 +647,10 @@
rust_test_host {
name: "packets_test_rust",
- defaults: ["gd_rust_defaults"],
+ defaults: [
+ "gd_rust_defaults",
+ "mts_defaults",
+ ],
srcs: ["rust/packets/test_lib.rs", ":TestGeneratedPackets_rust"],
test_suites: ["general-tests"],
edition: "2018",
diff --git a/system/gd/dumpsys/Android.bp b/system/gd/dumpsys/Android.bp
index 7b742c3..0241b00 100644
--- a/system/gd/dumpsys/Android.bp
+++ b/system/gd/dumpsys/Android.bp
@@ -177,6 +177,7 @@
cc_test {
name: "bluetooth_flatbuffer_tests",
test_suites: ["device-tests"],
+ defaults: ["mts_defaults"],
host_supported: true,
test_options: {
unit_test: true,
diff --git a/system/gd/hci/acl_manager/le_impl.h b/system/gd/hci/acl_manager/le_impl.h
index 0ae3016..0b82835 100644
--- a/system/gd/hci/acl_manager/le_impl.h
+++ b/system/gd/hci/acl_manager/le_impl.h
@@ -365,15 +365,20 @@
on_le_connection_canceled_on_pause();
return;
}
- AddressWithType remote_address(address, peer_address_type);
- // The address added to the connect list is the one that callbacks
- // should be sent for, given that is the address passed in
- // call to BluetoothDevice#connectGatt and tied to app layer callbacks.
- if (!peer_resolvable_address.IsEmpty() &&
- is_device_in_connect_list(AddressWithType(peer_resolvable_address, AddressType::RANDOM_DEVICE_ADDRESS))) {
- LOG_INFO("Using resolvable address");
- remote_address = AddressWithType(peer_resolvable_address, AddressType::RANDOM_DEVICE_ADDRESS);
+
+ AddressType remote_address_type;
+
+ switch (peer_address_type) {
+ case AddressType::PUBLIC_DEVICE_ADDRESS:
+ case AddressType::PUBLIC_IDENTITY_ADDRESS:
+ remote_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
+ break;
+ case AddressType::RANDOM_DEVICE_ADDRESS:
+ case AddressType::RANDOM_IDENTITY_ADDRESS:
+ remote_address_type = AddressType::RANDOM_DEVICE_ADDRESS;
+ break;
}
+ AddressWithType remote_address(address, remote_address_type);
on_common_le_connection_complete(remote_address);
if (status == ErrorCode::UNKNOWN_CONNECTION) {
diff --git a/system/gd/hci/facade/le_acl_manager_facade.cc b/system/gd/hci/facade/le_acl_manager_facade.cc
index 1dd51ce..115c69c 100644
--- a/system/gd/hci/facade/le_acl_manager_facade.cc
+++ b/system/gd/hci/facade/le_acl_manager_facade.cc
@@ -63,37 +63,29 @@
::grpc::Status CreateConnection(
::grpc::ServerContext* context,
- const ::blueberry::facade::BluetoothAddressWithType* request,
+ const CreateConnectionMsg* request,
::grpc::ServerWriter<LeConnectionEvent>* writer) override {
Address peer_address;
- ASSERT(Address::FromString(request->address().address(), peer_address));
- AddressWithType peer(peer_address, static_cast<AddressType>(request->type()));
- acl_manager_->CreateLeConnection(peer, /* is_direct */ true);
- if (per_connection_events_.size() > current_connection_request_) {
- return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding request is supported");
- }
- per_connection_events_.emplace_back(std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
- std::string("connection attempt ") + std::to_string(current_connection_request_)));
- return per_connection_events_[current_connection_request_]->RunLoop(context, writer);
- }
+ ASSERT(Address::FromString(request->peer_address().address().address(), peer_address));
+ AddressWithType peer(peer_address, static_cast<AddressType>(request->peer_address().type()));
+ bool is_direct = request->is_direct();
+ acl_manager_->CreateLeConnection(peer, is_direct);
- ::grpc::Status CreateBackgroundAndDirectConnection(
- ::grpc::ServerContext* context,
- const ::blueberry::facade::BluetoothAddressWithType* request,
- ::grpc::ServerWriter<LeConnectionEvent>* writer) override {
- Address peer_address;
- ASSERT(Address::FromString(request->address().address(), peer_address));
- AddressWithType peer(peer_address, static_cast<AddressType>(request->type()));
- // Create background connection first
- acl_manager_->CreateLeConnection(peer, /* is_direct */ false);
- acl_manager_->CreateLeConnection(peer, /* is_direct */ true);
- wait_for_background_connection_complete = true;
- if (per_connection_events_.size() > current_connection_request_) {
- return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding request is supported");
+ if (is_direct) {
+ if (direct_connection_events_ != nullptr) {
+ return ::grpc::Status(
+ ::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding direct request is supported");
+ }
+ direct_connection_events_ = std::make_shared<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
+ std::string("direct connection attempt ") + peer.ToString());
+ direct_connection_address_ = peer;
+ return direct_connection_events_->RunLoop(context, writer);
}
- per_connection_events_.emplace_back(std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
- std::string("connection attempt ") + std::to_string(current_connection_request_)));
- return per_connection_events_[current_connection_request_]->RunLoop(context, writer);
+ per_connection_events_.emplace(
+ peer,
+ std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
+ std::string("connection attempt ") + peer.ToString()));
+ return per_connection_events_[peer]->RunLoop(context, writer);
}
::grpc::Status CancelConnection(
@@ -103,9 +95,13 @@
Address peer_address;
ASSERT(Address::FromString(request->address().address(), peer_address));
AddressWithType peer(peer_address, static_cast<AddressType>(request->type()));
- if (per_connection_events_.size() == current_connection_request_) {
- // Todo: Check that the address matches an outstanding connection request
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "No matching outstanding connection");
+ if (peer == direct_connection_address_) {
+ direct_connection_address_ = AddressWithType();
+ direct_connection_events_.reset();
+ } else {
+ if (per_connection_events_.count(peer) == 0) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "No matching outstanding connection");
+ }
}
acl_manager_->CancelLeConnect(peer);
return ::grpc::Status::OK;
@@ -164,12 +160,43 @@
::grpc::ServerContext* context,
const google::protobuf::Empty* request,
::grpc::ServerWriter<LeConnectionEvent>* writer) override {
- if (per_connection_events_.size() > current_connection_request_) {
- return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding connection is supported");
+ if (incoming_connection_events_ != nullptr) {
+ return ::grpc::Status(
+ ::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding incoming connection is supported");
}
- per_connection_events_.emplace_back(std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
- std::string("incoming connection ") + std::to_string(current_connection_request_)));
- return per_connection_events_[current_connection_request_]->RunLoop(context, writer);
+ incoming_connection_events_ =
+ std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(std::string("incoming connection "));
+ return incoming_connection_events_->RunLoop(context, writer);
+ }
+
+ ::grpc::Status AddDeviceToResolvingList(
+ ::grpc::ServerContext* context, const IrkMsg* request, ::google::protobuf::Empty* response) override {
+ Address peer_address;
+ ASSERT(Address::FromString(request->peer().address().address(), peer_address));
+ AddressWithType peer(peer_address, static_cast<AddressType>(request->peer().type()));
+
+ auto request_peer_irk_length = request->peer_irk().end() - request->peer_irk().begin();
+
+ if (request_peer_irk_length != crypto_toolbox::OCTET16_LEN) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid Peer IRK");
+ }
+
+ auto request_local_irk_length = request->local_irk().end() - request->local_irk().begin();
+ if (request_local_irk_length != crypto_toolbox::OCTET16_LEN) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid Local IRK");
+ }
+
+ crypto_toolbox::Octet16 peer_irk = {};
+ crypto_toolbox::Octet16 local_irk = {};
+
+ std::vector<uint8_t> peer_irk_data(request->peer_irk().begin(), request->peer_irk().end());
+ std::copy_n(peer_irk_data.begin(), crypto_toolbox::OCTET16_LEN, peer_irk.begin());
+
+ std::vector<uint8_t> local_irk_data(request->local_irk().begin(), request->local_irk().end());
+ std::copy_n(local_irk_data.begin(), crypto_toolbox::OCTET16_LEN, local_irk.begin());
+
+ acl_manager_->AddDeviceToResolvingList(peer, peer_irk, local_irk);
+ return ::grpc::Status::OK;
}
::grpc::Status SendAclData(
@@ -233,17 +260,28 @@
connection_tracker->second.pending_acl_data_.OnIncomingEvent(acl_data);
}
- void OnLeConnectSuccess(AddressWithType address_with_type, std::unique_ptr<LeAclConnection> connection) override {
- LOG_INFO("%s", address_with_type.ToString().c_str());
+ void OnLeConnectSuccess(AddressWithType peer, std::unique_ptr<LeAclConnection> connection) override {
+ LOG_INFO("%s", peer.ToString().c_str());
std::unique_lock<std::mutex> lock(acl_connections_mutex_);
- auto addr = address_with_type.GetAddress();
std::shared_ptr<LeAclConnection> shared_connection = std::move(connection);
uint16_t handle = shared_connection->GetHandle();
+ auto role = shared_connection->GetRole();
+ if (role == Role::PERIPHERAL) {
+ ASSERT(incoming_connection_events_ != nullptr);
+ per_connection_events_.emplace(peer, incoming_connection_events_);
+ incoming_connection_events_.reset();
+ } else if (direct_connection_address_ == peer) {
+ direct_connection_address_ = AddressWithType();
+ per_connection_events_.emplace(peer, direct_connection_events_);
+ direct_connection_events_.reset();
+ } else {
+ ASSERT_LOG(per_connection_events_.count(peer) > 0, "No connection request for %s", peer.ToString().c_str());
+ }
acl_connections_.emplace(
std::piecewise_construct,
std::forward_as_tuple(handle),
- std::forward_as_tuple(handle, shared_connection, per_connection_events_[current_connection_request_]));
+ std::forward_as_tuple(handle, shared_connection, per_connection_events_[peer]));
shared_connection->GetAclQueueEnd()->RegisterDequeue(
facade_handler_,
common::Bind(&LeAclManagerFacadeService::on_incoming_acl, common::Unretained(this), shared_connection, handle));
@@ -251,21 +289,11 @@
shared_connection->RegisterCallbacks(callbacks, facade_handler_);
{
std::unique_ptr<BasePacketBuilder> builder = LeConnectionCompleteBuilder::Create(
- ErrorCode::SUCCESS,
- handle,
- Role::CENTRAL,
- address_with_type.GetAddressType(),
- addr,
- 1,
- 2,
- 3,
- ClockAccuracy::PPM_20);
+ ErrorCode::SUCCESS, handle, role, peer.GetAddressType(), peer.GetAddress(), 1, 2, 3, ClockAccuracy::PPM_20);
LeConnectionEvent success;
success.set_payload(builder_to_string(std::move(builder)));
- per_connection_events_[current_connection_request_]->OnIncomingEvent(success);
+ per_connection_events_[peer]->OnIncomingEvent(success);
}
- wait_for_background_connection_complete = false;
- current_connection_request_++;
}
void OnLeConnectFail(AddressWithType address, ErrorCode reason) override {
@@ -273,9 +301,11 @@
reason, 0, Role::CENTRAL, address.GetAddressType(), address.GetAddress(), 0, 0, 0, ClockAccuracy::PPM_20);
LeConnectionEvent fail;
fail.set_payload(builder_to_string(std::move(builder)));
- per_connection_events_[current_connection_request_]->OnIncomingEvent(fail);
- if (!wait_for_background_connection_complete) {
- current_connection_request_++;
+ if (address == direct_connection_address_) {
+ direct_connection_address_ = AddressWithType();
+ direct_connection_events_->OnIncomingEvent(fail);
+ } else {
+ per_connection_events_[address]->OnIncomingEvent(fail);
}
}
@@ -332,10 +362,12 @@
AclManager* acl_manager_;
::bluetooth::os::Handler* facade_handler_;
mutable std::mutex acl_connections_mutex_;
- std::vector<std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>> per_connection_events_;
+ std::map<bluetooth::hci::AddressWithType, std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>>
+ per_connection_events_;
+ std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>> direct_connection_events_;
+ bluetooth::hci::AddressWithType direct_connection_address_;
+ std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>> incoming_connection_events_;
std::map<uint16_t, Connection> acl_connections_;
- uint32_t current_connection_request_{0};
- bool wait_for_background_connection_complete = false;
};
void LeAclManagerFacadeModule::ListDependencies(ModuleList* list) const {
diff --git a/system/gd/hci/le_address_manager.cc b/system/gd/hci/le_address_manager.cc
index e2b8f14..6d1806d 100644
--- a/system/gd/hci/le_address_manager.cc
+++ b/system/gd/hci/le_address_manager.cc
@@ -130,6 +130,7 @@
minimum_rotation_time_ = minimum_rotation_time;
maximum_rotation_time_ = maximum_rotation_time;
address_rotation_alarm_ = std::make_unique<os::Alarm>(handler_);
+ set_random_address();
break;
case AddressPolicy::POLICY_NOT_SET:
LOG_ALWAYS_FATAL("invalid parameters");
diff --git a/system/gd/rust/stack/Android.bp b/system/gd/rust/stack/Android.bp
index 19d373b..37d7136 100644
--- a/system/gd/rust/stack/Android.bp
+++ b/system/gd/rust/stack/Android.bp
@@ -54,7 +54,10 @@
rust_test_host {
name: "libbluetooth_rs_test",
- defaults: ["gd_rust_defaults"],
+ defaults: [
+ "gd_rust_defaults",
+ "mts_defaults",
+ ],
srcs: ["src/lib.rs"],
test_suites: ["general-tests"],
edition: "2018",
diff --git a/system/hci/Android.bp b/system/hci/Android.bp
index af49566..d9f9542 100644
--- a/system/hci/Android.bp
+++ b/system/hci/Android.bp
@@ -58,7 +58,11 @@
cc_test {
name: "net_test_hci",
test_suites: ["device-tests"],
- defaults: ["fluoride_basic_defaults", "fluoride_test_defaults"],
+ defaults: [
+ "fluoride_basic_defaults",
+ "fluoride_test_defaults",
+ "mts_defaults",
+ ],
host_supported: false,
local_include_dirs: [
"include",
@@ -91,7 +95,10 @@
cc_test {
name: "net_test_hci_native",
test_suites: ["device-tests"],
- defaults: ["fluoride_unit_test_defaults"],
+ defaults: [
+ "fluoride_unit_test_defaults",
+ "mts_defaults",
+ ],
local_include_dirs: [
"include",
],
@@ -109,7 +116,10 @@
cc_test {
name: "net_test_hci_fragmenter_native",
test_suites: ["device-tests"],
- defaults: ["fluoride_unit_test_defaults"],
+ defaults: [
+ "fluoride_unit_test_defaults",
+ "mts_defaults",
+ ],
local_include_dirs: [
"include",
],
diff --git a/system/include/hardware/bt_le_audio.h b/system/include/hardware/bt_le_audio.h
index e8b4699..3188aa9 100644
--- a/system/include/hardware/bt_le_audio.h
+++ b/system/include/hardware/bt_le_audio.h
@@ -82,6 +82,9 @@
public:
virtual ~LeAudioClientCallbacks() = default;
+ /* Callback to notify Java that stack is ready */
+ virtual void OnInitialized(void) = 0;
+
/** Callback for profile connection state change */
virtual void OnConnectionState(ConnectionState state,
const RawAddress& address) = 0;
@@ -146,6 +149,9 @@
virtual void SetCodecConfigPreference(
int group_id, btle_audio_codec_config_t input_codec_config,
btle_audio_codec_config_t output_codec_config) = 0;
+
+ /* Set Ccid for context type */
+ virtual void SetCcidInformation(int ccid, int context_type) = 0;
};
/* Represents the broadcast source state. */
diff --git a/system/main/Android.bp b/system/main/Android.bp
index 3acba7c..8f8a245 100644
--- a/system/main/Android.bp
+++ b/system/main/Android.bp
@@ -152,7 +152,10 @@
test_options: {
unit_test: true,
},
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
include_dirs: [
"packages/modules/Bluetooth/system",
"packages/modules/Bluetooth/system/gd",
diff --git a/system/osi/Android.bp b/system/osi/Android.bp
index e33701d..bcbac81 100644
--- a/system/osi/Android.bp
+++ b/system/osi/Android.bp
@@ -109,7 +109,10 @@
cc_test {
name: "net_test_osi",
test_suites: ["device-tests"],
- defaults: ["fluoride_osi_defaults"],
+ defaults: [
+ "fluoride_osi_defaults",
+ "mts_defaults",
+ ],
host_supported: true,
srcs: [
"test/AlarmTestHarness.cc",
diff --git a/system/packet/Android.bp b/system/packet/Android.bp
index 4d8cb92..1033fc6 100644
--- a/system/packet/Android.bp
+++ b/system/packet/Android.bp
@@ -27,7 +27,10 @@
cc_test {
name: "net_test_btpackets",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
host_supported: true,
test_options: {
diff --git a/system/profile/avrcp/Android.bp b/system/profile/avrcp/Android.bp
index 8622dea..72e9b1b 100644
--- a/system/profile/avrcp/Android.bp
+++ b/system/profile/avrcp/Android.bp
@@ -48,6 +48,7 @@
"fluoride_defaults",
"clang_coverage_bin",
"libchrome_support_defaults",
+ "mts_defaults",
],
host_supported: true,
test_options: {
diff --git a/system/profile/sdp/Android.bp b/system/profile/sdp/Android.bp
index 7db1a4d..1c2f9ed 100644
--- a/system/profile/sdp/Android.bp
+++ b/system/profile/sdp/Android.bp
@@ -32,6 +32,7 @@
defaults: [
"fluoride_defaults",
"clang_coverage_bin",
+ "mts_defaults",
],
host_supported: true,
include_dirs: [
diff --git a/system/service/Android.bp b/system/service/Android.bp
index 92d71fc..cfd2979 100644
--- a/system/service/Android.bp
+++ b/system/service/Android.bp
@@ -156,7 +156,10 @@
cc_test {
name: "bluetoothtbd_test",
test_suites: ["device-tests"],
- defaults: ["fluoride_service_defaults"],
+ defaults: [
+ "fluoride_service_defaults",
+ "mts_defaults",
+ ],
srcs: btserviceBaseTestSrc +
btserviceDaemonSrc + [
"test/main.cc",
diff --git a/system/stack/Android.bp b/system/stack/Android.bp
index 93690e0..85095aed 100644
--- a/system/stack/Android.bp
+++ b/system/stack/Android.bp
@@ -213,7 +213,10 @@
// Bluetooth stack unit tests for target
cc_test {
name: "net_test_stack",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
local_include_dirs: [
"include",
@@ -276,7 +279,10 @@
cc_test {
name: "net_test_stack_rfcomm",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
host_supported: true,
local_include_dirs: [
@@ -335,7 +341,10 @@
// Bluetooth stack smp unit tests for target
cc_test {
name: "net_test_stack_smp",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
host_supported: true,
test_suites: ["device-tests"],
local_include_dirs: [
@@ -395,7 +404,10 @@
// Bluetooth stack multi-advertising unit tests for target
cc_test {
name: "net_test_stack_multi_adv",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
local_include_dirs: [
"include",
@@ -434,7 +446,10 @@
// Bluetooth stack advertise data parsing unit tests for target
cc_test {
name: "net_test_stack_ad_parser",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
local_include_dirs: [
"include",
@@ -490,7 +505,10 @@
cc_test {
name: "net_test_stack_gatt_native",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
host_supported: true,
test_options: {
@@ -535,7 +553,10 @@
cc_test {
name: "net_test_stack_avdtp",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
host_supported: true,
test_options: {
@@ -586,7 +607,10 @@
cc_test {
name: "net_test_stack_a2dp_native",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
host_supported: true,
test_options: {
@@ -629,7 +653,10 @@
// gatt sr hash test
cc_test {
name: "net_test_stack_gatt_sr_hash_native",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
test_suites: ["device-tests"],
host_supported: true,
include_dirs: [
@@ -673,7 +700,10 @@
test_options: {
unit_test: true,
},
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
local_include_dirs: [
"btm",
"include",
@@ -719,6 +749,7 @@
defaults: [
"fluoride_defaults",
"clang_coverage_bin",
+ "mts_defaults",
],
local_include_dirs: [
"include",
@@ -766,7 +797,10 @@
test_options: {
unit_test: true,
},
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
local_include_dirs: [
"include",
"btm",
@@ -860,7 +894,10 @@
name: "net_test_stack_hci",
test_suites: ["device-tests"],
host_supported: true,
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
local_include_dirs: [
"include",
"btm",
@@ -903,7 +940,10 @@
name: "net_test_stack_hid",
test_suites: ["device-tests"],
host_supported: true,
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
local_include_dirs: [
"include",
"test/common",
@@ -952,7 +992,10 @@
name: "net_test_stack_btu",
test_suites: ["device-tests"],
host_supported: true,
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
local_include_dirs: [
"include",
"test/common",
@@ -1011,7 +1054,10 @@
name: "net_test_stack_gatt",
test_suites: ["device-tests"],
host_supported: true,
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
local_include_dirs: [
"include",
"test/common",
@@ -1082,7 +1128,10 @@
name: "net_test_stack_l2cap",
test_suites: ["device-tests"],
host_supported: true,
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
local_include_dirs: [
"include",
"test/common",
@@ -1151,7 +1200,10 @@
name: "net_test_stack_acl",
test_suites: ["device-tests"],
host_supported: true,
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
local_include_dirs: [
"include",
"test/common",
diff --git a/system/test/Android.bp b/system/test/Android.bp
index 7754163a..f99db16 100644
--- a/system/test/Android.bp
+++ b/system/test/Android.bp
@@ -451,3 +451,21 @@
"mock/mock_legacy_hci_iterface.cc"
],
}
+
+cc_defaults {
+ name: "mts_defaults",
+ target: {
+ android: {
+ test_suites: ["mts-bluetooth",],
+ },
+ },
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+}
diff --git a/system/test/headless/Android.bp b/system/test/headless/Android.bp
index 42b222f..87f94c1 100644
--- a/system/test/headless/Android.bp
+++ b/system/test/headless/Android.bp
@@ -10,7 +10,10 @@
cc_test {
name: "bt_headless",
test_suites: ["device-tests"],
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
srcs: [
"connect/connect.cc",
"get_options.cc",
diff --git a/system/test/suite/Android.bp b/system/test/suite/Android.bp
index b7fd0ed..ec9545f 100644
--- a/system/test/suite/Android.bp
+++ b/system/test/suite/Android.bp
@@ -109,7 +109,10 @@
cc_test {
name: "net_test_bluetooth",
test_suites: ["device-tests"],
- defaults: ["net_test_defaults"],
+ defaults: [
+ "net_test_defaults",
+ "mts_defaults",
+ ],
srcs: [
"adapter/adapter_unittest.cc",
"gatt/gatt_test.cc",
diff --git a/system/types/Android.bp b/system/types/Android.bp
index b0be0d7..2009df6 100644
--- a/system/types/Android.bp
+++ b/system/types/Android.bp
@@ -49,7 +49,10 @@
cc_test {
name: "net_test_types",
test_suites: ["device-tests"],
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "mts_defaults",
+ ],
include_dirs: [
"packages/modules/Bluetooth/system",
],
diff --git a/tools/rootcanal/model/controller/acl_connection.cc b/tools/rootcanal/model/controller/acl_connection.cc
index db5c5e1..0f41176 100644
--- a/tools/rootcanal/model/controller/acl_connection.cc
+++ b/tools/rootcanal/model/controller/acl_connection.cc
@@ -17,9 +17,14 @@
#include "acl_connection.h"
namespace rootcanal {
-AclConnection::AclConnection(AddressWithType addr, AddressWithType own_addr,
+AclConnection::AclConnection(AddressWithType address,
+ AddressWithType own_address,
+ AddressWithType resolved_address,
Phy::Type phy_type)
- : address_(addr), own_address_(own_addr), type_(phy_type) {}
+ : address_(address),
+ own_address_(own_address),
+ resolved_address_(resolved_address),
+ type_(phy_type) {}
void AclConnection::Encrypt() { encrypted_ = true; };
@@ -31,8 +36,12 @@
AddressWithType AclConnection::GetOwnAddress() const { return own_address_; }
-void AclConnection::SetOwnAddress(AddressWithType own_addr) {
- own_address_ = own_addr;
+AddressWithType AclConnection::GetResolvedAddress() const {
+ return resolved_address_;
+}
+
+void AclConnection::SetOwnAddress(AddressWithType address) {
+ own_address_ = address;
}
Phy::Type AclConnection::GetPhyType() const { return type_; }
diff --git a/tools/rootcanal/model/controller/acl_connection.h b/tools/rootcanal/model/controller/acl_connection.h
index 80b35ad..c6e1393 100644
--- a/tools/rootcanal/model/controller/acl_connection.h
+++ b/tools/rootcanal/model/controller/acl_connection.h
@@ -28,8 +28,8 @@
// Model the connection of a device to the controller.
class AclConnection {
public:
- AclConnection(AddressWithType addr, AddressWithType own_addr,
- Phy::Type phy_type);
+ AclConnection(AddressWithType address, AddressWithType own_address,
+ AddressWithType resolved_address, Phy::Type phy_type);
virtual ~AclConnection() = default;
@@ -43,13 +43,16 @@
AddressWithType GetOwnAddress() const;
- void SetOwnAddress(AddressWithType own_addr);
+ void SetOwnAddress(AddressWithType address);
+
+ AddressWithType GetResolvedAddress() const;
Phy::Type GetPhyType() const;
private:
AddressWithType address_;
AddressWithType own_address_;
+ AddressWithType resolved_address_;
Phy::Type type_{Phy::Type::BR_EDR};
// State variables
diff --git a/tools/rootcanal/model/controller/acl_connection_handler.cc b/tools/rootcanal/model/controller/acl_connection_handler.cc
index 8aafaf9..28efac8 100644
--- a/tools/rootcanal/model/controller/acl_connection_handler.cc
+++ b/tools/rootcanal/model/controller/acl_connection_handler.cc
@@ -70,27 +70,35 @@
}
classic_connection_pending_ = false;
pending_connection_address_ = Address::kEmpty;
+ pending_le_connection_resolved_address_ = AddressWithType();
return true;
}
-bool AclConnectionHandler::CreatePendingLeConnection(AddressWithType addr) {
- bool device_connected = false;
+bool AclConnectionHandler::CreatePendingLeConnection(
+ AddressWithType peer, AddressWithType resolved_peer,
+ AddressWithType local_address) {
for (auto pair : acl_connections_) {
auto connection = std::get<AclConnection>(pair);
- if (connection.GetAddress() == addr) {
- device_connected = true;
+ if (connection.GetAddress() == peer ||
+ connection.GetResolvedAddress() == resolved_peer) {
+ LOG_INFO("%s: %s is already connected", __func__,
+ peer.ToString().c_str());
+ if (connection.GetResolvedAddress() == resolved_peer) {
+ LOG_INFO("%s: allowing a second connection with %s", __func__,
+ resolved_peer.ToString().c_str());
+ } else {
+ return false;
+ }
}
}
- if (device_connected) {
- LOG_INFO("%s: %s is already connected", __func__, addr.ToString().c_str());
- return false;
- }
if (le_connection_pending_) {
LOG_INFO("%s: connection already pending", __func__);
return false;
}
le_connection_pending_ = true;
- pending_le_connection_address_ = addr;
+ pending_le_connection_address_ = peer;
+ pending_le_connection_own_address_ = local_address;
+ pending_le_connection_resolved_address_ = resolved_peer;
return true;
}
@@ -105,6 +113,8 @@
le_connection_pending_ = false;
pending_le_connection_address_ =
AddressWithType{Address::kEmpty, AddressType::PUBLIC_DEVICE_ADDRESS};
+ pending_le_connection_resolved_address_ =
+ AddressWithType{Address::kEmpty, AddressType::PUBLIC_DEVICE_ADDRESS};
return true;
}
@@ -117,7 +127,7 @@
AclConnection{
AddressWithType{addr, AddressType::PUBLIC_DEVICE_ADDRESS},
AddressWithType{own_addr, AddressType::PUBLIC_DEVICE_ADDRESS},
- Phy::Type::BR_EDR});
+ AddressWithType(), Phy::Type::BR_EDR});
return handle;
}
return kReservedHandle;
@@ -125,10 +135,12 @@
uint16_t AclConnectionHandler::CreateLeConnection(AddressWithType addr,
AddressWithType own_addr) {
+ AddressWithType resolved_peer = pending_le_connection_resolved_address_;
if (CancelPendingLeConnection(addr)) {
uint16_t handle = GetUnusedHandle();
acl_connections_.emplace(
- handle, AclConnection{addr, own_addr, Phy::Type::LOW_ENERGY});
+ handle,
+ AclConnection{addr, own_addr, resolved_peer, Phy::Type::LOW_ENERGY});
return handle;
}
return kReservedHandle;
@@ -184,6 +196,12 @@
return acl_connections_.at(handle).GetOwnAddress();
}
+AddressWithType AclConnectionHandler::GetResolvedAddress(
+ uint16_t handle) const {
+ ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle);
+ return acl_connections_.at(handle).GetResolvedAddress();
+}
+
void AclConnectionHandler::Encrypt(uint16_t handle) {
if (!HasHandle(handle)) {
return;
@@ -198,15 +216,6 @@
return acl_connections_.at(handle).IsEncrypted();
}
-void AclConnectionHandler::SetAddress(uint16_t handle,
- AddressWithType address) {
- if (!HasHandle(handle)) {
- return;
- }
- auto connection = acl_connections_.at(handle);
- connection.SetAddress(address);
-}
-
Phy::Type AclConnectionHandler::GetPhyType(uint16_t handle) const {
if (!HasHandle(handle)) {
return Phy::Type::BR_EDR;
diff --git a/tools/rootcanal/model/controller/acl_connection_handler.h b/tools/rootcanal/model/controller/acl_connection_handler.h
index 7f8af70..d5a6b6d 100644
--- a/tools/rootcanal/model/controller/acl_connection_handler.h
+++ b/tools/rootcanal/model/controller/acl_connection_handler.h
@@ -58,7 +58,9 @@
bluetooth::hci::Address addr) const;
ScoLinkParameters GetScoLinkParameters(bluetooth::hci::Address addr) const;
- bool CreatePendingLeConnection(bluetooth::hci::AddressWithType addr);
+ bool CreatePendingLeConnection(bluetooth::hci::AddressWithType peer,
+ bluetooth::hci::AddressWithType resolved_peer,
+ bluetooth::hci::AddressWithType local_address);
bool HasPendingLeConnection(bluetooth::hci::AddressWithType addr) const;
bool CancelPendingLeConnection(bluetooth::hci::AddressWithType addr);
@@ -75,12 +77,11 @@
bluetooth::hci::AddressWithType GetAddress(uint16_t handle) const;
bluetooth::hci::Address GetScoAddress(uint16_t handle) const;
bluetooth::hci::AddressWithType GetOwnAddress(uint16_t handle) const;
+ bluetooth::hci::AddressWithType GetResolvedAddress(uint16_t handle) const;
void Encrypt(uint16_t handle);
bool IsEncrypted(uint16_t handle) const;
- void SetAddress(uint16_t handle, bluetooth::hci::AddressWithType address);
-
Phy::Type GetPhyType(uint16_t handle) const;
std::unique_ptr<bluetooth::hci::LeSetCigParametersCompleteBuilder>
@@ -135,6 +136,12 @@
bluetooth::hci::AddressWithType pending_le_connection_address_{
bluetooth::hci::Address::kEmpty,
bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+ bluetooth::hci::AddressWithType pending_le_connection_own_address_{
+ bluetooth::hci::Address::kEmpty,
+ bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+ bluetooth::hci::AddressWithType pending_le_connection_resolved_address_{
+ bluetooth::hci::Address::kEmpty,
+ bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS};
uint16_t GetUnusedHandle();
uint16_t last_handle_{kReservedHandle - 2};
diff --git a/tools/rootcanal/model/controller/dual_mode_controller.cc b/tools/rootcanal/model/controller/dual_mode_controller.cc
index af0c86c..2a83188 100644
--- a/tools/rootcanal/model/controller/dual_mode_controller.cc
+++ b/tools/rootcanal/model/controller/dual_mode_controller.cc
@@ -1602,13 +1602,18 @@
void DualModeController::LeSetHostFeature(CommandView command) {
auto command_view = gd_hci::LeSetHostFeatureView::Create(command);
ASSERT(command_view.IsValid());
- // TODO: if the controller has active connections, return COMMAND_DISALLOED
- ErrorCode error_code =
- properties_.SetLeHostFeature(
- static_cast<uint8_t>(command_view.GetBitNumber()),
- static_cast<uint8_t>(command_view.GetBitValue()))
- ? ErrorCode::SUCCESS
- : ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
+
+ ErrorCode error_code = ErrorCode::SUCCESS;
+ if (link_layer_controller_.HasAclConnection()) {
+ error_code = ErrorCode::COMMAND_DISALLOWED;
+ } else {
+ bool bit_was_set = properties_.SetLeHostFeature(
+ static_cast<uint8_t>(command_view.GetBitNumber()),
+ static_cast<uint8_t>(command_view.GetBitValue()));
+ if (!bit_was_set) {
+ error_code = ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
+ }
+ }
send_event_(bluetooth::hci::LeSetHostFeatureCompleteBuilder::Create(
kNumCommandPackets, error_code));
}
@@ -1945,10 +1950,13 @@
gd_hci::AclCommandView::Create(command)));
ASSERT(command_view.IsValid());
- uint8_t addr_type = static_cast<uint8_t>(command_view.GetAddressType());
- Address address = command_view.GetAddress();
- ErrorCode result =
- link_layer_controller_.LeFilterAcceptListAddDevice(address, addr_type);
+ ErrorCode result = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
+ if (command_view.GetAddressType() !=
+ bluetooth::hci::FilterAcceptListAddressType::ANONYMOUS_ADVERTISERS) {
+ result = link_layer_controller_.LeFilterAcceptListAddDevice(
+ command_view.GetAddress(), static_cast<bluetooth::hci::AddressType>(
+ command_view.GetAddressType()));
+ }
send_event_(
bluetooth::hci::LeAddDeviceToFilterAcceptListCompleteBuilder::Create(
kNumCommandPackets, result));
@@ -1961,12 +1969,18 @@
gd_hci::AclCommandView::Create(command)));
ASSERT(command_view.IsValid());
- uint8_t addr_type = static_cast<uint8_t>(command_view.GetAddressType());
- Address address = command_view.GetAddress();
- link_layer_controller_.LeFilterAcceptListRemoveDevice(address, addr_type);
+ ErrorCode status = ErrorCode::SUCCESS;
+ if (command_view.GetAddressType() !=
+ bluetooth::hci::FilterAcceptListAddressType::ANONYMOUS_ADVERTISERS) {
+ link_layer_controller_.LeFilterAcceptListAddDevice(
+ command_view.GetAddress(), static_cast<bluetooth::hci::AddressType>(
+ command_view.GetAddressType()));
+ } else {
+ status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
+ }
send_event_(
bluetooth::hci::LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(
- kNumCommandPackets, ErrorCode::SUCCESS));
+ kNumCommandPackets, status));
}
void DualModeController::LeClearResolvingList(CommandView command) {
@@ -2037,14 +2051,18 @@
auto command_view = gd_hci::LeAddDeviceToResolvingListView::Create(
gd_hci::LeSecurityCommandView::Create(command));
ASSERT(command_view.IsValid());
-
- auto addr_type =
- static_cast<uint8_t>(command_view.GetPeerIdentityAddressType());
- Address address = command_view.GetPeerIdentityAddress();
-
+ AddressType peer_address_type;
+ switch (command_view.GetPeerIdentityAddressType()) {
+ case bluetooth::hci::PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS:
+ peer_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
+ break;
+ case bluetooth::hci::PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS:
+ peer_address_type = AddressType::RANDOM_DEVICE_ADDRESS;
+ break;
+ }
auto status = link_layer_controller_.LeResolvingListAddDevice(
- address, addr_type, command_view.GetPeerIrk(),
- command_view.GetLocalIrk());
+ command_view.GetPeerIdentityAddress(), peer_address_type,
+ command_view.GetPeerIrk(), command_view.GetLocalIrk());
send_event_(bluetooth::hci::LeAddDeviceToResolvingListCompleteBuilder::Create(
kNumCommandPackets, status));
}
@@ -2054,10 +2072,17 @@
gd_hci::LeSecurityCommandView::Create(command));
ASSERT(command_view.IsValid());
- uint8_t addr_type =
- static_cast<uint8_t>(command_view.GetPeerIdentityAddressType());
- Address address = command_view.GetPeerIdentityAddress();
- link_layer_controller_.LeResolvingListRemoveDevice(address, addr_type);
+ AddressType peer_address_type;
+ switch (command_view.GetPeerIdentityAddressType()) {
+ case bluetooth::hci::PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS:
+ peer_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
+ break;
+ case bluetooth::hci::PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS:
+ peer_address_type = AddressType::RANDOM_DEVICE_ADDRESS;
+ break;
+ }
+ link_layer_controller_.LeResolvingListRemoveDevice(
+ command_view.GetPeerIdentityAddress(), peer_address_type);
send_event_(
bluetooth::hci::LeRemoveDeviceFromResolvingListCompleteBuilder::Create(
kNumCommandPackets, ErrorCode::SUCCESS));
@@ -2146,11 +2171,18 @@
gd_hci::LeSecurityCommandView::Create(command));
ASSERT(command_view.IsValid());
- uint8_t peer_identity_address_type =
- static_cast<uint8_t>(command_view.GetPeerIdentityAddressType());
Address peer_identity_address = command_view.GetPeerIdentityAddress();
uint8_t privacy_mode = static_cast<uint8_t>(command_view.GetPrivacyMode());
+ AddressType peer_identity_address_type;
+ switch (command_view.GetPeerIdentityAddressType()) {
+ case bluetooth::hci::PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS:
+ peer_identity_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
+ break;
+ case bluetooth::hci::PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS:
+ peer_identity_address_type = AddressType::RANDOM_DEVICE_ADDRESS;
+ break;
+ }
if (link_layer_controller_.LeResolvingListContainsDevice(
peer_identity_address, peer_identity_address_type)) {
link_layer_controller_.LeSetPrivacyMode(
diff --git a/tools/rootcanal/model/controller/le_advertiser.cc b/tools/rootcanal/model/controller/le_advertiser.cc
index ed9c090..3f1d1fd 100644
--- a/tools/rootcanal/model/controller/le_advertiser.cc
+++ b/tools/rootcanal/model/controller/le_advertiser.cc
@@ -38,12 +38,16 @@
}
void LeAdvertiser::InitializeExtended(
- unsigned advertising_handle, AddressType address_type,
- AddressWithType peer_address, LeScanningFilterPolicy filter_policy,
+ unsigned advertising_handle, OwnAddressType address_type,
+ AddressWithType public_address, AddressWithType peer_address,
+ LeScanningFilterPolicy filter_policy,
model::packets::AdvertisementType type,
- std::chrono::steady_clock::duration interval, uint8_t tx_power) {
+ std::chrono::steady_clock::duration interval, uint8_t tx_power,
+ const std::function<bluetooth::hci::Address()>& get_address) {
+ get_address_ = get_address;
+ own_address_type_ = address_type;
+ public_address_ = public_address;
advertising_handle_ = advertising_handle;
- address_ = AddressWithType(address_.GetAddress(), address_type);
peer_address_ = peer_address;
filter_policy_ = filter_policy;
type_ = type;
@@ -99,6 +103,34 @@
Duration duration = duration_ms;
TimePoint now = std::chrono::steady_clock::now();
+ bluetooth::hci::Address resolvable_address = get_address_();
+ switch (own_address_type_) {
+ case bluetooth::hci::OwnAddressType::PUBLIC_DEVICE_ADDRESS:
+ address_ = public_address_;
+ break;
+ case bluetooth::hci::OwnAddressType::RANDOM_DEVICE_ADDRESS:
+ address_ = AddressWithType(address_.GetAddress(),
+ AddressType::RANDOM_DEVICE_ADDRESS);
+ break;
+ case bluetooth::hci::OwnAddressType::RESOLVABLE_OR_PUBLIC_ADDRESS:
+ if (resolvable_address != Address::kEmpty) {
+ address_ = AddressWithType(resolvable_address,
+ AddressType::RANDOM_DEVICE_ADDRESS);
+ } else {
+ address_ = public_address_;
+ }
+ break;
+ case bluetooth::hci::OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS:
+ if (resolvable_address != Address::kEmpty) {
+ address_ = AddressWithType(resolvable_address,
+ AddressType::RANDOM_DEVICE_ADDRESS);
+ } else {
+ address_ = AddressWithType(address_.GetAddress(),
+ AddressType::RANDOM_DEVICE_ADDRESS);
+ }
+ break;
+ }
+
switch (type_) {
// [Vol 6] Part B. 4.4.2.4.3 High duty cycle connectable directed
// advertising
diff --git a/tools/rootcanal/model/controller/le_advertiser.h b/tools/rootcanal/model/controller/le_advertiser.h
index 0b7a92b7..afd1ad1 100644
--- a/tools/rootcanal/model/controller/le_advertiser.h
+++ b/tools/rootcanal/model/controller/le_advertiser.h
@@ -40,13 +40,14 @@
const std::vector<uint8_t>& scan_response,
std::chrono::steady_clock::duration interval);
- void InitializeExtended(unsigned advertising_handle,
- bluetooth::hci::AddressType address_type,
- bluetooth::hci::AddressWithType peer_address,
- bluetooth::hci::LeScanningFilterPolicy filter_policy,
- model::packets::AdvertisementType type,
- std::chrono::steady_clock::duration interval,
- uint8_t tx_power);
+ void InitializeExtended(
+ unsigned advertising_handle, bluetooth::hci::OwnAddressType address_type,
+ bluetooth::hci::AddressWithType public_address,
+ bluetooth::hci::AddressWithType peer_address,
+ bluetooth::hci::LeScanningFilterPolicy filter_policy,
+ model::packets::AdvertisementType type,
+ std::chrono::steady_clock::duration interval, uint8_t tx_power,
+ const std::function<bluetooth::hci::Address()>& get_address);
void SetAddress(bluetooth::hci::Address address);
@@ -80,7 +81,13 @@
bluetooth::hci::AddressWithType GetAddress() const;
private:
+ std::function<bluetooth::hci::Address()> default_get_address_ = []() {
+ return bluetooth::hci::Address::kEmpty;
+ };
+ std::function<bluetooth::hci::Address()>& get_address_ = default_get_address_;
bluetooth::hci::AddressWithType address_{};
+ bluetooth::hci::AddressWithType public_address_{};
+ bluetooth::hci::OwnAddressType own_address_type_;
bluetooth::hci::AddressWithType
peer_address_{}; // For directed advertisements
bluetooth::hci::LeScanningFilterPolicy filter_policy_{};
diff --git a/tools/rootcanal/model/controller/link_layer_controller.cc b/tools/rootcanal/model/controller/link_layer_controller.cc
index 3404eb3..780dff6 100644
--- a/tools/rootcanal/model/controller/link_layer_controller.cc
+++ b/tools/rootcanal/model/controller/link_layer_controller.cc
@@ -1361,8 +1361,8 @@
adv_type == model::packets::AdvertisementType::ADV_DIRECT_IND)) {
return;
}
- Address resolved_address = address;
- uint8_t resolved_address_type = static_cast<uint8_t>(address_type);
+ Address resolved_address = Address::kEmpty;
+ AddressType resolved_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
bool resolved = false;
Address rpa;
if (le_resolving_list_enabled_) {
@@ -1381,17 +1381,10 @@
// Connect
if ((le_peer_address_ == address &&
le_peer_address_type_ == static_cast<uint8_t>(address_type)) ||
- (LeFilterAcceptListContainsDevice(address,
- static_cast<uint8_t>(address_type))) ||
- (resolved &&
- LeFilterAcceptListContainsDevice(
- resolved_address, static_cast<uint8_t>(resolved_address_type)))) {
- if (!connections_.CreatePendingLeConnection(AddressWithType(
- address, static_cast<bluetooth::hci::AddressType>(address_type)))) {
- LOG_WARN(
- "CreatePendingLeConnection failed for connection to %s (type %hhx)",
- incoming.GetSourceAddress().ToString().c_str(), address_type);
- }
+ (LeFilterAcceptListContainsDevice(
+ address, static_cast<AddressType>(address_type))) ||
+ (resolved && LeFilterAcceptListContainsDevice(resolved_address,
+ resolved_address_type))) {
Address own_address;
auto own_address_type =
static_cast<bluetooth::hci::OwnAddressType>(le_address_type_);
@@ -1425,6 +1418,18 @@
le_connect_ = false;
le_scan_enable_ = bluetooth::hci::OpCode::NONE;
+ if (!connections_.CreatePendingLeConnection(
+ AddressWithType(
+ incoming.GetSourceAddress(),
+ static_cast<bluetooth::hci::AddressType>(address_type)),
+ AddressWithType(resolved_address, resolved_address_type),
+ AddressWithType(
+ own_address,
+ static_cast<bluetooth::hci::AddressType>(own_address_type)))) {
+ LOG_WARN(
+ "CreatePendingLeConnection failed for connection to %s (type %hhx)",
+ incoming.GetSourceAddress().ToString().c_str(), address_type);
+ }
SendLeLinkLayerPacket(model::packets::LeConnectBuilder::Create(
own_address, incoming.GetSourceAddress(), le_connection_interval_min_,
le_connection_interval_max_, le_connection_latency_,
@@ -1572,12 +1577,37 @@
if (properties_.IsUnmasked(EventCode::LE_META_EVENT) &&
properties_.GetLeEventSupported(
SubeventCode::ENHANCED_CONNECTION_COMPLETE)) {
+ AddressWithType peer_resolved_address =
+ connections_.GetResolvedAddress(handle);
+ Address peer_resolvable_private_address;
+ Address connection_address = address.GetAddress();
+ AddressType peer_address_type = address.GetAddressType();
+ if (peer_resolved_address != AddressWithType()) {
+ peer_resolvable_private_address = address.GetAddress();
+ if (peer_resolved_address.GetAddressType() ==
+ AddressType::PUBLIC_DEVICE_ADDRESS) {
+ peer_address_type = AddressType::PUBLIC_IDENTITY_ADDRESS;
+ } else if (peer_resolved_address.GetAddressType() ==
+ AddressType::RANDOM_DEVICE_ADDRESS) {
+ peer_address_type = AddressType::RANDOM_IDENTITY_ADDRESS;
+ } else {
+ LOG_WARN("Unhandled resolved address type %s -> %s",
+ address.ToString().c_str(),
+ peer_resolved_address.ToString().c_str());
+ }
+ connection_address = peer_resolved_address.GetAddress();
+ }
+ Address local_resolved_address = own_address.GetAddress();
+ if (local_resolved_address == properties_.GetAddress() ||
+ local_resolved_address == properties_.GetLeAddress()) {
+ local_resolved_address = Address::kEmpty;
+ }
+
send_event_(bluetooth::hci::LeEnhancedConnectionCompleteBuilder::Create(
ErrorCode::SUCCESS, handle, static_cast<bluetooth::hci::Role>(role),
- address.GetAddressType(), address.GetAddress(),
- Address(), // TODO local resolvable private address, if applicable
- Address(), // TODO Peer resolvable private address, if applicable
- connection_interval, connection_latency, supervision_timeout,
+ peer_address_type, connection_address, local_resolved_address,
+ peer_resolvable_private_address, connection_interval,
+ connection_latency, supervision_timeout,
static_cast<bluetooth::hci::ClockAccuracy>(0x00)));
} else if (properties_.IsUnmasked(EventCode::LE_META_EVENT) &&
properties_.GetLeEventSupported(
@@ -1602,16 +1632,6 @@
uint16_t connection_interval = (connect.GetLeConnectionIntervalMax() +
connect.GetLeConnectionIntervalMin()) /
2;
- if (!connections_.CreatePendingLeConnection(AddressWithType(
- incoming.GetSourceAddress(), static_cast<bluetooth::hci::AddressType>(
- connect.GetAddressType())))) {
- LOG_WARN(
- "CreatePendingLeConnection failed for connection from %s (type "
- "%hhx)",
- incoming.GetSourceAddress().ToString().c_str(),
- connect.GetAddressType());
- return;
- }
bluetooth::hci::AddressWithType my_address{};
bool matched_advertiser = false;
size_t set = 0;
@@ -1637,6 +1657,21 @@
return;
}
+ // TODO: Implement for Directed Advertisements
+ AddressWithType peer_resolved_address;
+
+ if (!connections_.CreatePendingLeConnection(
+ AddressWithType(incoming.GetSourceAddress(),
+ static_cast<bluetooth::hci::AddressType>(
+ connect.GetAddressType())),
+ peer_resolved_address, my_address)) {
+ LOG_WARN(
+ "CreatePendingLeConnection failed for connection from %s (type "
+ "%hhx)",
+ incoming.GetSourceAddress().ToString().c_str(),
+ connect.GetAddressType());
+ return;
+ }
uint16_t handle = HandleLeConnection(
AddressWithType(
incoming.GetSourceAddress(),
@@ -3009,28 +3044,6 @@
bluetooth::hci::PeerAddressType peer_address_type, Address peer,
bluetooth::hci::AdvertisingFilterPolicy filter_policy, uint8_t tx_power) {
model::packets::AdvertisementType ad_type;
- switch (type) {
- case bluetooth::hci::LegacyAdvertisingProperties::ADV_IND:
- ad_type = model::packets::AdvertisementType::ADV_IND;
- peer = Address::kEmpty;
- break;
- case bluetooth::hci::LegacyAdvertisingProperties::ADV_NONCONN_IND:
- ad_type = model::packets::AdvertisementType::ADV_NONCONN_IND;
- peer = Address::kEmpty;
- break;
- case bluetooth::hci::LegacyAdvertisingProperties::ADV_SCAN_IND:
- ad_type = model::packets::AdvertisementType::ADV_SCAN_IND;
- peer = Address::kEmpty;
- break;
- case bluetooth::hci::LegacyAdvertisingProperties::ADV_DIRECT_IND_HIGH:
- ad_type = model::packets::AdvertisementType::ADV_DIRECT_IND;
- break;
- case bluetooth::hci::LegacyAdvertisingProperties::ADV_DIRECT_IND_LOW:
- ad_type = model::packets::AdvertisementType::SCAN_RESPONSE;
- break;
- }
- auto interval_ms =
- static_cast<int>((interval_max + interval_min) * 0.625 / 2);
AddressWithType peer_address;
switch (peer_address_type) {
@@ -3044,25 +3057,33 @@
break;
}
- bluetooth::hci::AddressType own_address_address_type;
- switch (own_address_type) {
- case bluetooth::hci::OwnAddressType::RANDOM_DEVICE_ADDRESS:
- own_address_address_type =
- bluetooth::hci::AddressType::RANDOM_DEVICE_ADDRESS;
+ AddressWithType directed_address{};
+ switch (type) {
+ case bluetooth::hci::LegacyAdvertisingProperties::ADV_IND:
+ ad_type = model::packets::AdvertisementType::ADV_IND;
break;
- case bluetooth::hci::OwnAddressType::PUBLIC_DEVICE_ADDRESS:
- own_address_address_type =
- bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS;
+ case bluetooth::hci::LegacyAdvertisingProperties::ADV_NONCONN_IND:
+ ad_type = model::packets::AdvertisementType::ADV_NONCONN_IND;
break;
- case bluetooth::hci::OwnAddressType::RESOLVABLE_OR_PUBLIC_ADDRESS:
- own_address_address_type =
- bluetooth::hci::AddressType::PUBLIC_IDENTITY_ADDRESS;
+ case bluetooth::hci::LegacyAdvertisingProperties::ADV_SCAN_IND:
+ ad_type = model::packets::AdvertisementType::ADV_SCAN_IND;
break;
- case bluetooth::hci::OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS:
- own_address_address_type =
- bluetooth::hci::AddressType::RANDOM_IDENTITY_ADDRESS;
+ case bluetooth::hci::LegacyAdvertisingProperties::ADV_DIRECT_IND_HIGH:
+ ad_type = model::packets::AdvertisementType::ADV_DIRECT_IND;
+ directed_address = peer_address;
+ break;
+ case bluetooth::hci::LegacyAdvertisingProperties::ADV_DIRECT_IND_LOW:
+ ad_type = model::packets::AdvertisementType::SCAN_RESPONSE;
+ directed_address = peer_address;
break;
}
+ auto interval_ms =
+ static_cast<int>((interval_max + interval_min) * 0.625 / 2);
+
+ LOG_INFO("peer %s", peer.ToString().c_str());
+ LOG_INFO("peer_address_type %s",
+ bluetooth::hci::PeerAddressTypeText(peer_address_type).c_str());
+ LOG_INFO("peer_address %s", peer_address.ToString().c_str());
bluetooth::hci::LeScanningFilterPolicy scanning_filter_policy;
switch (filter_policy) {
@@ -3085,8 +3106,26 @@
}
advertisers_[set].InitializeExtended(
- set, own_address_address_type, peer_address, scanning_filter_policy,
- ad_type, std::chrono::milliseconds(interval_ms), tx_power);
+ set, own_address_type,
+ bluetooth::hci::AddressWithType(
+ properties_.GetAddress(),
+ bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS),
+ directed_address, scanning_filter_policy, ad_type,
+ std::chrono::milliseconds(interval_ms), tx_power,
+ [this, own_address_type, peer_address]() {
+ if (own_address_type ==
+ bluetooth::hci::OwnAddressType::RESOLVABLE_OR_PUBLIC_ADDRESS ||
+ own_address_type ==
+ bluetooth::hci::OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS) {
+ for (const auto& entry : le_resolving_list_) {
+ if (entry.address == peer_address.GetAddress() &&
+ entry.address_type == peer_address.GetAddressType()) {
+ return generate_rpa(entry.local_irk);
+ }
+ }
+ }
+ return bluetooth::hci::Address::kEmpty;
+ });
return ErrorCode::SUCCESS;
}
@@ -3221,26 +3260,25 @@
return ErrorCode::SUCCESS;
}
-ErrorCode LinkLayerController::LeFilterAcceptListAddDevice(Address addr,
- uint8_t addr_type) {
+ErrorCode LinkLayerController::LeFilterAcceptListAddDevice(
+ Address addr, AddressType addr_type) {
if (FilterAcceptListBusy()) {
return ErrorCode::COMMAND_DISALLOWED;
}
- std::tuple<Address, uint8_t> new_tuple = std::make_tuple(addr, addr_type);
for (auto dev : le_connect_list_) {
- if (dev == new_tuple) {
+ if (dev.address == addr && dev.address_type == addr_type) {
return ErrorCode::SUCCESS;
}
}
if (LeFilterAcceptListFull()) {
return ErrorCode::MEMORY_CAPACITY_EXCEEDED;
}
- le_connect_list_.emplace_back(new_tuple);
+ le_connect_list_.emplace_back(ConnectListEntry{addr, addr_type});
return ErrorCode::SUCCESS;
}
ErrorCode LinkLayerController::LeResolvingListAddDevice(
- Address addr, uint8_t addr_type, std::array<uint8_t, kIrkSize> peerIrk,
+ Address addr, AddressType addr_type, std::array<uint8_t, kIrkSize> peerIrk,
std::array<uint8_t, kIrkSize> localIrk) {
if (ResolvingListBusy()) {
return ErrorCode::COMMAND_DISALLOWED;
@@ -3253,10 +3291,14 @@
return ErrorCode::SUCCESS;
}
-void LinkLayerController::LeSetPrivacyMode(uint8_t address_type, Address addr,
- uint8_t mode) {
+bool LinkLayerController::HasAclConnection() {
+ return (connections_.GetAclHandles().size() > 0);
+}
+
+void LinkLayerController::LeSetPrivacyMode(AddressType address_type,
+ Address addr, uint8_t mode) {
// set mode for addr
- LOG_INFO("address type = %d ", address_type);
+ LOG_INFO("address type = %s ", AddressTypeText(address_type).c_str());
LOG_INFO("address = %s ", addr.ToString().c_str());
LOG_INFO("mode = %d ", mode);
}
@@ -3597,38 +3639,38 @@
}
ErrorCode LinkLayerController::LeFilterAcceptListRemoveDevice(
- Address addr, uint8_t addr_type) {
+ Address addr, AddressType addr_type) {
if (FilterAcceptListBusy()) {
return ErrorCode::COMMAND_DISALLOWED;
}
- std::tuple<Address, uint8_t> erase_tuple = std::make_tuple(addr, addr_type);
for (size_t i = 0; i < le_connect_list_.size(); i++) {
- if (le_connect_list_[i] == erase_tuple) {
+ if (le_connect_list_[i].address == addr &&
+ le_connect_list_[i].address_type == addr_type) {
le_connect_list_.erase(le_connect_list_.begin() + i);
}
}
return ErrorCode::SUCCESS;
}
-ErrorCode LinkLayerController::LeResolvingListRemoveDevice(Address addr,
- uint8_t addr_type) {
+ErrorCode LinkLayerController::LeResolvingListRemoveDevice(
+ Address addr, AddressType addr_type) {
if (ResolvingListBusy()) {
return ErrorCode::COMMAND_DISALLOWED;
}
- for (size_t i = 0; i < le_connect_list_.size(); i++) {
- auto curr = le_connect_list_[i];
- if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) {
+ for (size_t i = 0; i < le_resolving_list_.size(); i++) {
+ auto curr = le_resolving_list_[i];
+ if (curr.address == addr && curr.address_type == addr_type) {
le_resolving_list_.erase(le_resolving_list_.begin() + i);
}
}
return ErrorCode::SUCCESS;
}
-bool LinkLayerController::LeFilterAcceptListContainsDevice(Address addr,
- uint8_t addr_type) {
- std::tuple<Address, uint8_t> sought_tuple = std::make_tuple(addr, addr_type);
+bool LinkLayerController::LeFilterAcceptListContainsDevice(
+ Address addr, AddressType addr_type) {
for (size_t i = 0; i < le_connect_list_.size(); i++) {
- if (le_connect_list_[i] == sought_tuple) {
+ if (le_connect_list_[i].address == addr &&
+ le_connect_list_[i].address_type == addr_type) {
return true;
}
}
@@ -3636,10 +3678,10 @@
}
bool LinkLayerController::LeResolvingListContainsDevice(Address addr,
- uint8_t addr_type) {
+ AddressType addr_type) {
for (size_t i = 0; i < le_connect_list_.size(); i++) {
auto curr = le_connect_list_[i];
- if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) {
+ if (curr.address == addr && curr.address_type == addr_type) {
return true;
}
}
diff --git a/tools/rootcanal/model/controller/link_layer_controller.h b/tools/rootcanal/model/controller/link_layer_controller.h
index 9bd55f4..4643e7b 100644
--- a/tools/rootcanal/model/controller/link_layer_controller.h
+++ b/tools/rootcanal/model/controller/link_layer_controller.h
@@ -29,6 +29,7 @@
namespace rootcanal {
using ::bluetooth::hci::Address;
+using ::bluetooth::hci::AddressType;
using ::bluetooth::hci::ErrorCode;
using ::bluetooth::hci::OpCode;
@@ -188,20 +189,20 @@
bool FilterAcceptListBusy();
ErrorCode LeFilterAcceptListClear();
- ErrorCode LeFilterAcceptListAddDevice(Address addr, uint8_t addr_type);
- ErrorCode LeFilterAcceptListRemoveDevice(Address addr, uint8_t addr_type);
- bool LeFilterAcceptListContainsDevice(Address addr, uint8_t addr_type);
+ ErrorCode LeFilterAcceptListAddDevice(Address addr, AddressType addr_type);
+ ErrorCode LeFilterAcceptListRemoveDevice(Address addr, AddressType addr_type);
+ bool LeFilterAcceptListContainsDevice(Address addr, AddressType addr_type);
bool LeFilterAcceptListFull();
bool ResolvingListBusy();
ErrorCode LeSetAddressResolutionEnable(bool enable);
ErrorCode LeResolvingListClear();
- ErrorCode LeResolvingListAddDevice(Address addr, uint8_t addr_type,
+ ErrorCode LeResolvingListAddDevice(Address addr, AddressType addr_type,
std::array<uint8_t, kIrkSize> peerIrk,
std::array<uint8_t, kIrkSize> localIrk);
- ErrorCode LeResolvingListRemoveDevice(Address addr, uint8_t addr_type);
- bool LeResolvingListContainsDevice(Address addr, uint8_t addr_type);
+ ErrorCode LeResolvingListRemoveDevice(Address addr, AddressType addr_type);
+ bool LeResolvingListContainsDevice(Address addr, AddressType addr_type);
bool LeResolvingListFull();
- void LeSetPrivacyMode(uint8_t address_type, Address addr, uint8_t mode);
+ void LeSetPrivacyMode(AddressType address_type, Address addr, uint8_t mode);
void LeReadIsoTxSync(uint16_t handle);
void LeSetCigParameters(
@@ -367,6 +368,8 @@
uint8_t retransmission_effort, uint16_t packet_types);
ErrorCode RejectSynchronousConnection(Address bd_addr, uint16_t reason);
+ bool HasAclConnection();
+
void HandleIso(bluetooth::hci::IsoView iso);
protected:
@@ -480,10 +483,14 @@
uint32_t key_id_ = 1;
// LE state
- std::vector<std::tuple<Address, uint8_t>> le_connect_list_;
+ struct ConnectListEntry {
+ Address address;
+ AddressType address_type;
+ };
+ std::vector<ConnectListEntry> le_connect_list_;
struct ResolvingListEntry {
Address address;
- uint8_t address_type;
+ AddressType address_type;
std::array<uint8_t, kIrkSize> peer_irk;
std::array<uint8_t, kIrkSize> local_irk;
};