diff options
author | Rob Seymour <rseymour@google.com> | 2022-04-02 03:52:13 +0000 |
---|---|---|
committer | Rob Seymour <rseymour@google.com> | 2022-04-02 04:01:22 +0000 |
commit | 4c7dc59bef24cc991251f9a7924ceada90c6bd63 (patch) | |
tree | a90550aa3ce1bc5e002ab6444c96954deca81af0 | |
parent | 6fa2bea006b362a285f744f65f15b5902e55797a (diff) | |
parent | dd4d23c4e1de011f8cd4eb132422172d5e283a73 (diff) |
Merge TP1A.220328.001
Change-Id: I5f07094ba2fb3991da03673f97d2957b1f68018b
196 files changed, 4821 insertions, 1731 deletions
diff --git a/android/app/Android.bp b/android/app/Android.bp index 0a765f03a0..21b93717aa 100644 --- a/android/app/Android.bp +++ b/android/app/Android.bp @@ -87,6 +87,7 @@ android_app { ], platform_apis: true, certificate: "platform", + aaptflags: [ "--custom-package", "com.android.bluetooth" ], jni_libs: ["libbluetooth_jni"], libs: [ diff --git a/android/app/AndroidManifest.xml b/android/app/AndroidManifest.xml index 6613470e34..50225ae84d 100644 --- a/android/app/AndroidManifest.xml +++ b/android/app/AndroidManifest.xml @@ -1,10 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.bluetooth" - android:sharedUserId="android.uid.bluetooth"> - - <original-package android:name="com.android.bluetooth"/> + package="com.android.bluetooth.services" + android:sharedUserId="android.uid.bluetooth"> <!-- Allows access to the Bluetooth Share Manager --> <permission android:name="android.permission.ACCESS_BLUETOOTH_SHARE" @@ -84,7 +82,7 @@ <!-- For PBAP Owner Vcard Info --> <uses-permission android:name="android.permission.READ_PROFILE"/> - <application android:name=".btservice.AdapterApp" + <application android:name="com.android.bluetooth.btservice.AdapterApp" android:icon="@mipmap/bt_share" android:persistent="false" android:label="@string/app_name" @@ -93,14 +91,14 @@ android:directBootAware="true" android:defaultToDeviceProtectedStorage="true" android:memtagMode="async"> - <provider android:name=".opp.BluetoothOppProvider" + <provider android:name="com.android.bluetooth.opp.BluetoothOppProvider" android:authorities="com.android.bluetooth.opp" android:exported="true" android:process="@string/process"> <path-permission android:pathPrefix="/btopp" android:permission="android.permission.ACCESS_BLUETOOTH_SHARE"/> </provider> - <provider android:name=".opp.BluetoothOppFileProvider" + <provider android:name="com.android.bluetooth.opp.BluetoothOppFileProvider" android:authorities="com.android.bluetooth.opp.fileprovider" android:grantUriPermissions="true" android:exported="false"> @@ -108,7 +106,7 @@ android:resource="@xml/file_paths"/> </provider> <service android:process="@string/process" - android:name=".btservice.AdapterService" + android:name="com.android.bluetooth.btservice.AdapterService" android:exported="true" android:permission="android.permission.ACCESS_BLUETOOTH_SHARE"> <intent-filter> @@ -116,19 +114,19 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".opp.BluetoothOppService" + android:name="com.android.bluetooth.opp.BluetoothOppService" android:permission="android.permission.ACCESS_BLUETOOTH_SHARE" android:enabled="@bool/profile_supported_opp"/> <receiver android:process="@string/process" android:exported="true" - android:name=".opp.BluetoothOppReceiver" + android:name="com.android.bluetooth.opp.BluetoothOppReceiver" android:enabled="@bool/profile_supported_opp"> <intent-filter> <action android:name="android.btopp.intent.action.OPEN_RECEIVED_FILES"/> </intent-filter> </receiver> <receiver android:process="@string/process" - android:name=".opp.BluetoothOppHandoverReceiver" + android:name="com.android.bluetooth.opp.BluetoothOppHandoverReceiver" android:permission="com.android.permission.ALLOWLIST_BLUETOOTH_DEVICE" android:exported="true"> <intent-filter> @@ -146,7 +144,7 @@ <data android:mimeType="*/*"/> </intent-filter> </receiver> - <activity android:name=".opp.BluetoothOppLauncherActivity" + <activity android:name="com.android.bluetooth.opp.BluetoothOppLauncherActivity" android:process="@string/process" android:theme="@android:style/Theme.Material.Light.Dialog" android:label="@string/bt_share_picker_label" @@ -188,36 +186,36 @@ <data android:mimeType="vnd.android.cursor.item/vnd.android.btopp"/> </intent-filter> </activity> - <activity android:name=".opp.BluetoothOppBtEnableActivity" + <activity android:name="com.android.bluetooth.opp.BluetoothOppBtEnableActivity" android:process="@string/process" android:excludeFromRecents="true" android:theme="@style/dialog" android:enabled="@bool/profile_supported_opp"> </activity> - <activity android:name=".opp.BluetoothOppBtErrorActivity" + <activity android:name="com.android.bluetooth.opp.BluetoothOppBtErrorActivity" android:process="@string/process" android:excludeFromRecents="true" android:theme="@style/dialog"> </activity> - <activity android:name=".opp.BluetoothOppBtEnablingActivity" + <activity android:name="com.android.bluetooth.opp.BluetoothOppBtEnablingActivity" android:process="@string/process" android:excludeFromRecents="true" android:theme="@style/dialog" android:enabled="@bool/profile_supported_opp"> </activity> - <activity android:name=".opp.BluetoothOppIncomingFileConfirmActivity" + <activity android:name="com.android.bluetooth.opp.BluetoothOppIncomingFileConfirmActivity" android:process="@string/process" android:excludeFromRecents="true" android:theme="@style/dialog" android:enabled="@bool/profile_supported_opp"> </activity> - <activity android:name=".opp.BluetoothOppTransferActivity" + <activity android:name="com.android.bluetooth.opp.BluetoothOppTransferActivity" android:process="@string/process" android:excludeFromRecents="true" android:theme="@style/dialog" android:enabled="@bool/profile_supported_opp"> </activity> - <activity android:name=".opp.BluetoothOppTransferHistory" + <activity android:name="com.android.bluetooth.opp.BluetoothOppTransferHistory" android:process="@string/process" android:label="" android:excludeFromRecents="true" @@ -230,7 +228,7 @@ <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity> - <activity android:name=".pbap.BluetoothPbapActivity" + <activity android:name="com.android.bluetooth.pbap.BluetoothPbapActivity" android:process="@string/process" android:excludeFromRecents="true" android:theme="@style/dialog" @@ -238,7 +236,7 @@ </activity> <service android:process="@string/process" android:permission="android.permission.BLUETOOTH_PRIVILEGED" - android:name=".pbap.BluetoothPbapService" + android:name="com.android.bluetooth.pbap.BluetoothPbapService" android:enabled="@bool/profile_supported_pbap" android:exported="true"> <intent-filter> @@ -246,7 +244,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".map.BluetoothMapService" + android:name="com.android.bluetooth.map.BluetoothMapService" android:enabled="@bool/profile_supported_map" android:exported="true"> <intent-filter> @@ -255,21 +253,21 @@ <action android:name="com.android.bluetooth.map.USER_CONFIRM_TIMEOUT"/> </intent-filter> </service> - <activity android:name=".map.BluetoothMapSettings" + <activity android:name="com.android.bluetooth.map.BluetoothMapSettings" android:process="@string/process" android:label="@string/bluetooth_map_settings_title" android:excludeFromRecents="true" android:configChanges="orientation|keyboardHidden" android:enabled="@bool/profile_supported_map"> </activity> - <provider android:name=".map.MmsFileProvider" + <provider android:name="com.android.bluetooth.map.MmsFileProvider" android:authorities="com.android.bluetooth.map.MmsFileProvider" android:enabled="true" android:grantUriPermissions="true" android:exported="false"> </provider> <service android:process="@string/process" - android:name=".mapclient.MapClientService" + android:name="com.android.bluetooth.mapclient.MapClientService" android:enabled="@bool/profile_supported_mapmce" android:exported="true"> <intent-filter> @@ -277,7 +275,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".sap.SapService" + android:name="com.android.bluetooth.sap.SapService" android:enabled="@bool/profile_supported_sap" android:exported="true"> <intent-filter> @@ -285,7 +283,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".gatt.GattService" + android:name="com.android.bluetooth.gatt.GattService" android:enabled="@bool/profile_supported_gatt" android:exported="true" android:permission="android.permission.ACCESS_BLUETOOTH_SHARE"> @@ -294,7 +292,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".hfp.HeadsetService" + android:name="com.android.bluetooth.hfp.HeadsetService" android:enabled="@bool/profile_supported_hs_hfp" android:exported="true"> <intent-filter> @@ -302,7 +300,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".a2dp.A2dpService" + android:name="com.android.bluetooth.a2dp.A2dpService" android:enabled="@bool/profile_supported_a2dp" android:exported="true"> <intent-filter> @@ -310,7 +308,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".a2dpsink.A2dpSinkService" + android:name="com.android.bluetooth.a2dpsink.A2dpSinkService" android:enabled="@bool/profile_supported_a2dp_sink" android:exported="true"> <intent-filter> @@ -318,7 +316,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".avrcpcontroller.BluetoothMediaBrowserService" + android:name="com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService" android:exported="true" android:enabled="@bool/profile_supported_a2dp_sink" android:label="@string/a2dp_sink_mbs_label"> @@ -327,7 +325,7 @@ </intent-filter> </service> - <activity android:name=".BluetoothPrefs" + <activity android:name="com.android.bluetooth.BluetoothPrefs" android:exported="@bool/profile_supported_a2dp_sink" android:enabled="@bool/profile_supported_a2dp_sink"> <intent-filter> @@ -336,7 +334,7 @@ </activity> <service android:process="@string/process" - android:name=".avrcp.AvrcpTargetService" + android:name="com.android.bluetooth.avrcp.AvrcpTargetService" android:enabled="@bool/profile_supported_avrcp_target" android:exported="true"> <intent-filter> @@ -344,7 +342,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".avrcpcontroller.AvrcpControllerService" + android:name="com.android.bluetooth.avrcpcontroller.AvrcpControllerService" android:enabled="@bool/profile_supported_avrcp_controller" android:exported="true"> <intent-filter> @@ -352,14 +350,14 @@ </intent-filter> </service> <provider android:process="@string/process" - android:name=".avrcpcontroller.AvrcpCoverArtProvider" + android:name="com.android.bluetooth.avrcpcontroller.AvrcpCoverArtProvider" android:authorities="com.android.bluetooth.avrcpcontroller.AvrcpCoverArtProvider" android:enabled="@bool/avrcp_controller_enable_cover_art" android:grantUriPermissions="true" android:exported="true"> </provider> <service android:process="@string/process" - android:name=".hid.HidHostService" + android:name="com.android.bluetooth.hid.HidHostService" android:enabled="@bool/profile_supported_hid_host" android:exported="true"> <intent-filter> @@ -367,7 +365,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".hid.HidDeviceService" + android:name="com.android.bluetooth.hid.HidDeviceService" android:enabled="@bool/profile_supported_hid_device" android:exported="true"> <intent-filter> @@ -375,7 +373,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".mcp.McpService" + android:name="com.android.bluetooth.mcp.McpService" android:exported="true" android:enabled="@bool/profile_supported_mcp_server"> <intent-filter> @@ -384,7 +382,7 @@ </service> <service android:process="@string/process" - android:name=".pan.PanService" + android:name="com.android.bluetooth.pan.PanService" android:enabled="@bool/profile_supported_pan" android:exported="true"> <intent-filter> @@ -392,7 +390,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".hfpclient.HeadsetClientService" + android:name="com.android.bluetooth.hfpclient.HeadsetClientService" android:enabled="@bool/profile_supported_hfpclient" android:exported="true"> <intent-filter> @@ -400,7 +398,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".hfpclient.HfpClientConnectionService" + android:name="com.android.bluetooth.hfpclient.HfpClientConnectionService" android:permission="android.permission.BIND_CONNECTION_SERVICE" android:enabled="@bool/hfp_client_connection_service_enabled" android:exported="true"> @@ -410,7 +408,7 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".pbapclient.PbapClientService" + android:name="com.android.bluetooth.pbapclient.PbapClientService" android:enabled="@bool/profile_supported_pbapclient" android:exported="true"> <intent-filter> @@ -418,14 +416,14 @@ </intent-filter> </service> <service android:process="@string/process" - android:name=".hearingaid.HearingAidService" + android:name="com.android.bluetooth.hearingaid.HearingAidService" android:exported="true"> <intent-filter> <action android:name="android.bluetooth.IBluetoothHearingAid"/> </intent-filter> </service> <service android:process="@string/process" - android:name=".hap.HapClientService" + android:name="com.android.bluetooth.hap.HapClientService" android:enabled="@bool/profile_supported_hap_client" android:exported="true"> <intent-filter> @@ -434,7 +432,7 @@ </service> <service android:process="@string/process" - android:name=".vc.VolumeControlService" + android:name="com.android.bluetooth.vc.VolumeControlService" android:exported="true" android:enabled="@bool/profile_supported_vc"> <intent-filter> @@ -443,7 +441,7 @@ </service> <service android:process="@string/process" - android:name = ".le_audio.LeAudioService" + android:name = "com.android.bluetooth.le_audio.LeAudioService" android:enabled="@bool/profile_supported_le_audio" android:exported = "true"> <intent-filter> @@ -452,7 +450,7 @@ </service> <service android:process="@string/process" - android:name = ".csip.CsipSetCoordinatorService" + android:name = "com.android.bluetooth.csip.CsipSetCoordinatorService" android:enabled="@bool/profile_supported_csip_set_coordinator" android:exported = "true"> <intent-filter> @@ -461,7 +459,7 @@ </service> <service android:process="@string/process" - android:name = ".tbs.TbsService" + android:name = "com.android.bluetooth.tbs.TbsService" android:enabled="@bool/profile_supported_le_call_control" android:exported = "true"> <intent-filter> @@ -470,7 +468,7 @@ </service> <service android:process="@string/process" - android:name = ".bass_client.BassClientService" + android:name = "com.android.bluetooth.bass_client.BassClientService" android:enabled="@bool/profile_supported_bass_client" android:exported = "true"> <intent-filter> @@ -479,7 +477,7 @@ </service> <!-- Authenticator for PBAP account. --> <service android:process="@string/process" - android:name=".pbapclient.AuthenticationService" + android:name="com.android.bluetooth.pbapclient.AuthenticationService" android:exported="true" android:enabled="@bool/profile_supported_pbapclient"> <intent-filter> @@ -489,7 +487,7 @@ android:resource="@xml/authenticator"/> </service> <service - android:name=".telephony.BluetoothInCallService" + android:name="com.android.bluetooth.telephony.BluetoothInCallService" android:permission="android.permission.BIND_INCALL_SERVICE" android:process="@string/process" android:enabled="@bool/profile_supported_hfp_incallservice" @@ -502,7 +500,7 @@ </service> <service android:process="@string/process" - android:name=".bas.BatteryService" + android:name="com.android.bluetooth.bas.BatteryService" android:enabled="@bool/profile_supported_battery" android:exported = "true"> <intent-filter> diff --git a/android/app/jni/com_android_bluetooth_le_audio.cpp b/android/app/jni/com_android_bluetooth_le_audio.cpp index 61cb49a966..45111b54ba 100644 --- a/android/app/jni/com_android_bluetooth_le_audio.cpp +++ b/android/app/jni/com_android_bluetooth_le_audio.cpp @@ -491,7 +491,6 @@ static JNINativeMethod sMethods[] = { static jmethodID method_onBroadcastCreated; static jmethodID method_onBroadcastDestroyed; static jmethodID method_onBroadcastStateChanged; -static jmethodID method_onBroadcastId; static LeAudioBroadcasterInterface* sLeAudioBroadcasterInterface = nullptr; static std::shared_timed_mutex sBroadcasterInterfaceMutex; @@ -503,7 +502,7 @@ class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks { public: ~LeAudioBroadcasterCallbacksImpl() = default; - void OnBroadcastCreated(uint8_t instance_id, bool success) override { + void OnBroadcastCreated(uint32_t broadcast_id, bool success) override { LOG(INFO) << __func__; std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex); @@ -511,11 +510,11 @@ class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks { if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return; sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj, - method_onBroadcastCreated, (jint)instance_id, + method_onBroadcastCreated, (jint)broadcast_id, success ? JNI_TRUE : JNI_FALSE); } - void OnBroadcastDestroyed(uint8_t instance_id) override { + void OnBroadcastDestroyed(uint32_t broadcast_id) override { LOG(INFO) << __func__; std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex); @@ -524,10 +523,10 @@ class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks { if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return; sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj, method_onBroadcastDestroyed, - (jint)instance_id); + (jint)broadcast_id); } - void OnBroadcastStateChanged(uint8_t instance_id, + void OnBroadcastStateChanged(uint32_t broadcast_id, BroadcastState state) override { LOG(INFO) << __func__; @@ -537,35 +536,9 @@ class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks { if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return; sCallbackEnv->CallVoidMethod( sBroadcasterCallbacksObj, method_onBroadcastStateChanged, - (jint)instance_id, + (jint)broadcast_id, (jint) static_cast<std::underlying_type<BroadcastState>::type>(state)); } - - void OnBroadcastId(uint8_t instance_id, - const BroadcastId& broadcast_id) override { - LOG(INFO) << __func__; - - std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex); - CallbackEnv sCallbackEnv(__func__); - - // broadcast_id - int field_size = broadcast_id.size(); - ScopedLocalRef<jbyteArray> serialized_broadcast_id( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(field_size)); - if (!serialized_broadcast_id.get()) { - LOG(ERROR) << "Failed to allocate new jbyteArray broadcast_id for the " - "announcement"; - return; - } - - sCallbackEnv->SetByteArrayRegion(serialized_broadcast_id.get(), 0, - field_size, (jbyte*)broadcast_id.data()); - - if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return; - sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj, method_onBroadcastId, - (jint)instance_id, - serialized_broadcast_id.get()); - } }; static LeAudioBroadcasterCallbacksImpl sLeAudioBroadcasterCallbacks; @@ -577,7 +550,6 @@ static void BroadcasterClassInitNative(JNIEnv* env, jclass clazz) { env->GetMethodID(clazz, "onBroadcastDestroyed", "(I)V"); method_onBroadcastStateChanged = env->GetMethodID(clazz, "onBroadcastStateChanged", "(II)V"); - method_onBroadcastId = env->GetMethodID(clazz, "onBroadcastId", "(I[B)V"); } static void BroadcasterInitNative(JNIEnv* env, jobject object) { @@ -672,52 +644,45 @@ static void CreateBroadcastNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(metadata, meta, 0); } -static void UpdateMetadataNative(JNIEnv* env, jobject object, jint instance_id, +static void UpdateMetadataNative(JNIEnv* env, jobject object, jint broadcast_id, jbyteArray metadata) { jbyte* meta = env->GetByteArrayElements(metadata, nullptr); sLeAudioBroadcasterInterface->UpdateMetadata( - instance_id, + broadcast_id, std::vector<uint8_t>(meta, meta + env->GetArrayLength(metadata))); env->ReleaseByteArrayElements(metadata, meta, 0); } static void StartBroadcastNative(JNIEnv* env, jobject object, - jint instance_id) { + jint broadcast_id) { LOG(INFO) << __func__; std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex); if (!sLeAudioBroadcasterInterface) return; - sLeAudioBroadcasterInterface->StartBroadcast(instance_id); + sLeAudioBroadcasterInterface->StartBroadcast(broadcast_id); } -static void StopBroadcastNative(JNIEnv* env, jobject object, jint instance_id) { +static void StopBroadcastNative(JNIEnv* env, jobject object, + jint broadcast_id) { LOG(INFO) << __func__; std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex); if (!sLeAudioBroadcasterInterface) return; - sLeAudioBroadcasterInterface->StopBroadcast(instance_id); + sLeAudioBroadcasterInterface->StopBroadcast(broadcast_id); } static void PauseBroadcastNative(JNIEnv* env, jobject object, - jint instance_id) { + jint broadcast_id) { LOG(INFO) << __func__; std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex); if (!sLeAudioBroadcasterInterface) return; - sLeAudioBroadcasterInterface->PauseBroadcast(instance_id); + sLeAudioBroadcasterInterface->PauseBroadcast(broadcast_id); } static void DestroyBroadcastNative(JNIEnv* env, jobject object, - jint instance_id) { - LOG(INFO) << __func__; - std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex); - if (!sLeAudioBroadcasterInterface) return; - sLeAudioBroadcasterInterface->DestroyBroadcast(instance_id); -} - -static void GetBroadcastIdNative(JNIEnv* env, jobject object, - jint instance_id) { + jint broadcast_id) { LOG(INFO) << __func__; std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex); if (!sLeAudioBroadcasterInterface) return; - sLeAudioBroadcasterInterface->GetBroadcastId(instance_id); + sLeAudioBroadcasterInterface->DestroyBroadcast(broadcast_id); } static void GetAllBroadcastStatesNative(JNIEnv* env, jobject object) { @@ -738,7 +703,6 @@ static JNINativeMethod sBroadcasterMethods[] = { {"stopBroadcastNative", "(I)V", (void*)StopBroadcastNative}, {"pauseBroadcastNative", "(I)V", (void*)PauseBroadcastNative}, {"destroyBroadcastNative", "(I)V", (void*)DestroyBroadcastNative}, - {"getBroadcastIdNative", "(I)V", (void*)GetBroadcastIdNative}, {"getAllBroadcastStatesNative", "()V", (void*)GetAllBroadcastStatesNative}, }; diff --git a/android/app/res/values-fa/strings.xml b/android/app/res/values-fa/strings.xml index e16bda920e..70c818e3c7 100644 --- a/android/app/res/values-fa/strings.xml +++ b/android/app/res/values-fa/strings.xml @@ -51,7 +51,7 @@ <string name="download_line3" msgid="6722284930665532816">"اندازه فایل: <xliff:g id="SIZE">%1$s</xliff:g>"</string> <string name="download_line4" msgid="5234701398884321314"></string> <string name="download_line5" msgid="4124272066218470715">"درحال دریافت فایل…"</string> - <string name="download_cancel" msgid="1705762428762702342">"توقف"</string> + <string name="download_cancel" msgid="1705762428762702342">"متوقف کردن"</string> <string name="download_ok" msgid="2404442707314575833">"پنهان کردن"</string> <string name="incoming_line1" msgid="6342300988329482408">"از"</string> <string name="incoming_line2" msgid="2199520895444457585">"نام فایل"</string> diff --git a/android/app/res/values-hy/strings.xml b/android/app/res/values-hy/strings.xml index 4a259944a2..98b9472381 100644 --- a/android/app/res/values-hy/strings.xml +++ b/android/app/res/values-hy/strings.xml @@ -51,7 +51,7 @@ <string name="download_line3" msgid="6722284930665532816">"Ֆայլի չափը՝ <xliff:g id="SIZE">%1$s</xliff:g>"</string> <string name="download_line4" msgid="5234701398884321314"></string> <string name="download_line5" msgid="4124272066218470715">"Ֆայլի ստացում..."</string> - <string name="download_cancel" msgid="1705762428762702342">"Դադարեցնել"</string> + <string name="download_cancel" msgid="1705762428762702342">"Կանգնեցնել"</string> <string name="download_ok" msgid="2404442707314575833">"Թաքցնել"</string> <string name="incoming_line1" msgid="6342300988329482408">"Ումից"</string> <string name="incoming_line2" msgid="2199520895444457585">"Ֆայլի անունը"</string> diff --git a/android/app/res/values/config.xml b/android/app/res/values/config.xml index 092860759f..bd4c838049 100644 --- a/android/app/res/values/config.xml +++ b/android/app/res/values/config.xml @@ -39,7 +39,7 @@ <bool name="profile_supported_csip_set_coordinator">true</bool> <bool name="profile_supported_le_call_control">true</bool> <bool name="profile_supported_hap_client">true</bool> - <bool name="profile_supported_bass_client">false</bool> + <bool name="profile_supported_bass_client">true</bool> <bool name="profile_supported_battery">true</bool> <!-- If true, we will require location to be enabled on the device to diff --git a/android/app/src/com/android/bluetooth/Utils.java b/android/app/src/com/android/bluetooth/Utils.java index fb0be8ea83..b063de0cef 100644 --- a/android/app/src/com/android/bluetooth/Utils.java +++ b/android/app/src/com/android/bluetooth/Utils.java @@ -844,12 +844,26 @@ public final class Utils { android.Manifest.permission.WRITE_SMS) == PackageManager.PERMISSION_GRANTED; } - public static boolean isQApp(Context context, String pkgName) { + /** + * Checks that the target sdk of the app corresponding to the provided package name is greater + * than or equal to the passed in target sdk. + * <p> + * For example, if the calling app has target SDK {@link Build.VERSION_CODES#S} and we pass in + * the targetSdk {@link Build.VERSION_CODES#R}, the API will return true because S >= R. + * + * @param context Bluetooth service context + * @param pkgName caller's package name + * @param expectedMinimumTargetSdk one of the values from {@link Build.VERSION_CODES} + * @return {@code true} if the caller's target sdk is greater than or equal to + * expectedMinimumTargetSdk, {@code false} otherwise + */ + public static boolean checkCallerTargetSdk(Context context, String pkgName, + int expectedMinimumTargetSdk) { try { return context.getPackageManager().getApplicationInfo(pkgName, 0).targetSdkVersion - >= Build.VERSION_CODES.Q; + >= expectedMinimumTargetSdk; } catch (PackageManager.NameNotFoundException e) { - // In case of exception, assume Q app + // In case of exception, assume true } return true; } diff --git a/android/app/src/com/android/bluetooth/avrcp/AvrcpVolumeManager.java b/android/app/src/com/android/bluetooth/avrcp/AvrcpVolumeManager.java index 39f1f14975..d0cfa58fbc 100644 --- a/android/app/src/com/android/bluetooth/avrcp/AvrcpVolumeManager.java +++ b/android/app/src/com/android/bluetooth/avrcp/AvrcpVolumeManager.java @@ -176,7 +176,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { void setVolume(@NonNull BluetoothDevice device, int avrcpVolume) { int deviceVolume = - (int) Math.floor((double) avrcpVolume * sDeviceMaxVolume / AVRCP_MAX_VOL); + (int) Math.round((double) avrcpVolume * sDeviceMaxVolume / AVRCP_MAX_VOL); mVolumeEventLogger.logd(DEBUG, TAG, "setVolume:" + " device=" + device + " avrcpVolume=" + avrcpVolume @@ -194,7 +194,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { return; } int avrcpVolume = - (int) Math.floor((double) deviceVolume * AVRCP_MAX_VOL / sDeviceMaxVolume); + (int) Math.round((double) deviceVolume * AVRCP_MAX_VOL / sDeviceMaxVolume); if (avrcpVolume > 127) avrcpVolume = 127; mVolumeEventLogger.logd(DEBUG, TAG, "sendVolumeChanged:" + " device=" + device diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java b/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java index d58969af49..0c4cc1d86a 100644 --- a/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java +++ b/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java @@ -949,8 +949,7 @@ class AdapterProperties { case AbstractionLayer.BT_PROPERTY_LOCAL_LE_FEATURES: updateFeatureSupport(val); - mService.updateLeAudioProfileServiceState( - mIsLeConnectedIsochronousStreamCentralSupported); + mService.updateLeAudioProfileServiceState(); break; case AbstractionLayer.BT_PROPERTY_DYNAMIC_AUDIO_BUFFER: diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterService.java b/android/app/src/com/android/bluetooth/btservice/AdapterService.java index e6c03e21bf..ff5b89d106 100644 --- a/android/app/src/com/android/bluetooth/btservice/AdapterService.java +++ b/android/app/src/com/android/bluetooth/btservice/AdapterService.java @@ -76,6 +76,7 @@ import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.BatteryStatsManager; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -211,7 +212,7 @@ public class AdapterService extends Service { private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30; private static final ComponentName BLUETOOTH_INCALLSERVICE_COMPONENT = - new ComponentName("com.android.bluetooth", + new ComponentName("com.android.bluetooth.services", BluetoothInCallService.class.getCanonicalName()); public static final String ACTIVITY_ATTRIBUTION_NO_ACTIVE_DEVICE_ADDRESS = @@ -741,19 +742,27 @@ public class AdapterService extends Service { BluetoothAdapter.invalidateBluetoothGetStateCache(); } - void updateLeAudioProfileServiceState(boolean isCisCentralSupported) { - if (isCisCentralSupported) { - return; + void updateLeAudioProfileServiceState() { + HashSet<Class> nonSupportedProfiles = new HashSet<>(); + + if (!isLeConnectedIsochronousStreamCentralSupported()) { + nonSupportedProfiles.addAll(Config.geLeAudioUnicastProfiles()); + } + + if (!isLeAudioBroadcastAssistantSupported()) { + nonSupportedProfiles.add(BassClientService.class); } - // Remove the Le audio unicast profiles from the supported list - // since the controller doesn't support - Config.removeLeAudioUnicastProfilesFromSupportedList(); - HashSet<Class> leAudioUnicastProfiles = Config.geLeAudioUnicastProfiles(); + if (!nonSupportedProfiles.isEmpty()) { + // Remove non-supported profiles from the supported list + // since the controller doesn't support + Config.removeProfileFromSupportedList(nonSupportedProfiles); - for (Class profileService : leAudioUnicastProfiles) { - if (isStartedProfile(profileService.getSimpleName())){ - setProfileServiceState(profileService, BluetoothAdapter.STATE_OFF); + // Disable the non-supported profiles service + for (Class profileService : nonSupportedProfiles) { + if (isStartedProfile(profileService.getSimpleName())) { + setProfileServiceState(profileService, BluetoothAdapter.STATE_OFF); + } } } } @@ -3421,7 +3430,10 @@ public class AdapterService extends Service { return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } - if (service.isLeAudioBroadcastAssistantSupported()) { + HashSet<Class> supportedProfileServices = + new HashSet<Class>(Arrays.asList(Config.getSupportedProfiles())); + + if (supportedProfileServices.contains(BassClientService.class)) { return BluetoothStatusCodes.FEATURE_SUPPORTED; } @@ -3830,7 +3842,7 @@ public class AdapterService extends Service { debugLog("startDiscovery"); String callingPackage = attributionSource.getPackageName(); mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); - boolean isQApp = Utils.isQApp(this, callingPackage); + boolean isQApp = Utils.checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.Q); boolean hasDisavowedLocation = Utils.hasDisavowedLocationForScan(this, attributionSource, mTestModeEnabled); String permission = null; @@ -4643,13 +4655,21 @@ public class AdapterService extends Service { * @return true, if the LE audio broadcast assistant is supported */ public boolean isLeAudioBroadcastAssistantSupported() { - //TODO: check the profile support status as well after we have the implementation return mAdapterProperties.isLePeriodicAdvertisingSupported() && mAdapterProperties.isLeExtendedAdvertisingSupported() && (mAdapterProperties.isLePeriodicAdvertisingSyncTransferSenderSupported() || mAdapterProperties.isLePeriodicAdvertisingSyncTransferRecipientSupported()); } + /** + * Check if the LE audio CIS central feature is supported. + * + * @return true, if the LE audio CIS central is supported + */ + public boolean isLeConnectedIsochronousStreamCentralSupported() { + return mAdapterProperties.isLeConnectedIsochronousStreamCentralSupported(); + } + public int getLeMaximumAdvertisingDataLength() { return mAdapterProperties.getLeMaximumAdvertisingDataLength(); } diff --git a/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java b/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java index be2f5a6c4d..d2a9fd3458 100644 --- a/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java +++ b/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java @@ -148,7 +148,7 @@ final class BondStateMachine extends StateMachine { int newState = msg.arg1; /* if incoming pairing, transition to pending state */ if (newState == BluetoothDevice.BOND_BONDING) { - sendIntent(dev, newState, 0); + deferMessage(msg); transitionTo(mPendingCommandState); } else if (newState == BluetoothDevice.BOND_NONE) { /* if the link key was deleted by the stack */ diff --git a/android/app/src/com/android/bluetooth/btservice/Config.java b/android/app/src/com/android/bluetooth/btservice/Config.java index 85884b0fe3..718fabdb20 100644 --- a/android/app/src/com/android/bluetooth/btservice/Config.java +++ b/android/app/src/com/android/bluetooth/btservice/Config.java @@ -199,16 +199,16 @@ public class Config { } /** - * Remove LE audio unicast related profiles from the supported list. + * Remove the input profiles from the supported list. */ - static void removeLeAudioUnicastProfilesFromSupportedList() { + static void removeProfileFromSupportedList(HashSet<Class> nonSupportedProfiles) { ArrayList<Class> profilesList = new ArrayList<Class>(Arrays.asList(sSupportedProfiles)); Iterator<Class> iter = profilesList.iterator(); while (iter.hasNext()) { Class profileClass = iter.next(); - if (mLeAudioUnicastProfiles.contains(profileClass)) { + if (nonSupportedProfiles.contains(profileClass)) { iter.remove(); Log.v(TAG, "Remove " + profileClass.getSimpleName() + " from supported list."); } diff --git a/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java b/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java index e8857e35ac..39f456cc07 100644 --- a/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java +++ b/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java @@ -205,7 +205,7 @@ public class MetricsLogger { private PendingIntent getDrainIntent() { Intent counterMetricsIntent = new Intent(BLUETOOTH_COUNTER_METRICS_ACTION); - counterMetricsIntent.setPackage("com.android.bluetooth"); + counterMetricsIntent.setPackage("com.android.bluetooth.services"); return PendingIntent.getBroadcast( mContext, 0, counterMetricsIntent, PendingIntent.FLAG_IMMUTABLE); } diff --git a/android/app/src/com/android/bluetooth/btservice/storage/CustomizedMetadataEntity.java b/android/app/src/com/android/bluetooth/btservice/storage/CustomizedMetadataEntity.java index 2bb71efea8..554e0753fc 100644 --- a/android/app/src/com/android/bluetooth/btservice/storage/CustomizedMetadataEntity.java +++ b/android/app/src/com/android/bluetooth/btservice/storage/CustomizedMetadataEntity.java @@ -44,6 +44,8 @@ class CustomizedMetadataEntity { public byte[] untethered_left_low_battery_threshold; public byte[] untethered_right_low_battery_threshold; public byte[] untethered_case_low_battery_threshold; + public byte[] spatial_audio; + public byte[] fastpair_customized; public String toString() { StringBuilder builder = new StringBuilder(); @@ -94,7 +96,11 @@ class CustomizedMetadataEntity { .append("|untethered_right_low_battery_threshold=") .append(metadataToString(untethered_right_low_battery_threshold)) .append("|untethered_case_low_battery_threshold=") - .append(metadataToString(untethered_case_low_battery_threshold)); + .append(metadataToString(untethered_case_low_battery_threshold)) + .append("|spatial_audio=") + .append(metadataToString(spatial_audio)) + .append("|fastpair_customized=") + .append(metadataToString(fastpair_customized)); return builder.toString(); } diff --git a/android/app/src/com/android/bluetooth/btservice/storage/Metadata.java b/android/app/src/com/android/bluetooth/btservice/storage/Metadata.java index 36d6b43cae..2b7f0d5809 100644 --- a/android/app/src/com/android/bluetooth/btservice/storage/Metadata.java +++ b/android/app/src/com/android/bluetooth/btservice/storage/Metadata.java @@ -254,6 +254,12 @@ class Metadata { case BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD: publicMetadata.untethered_case_low_battery_threshold = value; break; + case BluetoothDevice.METADATA_SPATIAL_AUDIO: + publicMetadata.spatial_audio = value; + break; + case BluetoothDevice.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS: + publicMetadata.fastpair_customized = value; + break; } } @@ -332,6 +338,12 @@ class Metadata { case BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD: value = publicMetadata.untethered_case_low_battery_threshold; break; + case BluetoothDevice.METADATA_SPATIAL_AUDIO: + value = publicMetadata.spatial_audio; + break; + case BluetoothDevice.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS: + value = publicMetadata.fastpair_customized; + break; } return value; } diff --git a/android/app/src/com/android/bluetooth/btservice/storage/MetadataDatabase.java b/android/app/src/com/android/bluetooth/btservice/storage/MetadataDatabase.java index 91338179f2..a2db277c0d 100644 --- a/android/app/src/com/android/bluetooth/btservice/storage/MetadataDatabase.java +++ b/android/app/src/com/android/bluetooth/btservice/storage/MetadataDatabase.java @@ -33,7 +33,7 @@ import java.util.List; /** * MetadataDatabase is a Room database stores Bluetooth persistence data */ -@Database(entities = {Metadata.class}, version = 112) +@Database(entities = {Metadata.class}, version = 113) public abstract class MetadataDatabase extends RoomDatabase { /** * The metadata database file name @@ -65,6 +65,7 @@ public abstract class MetadataDatabase extends RoomDatabase { .addMigrations(MIGRATION_109_110) .addMigrations(MIGRATION_110_111) .addMigrations(MIGRATION_111_112) + .addMigrations(MIGRATION_112_113) .allowMainThreadQueries() .build(); } @@ -465,4 +466,21 @@ public abstract class MetadataDatabase extends RoomDatabase { } } }; + + @VisibleForTesting + static final Migration MIGRATION_112_113 = new Migration(112, 113) { + @Override + public void migrate(SupportSQLiteDatabase database) { + try { + database.execSQL("ALTER TABLE metadata ADD COLUMN `spatial_audio` BLOB"); + database.execSQL("ALTER TABLE metadata ADD COLUMN `fastpair_customized` BLOB"); + } catch (SQLException ex) { + // Check if user has new schema, but is just missing the version update + Cursor cursor = database.query("SELECT * FROM metadata"); + if (cursor == null || cursor.getColumnIndex("spatial_audio") == -1) { + throw ex; + } + } + } + }; } diff --git a/android/app/src/com/android/bluetooth/gatt/ContextMap.java b/android/app/src/com/android/bluetooth/gatt/ContextMap.java index d4525327f1..ed95301ad6 100644 --- a/android/app/src/com/android/bluetooth/gatt/ContextMap.java +++ b/android/app/src/com/android/bluetooth/gatt/ContextMap.java @@ -95,9 +95,6 @@ import java.util.UUID; /** The user handle of the app that started the scan */ UserHandle mUserHandle; - /** Whether the calling app is targeting Q or better */ - boolean mIsQApp; - /** Whether the calling app has the network settings permission */ boolean mHasNetworkSettingsPermission; diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java index 2649ebf355..063b752f3f 100644 --- a/android/app/src/com/android/bluetooth/gatt/GattService.java +++ b/android/app/src/com/android/bluetooth/gatt/GattService.java @@ -16,6 +16,7 @@ package com.android.bluetooth.gatt; +import static com.android.bluetooth.Utils.checkCallerTargetSdk; import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission; import android.annotation.RequiresPermission; @@ -2308,8 +2309,8 @@ public class GattService extends ProfileService { try { permissionCheck(connId, handle); } catch (SecurityException ex) { - // Only throws on T+ as this is an older API and did not throw prior to T - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // Only throws on apps with target SDK T+ as this old API did not throw prior to T + if (checkCallerTargetSdk(this, app.name, Build.VERSION_CODES.TIRAMISU)) { throw ex; } Log.w(TAG, "onNotify() - permission check failed!"); @@ -2976,7 +2977,7 @@ public class GattService extends ProfileService { scanClient.hasDisavowedLocation = Utils.hasDisavowedLocationForScan(this, attributionSource, isTestModeEnabled()); - scanClient.isQApp = Utils.isQApp(this, callingPackage); + scanClient.isQApp = checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.Q); if (!scanClient.hasDisavowedLocation) { if (scanClient.isQApp) { scanClient.hasLocationPermission = Utils.checkCallerHasFineLocation( @@ -3052,10 +3053,9 @@ public class GattService extends ProfileService { app.mHasDisavowedLocation = Utils.hasDisavowedLocationForScan(this, attributionSource, isTestModeEnabled()); - app.mIsQApp = Utils.isQApp(this, callingPackage); if (!app.mHasDisavowedLocation) { try { - if (app.mIsQApp) { + if (checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.Q)) { app.hasLocationPermission = Utils.checkCallerHasFineLocation( this, attributionSource, app.mUserHandle); } else { @@ -3089,7 +3089,7 @@ public class GattService extends ProfileService { new ScanClient(scannerId, piInfo.settings, piInfo.filters); scanClient.hasLocationPermission = app.hasLocationPermission; scanClient.userHandle = app.mUserHandle; - scanClient.isQApp = app.mIsQApp; + scanClient.isQApp = checkCallerTargetSdk(this, app.name, Build.VERSION_CODES.Q); scanClient.eligibleForSanitizedExposureNotification = app.mEligibleForSanitizedExposureNotification; scanClient.hasNetworkSettingsPermission = app.mHasNetworkSettingsPermission; @@ -3556,8 +3556,9 @@ public class GattService extends ProfileService { try { permissionCheck(connId, handle); } catch (SecurityException ex) { - // Only throws on T+ as this is an older API and did not throw prior to T - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + String callingPackage = attributionSource.getPackageName(); + // Only throws on apps with target SDK T+ as this old API did not throw prior to T + if (checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.TIRAMISU)) { throw ex; } Log.w(TAG, "readCharacteristic() - permission check failed!"); @@ -3588,8 +3589,9 @@ public class GattService extends ProfileService { try { permissionCheck(uuid); } catch (SecurityException ex) { - // Only throws on T+ as this is an older API and did not throw prior to T - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + String callingPackage = attributionSource.getPackageName(); + // Only throws on apps with target SDK T+ as this old API did not throw prior to T + if (checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.TIRAMISU)) { throw ex; } Log.w(TAG, "readUsingCharacteristicUuid() - permission check failed!"); @@ -3665,8 +3667,9 @@ public class GattService extends ProfileService { try { permissionCheck(connId, handle); } catch (SecurityException ex) { - // Only throws on T+ as this is an older API and did not throw prior to T - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + String callingPackage = attributionSource.getPackageName(); + // Only throws on apps with target SDK T+ as this old API did not throw prior to T + if (checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.TIRAMISU)) { throw ex; } Log.w(TAG, "readDescriptor() - permission check failed!"); @@ -3751,8 +3754,9 @@ public class GattService extends ProfileService { try { permissionCheck(connId, handle); } catch (SecurityException ex) { - // Only throws on T+ as this is an older API and did not throw prior to T - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + String callingPackage = attributionSource.getPackageName(); + // Only throws on apps with target SDK T+ as this old API did not throw prior to T + if (checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.TIRAMISU)) { throw ex; } Log.w(TAG, "registerForNotification() - permission check failed!"); diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface.java index 7c3e06e992..5c93ff5a46 100644 --- a/android/app/src/com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface.java +++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface.java @@ -81,34 +81,34 @@ public class LeAudioBroadcasterNativeInterface { // Callbacks from the native stack back into the Java framework. @VisibleForTesting - public void onBroadcastCreated(int instanceId, boolean success) { + public void onBroadcastCreated(int broadcastId, boolean success) { if (DBG) { - Log.d(TAG, "onBroadcastCreated: instanceId=" + instanceId); + Log.d(TAG, "onBroadcastCreated: broadcastId=" + broadcastId); } LeAudioStackEvent event = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_CREATED); - event.valueInt1 = instanceId; + event.valueInt1 = broadcastId; event.valueBool1 = success; sendMessageToService(event); } @VisibleForTesting - public void onBroadcastDestroyed(int instanceId) { + public void onBroadcastDestroyed(int broadcastId) { if (DBG) { - Log.d(TAG, "onBroadcastDestroyed: instanceId=" + instanceId); + Log.d(TAG, "onBroadcastDestroyed: broadcastId=" + broadcastId); } LeAudioStackEvent event = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_DESTROYED); - event.valueInt1 = instanceId; + event.valueInt1 = broadcastId; sendMessageToService(event); } @VisibleForTesting - public void onBroadcastStateChanged(int instanceId, int state) { + public void onBroadcastStateChanged(int broadcastId, int state) { if (DBG) { - Log.d(TAG, "onBroadcastStateChanged: instanceId=" + instanceId + " state=" + state); + Log.d(TAG, "onBroadcastStateChanged: broadcastId=" + broadcastId + " state=" + state); } LeAudioStackEvent event = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_STATE); @@ -120,23 +120,11 @@ public class LeAudioBroadcasterNativeInterface { * For now it's only important that this device is a Bluetooth device. */ event.device = getDevice(Utils.getBytesFromAddress("FF:FF:FF:FF:FF:FF")); - event.valueInt1 = instanceId; + event.valueInt1 = broadcastId; event.valueInt2 = state; sendMessageToService(event); } - @VisibleForTesting - public void onBroadcastId(int instanceId, byte[] broadcastId) { - LeAudioStackEvent event = - new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_ID); - event.valueInt1 = instanceId; - event.valueByte1 = broadcastId; - if (DBG) { - Log.d(TAG, "onBroadcastId: " + event); - } - sendMessageToService(event); - } - /** * Initializes the native interface. * @@ -178,62 +166,52 @@ public class LeAudioBroadcasterNativeInterface { /** * Update LeAudio Broadcast instance metadata. * - * @param instanceId broadcast instance identifier + * @param broadcastId broadcast instance identifier * @param metadata metadata buffer with TLVs */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void updateMetadata(int instanceId, byte[] metadata) { - updateMetadataNative(instanceId, metadata); + public void updateMetadata(int broadcastId, byte[] metadata) { + updateMetadataNative(broadcastId, metadata); } /** * Start LeAudio Broadcast instance. * - * @param instanceId broadcast instance identifier + * @param broadcastId broadcast instance identifier */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void startBroadcast(int instanceId) { - startBroadcastNative(instanceId); + public void startBroadcast(int broadcastId) { + startBroadcastNative(broadcastId); } /** * Stop LeAudio Broadcast instance. * - * @param instanceId broadcast instance identifier + * @param broadcastId broadcast instance identifier */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void stopBroadcast(int instanceId) { - stopBroadcastNative(instanceId); + public void stopBroadcast(int broadcastId) { + stopBroadcastNative(broadcastId); } /** * Pause LeAudio Broadcast instance. * - * @param instanceId broadcast instance identifier + * @param broadcastId broadcast instance identifier */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void pauseBroadcast(int instanceId) { - pauseBroadcastNative(instanceId); + public void pauseBroadcast(int broadcastId) { + pauseBroadcastNative(broadcastId); } /** * Destroy LeAudio Broadcast instance. * - * @param instanceId broadcast instance identifier - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void destroyBroadcast(int instanceId) { - destroyBroadcastNative(instanceId); - } - - /** - * Get LeAudio Broadcast instance advertising address. - * - * @param instanceId broadcast instance identifier + * @param broadcastId broadcast instance identifier */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void getBroadcastId(int instanceId) { - getBroadcastIdNative(instanceId); + public void destroyBroadcast(int broadcastId) { + destroyBroadcastNative(broadcastId); } /** @@ -250,11 +228,10 @@ public class LeAudioBroadcasterNativeInterface { private native void stopNative(); private native void cleanupNative(); private native void createBroadcastNative(byte[] metadata, int profile, byte[] broadcastCode); - private native void updateMetadataNative(int instanceId, byte[] metadata); - private native void startBroadcastNative(int instanceId); - private native void stopBroadcastNative(int instanceId); - private native void pauseBroadcastNative(int instanceId); - private native void destroyBroadcastNative(int instanceId); - private native void getBroadcastIdNative(int instanceId); + private native void updateMetadataNative(int broadcastId, byte[] metadata); + private native void startBroadcastNative(int broadcastId); + private native void stopBroadcastNative(int broadcastId); + private native void pauseBroadcastNative(int broadcastId); + private native void destroyBroadcastNative(int broadcastId); private native void getAllBroadcastStatesNative(); } 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 2ac32d6dee..0ba5d43ea3 100644 --- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java +++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java @@ -61,7 +61,6 @@ import com.android.bluetooth.vc.VolumeControlService; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.SynchronousResultReceiver; -import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -69,7 +68,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; /** @@ -171,7 +169,6 @@ public class LeAudioService extends ProfileService { private Handler mHandler = new Handler(Looper.getMainLooper()); private final Map<Integer, Integer> mBroadcastStateMap = new HashMap<>(); - final Map<Integer, Integer> mBroadcastIdMap = new HashMap<>(); private final Map<Integer, Boolean> mBroadcastsPlaybackMap = new HashMap<>(); private final List<BluetoothLeBroadcastMetadata> mBroadcastMetadataList = new ArrayList<>(); @@ -211,7 +208,6 @@ public class LeAudioService extends ProfileService { mDeviceGroupIdMap.clear(); mDeviceAudioLocationMap.clear(); mBroadcastStateMap.clear(); - mBroadcastIdMap.clear(); mBroadcastMetadataList.clear(); mBroadcastsPlaybackMap.clear(); @@ -309,7 +305,6 @@ public class LeAudioService extends ProfileService { } mBroadcastStateMap.clear(); - mBroadcastIdMap.clear(); mBroadcastsPlaybackMap.clear(); mBroadcastMetadataList.clear(); @@ -591,76 +586,64 @@ public class LeAudioService extends ProfileService { /** * Start LeAudio Broadcast instance. - * @param instanceId broadcast instance identifier + * @param broadcastId broadcast instance identifier */ - public void startBroadcast(int instanceId) { + public void startBroadcast(int broadcastId) { if (mLeAudioBroadcasterNativeInterface == null) { Log.w(TAG, "Native interface not available."); return; } if (DBG) Log.d(TAG, "startBroadcast"); - mLeAudioBroadcasterNativeInterface.startBroadcast(instanceId); + mLeAudioBroadcasterNativeInterface.startBroadcast(broadcastId); } /** * Updates LeAudio Broadcast instance metadata. - * @param instanceId broadcast instance identifier + * @param broadcastId broadcast instance identifier * @param metadata metadata for the default Broadcast subgroup */ - public void updateBroadcast(int instanceId, BluetoothLeAudioContentMetadata metadata) { + public void updateBroadcast(int broadcastId, BluetoothLeAudioContentMetadata metadata) { if (mLeAudioBroadcasterNativeInterface == null) { Log.w(TAG, "Native interface not available."); return; } if (DBG) Log.d(TAG, "updateBroadcast"); - mLeAudioBroadcasterNativeInterface.updateMetadata(instanceId, metadata.getRawMetadata()); + mLeAudioBroadcasterNativeInterface.updateMetadata(broadcastId, metadata.getRawMetadata()); } /** * Stop LeAudio Broadcast instance. - * @param instanceId broadcast instance identifier + * @param broadcastId broadcast instance identifier */ - public void stopBroadcast(Integer instanceId) { + public void stopBroadcast(Integer broadcastId) { if (mLeAudioBroadcasterNativeInterface == null) { Log.w(TAG, "Native interface not available."); return; } if (DBG) Log.d(TAG, "stopBroadcast"); - mLeAudioBroadcasterNativeInterface.stopBroadcast(instanceId); + mLeAudioBroadcasterNativeInterface.stopBroadcast(broadcastId); } /** * Destroy LeAudio Broadcast instance. - * @param instanceId broadcast instance identifier + * @param broadcastId broadcast instance identifier */ - public void destroyBroadcast(int instanceId) { + public void destroyBroadcast(int broadcastId) { if (mLeAudioBroadcasterNativeInterface == null) { Log.w(TAG, "Native interface not available."); return; } if (DBG) Log.d(TAG, "destroyBroadcast"); - mLeAudioBroadcasterNativeInterface.destroyBroadcast(instanceId); - } - - /** - * Get LeAudio Broadcast id. - * @param instanceId broadcast instance identifier - */ - public void getBroadcastId(int instanceId) { - if (mLeAudioBroadcasterNativeInterface == null) { - Log.w(TAG, "Native interface not available."); - return; - } - mLeAudioBroadcasterNativeInterface.getBroadcastId(instanceId); + mLeAudioBroadcasterNativeInterface.destroyBroadcast(broadcastId); } /** * Checks if Broadcast instance is playing. - * @param instanceId broadcast instance identifier + * @param broadcastId broadcast instance identifier * @return true if if broadcast is playing, false otherwise */ - public boolean isPlaying(int instanceId) { - return mBroadcastsPlaybackMap.getOrDefault(instanceId, false); + public boolean isPlaying(int broadcastId) { + return mBroadcastsPlaybackMap.getOrDefault(broadcastId, false); } /** @@ -1138,55 +1121,37 @@ public class LeAudioService extends ProfileService { } } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_BROADCAST_CREATED) { - int instanceId = stackEvent.valueInt1; + int broadcastId = stackEvent.valueInt1; boolean success = stackEvent.valueBool1; if (success) { - Log.d(TAG, "Broadcast Instance id: " + instanceId + " created."); - startBroadcast(instanceId); - getBroadcastId(instanceId); + Log.d(TAG, "Broadcast broadcastId: " + broadcastId + " created."); + startBroadcast(broadcastId); } else { // TODO: Improve reason reporting or extend the native stack event with reason code - notifyBroadcastStartFailed(instanceId, BluetoothStatusCodes.ERROR_UNKNOWN); + notifyBroadcastStartFailed(broadcastId, BluetoothStatusCodes.ERROR_UNKNOWN); } } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_BROADCAST_DESTROYED) { - Integer instanceId = stackEvent.valueInt1; + Integer broadcastId = stackEvent.valueInt1; // TODO: Improve reason reporting or extend the native stack event with reason code - notifyOnBroadcastStopped(instanceId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); + notifyOnBroadcastStopped(broadcastId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); - mBroadcastStateMap.remove(instanceId); - mBroadcastsPlaybackMap.remove(instanceId); - if (mBroadcastIdMap.containsKey(instanceId)) { - Integer broadcastId = mBroadcastIdMap.get(instanceId); - mBroadcastMetadataList.removeIf(m -> broadcastId == m.getBroadcastId()); - mBroadcastIdMap.remove(instanceId); - } + mBroadcastsPlaybackMap.remove(broadcastId); + mBroadcastStateMap.remove(broadcastId); + mBroadcastMetadataList.removeIf(m -> broadcastId == m.getBroadcastId()); } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_BROADCAST_STATE) { - int instanceId = stackEvent.valueInt1; + int broadcastId = stackEvent.valueInt1; int state = stackEvent.valueInt2; - mBroadcastStateMap.put(instanceId, state); + mBroadcastStateMap.put(broadcastId, state); if (state == LeAudioStackEvent.BROADCAST_STATE_STOPPED) { - if (DBG) Log.d(TAG, "Broadcast Instance id: " + instanceId + " stopped."); - destroyBroadcast(instanceId); + if (DBG) Log.d(TAG, "Broadcast broadcastId: " + broadcastId + " stopped."); - } else if (state == LeAudioStackEvent.BROADCAST_STATE_CONFIGURING) { - if (DBG) Log.d(TAG, "Broadcast Instance id: " + instanceId + " configuring."); - - } else if (state == LeAudioStackEvent.BROADCAST_STATE_PAUSED) { - if (DBG) Log.d(TAG, "Broadcast Instance id: " + instanceId + " paused."); - - if (!mBroadcastsPlaybackMap.containsKey(instanceId)) { - // Initial playback state after the creation - notifyBroadcastStarted(instanceId, - BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); - } - - // Playback paused - mBroadcastsPlaybackMap.put(instanceId, false); - notifyPlaybackStopped(instanceId, BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST); + // Playback stopped + mBroadcastsPlaybackMap.put(broadcastId, false); + notifyPlaybackStopped(broadcastId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); // Notify audio manager if (Collections.frequency(mBroadcastsPlaybackMap.values(), true) == 0) { @@ -1196,24 +1161,36 @@ public class LeAudioService extends ProfileService { mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioOutDevice, previousDevice, // TODO: implement createLeAudioBroadcastInfo() - BluetoothProfileConnectionInfo.createLeAudioInfo(true, true)); + BluetoothProfileConnectionInfo.createLeAudioInfo(false, true)); } } + destroyBroadcast(broadcastId); + + } else if (state == LeAudioStackEvent.BROADCAST_STATE_CONFIGURING) { + if (DBG) Log.d(TAG, "Broadcast broadcastId: " + broadcastId + " configuring."); + + } else if (state == LeAudioStackEvent.BROADCAST_STATE_PAUSED) { + if (DBG) Log.d(TAG, "Broadcast broadcastId: " + broadcastId + " paused."); + + // Playback paused + mBroadcastsPlaybackMap.put(broadcastId, false); + notifyPlaybackStopped(broadcastId, BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST); + } else if (state == LeAudioStackEvent.BROADCAST_STATE_STOPPING) { - if (DBG) Log.d(TAG, "Broadcast Instance id: " + instanceId + " stopping."); + if (DBG) Log.d(TAG, "Broadcast broadcastId: " + broadcastId + " stopping."); } else if (state == LeAudioStackEvent.BROADCAST_STATE_STREAMING) { - if (DBG) Log.d(TAG, "Broadcast Instance id: " + instanceId + " streaming."); + if (DBG) Log.d(TAG, "Broadcast broadcastId: " + broadcastId + " streaming."); - if (!mBroadcastsPlaybackMap.containsKey(instanceId)) { - notifyBroadcastStarted(instanceId, + if (!mBroadcastsPlaybackMap.containsKey(broadcastId)) { + notifyBroadcastStarted(broadcastId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); } // Stream resumed - mBroadcastsPlaybackMap.put(instanceId, true); - notifyPlaybackStarted(instanceId, BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST); + mBroadcastsPlaybackMap.put(broadcastId, true); + notifyPlaybackStarted(broadcastId, BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST); // Notify audio manager if (Collections.frequency(mBroadcastsPlaybackMap.values(), true) == 1) { @@ -1223,15 +1200,10 @@ public class LeAudioService extends ProfileService { mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioOutDevice, previousDevice, // TODO: implement createLeAudioBroadcastInfo() - BluetoothProfileConnectionInfo.createLeAudioInfo(false, true)); + BluetoothProfileConnectionInfo.createLeAudioInfo(true, true)); } } } - - } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_BROADCAST_ID) { - int instanceId = stackEvent.valueInt1; - byte[] broadcastId = stackEvent.valueByte1; - mBroadcastIdMap.put(instanceId, new BigInteger(broadcastId).intValue()); } // TODO: Support Broadcast metadata updates @@ -1624,13 +1596,7 @@ public class LeAudioService extends ProfileService { } } - private void notifyBroadcastStarted(Integer instanceId, int reason) { - if (!mBroadcastIdMap.containsKey(instanceId)) { - Log.e(TAG, "Unknown Broadcast ID for broadcast instance: " + instanceId); - return; - } - - Integer broadcastId = mBroadcastIdMap.get(instanceId); + private void notifyBroadcastStarted(Integer broadcastId, int reason) { if (mBroadcastCallbacks != null) { int n = mBroadcastCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { @@ -1644,7 +1610,7 @@ public class LeAudioService extends ProfileService { } } - private void notifyBroadcastStartFailed(Integer instanceId, int reason) { + private void notifyBroadcastStartFailed(Integer broadcastId, int reason) { if (mBroadcastCallbacks != null) { int n = mBroadcastCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { @@ -1658,13 +1624,7 @@ public class LeAudioService extends ProfileService { } } - private void notifyOnBroadcastStopped(Integer instanceId, int reason) { - if (!mBroadcastIdMap.containsKey(instanceId)) { - Log.e(TAG, "Unknown Broadcast ID for broadcast instance: " + instanceId); - return; - } - - Integer broadcastId = mBroadcastIdMap.get(instanceId); + private void notifyOnBroadcastStopped(Integer broadcastId, int reason) { if (mBroadcastCallbacks != null) { int n = mBroadcastCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { @@ -1692,13 +1652,7 @@ public class LeAudioService extends ProfileService { } } - private void notifyPlaybackStarted(Integer instanceId, int reason) { - if (!mBroadcastIdMap.containsKey(instanceId)) { - Log.e(TAG, "Unknown Broadcast ID for broadcast instance: " + instanceId); - return; - } - - Integer broadcastId = mBroadcastIdMap.get(instanceId); + private void notifyPlaybackStarted(Integer broadcastId, int reason) { if (mBroadcastCallbacks != null) { int n = mBroadcastCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { @@ -1712,13 +1666,7 @@ public class LeAudioService extends ProfileService { } } - private void notifyPlaybackStopped(Integer instanceId, int reason) { - if (!mBroadcastIdMap.containsKey(instanceId)) { - Log.e(TAG, "Unknown Broadcast ID for broadcast instance: " + instanceId); - return; - } - - Integer broadcastId = mBroadcastIdMap.get(instanceId); + private void notifyPlaybackStopped(Integer broadcastId, int reason) { if (mBroadcastCallbacks != null) { int n = mBroadcastCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { @@ -1732,13 +1680,7 @@ public class LeAudioService extends ProfileService { } } - private void notifyBroadcastUpdated(int instanceId, int reason) { - if (!mBroadcastIdMap.containsKey(instanceId)) { - Log.e(TAG, "Unknown Broadcast ID for broadcast instance: " + instanceId); - return; - } - - Integer broadcastId = mBroadcastIdMap.get(instanceId); + private void notifyBroadcastUpdated(int broadcastId, int reason) { if (mBroadcastCallbacks != null) { int n = mBroadcastCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { @@ -1752,13 +1694,7 @@ public class LeAudioService extends ProfileService { } } - private void notifyBroadcastUpdateFailed(int instanceId, int reason) { - if (!mBroadcastIdMap.containsKey(instanceId)) { - Log.e(TAG, "Unknown Broadcast ID for broadcast instance: " + instanceId); - return; - } - - Integer broadcastId = mBroadcastIdMap.get(instanceId); + private void notifyBroadcastUpdateFailed(int broadcastId, int reason) { if (mBroadcastCallbacks != null) { int n = mBroadcastCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { @@ -1773,14 +1709,8 @@ public class LeAudioService extends ProfileService { } } - private void notifyBroadcastMetadataChanged(int instanceId, + private void notifyBroadcastMetadataChanged(int broadcastId, BluetoothLeBroadcastMetadata metadata) { - if (!mBroadcastIdMap.containsKey(instanceId)) { - Log.e(TAG, "Unknown Broadcast ID for broadcast instance: " + instanceId); - return; - } - - Integer broadcastId = mBroadcastIdMap.get(instanceId); if (mBroadcastCallbacks != null) { int n = mBroadcastCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { @@ -2195,14 +2125,7 @@ public class LeAudioService extends ProfileService { public void stopBroadcast(int broadcastId, AttributionSource source) { LeAudioService service = getService(source); if (service != null) { - Optional<Integer> instanceId = service.mBroadcastIdMap.entrySet() - .stream() - .filter(entry -> Objects.equals(entry.getValue(), broadcastId)) - .map(Map.Entry::getKey) - .findFirst(); - if (instanceId.isPresent()) { - service.stopBroadcast(instanceId.get()); - } + service.stopBroadcast(broadcastId); } } @@ -2211,14 +2134,7 @@ public class LeAudioService extends ProfileService { BluetoothLeAudioContentMetadata contentMetadata, AttributionSource source) { LeAudioService service = getService(source); if (service != null) { - Optional<Integer> instanceId = service.mBroadcastIdMap.entrySet() - .stream() - .filter(entry -> Objects.equals(entry.getValue(), broadcastId)) - .map(Map.Entry::getKey) - .findFirst(); - if (instanceId.isPresent()) { - service.updateBroadcast(instanceId.get(), contentMetadata); - } + service.updateBroadcast(broadcastId, contentMetadata); } } @@ -2229,14 +2145,7 @@ public class LeAudioService extends ProfileService { boolean defaultValue = false; LeAudioService service = getService(source); if (service != null) { - Optional<Integer> instanceId = service.mBroadcastIdMap.entrySet() - .stream() - .filter(entry -> Objects.equals(entry.getValue(), broadcastId)) - .map(Map.Entry::getKey) - .findFirst(); - if (instanceId.isPresent()) { - defaultValue = service.isPlaying(instanceId.get()); - } + defaultValue = service.isPlaying(broadcastId); } receiver.send(defaultValue); } catch (RuntimeException e) { 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 b20b7790f9..1ddbdf10b3 100644 --- a/android/app/src/com/android/bluetooth/le_audio/LeAudioStackEvent.java +++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioStackEvent.java @@ -42,7 +42,6 @@ public class LeAudioStackEvent { public static final int EVENT_TYPE_BROADCAST_CREATED = EVENT_TYPE_UNICAST_MAX + 1; public static final int EVENT_TYPE_BROADCAST_DESTROYED = EVENT_TYPE_UNICAST_MAX + 2; public static final int EVENT_TYPE_BROADCAST_STATE = EVENT_TYPE_UNICAST_MAX + 3; - public static final int EVENT_TYPE_BROADCAST_ID = EVENT_TYPE_UNICAST_MAX + 4; // Do not modify without updating the HAL bt_le_audio.h files. // Match up with GroupStatus enum of bt_le_audio.h @@ -73,7 +72,6 @@ public class LeAudioStackEvent { public int valueInt4 = 0; public int valueInt5 = 0; public boolean valueBool1 = false; - public byte[] valueByte1; public BluetoothLeAudioCodecConfig valueCodec1; public BluetoothLeAudioCodecConfig valueCodec2; public List<BluetoothLeAudioCodecConfig> valueCodecList1; @@ -101,7 +99,6 @@ public class LeAudioStackEvent { + eventTypeValueCodecList1ToString(type, valueCodecList1)); result.append(", valueCodecList2:" + eventTypeValueCodecList2ToString(type, valueCodecList2)); - result.append(", " + eventTypeValueByte1ToString(type, valueByte1)); result.append("}"); return result.toString(); } @@ -126,8 +123,6 @@ public class LeAudioStackEvent { return "EVENT_TYPE_BROADCAST_DESTROYED"; case EVENT_TYPE_BROADCAST_STATE: return "EVENT_TYPE_BROADCAST_STATE"; - case EVENT_TYPE_BROADCAST_ID: - return "EVENT_TYPE_BROADCAST_ID"; case EVENT_TYPE_AUDIO_LOCAL_CODEC_CONFIG_CAPA_CHANGED: return "EVENT_TYPE_AUDIO_LOCAL_CODEC_CONFIG_CAPA_CHANGED"; case EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED: @@ -164,13 +159,11 @@ public class LeAudioStackEvent { case EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE: return "{sink_audio_location:" + value + "}"; case EVENT_TYPE_BROADCAST_CREATED: - return "{instance_id:" + value + "}"; + return "{broadcastId:" + value + "}"; case EVENT_TYPE_BROADCAST_DESTROYED: - return "{instance_id:" + value + "}"; + return "{broadcastId:" + value + "}"; case EVENT_TYPE_BROADCAST_STATE: - return "{instance_id:" + value + "}"; - case EVENT_TYPE_BROADCAST_ID: - return "{instance_id:" + value + "}"; + return "{broadcastId:" + value + "}"; default: break; } @@ -202,8 +195,6 @@ public class LeAudioStackEvent { return "{group_id:" + Integer.toString(value) + "}"; case EVENT_TYPE_BROADCAST_STATE: return "{state:" + broadcastStateToString(value) + "}"; - case EVENT_TYPE_BROADCAST_ID: - return "{addr_type:" + addrTypeToString(value) + "}"; default: break; } @@ -242,18 +233,6 @@ public class LeAudioStackEvent { return Integer.toString(value); } - private static String eventTypeValueByte1ToString(int type, byte[] value) { - switch (type) { - case EVENT_TYPE_BROADCAST_ID: - if (value == null) { - return "empty"; - } - return "broadcast_id: [" + encodeHexString(value) + "]"; - default: - return "<unused>"; - } - } - private static String eventTypeValueBool1ToString(int type, boolean value) { switch (type) { case EVENT_TYPE_BROADCAST_CREATED: @@ -324,17 +303,6 @@ public class LeAudioStackEvent { } } - private static String addrTypeToString(int value) { - switch (value) { - case 0: - return "Static"; - case 1: - return "Random"; - default: - return "Unknown {" + value + "}"; - } - } - protected static String encodeHexString(byte[] pduData) { StringBuilder out = new StringBuilder(pduData.length * 2); for (int i = 0; i < pduData.length; i++) { diff --git a/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java b/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java index fb72a36c6a..9cf2ac75cd 100644 --- a/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java +++ b/android/app/src/com/android/bluetooth/mcp/MediaControlProfile.java @@ -751,7 +751,7 @@ public class MediaControlProfile implements MediaControlServiceCallbacks { private final Map<String, MediaControlGattServiceInterface> mServiceMap; - static final String THIS_PACKAGE_NAME = "com.android.bluetooth"; + static final String THIS_PACKAGE_NAME = "com.android.bluetooth.services"; public void unregisterServiceInstance(String appToken) { Log.d(TAG, "unregisterServiceInstance"); diff --git a/android/app/src/com/android/bluetooth/opp/Constants.java b/android/app/src/com/android/bluetooth/opp/Constants.java index bb98752b74..c453a388d4 100644 --- a/android/app/src/com/android/bluetooth/opp/Constants.java +++ b/android/app/src/com/android/bluetooth/opp/Constants.java @@ -159,7 +159,7 @@ public class Constants { /** the intent that gets sent when clicking a incoming file confirm notification */ static final String ACTION_INCOMING_FILE_CONFIRM = "android.btopp.intent.action.CONFIRM"; - static final String THIS_PACKAGE_NAME = "com.android.bluetooth"; + static final String THIS_PACKAGE_NAME = "com.android.bluetooth.services"; /** The column that is used to remember whether the media scanner was invoked */ static final String MEDIA_SCANNED = "scanned"; diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java index 3f9ee0da61..92dce2a1d7 100755..100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java @@ -93,7 +93,6 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { 0x66 }; - // Currently not support SIM card private static final String[] LEGAL_PATH = { "/telecom", "/telecom/pb", @@ -101,16 +100,6 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { "/telecom/ich", "/telecom/och", "/telecom/mch", - "/telecom/cch" - }; - - @SuppressWarnings("unused") private static final String[] LEGAL_PATH_WITH_SIM = { - "/telecom", - "/telecom/pb", - "/telecom/fav", - "/telecom/ich", - "/telecom/och", - "/telecom/mch", "/telecom/cch", "/SIM1", "/SIM1/telecom", @@ -157,6 +146,19 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private static final String FAV_PATH = "/telecom/fav"; + // SIM Support + private static final String SIM_PATH = "/SIM1/telecom"; + + private static final String SIM_ICH_PATH = "/SIM1/telecom/ich"; + + private static final String SIM_OCH_PATH = "/SIM1/telecom/och"; + + private static final String SIM_MCH_PATH = "/SIM1/telecom/mch"; + + private static final String SIM_CCH_PATH = "/SIM1/telecom/cch"; + + private static final String SIM_PB_PATH = "/SIM1/telecom/pb"; + // type for list vcard objects private static final String TYPE_LISTING = "x-bt/vcard-listing"; @@ -187,6 +189,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private BluetoothPbapVcardManager mVcardManager; + BluetoothPbapSimVcardManager mVcardSimManager; + private int mOrderBy = ORDER_BY_INDEXED; private static final int CALLLOG_NUM_LIMIT = 50; @@ -209,6 +213,10 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private PbapStateMachine mStateMachine; + private enum ContactsType { + TYPE_PHONEBOOK , TYPE_SIM ; + } + public static class ContentType { public static final int PHONEBOOK = 1; @@ -221,6 +229,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { public static final int COMBINED_CALL_HISTORY = 5; public static final int FAVORITES = 6; + + public static final int SIM_PHONEBOOK = 7; } public BluetoothPbapObexServer(Handler callback, Context context, @@ -229,6 +239,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { mCallback = callback; mContext = context; mVcardManager = new BluetoothPbapVcardManager(mContext); + mVcardSimManager = new BluetoothPbapSimVcardManager(mContext); mStateMachine = stateMachine; } @@ -452,21 +463,23 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { appParamValue.needTag = ContentType.PHONEBOOK; } else if (mCurrentPath.equals(FAV_PATH)) { appParamValue.needTag = ContentType.FAVORITES; - } else if (mCurrentPath.equals(ICH_PATH)) { + } else if (mCurrentPath.equals(ICH_PATH) || mCurrentPath.equals(SIM_ICH_PATH)) { appParamValue.needTag = ContentType.INCOMING_CALL_HISTORY; - } else if (mCurrentPath.equals(OCH_PATH)) { + } else if (mCurrentPath.equals(OCH_PATH)|| mCurrentPath.equals(SIM_OCH_PATH)) { appParamValue.needTag = ContentType.OUTGOING_CALL_HISTORY; - } else if (mCurrentPath.equals(MCH_PATH)) { + } else if (mCurrentPath.equals(MCH_PATH)|| mCurrentPath.equals(SIM_MCH_PATH)) { appParamValue.needTag = ContentType.MISSED_CALL_HISTORY; mNeedNewMissedCallsNum = true; - } else if (mCurrentPath.equals(CCH_PATH)) { + } else if (mCurrentPath.equals(CCH_PATH)|| mCurrentPath.equals(SIM_CCH_PATH)) { appParamValue.needTag = ContentType.COMBINED_CALL_HISTORY; - } else if (mCurrentPath.equals(TELECOM_PATH)) { + } else if (mCurrentPath.equals(TELECOM_PATH)|| mCurrentPath.equals(SIM_PATH)) { /* PBAP 1.1.1 change */ if (!validName && type.equals(TYPE_LISTING)) { Log.e(TAG, "invalid vcard listing request in default folder"); return ResponseCodes.OBEX_HTTP_NOT_FOUND; } + } else if (mCurrentPath.equals(SIM_PB_PATH)) { + appParamValue.needTag = ContentType.SIM_PHONEBOOK; } else { Log.w(TAG, "mCurrentpath is not valid path!!!"); return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; @@ -475,16 +488,14 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { Log.v(TAG, "onGet(): appParamValue.needTag=" + appParamValue.needTag); } } else { - // Not support SIM card currently - if (name.contains(SIM1.subSequence(0, SIM1.length()))) { - Log.w(TAG, "Not support access SIM card info!"); - return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; - } - // we have weak name checking here to provide better // compatibility with other devices,although unique name such as // "pb.vcf" is required by SIG spec. - if (isNameMatchTarget(name, PB)) { + if (mVcardSimManager.isSimPhoneBook(name, type, PB, SIM1, + TYPE_PB, TYPE_LISTING, mCurrentPath)) { + appParamValue.needTag = ContentType.SIM_PHONEBOOK; + if (D) Log.d(TAG, "download SIM phonebook request"); + } else if (isNameMatchTarget(name, PB)) { appParamValue.needTag = ContentType.PHONEBOOK; if (D) { Log.v(TAG, "download phonebook request"); @@ -765,23 +776,32 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { result.append("<?xml version=\"1.0\"?>"); result.append("<!DOCTYPE vcard-listing SYSTEM \"vcard-listing.dtd\">"); result.append("<vCard-listing version=\"1.0\">"); - + String type = ""; // Phonebook listing request if ((appParamValue.needTag == ContentType.PHONEBOOK) || (appParamValue.needTag == ContentType.FAVORITES)) { - String type = ""; if (appParamValue.searchAttr.equals("0")) { type = "name"; } else if (appParamValue.searchAttr.equals("1")) { type = "number"; } if (type.length() > 0) { - itemsFound = createList(appParamValue, needSendBody, size, result, type); + itemsFound = createList(appParamValue, needSendBody, size, result, type, + ContactsType.TYPE_PHONEBOOK); } else { return ResponseCodes.OBEX_HTTP_PRECON_FAILED; } + // SIM Phonebook listing Request + } else if (appParamValue.needTag == ContentType.SIM_PHONEBOOK) { + type = mVcardSimManager.getType(appParamValue.searchAttr); + if (type.length() > 0) { + itemsFound = createList(appParamValue, needSendBody, size, result, type, + ContactsType.TYPE_SIM); + } else { + return ResponseCodes.OBEX_HTTP_PRECON_FAILED; + } + // Call history listing request } else { - // Call history listing request ArrayList<String> nameList = mVcardManager.loadCallHistoryList(appParamValue.needTag); int requestSize = nameList.size() >= appParamValue.maxListCount ? appParamValue.maxListCount @@ -810,16 +830,24 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { } private int createList(AppParamValue appParamValue, int needSendBody, int size, - StringBuilder result, String type) { + StringBuilder result, String type, ContactsType contactType) { int itemsFound = 0; ArrayList<String> nameList = null; if (mVcardSelector) { - nameList = mVcardManager.getSelectedPhonebookNameList(mOrderBy, appParamValue.vcard21, - needSendBody, size, appParamValue.vCardSelector, + if (contactType == ContactsType.TYPE_PHONEBOOK) { + nameList = mVcardManager.getSelectedPhonebookNameList(mOrderBy, + appParamValue.vcard21, needSendBody, size, appParamValue.vCardSelector, appParamValue.vCardSelectorOperator); + } else if(contactType == ContactsType.TYPE_SIM) { + nameList = mVcardSimManager.getSIMPhonebookNameList(mOrderBy); + } } else { - nameList = mVcardManager.getPhonebookNameList(mOrderBy); + if (contactType == ContactsType.TYPE_PHONEBOOK) { + nameList = mVcardManager.getPhonebookNameList(mOrderBy); + } else if( contactType == ContactsType.TYPE_SIM) { + nameList = mVcardSimManager.getSIMPhonebookNameList(mOrderBy); + } } final int requestSize = @@ -837,8 +865,12 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { ArrayList<Integer> savedPosList = new ArrayList<>(); ArrayList<String> selectedNameList = new ArrayList<String>(); // query the number, to get the names - ArrayList<String> names = - mVcardManager.getContactNamesByNumber(appParamValue.searchValue); + ArrayList<String> names = new ArrayList<>(); + if (contactType == ContactsType.TYPE_PHONEBOOK) { + names = mVcardManager.getContactNamesByNumber(appParamValue.searchValue); + } else if(contactType== ContactsType.TYPE_SIM) { + names = mVcardSimManager.getSIMContactNamesByNumber(appParamValue.searchValue); + } if (mOrderBy == ORDER_BY_ALPHABETICAL) Collections.sort(names); for (int i = 0; i < names.size(); i++) { compareValue = names.get(i).trim(); @@ -1134,7 +1166,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { Log.i(TAG, "searchAttr is valid: " + searchAttr); } - int size = mVcardManager.getPhonebookSize(appParamValue.needTag); + int size = mVcardManager.getPhonebookSize(appParamValue.needTag, mVcardSimManager); int needSendBody = handleAppParaForResponse(appParamValue, size, reply, op, name); if (needSendBody != NEED_SEND_BODY) { op.noBodyHeader(); @@ -1198,7 +1230,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { } } - int size = mVcardManager.getPhonebookSize(appParamValue.needTag); + int size = mVcardManager.getPhonebookSize(appParamValue.needTag, mVcardSimManager); int needSendBody = handleAppParaForResponse(appParamValue, size, reply, op, name); if (size == 0) { if (D) { @@ -1225,6 +1257,19 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { return mVcardManager.composeAndSendPhonebookOneVcard(op, intIndex, vcard21, null, mOrderBy, appParamValue.ignorefilter, appParamValue.propertySelector); } + } else if (appParamValue.needTag == ContentType.SIM_PHONEBOOK) { + if (intIndex < 0 || intIndex >= size) { + Log.w(TAG, "The requested vcard is not acceptable! name= " + name); + return ResponseCodes.OBEX_HTTP_NOT_FOUND; + } else if (intIndex == 0) { + // For PB_PATH, 0.vcf is the phone number of this phone. + String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21, + appParamValue.ignorefilter ? null : appParamValue.propertySelector); + return pushBytes(op, ownerVcard); + } else { + return mVcardSimManager.composeAndSendSIMPhonebookOneVcard(op, intIndex, + vcard21, null, mOrderBy); + } } else { if (intIndex <= 0 || intIndex > size) { Log.w(TAG, "The requested vcard is not acceptable! name= " + name); @@ -1256,7 +1301,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { } } // code end for passing PTS3.2 TC_PSE_PBD_BI_01_C - int pbSize = mVcardManager.getPhonebookSize(appParamValue.needTag); + int pbSize = mVcardManager.getPhonebookSize(appParamValue.needTag, mVcardSimManager); int needSendBody = handleAppParaForResponse(appParamValue, pbSize, reply, op, name); if (needSendBody != NEED_SEND_BODY) { op.noBodyHeader(); @@ -1299,7 +1344,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { // Limit the number of call log to CALLLOG_NUM_LIMIT if ((appParamValue.needTag != BluetoothPbapObexServer.ContentType.PHONEBOOK) - && (appParamValue.needTag != BluetoothPbapObexServer.ContentType.FAVORITES)) { + && (appParamValue.needTag != BluetoothPbapObexServer.ContentType.FAVORITES) + && (appParamValue.needTag != BluetoothPbapObexServer.ContentType.SIM_PHONEBOOK)) { if (requestSize > CALLLOG_NUM_LIMIT) { requestSize = CALLLOG_NUM_LIMIT; } @@ -1332,6 +1378,20 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { appParamValue.propertySelector, appParamValue.vCardSelector, appParamValue.vCardSelectorOperator, mVcardSelector, favorites); } + } else if (appParamValue.needTag == BluetoothPbapObexServer.ContentType.SIM_PHONEBOOK) { + if (startPoint == 0) { + String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21, + appParamValue.propertySelector); + if (endPoint == 0) { + return pushBytes(op, ownerVcard); + } else { + return mVcardSimManager.composeAndSendSIMPhonebookVcards(op, 1, endPoint, + vcard21, ownerVcard); + } + } else { + return mVcardSimManager.composeAndSendSIMPhonebookVcards(op, startPoint, + endPoint, vcard21, null); + } } else { return mVcardManager.composeAndSendSelectedCallLogVcards(appParamValue.needTag, op, startPoint, endPoint, vcard21, needSendBody, pbSize, diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java index 2fa5da0fc8..da36515e0c 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java @@ -86,7 +86,7 @@ public class BluetoothPbapService extends ProfileService implements IObexConnect public static final boolean DEBUG = true; - public static final boolean VERBOSE = false; + public static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); /** * Intent indicating incoming obex authentication request which is from @@ -147,7 +147,7 @@ public class BluetoothPbapService extends ProfileService implements IObexConnect private static final int SDP_PBAP_SERVER_VERSION = 0x0102; // PBAP v1.2.3, Sec. 7.1.2: local phonebook and favorites - private static final int SDP_PBAP_SUPPORTED_REPOSITORIES = 0x0009; + private static final int SDP_PBAP_SUPPORTED_REPOSITORIES = 0x000B; private static final int SDP_PBAP_SUPPORTED_FEATURES = 0x021F; /* PBAP will use Bluetooth notification ID from 1000000 (included) to 2000000 (excluded). diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManager.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManager.java new file mode 100644 index 0000000000..267ce5bf28 --- /dev/null +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManager.java @@ -0,0 +1,540 @@ +/* +* Copyright (c) 2015, The Linux Foundation. All rights reserved. +* Copyright (C) 2014 Samsung System LSI +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.android.bluetooth.pbap; + +import com.android.bluetooth.R; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteException; +import android.net.Uri; +import com.android.vcard.VCardBuilder; +import com.android.vcard.VCardConfig; +import com.android.vcard.VCardConstants; +import com.android.vcard.VCardUtils; + +import android.content.ContentValues; +import android.provider.CallLog; +import android.provider.CallLog.Calls; +import android.text.TextUtils; +import android.util.Log; +import android.provider.ContactsContract.Contacts; +import android.provider.ContactsContract.CommonDataKinds; +import android.provider.ContactsContract.CommonDataKinds.Phone; +import android.provider.ContactsContract.CommonDataKinds.StructuredName; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Collections; +import java.util.Comparator; + +import com.android.obex.Operation; +import com.android.obex.ResponseCodes; +import com.android.obex.ServerOperation; + +/** + * VCard composer especially for Call Log used in Bluetooth. + */ +public class BluetoothPbapSimVcardManager { + private static final String TAG = "PbapSIMvCardComposer"; + + private static final boolean V = BluetoothPbapService.VERBOSE; + + private static final String FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO = + "Failed to get database information"; + + private static final String FAILURE_REASON_NO_ENTRY = + "There's no exportable in the database"; + + private static final String FAILURE_REASON_NOT_INITIALIZED = + "The vCard composer object is not correctly initialized"; + + /** Should be visible only from developers... (no need to translate, hopefully) */ + private static final String FAILURE_REASON_UNSUPPORTED_URI = + "The Uri vCard composer received is not supported by the composer."; + + private static final String NO_ERROR = "No error"; + + private final String SIM_URI = "content://icc/adn"; + private final String SIM_PATH = "/SIM1/telecom"; + + private static final String[] SIM_PROJECTION = new String[] { + Contacts.DISPLAY_NAME, + CommonDataKinds.Phone.NUMBER, + CommonDataKinds.Phone.TYPE, + CommonDataKinds.Phone.LABEL + }; + + private static final int NAME_COLUMN_INDEX = 0; + private static final int NUMBER_COLUMN_INDEX = 1; + private static final int NUMBERTYPE_COLUMN_INDEX = 2; + private static final int NUMBERLABEL_COLUMN_INDEX = 3; + + + private final Context mContext; + private ContentResolver mContentResolver; + private Cursor mCursor; + private boolean mTerminateIsCalled; + private String mErrorReason = NO_ERROR; + + public BluetoothPbapSimVcardManager(final Context context) { + mContext = context; + mContentResolver = context.getContentResolver(); + } + + public boolean init(final Uri contentUri, final String selection, + final String[] selectionArgs, final String sortOrder) { + final Uri myUri = Uri.parse(SIM_URI); + if (!myUri.equals(contentUri)) { + + mErrorReason = FAILURE_REASON_UNSUPPORTED_URI; + return false; + } + + //checkpoint Figure out if we can apply selection, projection and sort order. + mCursor = mContentResolver.query( + contentUri, SIM_PROJECTION, null, null,sortOrder); + + if (mCursor == null) { + mErrorReason = FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO; + return false; + } + if (mCursor.getCount() == 0 || !mCursor.moveToFirst()) { + try { + mCursor.close(); + } catch (SQLiteException e) { + Log.e(TAG, "SQLiteException on Cursor#close(): " + e.getMessage()); + } finally { + mErrorReason = FAILURE_REASON_NO_ENTRY; + mCursor = null; + } + return false; + } + return true; + } + + public String createOneEntry(boolean vcardVer21) { + if (mCursor == null || mCursor.isAfterLast()) { + mErrorReason = FAILURE_REASON_NOT_INITIALIZED; + return null; + } + try { + return createOnevCardEntryInternal(vcardVer21); + } finally { + mCursor.moveToNext(); + } + } + + private String createOnevCardEntryInternal(boolean vcardVer21) { + final int vcardType = (vcardVer21 ? VCardConfig.VCARD_TYPE_V21_GENERIC : + VCardConfig.VCARD_TYPE_V30_GENERIC) | + VCardConfig.FLAG_REFRAIN_PHONE_NUMBER_FORMATTING; + final VCardBuilder builder = new VCardBuilder(vcardType); + String name = mCursor.getString(NAME_COLUMN_INDEX); + if (TextUtils.isEmpty(name)) { + name = mCursor.getString(NUMBER_COLUMN_INDEX); + } + final boolean needCharset = !(VCardUtils.containsOnlyPrintableAscii(name)); + // Create ContentValues for making name as Structured name + List<ContentValues> contentValuesList = new ArrayList<ContentValues>(); + ContentValues nameContentValues = new ContentValues(); + nameContentValues.put(StructuredName.DISPLAY_NAME, name); + contentValuesList.add(nameContentValues); + builder.appendNameProperties(contentValuesList); + + String number = mCursor.getString(NUMBER_COLUMN_INDEX); + if (TextUtils.isEmpty(number)) { + // To avoid Spec violation and IOT issues, initialize with invalid number + number = "000000"; + } + if (number.equals("-1")) { + number = mContext.getString(R.string.unknownNumber); + } + + // checkpoint Figure out what are the type and label + int type = mCursor.getInt(NUMBERTYPE_COLUMN_INDEX); + String label = mCursor.getString(NUMBERLABEL_COLUMN_INDEX); + if (type == 0) { // value for type is not present in db + type = Phone.TYPE_MOBILE; + } + if (TextUtils.isEmpty(label)) { + label = Integer.toString(type); + } + builder.appendTelLine(type, label, number, false); + return builder.toString(); + } + + public void terminate() { + if (mCursor != null) { + try { + mCursor.close(); + } catch (SQLiteException e) { + Log.e(TAG, "SQLiteException on Cursor#close(): " + e.getMessage()); + } + mCursor = null; + } + + mTerminateIsCalled = true; + } + + @Override + public void finalize() { + if (!mTerminateIsCalled) { + terminate(); + } + } + + public int getCount() { + if (mCursor == null) { + return 0; + } + return mCursor.getCount(); + } + + public boolean isAfterLast() { + if (mCursor == null) { + return false; + } + return mCursor.isAfterLast(); + } + + public void moveToPosition(final int position, boolean sortalpha) { + if(mCursor == null) { + return; + } + if(sortalpha) { + setPositionByAlpha(position); + return; + } + mCursor.moveToPosition(position); + } + + public String getErrorReason() { + return mErrorReason; + } + + public void setPositionByAlpha(int position) { + if(mCursor == null) { + return; + } + ArrayList<String> nameList = new ArrayList<String>(); + for (mCursor.moveToFirst(); !mCursor.isAfterLast(); mCursor + .moveToNext()) { + String name = mCursor.getString(NAME_COLUMN_INDEX); + if (TextUtils.isEmpty(name)) { + name = mContext.getString(android.R.string.unknownName); + } + nameList.add(name); + } + + Collections.sort(nameList, new Comparator <String> () { + @Override + public int compare(String str1, String str2){ + return str1.compareToIgnoreCase(str2); + } + }); + + for (mCursor.moveToFirst(); !mCursor.isAfterLast(); mCursor.moveToNext()) { + if(mCursor.getString(NAME_COLUMN_INDEX).equals(nameList.get(position))) { + break; + } + + } + } + + public final int getSIMContactsSize() { + final Uri myUri = Uri.parse(SIM_URI); + int size = 0; + Cursor contactCursor = null; + try { + contactCursor = mContentResolver.query(myUri, SIM_PROJECTION, null,null, null); + if (contactCursor != null) { + size = contactCursor.getCount() +1; //always has the 0.vcf + } + } finally { + if (contactCursor != null) { + contactCursor.close(); + } + } + return size; + } + + public final ArrayList<String> getSIMPhonebookNameList(final int orderByWhat) { + ArrayList<String> nameList = new ArrayList<String>(); + nameList.add(BluetoothPbapService.getLocalPhoneName()); + //Since owner card should always be 0.vcf, maintain a separate list to avoid sorting + ArrayList<String> allnames = new ArrayList<String>(); + final Uri myUri = Uri.parse(SIM_URI); + Cursor contactCursor = null; + try { + contactCursor = mContentResolver.query(myUri, SIM_PROJECTION, null,null,null); + if (contactCursor != null) { + for (contactCursor.moveToFirst(); !contactCursor.isAfterLast(); contactCursor + .moveToNext()) { + String name = contactCursor.getString(NAME_COLUMN_INDEX); + if (TextUtils.isEmpty(name)) { + name = mContext.getString(android.R.string.unknownName); + } + allnames.add(name); + } + } + } finally { + if (contactCursor != null) { + contactCursor.close(); + } + } + if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_INDEXED) { + if (V) Log.v(TAG, "getPhonebookNameList, order by index"); + } else if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL) { + if (V) Log.v(TAG, "getPhonebookNameList, order by alpha"); + Collections.sort(allnames, new Comparator <String> () { + @Override + public int compare(String str1, String str2) { + return str1.compareToIgnoreCase(str2); + } + }); + } + + nameList.addAll(allnames); + return nameList; + + } + + public final ArrayList<String> getSIMContactNamesByNumber( + final String phoneNumber) { + ArrayList<String> nameList = new ArrayList<String>(); + ArrayList<String> startNameList = new ArrayList<String>(); + Cursor contactCursor = null; + final Uri uri = Uri.parse(SIM_URI); + + try { + contactCursor = mContentResolver.query(uri, SIM_PROJECTION, + null, null, null); + + if (contactCursor != null) { + for (contactCursor.moveToFirst(); !contactCursor.isAfterLast(); contactCursor + .moveToNext()) { + String number = contactCursor.getString(NUMBER_COLUMN_INDEX); + if (number == null) { + if (V) Log.v(TAG, "number is null"); + continue; + } + + if (V) Log.v(TAG, "number: " + number + " phoneNumber:" + phoneNumber); + if ((number.endsWith(phoneNumber)) || (number.startsWith(phoneNumber))) { + String name = contactCursor.getString(NAME_COLUMN_INDEX); + if (TextUtils.isEmpty(name)) { + name = mContext.getString(android.R.string.unknownName); + } + if (V) Log.v(TAG, "got name " + name + " by number " + phoneNumber); + + if (number.endsWith(phoneNumber)) { + if (V) Log.v(TAG, "Adding to end name list"); + nameList.add(name); + } else { + if (V) Log.v(TAG, "Adding to start name list"); + startNameList.add(name); + } + } + } + } + } finally { + if (contactCursor != null) { + contactCursor.close(); + } + } + int startListSize = startNameList.size(); + for (int index = 0; index < startListSize; index++) { + String object = startNameList.get(index); + if (!nameList.contains(object)) + nameList.add(object); + } + + return nameList; + } + + public final int composeAndSendSIMPhonebookVcards(Operation op, + final int startPoint, final int endPoint, final boolean vcardType21, + String ownerVCard) { + if (startPoint < 1 || startPoint > endPoint) { + Log.e(TAG, "internal error: startPoint or endPoint is not correct."); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + final Uri myUri = Uri.parse(SIM_URI); + BluetoothPbapSimVcardManager composer = null; + HandlerForStringBuffer buffer = null; + try { + composer = new BluetoothPbapSimVcardManager(mContext); + buffer = new HandlerForStringBuffer(op, ownerVCard); + + if (!composer.init(myUri, null, null, null) || !buffer.onInit(mContext)) { + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + composer.moveToPosition(startPoint -1, false); + for (int count =startPoint -1; count < endPoint; count++) { + if (BluetoothPbapObexServer.sIsAborted) { + ((ServerOperation)op).setAborted(true); + BluetoothPbapObexServer.sIsAborted = false; + break; + } + String vcard = composer.createOneEntry(vcardType21); + if (vcard == null) { + Log.e(TAG, "Failed to read a contact. Error reason: " + + composer.getErrorReason()); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + buffer.onEntryCreated(vcard); + } + } finally { + if (composer != null) { + composer.terminate(); + } + if (buffer != null) { + buffer.onTerminate(); + } + } + return ResponseCodes.OBEX_HTTP_OK; + } + + /** + * Handler to emit vCards to PCE. + */ + public class HandlerForStringBuffer { + private Operation operation; + + private OutputStream outputStream; + + private String phoneOwnVCard = null; + + public HandlerForStringBuffer(Operation op, String ownerVCard) { + operation = op; + if (ownerVCard != null) { + phoneOwnVCard = ownerVCard; + if (V) Log.v(TAG, "phoneOwnVCard \n " + phoneOwnVCard); + } + } + + private boolean write(String vCard) { + try { + if (vCard != null) { + outputStream.write(vCard.getBytes()); + return true; + } + } catch (IOException e) { + Log.e(TAG, "write outputstrem failed" + e.toString()); + } + return false; + } + + public boolean onInit(Context context) { + try { + outputStream = operation.openOutputStream(); + if (phoneOwnVCard != null) { + return write(phoneOwnVCard); + } + return true; + } catch (IOException e) { + Log.e(TAG, "open outputstrem failed" + e.toString()); + } + return false; + } + + public boolean onEntryCreated(String vcard) { + return write(vcard); + } + + public void onTerminate() { + if (!BluetoothPbapObexServer.closeStream(outputStream, operation)) { + if (V) Log.v(TAG, "CloseStream failed!"); + } else { + if (V) Log.v(TAG, "CloseStream ok!"); + } + } + } + + public final int composeAndSendSIMPhonebookOneVcard(Operation op, + final int offset, final boolean vcardType21, String ownerVCard, + int orderByWhat) { + if (offset < 1) { + Log.e(TAG, "Internal error: offset is not correct."); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + final Uri myUri = Uri.parse(SIM_URI); + if (V) Log.v(TAG, "composeAndSendSIMPhonebookOneVcard orderByWhat " + orderByWhat); + BluetoothPbapSimVcardManager composer = null; + HandlerForStringBuffer buffer = null; + try { + composer = new BluetoothPbapSimVcardManager(mContext); + buffer = new HandlerForStringBuffer(op, ownerVCard); + if (!composer.init(myUri, null, null,null)|| + !buffer.onInit(mContext)) { + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_INDEXED) { + composer.moveToPosition(offset -1, false); + } else if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL) { + composer.moveToPosition(offset -1, true); + } + if (BluetoothPbapObexServer.sIsAborted) { + ((ServerOperation)op).setAborted(true); + BluetoothPbapObexServer.sIsAborted = false; + } + String vcard = composer.createOneEntry(vcardType21); + if (vcard == null) { + Log.e(TAG, "Failed to read a contact. Error reason: " + + composer.getErrorReason()); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + buffer.onEntryCreated(vcard); + } finally { + if (composer != null) { + composer.terminate(); + } + if (buffer != null) { + buffer.onTerminate(); + } + } + + return ResponseCodes.OBEX_HTTP_OK; + } + + protected boolean isSimPhoneBook(String name, String type, String PB, + String SIM1, String TYPE_PB, String TYPE_LISTING, String mCurrentPath) { + + return ((name.contains(PB.subSequence(0, PB.length())) + && name.contains(SIM1.subSequence(0, + SIM1.length()))) + && (type.equals(TYPE_PB))) + || (((name.contains( + PB.subSequence(0, PB.length()))) + && (mCurrentPath.equals(SIM_PATH))) + && (type.equals(TYPE_LISTING))); + } + + protected String getType(String searchAttr) { + String type = ""; + if (searchAttr.equals("0")) { + type = "name"; + } else if (searchAttr.equals("1")) { + type = "number"; + } + return type; + } +} diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java index e968852771..b22713fc5e 100755..100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java @@ -148,13 +148,17 @@ public class BluetoothPbapVcardManager { return vcard; } - public final int getPhonebookSize(final int type) { + public final int getPhonebookSize(final int type, + BluetoothPbapSimVcardManager vCardSimManager) { int size; switch (type) { case BluetoothPbapObexServer.ContentType.PHONEBOOK: case BluetoothPbapObexServer.ContentType.FAVORITES: size = getContactsSize(type); break; + case BluetoothPbapObexServer.ContentType.SIM_PHONEBOOK: + size = vCardSimManager.getSIMContactsSize(); + break; default: size = getCallHistorySize(type); break; diff --git a/android/app/tests/unit/AndroidManifest.xml b/android/app/tests/unit/AndroidManifest.xml index cf50f48508..e1927e5402 100644 --- a/android/app/tests/unit/AndroidManifest.xml +++ b/android/app/tests/unit/AndroidManifest.xml @@ -61,11 +61,11 @@ </application> <!-- This declares that this application uses the instrumentation test runner targeting - the package of com.android.bluetooth. To run the tests use the command: + the package of com.android.bluetooth.services. To run the tests use the command: "adb shell am instrument -w com.android.bluetooth.tests/android.test.InstrumentationTestRunner" --> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.bluetooth" - android:label="Tests for com.android.bluetooth"/> + android:targetPackage="com.android.bluetooth.services" + android:label="Tests for com.android.bluetooth.services"/> </manifest> diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java index eb046d832e..42498b47c0 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java @@ -381,6 +381,10 @@ public final class DatabaseManagerTest { testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD, value, true); + testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_SPATIAL_AUDIO, + value, true); + testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS, + value, true); testSetGetCustomMetaCase(false, badKey, value, false); // Device is in database @@ -435,6 +439,10 @@ public final class DatabaseManagerTest { testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD, value, true); + testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_SPATIAL_AUDIO, + value, true); + testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS, + value, true); } @Test @@ -1151,6 +1159,30 @@ public final class DatabaseManagerTest { } } + @Test + public void testDatabaseMigration_112_113() throws IOException { + // Create a database with version 112 + SupportSQLiteDatabase db = testHelper.createDatabase(DB_NAME, 112); + // insert a device to the database + ContentValues device = new ContentValues(); + device.put("address", TEST_BT_ADDR); + device.put("migrated", false); + assertThat(db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device), + CoreMatchers.not(-1)); + // Migrate database from 112 to 113 + db.close(); + db = testHelper.runMigrationsAndValidate(DB_NAME, 113, true, + MetadataDatabase.MIGRATION_112_113); + Cursor cursor = db.query("SELECT * FROM metadata"); + assertHasColumn(cursor, "spatial_audio", true); + assertHasColumn(cursor, "fastpair_customized", true); + while (cursor.moveToNext()) { + // Check the new columns was added with default value + assertColumnBlobData(cursor, "spatial_audio", null); + assertColumnBlobData(cursor, "fastpair_customized", null); + } + } + /** * Helper function to check whether the database has the expected column */ diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/schemas/com.android.bluetooth.btservice.storage.MetadataDatabase/113.json b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/schemas/com.android.bluetooth.btservice.storage.MetadataDatabase/113.json new file mode 100644 index 0000000000..08c9ca145c --- /dev/null +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/schemas/com.android.bluetooth.btservice.storage.MetadataDatabase/113.json @@ -0,0 +1,334 @@ +{ + "formatVersion": 1, + "database": { + "version": 113, + "identityHash": "1949f73d922d80a81335edc130b9871d", + "entities": [ + { + "tableName": "metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`address` TEXT NOT NULL, `migrated` INTEGER NOT NULL, `a2dpSupportsOptionalCodecs` INTEGER NOT NULL, `a2dpOptionalCodecsEnabled` INTEGER NOT NULL, `last_active_time` INTEGER NOT NULL, `is_active_a2dp_device` INTEGER NOT NULL, `a2dp_connection_policy` INTEGER, `a2dp_sink_connection_policy` INTEGER, `hfp_connection_policy` INTEGER, `hfp_client_connection_policy` INTEGER, `hid_host_connection_policy` INTEGER, `pan_connection_policy` INTEGER, `pbap_connection_policy` INTEGER, `pbap_client_connection_policy` INTEGER, `map_connection_policy` INTEGER, `sap_connection_policy` INTEGER, `hearing_aid_connection_policy` INTEGER, `hap_client_connection_policy` INTEGER, `map_client_connection_policy` INTEGER, `le_audio_connection_policy` INTEGER, `volume_control_connection_policy` INTEGER, `csip_set_coordinator_connection_policy` INTEGER, `le_call_control_connection_policy` INTEGER, `bass_client_connection_policy` INTEGER, `battery_connection_policy` INTEGER, `manufacturer_name` BLOB, `model_name` BLOB, `software_version` BLOB, `hardware_version` BLOB, `companion_app` BLOB, `main_icon` BLOB, `is_untethered_headset` BLOB, `untethered_left_icon` BLOB, `untethered_right_icon` BLOB, `untethered_case_icon` BLOB, `untethered_left_battery` BLOB, `untethered_right_battery` BLOB, `untethered_case_battery` BLOB, `untethered_left_charging` BLOB, `untethered_right_charging` BLOB, `untethered_case_charging` BLOB, `enhanced_settings_ui_uri` BLOB, `device_type` BLOB, `main_battery` BLOB, `main_charging` BLOB, `main_low_battery_threshold` BLOB, `untethered_left_low_battery_threshold` BLOB, `untethered_right_low_battery_threshold` BLOB, `untethered_case_low_battery_threshold` BLOB, `spatial_audio` BLOB, `fastpair_customized` BLOB, PRIMARY KEY(`address`))", + "fields": [ + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "migrated", + "columnName": "migrated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "a2dpSupportsOptionalCodecs", + "columnName": "a2dpSupportsOptionalCodecs", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "a2dpOptionalCodecsEnabled", + "columnName": "a2dpOptionalCodecsEnabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "last_active_time", + "columnName": "last_active_time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "is_active_a2dp_device", + "columnName": "is_active_a2dp_device", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "profileConnectionPolicies.a2dp_connection_policy", + "columnName": "a2dp_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.a2dp_sink_connection_policy", + "columnName": "a2dp_sink_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.hfp_connection_policy", + "columnName": "hfp_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.hfp_client_connection_policy", + "columnName": "hfp_client_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.hid_host_connection_policy", + "columnName": "hid_host_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.pan_connection_policy", + "columnName": "pan_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.pbap_connection_policy", + "columnName": "pbap_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.pbap_client_connection_policy", + "columnName": "pbap_client_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.map_connection_policy", + "columnName": "map_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.sap_connection_policy", + "columnName": "sap_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.hearing_aid_connection_policy", + "columnName": "hearing_aid_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.hap_client_connection_policy", + "columnName": "hap_client_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.map_client_connection_policy", + "columnName": "map_client_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.le_audio_connection_policy", + "columnName": "le_audio_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.volume_control_connection_policy", + "columnName": "volume_control_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.csip_set_coordinator_connection_policy", + "columnName": "csip_set_coordinator_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.le_call_control_connection_policy", + "columnName": "le_call_control_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.bass_client_connection_policy", + "columnName": "bass_client_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileConnectionPolicies.battery_connection_policy", + "columnName": "battery_connection_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "publicMetadata.manufacturer_name", + "columnName": "manufacturer_name", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.model_name", + "columnName": "model_name", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.software_version", + "columnName": "software_version", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.hardware_version", + "columnName": "hardware_version", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.companion_app", + "columnName": "companion_app", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.main_icon", + "columnName": "main_icon", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.is_untethered_headset", + "columnName": "is_untethered_headset", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_left_icon", + "columnName": "untethered_left_icon", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_right_icon", + "columnName": "untethered_right_icon", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_case_icon", + "columnName": "untethered_case_icon", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_left_battery", + "columnName": "untethered_left_battery", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_right_battery", + "columnName": "untethered_right_battery", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_case_battery", + "columnName": "untethered_case_battery", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_left_charging", + "columnName": "untethered_left_charging", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_right_charging", + "columnName": "untethered_right_charging", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_case_charging", + "columnName": "untethered_case_charging", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.enhanced_settings_ui_uri", + "columnName": "enhanced_settings_ui_uri", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.device_type", + "columnName": "device_type", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.main_battery", + "columnName": "main_battery", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.main_charging", + "columnName": "main_charging", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.main_low_battery_threshold", + "columnName": "main_low_battery_threshold", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_left_low_battery_threshold", + "columnName": "untethered_left_low_battery_threshold", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_right_low_battery_threshold", + "columnName": "untethered_right_low_battery_threshold", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.untethered_case_low_battery_threshold", + "columnName": "untethered_case_low_battery_threshold", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.spatial_audio", + "columnName": "spatial_audio", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "publicMetadata.fastpair_customized", + "columnName": "fastpair_customized", + "affinity": "BLOB", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "address" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1949f73d922d80a81335edc130b9871d')" + ] + } +}
\ No newline at end of file diff --git a/android/blueberry/server/Android.bp b/android/blueberry/server/Android.bp index 7d3d0b0658..1831b8f875 100644 --- a/android/blueberry/server/Android.bp +++ b/android/blueberry/server/Android.bp @@ -2,7 +2,7 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } -android_test { +android_test_helper_app { name: "BlueberryServer", srcs: ["src/**/*.kt"], platform_apis: true, @@ -29,6 +29,13 @@ android_test { }, } +android_test { + name: "pts-bot", + required: ["BlueberryServer"], + test_config: "configs/PtsBotTest.xml", + data: ["configs/pts_bot_tests_config.json"], +} + java_library { name: "blueberry-grpc-java", visibility: ["//visibility:private"], diff --git a/android/blueberry/server/configs/PtsBotTest.xml b/android/blueberry/server/configs/PtsBotTest.xml new file mode 100644 index 0000000000..7ee909a909 --- /dev/null +++ b/android/blueberry/server/configs/PtsBotTest.xml @@ -0,0 +1,19 @@ +<configuration description="Runs PTS-bot tests"> + + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="BlueberryServer.apk" /> + <option name="install-arg" value="-r" /> + <option name="install-arg" value="-g" /> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.InstallApkSetup"> + <option name="post-install-cmd" value="am instrument -e Debug false com.android.blueberry/.Main" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.blueberry.PtsBotTest" > + <option name="mmi2grpc" value="empty" /> + <option name="tests-config-file" value="pts_bot_tests_config.json" /> + <option name="physical" value="false" /> + <option name="profile" value="A2DP/SRC" /> + </test> + +</configuration> diff --git a/android/blueberry/server/configs/pts_bot_tests_config.json b/android/blueberry/server/configs/pts_bot_tests_config.json new file mode 100644 index 0000000000..45153dfb5c --- /dev/null +++ b/android/blueberry/server/configs/pts_bot_tests_config.json @@ -0,0 +1,179 @@ +{ + "ics": { + "TSPC_A2DP_9_4": true, + "TSPC_A2DP_9_2": true, + "TSPC_A2DP_9_1": true, + "TSPC_A2DP_8_3": true, + "TSPC_A2DP_13_3": true, + "TSPC_A2DP_13_2": true, + "TSPC_A2DP_9_3": true, + "TSPC_A2DP_13_1": true, + "TSPC_A2DP_8_2": true, + "TSPC_A2DP_12_3": true, + "TSPC_A2DP_12_4": true, + "TSPC_A2DP_12_2": true, + "TSPC_A2DP_8_4": true, + "TSPC_A2DP_1_1": true, + "TSPC_A2DP_1_2": true, + "TSPC_A2DP_2a_3": true, + "TSPC_A2DP_2b_2": true, + "TSPC_A2DP_2_1": true, + "TSPC_A2DP_2_10": true, + "TSPC_A2DP_2_10a": true, + "TSPC_A2DP_2_13": true, + "TSPC_A2DP_2_2": true, + "TSPC_A2DP_2_3": true, + "TSPC_A2DP_2_4": true, + "TSPC_A2DP_2_5": true, + "TSPC_A2DP_2_6": true, + "TSPC_A2DP_2_7": true, + "TSPC_A2DP_2_8": true, + "TSPC_A2DP_2_9": true, + "TSPC_A2DP_3_1": true, + "TSPC_A2DP_3_1a": true, + "TSPC_A2DP_3a_1": true, + "TSPC_A2DP_3a_10": true, + "TSPC_A2DP_3a_11": true, + "TSPC_A2DP_3a_12": true, + "TSPC_A2DP_3a_2": true, + "TSPC_A2DP_3a_3": true, + "TSPC_A2DP_3a_4": true, + "TSPC_A2DP_3a_5": true, + "TSPC_A2DP_3a_6": true, + "TSPC_A2DP_3a_7": true, + "TSPC_A2DP_3a_8": true, + "TSPC_A2DP_3a_9": true, + "TSPC_A2DP_4_1": true, + "TSPC_A2DP_4_10": true, + "TSPC_A2DP_4_10a": true, + "TSPC_A2DP_4_13": true, + "TSPC_A2DP_4_15": true, + "TSPC_A2DP_4_2": true, + "TSPC_A2DP_4_3": false, + "TSPC_A2DP_4_4": true, + "TSPC_A2DP_4_5": true, + "TSPC_A2DP_4_6": true, + "TSPC_A2DP_4_7": true, + "TSPC_A2DP_4_8": false, + "TSPC_A2DP_4_9": true, + "TSPC_A2DP_7a_3": true, + "TSPC_A2DP_7b_2": true, + "TSPC_A2DP_5_1": true, + "TSPC_A2DP_5_1a": true, + "TSPC_A2DP_5a_1": true, + "TSPC_A2DP_5a_10": true, + "TSPC_A2DP_5a_11": true, + "TSPC_A2DP_5a_12": true, + "TSPC_A2DP_5a_2": true, + "TSPC_A2DP_5a_3": true, + "TSPC_A2DP_5a_4": true, + "TSPC_A2DP_5a_5": true, + "TSPC_A2DP_5a_6": true, + "TSPC_A2DP_5a_7": true, + "TSPC_A2DP_5a_8": true, + "TSPC_A2DP_5a_9": true, + "TSPC_AVDTP_1_1": true, + "TSPC_AVDTP_1_2": true, + "TSPC_AVDTP_1_3": true, + "TSPC_AVDTP_1_4": true, + "TSPC_AVDTP_16_1": true, + "TSPC_AVDTP_16_3": true, + "TSPC_AVDTP_2_1": true, + "TSPC_AVDTP_2_2": true, + "TSPC_AVDTP_2_3": true, + "TSPC_AVDTP_2_4": true, + "TSPC_AVDTP_2b_1": true, + "TSPC_AVDTP_2b_2": true, + "TSPC_AVDTP_2b_3": true, + "TSPC_AVDTP_2b_4": true, + "TSPC_AVDTP_3_1": true, + "TSPC_AVDTP_3_2": true, + "TSPC_AVDTP_3b_1": true, + "TSPC_AVDTP_3b_2": true, + "TSPC_AVDTP_4_1": true, + "TSPC_AVDTP_4_2": true, + "TSPC_AVDTP_4_3": true, + "TSPC_AVDTP_4_4": true, + "TSPC_AVDTP_4_5": false, + "TSPC_AVDTP_4_6": true, + "TSPC_AVDTP_4b_1": true, + "TSPC_AVDTP_4b_2": true, + "TSPC_AVDTP_4b_3": true, + "TSPC_AVDTP_4b_4": false, + "TSPC_AVDTP_4b_5": false, + "TSPC_AVDTP_4b_6": true, + "TSPC_AVDTP_5_1": true, + "TSPC_AVDTP_5_2": true, + "TSPC_AVDTP_5_3": true, + "TSPC_AVDTP_5_4": true, + "TSPC_AVDTP_5_5": true, + "TSPC_AVDTP_5b_1": true, + "TSPC_AVDTP_5b_2": false, + "TSPC_AVDTP_5b_3": true, + "TSPC_AVDTP_5b_4": false, + "TSPC_AVDTP_5b_5": true, + "TSPC_AVDTP_6b_1": true, + "TSPC_AVDTP_7_1": true, + "TSPC_AVDTP_7b_1": true, + "TSPC_AVDTP_10_1": true, + "TSPC_AVDTP_10_2": true, + "TSPC_AVDTP_10_3": true, + "TSPC_AVDTP_10_4": true, + "TSPC_AVDTP_10_5": true, + "TSPC_AVDTP_10_6": true, + "TSPC_AVDTP_10b_1": true, + "TSPC_AVDTP_10b_2": true, + "TSPC_AVDTP_10b_3": true, + "TSPC_AVDTP_10b_4": true, + "TSPC_AVDTP_10b_5": true, + "TSPC_AVDTP_10b_6": true, + "TSPC_AVDTP_11_1": true, + "TSPC_AVDTP_11_2": true, + "TSPC_AVDTP_11_3": true, + "TSPC_AVDTP_11_4": true, + "TSPC_AVDTP_11_5": true, + "TSPC_AVDTP_11_6": true, + "TSPC_AVDTP_11b_1": true, + "TSPC_AVDTP_11b_2": true, + "TSPC_AVDTP_11b_3": true, + "TSPC_AVDTP_11b_4": true, + "TSPC_AVDTP_11b_5": true, + "TSPC_AVDTP_11b_6": true, + "TSPC_AVDTP_12b_1": true, + "TSPC_AVDTP_13_1": true, + "TSPC_AVDTP_13b_1": true, + "TSPC_AVDTP_8_1": true, + "TSPC_AVDTP_8_2": true, + "TSPC_AVDTP_8_3": true, + "TSPC_AVDTP_8_4": true, + "TSPC_AVDTP_8b_1": true, + "TSPC_AVDTP_8b_2": true, + "TSPC_AVDTP_8b_3": true, + "TSPC_AVDTP_8b_4": true, + "TSPC_AVDTP_9_1": true, + "TSPC_AVDTP_9_2": true, + "TSPC_AVDTP_9b_1": true, + "TSPC_AVDTP_9b_2": true, + "TSPC_AVDTP_14_1": true, + "TSPC_AVDTP_14_6": true, + "TSPC_AVDTP_14a_3": true, + "TSPC_AVDTP_15_1": true, + "TSPC_AVDTP_15_6": false, + "TSPC_AVDTP_15a_3": true, + "TSPC_SUM ICS_31_22": true, + "TSPC_PROD_1_2": true, + "TSPC_PROD_3_1": true + }, + "ixit": {"default": {}, "A2DP": {}, "AVDTP": {}}, + "skip": [ + "A2DP/SRC/SET/BV-05-I", + "A2DP/SRC/SET/BV-06-I", + "A2DP/SNK/SYN/BV-01-C", + "AVDTP/SRC/INT/SIG/SMG/BV-11-C", + "AVDTP/SRC/INT/SIG/SMG/BV-23-C", + "AVDTP/SNK/INT/SIG/SMG/BV-19-C", + "AVDTP/SNK/INT/SIG/SMG/BV-23-C", + "A2DP/SRC/CC/BV-09-I" + ] + } + diff --git a/android/blueberry/server/src/com/android/blueberry/Host.kt b/android/blueberry/server/src/com/android/blueberry/Host.kt index 373cabbd20..433c75287c 100644 --- a/android/blueberry/server/src/com/android/blueberry/Host.kt +++ b/android/blueberry/server/src/com/android/blueberry/Host.kt @@ -76,7 +76,7 @@ class Host(private val context: Context, private val server: Server) : HostImplB grpcUnary<Empty>(scope, responseObserver) { Log.i(TAG, "reset") - bluetoothAdapter.factoryReset() + bluetoothAdapter.clearBluetooth() val stateFlow = flow.filter { it.getAction() == BluetoothAdapter.ACTION_STATE_CHANGED }.map { diff --git a/apex/Android.bp b/apex/Android.bp index 46c5db7b4a..f3280eebf5 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -22,10 +22,19 @@ apex { compile_multilib: "both", + prebuilts: [ + "bluetooth-linker-config", + ], key: "com.android.bluetooth.key", certificate: ":com.android.bluetooth.certificate", } +linker_config { + name: "bluetooth-linker-config", + src: "linker.config.json", + installable: false, +} + apex_key { name: "com.android.bluetooth.key", public_key: "com.android.bluetooth.avbpubkey", diff --git a/apex/linker.config.json b/apex/linker.config.json new file mode 100644 index 0000000000..7593c0234f --- /dev/null +++ b/apex/linker.config.json @@ -0,0 +1,5 @@ +{ + "permittedPaths": [ + "/system_ext/${LIB}" + ] +} diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt index aa75707efc..020955f866 100644 --- a/framework/api/system-current.txt +++ b/framework/api/system-current.txt @@ -54,11 +54,11 @@ package android.bluetooth { public final class BluetoothAdapter { method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean clearBluetooth(); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean disable(boolean); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disableBLE(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableBLE(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableNoAutoConnect(); - method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean factoryReset(); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void generateLocalOobData(int, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OobDataCallback); method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getActiveDevices(int); method public int getConnectionState(); diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 6b4c8062b6..c21ba6596e 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1526,7 +1526,7 @@ public final class BluetoothAdapter { android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, }) - public boolean factoryReset() { + public boolean clearBluetooth() { try { mServiceLock.readLock().lock(); if (mService != null) { @@ -1548,6 +1548,22 @@ public final class BluetoothAdapter { return false; } + /** + * See {@link #clearBluetooth()} + * + * @return true to indicate that the config file was successfully cleared + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public boolean factoryReset() { + return clearBluetooth(); + } + /** * Get the UUIDs supported by the local Bluetooth adapter. * diff --git a/framework/java/android/bluetooth/BluetoothCodecConfig.java b/framework/java/android/bluetooth/BluetoothCodecConfig.java index 4cbf956c24..d1fb561107 100644 --- a/framework/java/android/bluetooth/BluetoothCodecConfig.java +++ b/framework/java/android/bluetooth/BluetoothCodecConfig.java @@ -566,6 +566,17 @@ public final class BluetoothCodecConfig implements Parcelable { * Returns the codec specific value1. * As the value and usage differ for each codec, please refer to the concerned * codec specification to obtain the codec specific information. + * + * <p>See section 4.3.2 of the Bluetooth A2dp specification for SBC codec specific + * information elements. + * <p>See section 4.4.2 of the Bluetooth A2dp specification for MPEG-1,2 Audio + * codec specific information elements. + * <p>See section 4.5.2 of the Bluetooth A2dp specification for MPEG-2, 4 AAC + * codec specific information elements. + * <p>See section 4.6.2 of the Bluetooth A2dp specification for ATRAC family + * codec specific information elements. + * <p>See section 4.7.2 of the Bluetooth A2dp specification for Vendor Specific A2DP + * codec specific information elements. */ public long getCodecSpecific1() { return mCodecSpecific1; @@ -575,6 +586,17 @@ public final class BluetoothCodecConfig implements Parcelable { * Returns the codec specific value2. * As the value and usage differ for each codec, please refer to the concerned * codec specification to obtain the codec specific information. + * + * <p>See section 4.3.2 of the Bluetooth A2dp specification for SBC codec specific + * information elements. + * <p>See section 4.4.2 of the Bluetooth A2dp specification for MPEG-1,2 Audio + * codec specific information elements. + * <p>See section 4.5.2 of the Bluetooth A2dp specification for MPEG-2, 4 AAC + * codec specific information elements. + * <p>See section 4.6.2 of the Bluetooth A2dp specification for ATRAC family + * codec specific information elements. + * <p>See section 4.7.2 of the Bluetooth A2dp specification for Vendor Specific A2DP + * codec specific information elements. */ public long getCodecSpecific2() { return mCodecSpecific2; @@ -584,6 +606,17 @@ public final class BluetoothCodecConfig implements Parcelable { * Returns the codec specific value3. * As the value and usage differ for each codec, please refer to the concerned * codec specification to obtain the codec specific information. + * + * <p>See section 4.3.2 of the Bluetooth A2dp specification for SBC codec specific + * information elements. + * <p>See section 4.4.2 of the Bluetooth A2dp specification for MPEG-1,2 Audio + * codec specific information elements. + * <p>See section 4.5.2 of the Bluetooth A2dp specification for MPEG-2, 4 AAC + * codec specific information elements. + * <p>See section 4.6.2 of the Bluetooth A2dp specification for ATRAC family + * codec specific information elements. + * <p>See section 4.7.2 of the Bluetooth A2dp specification for Vendor Specific A2DP + * codec specific information elements. */ public long getCodecSpecific3() { return mCodecSpecific3; @@ -593,6 +626,17 @@ public final class BluetoothCodecConfig implements Parcelable { * Returns the codec specific value4. * As the value and usage differ for each codec, please refer to the concerned * codec specification to obtain the codec specific information. + * + * <p>See section 4.3.2 of the Bluetooth A2dp specification for SBC codec specific + * information elements. + * <p>See section 4.4.2 of the Bluetooth A2dp specification for MPEG-1,2 Audio + * codec specific information elements. + * <p>See section 4.5.2 of the Bluetooth A2dp specification for MPEG-2, 4 AAC + * codec specific information elements. + * <p>See section 4.6.2 of the Bluetooth A2dp specification for ATRAC family + * codec specific information elements. + * <p>See section 4.7.2 of the Bluetooth A2dp specification for Vendor Specific A2DP + * codec specific information elements. */ public long getCodecSpecific4() { return mCodecSpecific4; diff --git a/framework/java/android/bluetooth/BluetoothDevice.java b/framework/java/android/bluetooth/BluetoothDevice.java index 5e674890b6..bf3d9697b0 100644 --- a/framework/java/android/bluetooth/BluetoothDevice.java +++ b/framework/java/android/bluetooth/BluetoothDevice.java @@ -652,7 +652,9 @@ public final class BluetoothDevice implements Parcelable, Attributable { METADATA_MAIN_LOW_BATTERY_THRESHOLD, METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD, METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD, - METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD}) + METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD, + METADATA_SPATIAL_AUDIO, + METADATA_FAST_PAIR_CUSTOMIZED_FIELDS}) @Retention(RetentionPolicy.SOURCE) public @interface MetadataKey{} @@ -862,6 +864,21 @@ public final class BluetoothDevice implements Parcelable, Attributable { @SystemApi public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23; + + /** + * The metadata of the audio spatial data. + * Data type should be {@link Byte} array. + * @hide + */ + public static final int METADATA_SPATIAL_AUDIO = 24; + + /** + * The metadata of the Fast Pair for any custmized feature. + * Data type should be {@link Byte} array. + * @hide + */ + public static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25; + /** * Device type which is used in METADATA_DEVICE_TYPE * Indicates this Bluetooth device is a standard Bluetooth accessory or @@ -3488,7 +3505,7 @@ public final class BluetoothDevice implements Parcelable, Attributable { * @hide */ public static @MetadataKey int getMaxMetadataKey() { - return METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD; + return METADATA_FAST_PAIR_CUSTOMIZED_FIELDS; } /** diff --git a/framework/java/android/bluetooth/BluetoothHapClient.java b/framework/java/android/bluetooth/BluetoothHapClient.java index dda803ef38..c05126d9c0 100644 --- a/framework/java/android/bluetooth/BluetoothHapClient.java +++ b/framework/java/android/bluetooth/BluetoothHapClient.java @@ -541,15 +541,19 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable @NonNull Callback callback) { Objects.requireNonNull(executor, "executor cannot be null"); Objects.requireNonNull(callback, "callback cannot be null"); - if (!isEnabled()) { - throw new IllegalStateException("service not enabled"); - } if (DBG) log("registerCallback"); synchronized (mCallbackExecutorMap) { // If the callback map is empty, we register the service-to-app callback if (mCallbackExecutorMap.isEmpty()) { + if (!isEnabled()) { + /* If Bluetooth is off, just store callback and it will be registered + * when Bluetooth is on + */ + mCallbackExecutorMap.put(callback, executor); + return; + } try { final IBluetoothHapClient service = getService(); if (service != null) { @@ -558,7 +562,7 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable service.registerCallback(mCallback, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } - } catch (IllegalStateException | TimeoutException e) { + } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/framework/java/android/bluetooth/BluetoothHeadset.java b/framework/java/android/bluetooth/BluetoothHeadset.java index 9cbfe2971a..693b86608c 100644 --- a/framework/java/android/bluetooth/BluetoothHeadset.java +++ b/framework/java/android/bluetooth/BluetoothHeadset.java @@ -1001,7 +1001,6 @@ public final class BluetoothHeadset implements BluetoothProfile { @Retention(RetentionPolicy.SOURCE) @IntDef(value = { BluetoothStatusCodes.SUCCESS, - BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, BluetoothStatusCodes.ERROR_TIMEOUT, BluetoothStatusCodes.ERROR_UNKNOWN, @@ -1013,7 +1012,6 @@ public final class BluetoothHeadset implements BluetoothProfile { @IntDef(value = { BluetoothStatusCodes.ALLOWED, BluetoothStatusCodes.NOT_ALLOWED, - BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, BluetoothStatusCodes.ERROR_TIMEOUT, BluetoothStatusCodes.ERROR_UNKNOWN, @@ -1046,21 +1044,22 @@ public final class BluetoothHeadset implements BluetoothProfile { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } else if (!isEnabled()) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - try { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setAudioRouteAllowed(allowed, mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - return BluetoothStatusCodes.SUCCESS; - } catch (TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - return BluetoothStatusCodes.ERROR_TIMEOUT; - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - e.rethrowFromSystemServer(); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.setAudioRouteAllowed(allowed, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + return BluetoothStatusCodes.SUCCESS; + } catch (TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + return BluetoothStatusCodes.ERROR_TIMEOUT; + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + e.rethrowFromSystemServer(); + } } + + Log.e(TAG, "setAudioRouteAllowed: Bluetooth disabled, but profile service still bound"); return BluetoothStatusCodes.ERROR_UNKNOWN; } @@ -1085,21 +1084,22 @@ public final class BluetoothHeadset implements BluetoothProfile { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } else if (!isEnabled()) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - try { - final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); - service.getAudioRouteAllowed(mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(false) - ? BluetoothStatusCodes.ALLOWED : BluetoothStatusCodes.NOT_ALLOWED; - } catch (TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - return BluetoothStatusCodes.ERROR_TIMEOUT; - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - e.rethrowFromSystemServer(); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.getAudioRouteAllowed(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(false) + ? BluetoothStatusCodes.ALLOWED : BluetoothStatusCodes.NOT_ALLOWED; + } catch (TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + return BluetoothStatusCodes.ERROR_TIMEOUT; + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + e.rethrowFromSystemServer(); + } } + + Log.e(TAG, "getAudioRouteAllowed: Bluetooth disabled, but profile service still bound"); return BluetoothStatusCodes.ERROR_UNKNOWN; } @@ -1136,7 +1136,6 @@ public final class BluetoothHeadset implements BluetoothProfile { BluetoothStatusCodes.ERROR_UNKNOWN, BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, BluetoothStatusCodes.ERROR_TIMEOUT, - BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_CONNECTED, BluetoothStatusCodes.ERROR_NO_ACTIVE_DEVICES, BluetoothStatusCodes.ERROR_NOT_ACTIVE_DEVICE, @@ -1186,9 +1185,10 @@ public final class BluetoothHeadset implements BluetoothProfile { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); return BluetoothStatusCodes.ERROR_TIMEOUT; } - } else { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } + + Log.e(TAG, "connectAudio: Bluetooth disabled, but profile service still bound"); + return defaultValue; } /** @hide */ @@ -1198,7 +1198,6 @@ public final class BluetoothHeadset implements BluetoothProfile { BluetoothStatusCodes.ERROR_UNKNOWN, BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, BluetoothStatusCodes.ERROR_TIMEOUT, - BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED, BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED }) @@ -1241,9 +1240,10 @@ public final class BluetoothHeadset implements BluetoothProfile { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); return BluetoothStatusCodes.ERROR_TIMEOUT; } - } else { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } + + Log.e(TAG, "disconnectAudio: Bluetooth disabled, but profile service still bound"); + return defaultValue; } /** diff --git a/framework/java/android/bluetooth/BluetoothLeAudio.java b/framework/java/android/bluetooth/BluetoothLeAudio.java index 6d416434b2..9d77125271 100644 --- a/framework/java/android/bluetooth/BluetoothLeAudio.java +++ b/framework/java/android/bluetooth/BluetoothLeAudio.java @@ -960,9 +960,8 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { service.registerCallback(mCallback, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } - } catch (IllegalStateException | TimeoutException e) { + } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw new IllegalStateException("Unexpected error", e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcast.java b/framework/java/android/bluetooth/BluetoothLeBroadcast.java index 58f794f2d6..38a8b34a89 100644 --- a/framework/java/android/bluetooth/BluetoothLeBroadcast.java +++ b/framework/java/android/bluetooth/BluetoothLeBroadcast.java @@ -425,15 +425,19 @@ public final class BluetoothLeBroadcast implements AutoCloseable, BluetoothProfi @NonNull Callback callback) { Objects.requireNonNull(executor, "executor cannot be null"); Objects.requireNonNull(callback, "callback cannot be null"); - if (!isEnabled()) { - throw new IllegalStateException("service not enabled"); - } if (DBG) log("registerCallback"); synchronized (mCallbackExecutorMap) { // If the callback map is empty, we register the service-to-app callback if (mCallbackExecutorMap.isEmpty()) { + if (!mAdapter.isEnabled()) { + /* If Bluetooth is off, just store callback and it will be registered + * when Bluetooth is on + */ + mCallbackExecutorMap.put(callback, executor); + return; + } try { final IBluetoothLeAudio service = getService(); if (service != null) { @@ -442,7 +446,7 @@ public final class BluetoothLeBroadcast implements AutoCloseable, BluetoothProfi service.registerLeBroadcastCallback(mCallback, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } - } catch (TimeoutException | IllegalStateException e) { + } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/framework/java/android/bluetooth/BluetoothVolumeControl.java b/framework/java/android/bluetooth/BluetoothVolumeControl.java index a359c91206..080b9a6d64 100644 --- a/framework/java/android/bluetooth/BluetoothVolumeControl.java +++ b/framework/java/android/bluetooth/BluetoothVolumeControl.java @@ -344,6 +344,13 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose synchronized (mCallbackExecutorMap) { // If the callback map is empty, we register the service-to-app callback if (mCallbackExecutorMap.isEmpty()) { + if (!mAdapter.isEnabled()) { + /* If Bluetooth is off, just store callback and it will be registered + * when Bluetooth is on + */ + mCallbackExecutorMap.put(callback, executor); + return; + } try { final IBluetoothVolumeControl service = getService(); if (service != null) { @@ -355,7 +362,7 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); throw e.rethrowFromSystemServer(); - } catch (IllegalStateException | TimeoutException e) { + } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } diff --git a/service/java/com/android/server/bluetooth/BluetoothManagerService.java b/service/java/com/android/server/bluetooth/BluetoothManagerService.java index 6a1c28beb0..f02432679a 100644 --- a/service/java/com/android/server/bluetooth/BluetoothManagerService.java +++ b/service/java/com/android/server/bluetooth/BluetoothManagerService.java @@ -229,6 +229,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { // used inside handler thread private boolean mQuietEnable = false; private boolean mEnable; + private boolean mShutdownInProgress = false; private static CharSequence timeToLog(long timestamp) { return android.text.format.DateFormat.format("MM-dd HH:mm:ss", timestamp); @@ -490,6 +491,23 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { Log.i(TAG, "Device disconnected, reactivating pending flag changes"); onInitFlagsChanged(); } + } else if (action.equals(Intent.ACTION_SHUTDOWN)) { + Log.i(TAG, "Device is shutting down."); + mShutdownInProgress = true; + mBluetoothLock.readLock().lock(); + try { + mEnable = false; + mEnableExternal = false; + if (mBluetooth != null && (mState == BluetoothAdapter.STATE_BLE_ON)) { + synchronousOnBrEdrDown(mContext.getAttributionSource()); + } else if (mBluetooth != null && (mState == BluetoothAdapter.STATE_ON)) { + synchronousDisable(mContext.getAttributionSource()); + } + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, "Unable to shutdown Bluetooth", e); + } finally { + mBluetoothLock.readLock().unlock(); + } } } }; @@ -547,6 +565,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { filter.addAction(Intent.ACTION_SETTING_RESTORED); filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); + filter.addAction(Intent.ACTION_SHUTDOWN); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(mReceiver, filter); @@ -2083,6 +2102,11 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { case MESSAGE_ENABLE: int quietEnable = msg.arg1; int isBle = msg.arg2; + if (mShutdownInProgress) { + Log.d(TAG, "Skip Bluetooth Enable in device shutdown process"); + break; + } + if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) { if (msg.arg2 == 0) { @@ -3274,7 +3298,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { */ private void updateOppLauncherComponentState(UserHandle userHandle, boolean bluetoothSharingDisallowed) { - final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth", + final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth.services", "com.android.bluetooth.opp.BluetoothOppLauncherActivity"); final int newState = bluetoothSharingDisallowed ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED diff --git a/system/audio_hal_interface/aidl/le_audio_software_aidl.cc b/system/audio_hal_interface/aidl/le_audio_software_aidl.cc index 5c946d2bbd..8ba16279d1 100644 --- a/system/audio_hal_interface/aidl/le_audio_software_aidl.cc +++ b/system/audio_hal_interface/aidl/le_audio_software_aidl.cc @@ -433,10 +433,9 @@ std::vector<AudioSetConfiguration> get_offload_capabilities() { if (hal_ucast_capability_to_stack_format(hal_encode_cap, encode_cap)) { audio_set_config.confs.push_back(SetConfiguration( - ::le_audio::types::kLeAudioDirectionSink, - ::le_audio::types::kTargetLatencyBalancedLatencyReliability, - hal_encode_cap.deviceCount, + ::le_audio::types::kLeAudioDirectionSink, hal_encode_cap.deviceCount, hal_encode_cap.deviceCount * hal_encode_cap.channelCountPerDevice, + ::le_audio::types::kTargetLatencyBalancedLatencyReliability, encode_cap)); str_capability_log = " Encode Capability: " + hal_encode_cap.toString(); } @@ -444,9 +443,9 @@ std::vector<AudioSetConfiguration> get_offload_capabilities() { if (hal_ucast_capability_to_stack_format(hal_decode_cap, decode_cap)) { audio_set_config.confs.push_back(SetConfiguration( ::le_audio::types::kLeAudioDirectionSource, - ::le_audio::types::kTargetLatencyBalancedLatencyReliability, hal_decode_cap.deviceCount, hal_decode_cap.deviceCount * hal_decode_cap.channelCountPerDevice, + ::le_audio::types::kTargetLatencyBalancedLatencyReliability, decode_cap)); str_capability_log += " Decode Capability: " + hal_decode_cap.toString(); } diff --git a/system/blueberry/tests/gd/cert/gd_device.py b/system/blueberry/tests/gd/cert/gd_device.py index 4674905842..8074c52433 100644 --- a/system/blueberry/tests/gd/cert/gd_device.py +++ b/system/blueberry/tests/gd/cert/gd_device.py @@ -527,7 +527,9 @@ class GdAndroidDevice(GdDeviceBase): # Ensure Bluetooth is disabled self.ensure_no_output(self.adb.shell("settings put global ble_scan_always_enabled 0")) - self.ensure_no_output(self.adb.shell("svc bluetooth disable")) + self.adb.shell("cmd bluetooth_manager disable") + device_bt_state = int(self.adb.shell("settings get global bluetooth_on")) + asserts.assert_equal(device_bt_state, 0, "Failed to disable Bluetooth on device %s %s" % (self.label, self.serial_number)) logging.info("Bluetooth disabled on device %s %s" % (self.label, self.serial_number)) # Start logcat logging @@ -771,12 +773,15 @@ class GdAndroidDevice(GdDeviceBase): # sys.boot_completed. while time.time() < timeout_start + timeout: try: + logging.debug("waiting for device %s to turn off", self.serial_number) self.adb.get_state() + logging.debug("device %s not turned off yet", self.serial_number) time.sleep(.1) except AdbError: # get_state will raise an error if the device is not found. We # want the device to be missing to prove the device has kicked # off the reboot. + logging.debug("device %s is turned off, waiting for it to boot", self.serial_number) break minutes_left = timeout_minutes - (time.time() - timeout_start) / 60.0 self.wait_for_boot_completion(timeout_minutes=minutes_left) diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc index bf385f8617..ba90f8a720 100644 --- a/system/bta/dm/bta_dm_act.cc +++ b/system/bta/dm/bta_dm_act.cc @@ -3200,7 +3200,8 @@ void bta_dm_eir_update_uuid(uint16_t uuid16, bool adding) { } else { LOG_INFO("EIR Removing UUID=0x%04X from extended inquiry response", uuid16); - BTM_RemoveEirService(bta_dm_cb.eir_uuid, uuid16); + get_btm_client_interface().eir.BTM_RemoveEirService(bta_dm_cb.eir_uuid, + uuid16); } bta_dm_set_eir(NULL); diff --git a/system/bta/dm/bta_dm_pm.cc b/system/bta/dm/bta_dm_pm.cc index 6a7d6577d6..204017c06d 100644 --- a/system/bta/dm/bta_dm_pm.cc +++ b/system/bta/dm/bta_dm_pm.cc @@ -57,7 +57,7 @@ static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER* p_timer, /* BTA_DM_PM_SSR1 will be dedicated for HH SSR setting entry, no other profile * can use it */ #define BTA_DM_PM_SSR_HH BTA_DM_PM_SSR1 -static void bta_dm_pm_ssr(const RawAddress& peer_addr, int ssr); +static void bta_dm_pm_ssr(const RawAddress& peer_addr, const int ssr); tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; static std::recursive_mutex pm_timer_schedule_mutex; @@ -759,10 +759,9 @@ void bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE* p_peer_dev, uint8_t index) { * Returns void * ******************************************************************************/ -static void bta_dm_pm_ssr(const RawAddress& peer_addr, int ssr) { - int current_ssr_index; +static void bta_dm_pm_ssr(const RawAddress& peer_addr, const int ssr) { int ssr_index = ssr; - tBTA_DM_SSR_SPEC* p_spec = &p_bta_dm_ssr_spec[ssr_index]; + tBTA_DM_SSR_SPEC* p_spec = &p_bta_dm_ssr_spec[ssr]; LOG_DEBUG("Request to put link to device:%s into power_mode:%s", PRIVATE_ADDRESS(peer_addr), p_spec->name); @@ -773,6 +772,7 @@ static void bta_dm_pm_ssr(const RawAddress& peer_addr, int ssr) { continue; } /* p_bta_dm_pm_cfg[0].app_id is the number of entries */ + int current_ssr_index = BTA_DM_PM_SSR0; for (int j = 1; j <= p_bta_dm_pm_cfg[0].app_id; j++) { /* find the associated p_bta_dm_pm_cfg */ const tBTA_DM_PM_CFG& config = p_bta_dm_pm_cfg[j]; diff --git a/system/bta/has/has_client.cc b/system/bta/has/has_client.cc index 044713437f..875a41c2a1 100644 --- a/system/bta/has/has_client.cc +++ b/system/bta/has/has_client.cc @@ -395,7 +395,7 @@ class HasClientImpl : public HasClient { } auto op = op_opt.value(); - if (op.opcode == PresetCtpOpcode::READ_PRESET_BY_INDEX) { + if (op.opcode == PresetCtpOpcode::READ_PRESETS) { callbacks_->OnPresetInfoError(device->addr, op.index, GattStatus2SvcErrorCode(status)); @@ -588,7 +588,7 @@ class HasClientImpl : public HasClient { if (status != ErrorCode::NO_ERROR) { switch (operation.opcode) { - case PresetCtpOpcode::READ_PRESET_BY_INDEX: + case PresetCtpOpcode::READ_PRESETS: LOG_ASSERT( std::holds_alternative<RawAddress>(operation.addr_or_group)) << " Unsupported group operation!"; @@ -837,8 +837,8 @@ class HasClientImpl : public HasClient { .available = preset->IsAvailable(), .preset_name = preset->GetName()}}); } else { - CpPresetIndexOperation(HasCtpOp( - address, PresetCtpOpcode::READ_PRESET_BY_INDEX, preset_index)); + CpPresetIndexOperation( + HasCtpOp(address, PresetCtpOpcode::READ_PRESETS, preset_index)); } } @@ -849,7 +849,7 @@ class HasClientImpl : public HasClient { CpWritePresetNameOperation(HasCtpOp(addr_or_group_id, PresetCtpOpcode::WRITE_PRESET_NAME, - preset_index, name)); + preset_index, 1 /* Don't care */, name)); } void CleanUp() { @@ -1662,8 +1662,9 @@ class HasClientImpl : public HasClient { ccc_val); /* Get all the presets */ - CpReadAllPresetsOperation( - HasCtpOp(device->addr, PresetCtpOpcode::READ_ALL_PRESETS)); + CpReadAllPresetsOperation(HasCtpOp( + device->addr, PresetCtpOpcode::READ_PRESETS, + le_audio::has::kStartPresetIndex, le_audio::has::kMaxNumOfPresets)); /* Read the current active preset index */ BtaGattQueue::ReadCharacteristic( diff --git a/system/bta/has/has_client_test.cc b/system/bta/has/has_client_test.cc index 571686981c..0c28ad7476 100644 --- a/system/bta/has/has_client_test.cc +++ b/system/bta/has/has_client_test.cc @@ -319,7 +319,7 @@ class HasClientTestBase : public ::testing::Test { void* cb_data) { auto pp = value.data(); auto len = value.size(); - uint8_t op, index; + uint8_t op, index, num_of_indices; const bool indicate = false; @@ -344,25 +344,21 @@ class HasClientTestBase : public ::testing::Test { } switch (static_cast<::le_audio::has::PresetCtpOpcode>(op)) { - case ::le_audio::has::PresetCtpOpcode::READ_ALL_PRESETS: - ASSERT_EQ(0u, len); - InjectNotifyReadPresetsResponse(conn_id, address, handle, value, - indicate, -1, cb, cb_data); - break; - - case ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX: - if (len < 1) { + case ::le_audio::has::PresetCtpOpcode::READ_PRESETS: + if (len < 2) { if (cb) cb(conn_id, GATT_INVALID_ATTR_LEN, handle, value.size(), value.data(), cb_data); } else { STREAM_TO_UINT8(index, pp); - --len; + STREAM_TO_UINT8(num_of_indices, pp); + len -= 2; ASSERT_EQ(0u, len); InjectNotifyReadPresetsResponse(conn_id, address, handle, value, - indicate, index, cb, cb_data); + indicate, index, num_of_indices, + cb, cb_data); } break; @@ -949,38 +945,43 @@ class HasClientTestBase : public ::testing::Test { value, indicate); } - void InjectNotifyReadPresetsResponse(uint16_t conn_id, - RawAddress const& address, - uint16_t handle, - std::vector<uint8_t> value, - bool indicate, int index, - GATT_WRITE_OP_CB cb, void* cb_data) { + void InjectNotifyReadPresetsResponse( + uint16_t conn_id, RawAddress const& address, uint16_t handle, + std::vector<uint8_t> value, bool indicate, int index, int num_of_indices, + GATT_WRITE_OP_CB cb, void* cb_data) { auto presets = current_peer_presets_.at(conn_id); LOG_ASSERT(!presets.empty()) << __func__ << " Mocking error!"; - if (index == -1) { + /* Index is a start index, not necessary is a valid index for the + * peer device */ + auto preset = presets.find(index); + while (preset == presets.end() && + index++ <= ::le_audio::has::kMaxNumOfPresets) { + preset = presets.find(index); + } + + if (preset == presets.end()) { + /* operation not possible */ if (cb) - cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(), cb_data); - /* Notify all presets */ - for (auto preset = presets.begin(); preset != presets.end(); preset++) { - InjectNotifyReadPresetResponse(conn_id, address, handle, *preset, - indicate, - (preset == std::prev(presets.end()))); - } - } else { - auto preset = presets.find(index); - if (preset != presets.end()) { - if (cb) - cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(), - cb_data); - InjectNotifyReadPresetResponse(conn_id, address, handle, *preset, - indicate, true); - } else { - /* operation not possible */ - if (cb) - cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(), value.data(), - cb_data); - } + cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(), value.data(), + cb_data); + + return; + } + + if (cb) + cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(), cb_data); + /* Notify presets */ + int num_of_notif = 1; + while (1) { + bool last = + preset == std::prev(presets.end()) || num_of_notif == num_of_indices; + InjectNotifyReadPresetResponse(conn_id, address, handle, *preset, + indicate, (last)); + if (last) return; + + num_of_notif++; + preset++; } } @@ -3023,8 +3024,7 @@ TEST_F(HasTypesTest, test_group_op_coordinator_init) { EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1); HasCtpGroupOpCoordinator wrapper( {address1, address2}, - HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX, - 6)); + HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6)); ASSERT_EQ(2u, wrapper.ref_cnt); EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1); @@ -3043,12 +3043,10 @@ TEST_F(HasTypesTest, test_group_op_coordinator_copy) { EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1); HasCtpGroupOpCoordinator wrapper( {address1, address2}, - HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX, - 6)); + HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6)); HasCtpGroupOpCoordinator wrapper2( {address1}, - HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX, - 6)); + HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6)); ASSERT_EQ(3u, wrapper.ref_cnt); HasCtpGroupOpCoordinator wrapper3 = wrapper2; auto* wrapper4 = @@ -3076,12 +3074,10 @@ TEST_F(HasTypesTest, test_group_op_coordinator_completion) { EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1); HasCtpGroupOpCoordinator wrapper( {address1, address3}, - HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX, - 6)); + HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6)); HasCtpGroupOpCoordinator wrapper2( {address2}, - HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX, - 6)); + HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6)); ASSERT_EQ(3u, wrapper.ref_cnt); EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(0); diff --git a/system/bta/has/has_ctp.cc b/system/bta/has/has_ctp.cc index 1b88dcadfb..940a494df8 100644 --- a/system/bta/has/has_ctp.cc +++ b/system/bta/has/has_ctp.cc @@ -138,14 +138,14 @@ std::vector<uint8_t> HasCtpOp::ToCharacteristicValue() const { auto* pp = value.data(); switch (opcode) { - case PresetCtpOpcode::READ_ALL_PRESETS: - value.resize(1); + case PresetCtpOpcode::READ_PRESETS: + value.resize(3); pp = value.data(); UINT8_TO_STREAM( pp, static_cast<std::underlying_type_t<PresetCtpOpcode>>(opcode)); + UINT8_TO_STREAM(pp, index); + UINT8_TO_STREAM(pp, num_of_indices); break; - - case PresetCtpOpcode::READ_PRESET_BY_INDEX: case PresetCtpOpcode::SET_ACTIVE_PRESET: case PresetCtpOpcode::SET_ACTIVE_PRESET_SYNC: value.resize(2); @@ -206,8 +206,7 @@ std::ostream& operator<<(std::ostream& out, const PresetCtpChangeId value) { std::ostream& operator<<(std::ostream& out, const PresetCtpOpcode value) { const char* ch = 0; switch (value) { - CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::READ_ALL_PRESETS); - CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::READ_PRESET_BY_INDEX); + CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::READ_PRESETS); CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::READ_PRESET_RESPONSE); CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::PRESET_CHANGED); CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::WRITE_PRESET_NAME); diff --git a/system/bta/has/has_ctp.h b/system/bta/has/has_ctp.h index 38cfe45514..963a23c7b1 100644 --- a/system/bta/has/has_ctp.h +++ b/system/bta/has/has_ctp.h @@ -41,8 +41,7 @@ std::ostream& operator<<(std::ostream& out, const PresetCtpChangeId value); /* HAS control point Opcodes */ enum class PresetCtpOpcode : uint8_t { - READ_ALL_PRESETS = 0, - READ_PRESET_BY_INDEX, + READ_PRESETS = 1, READ_PRESET_RESPONSE, PRESET_CHANGED, WRITE_PRESET_NAME, @@ -67,8 +66,7 @@ static constexpr uint16_t PresetCtpOpcode2Bitmask(PresetCtpOpcode op) { /* Mandatory opcodes if control point characteristic exists */ static constexpr uint16_t kControlPointMandatoryOpcodesBitmask = - PresetCtpOpcode2Bitmask(PresetCtpOpcode::READ_ALL_PRESETS) | - PresetCtpOpcode2Bitmask(PresetCtpOpcode::READ_PRESET_BY_INDEX) | + PresetCtpOpcode2Bitmask(PresetCtpOpcode::READ_PRESETS) | PresetCtpOpcode2Bitmask(PresetCtpOpcode::SET_ACTIVE_PRESET) | PresetCtpOpcode2Bitmask(PresetCtpOpcode::SET_NEXT_PRESET) | PresetCtpOpcode2Bitmask(PresetCtpOpcode::SET_PREV_PRESET); @@ -100,13 +98,19 @@ struct HasCtpOp { std::variant<RawAddress, int> addr_or_group; PresetCtpOpcode opcode; uint8_t index; + uint8_t num_of_indices; std::optional<std::string> name; uint16_t op_id; HasCtpOp(std::variant<RawAddress, int> addr_or_group_id, PresetCtpOpcode op, uint8_t index = bluetooth::has::kHasPresetIndexInvalid, + uint8_t num_of_indices = 1, std::optional<std::string> name = std::nullopt) - : addr_or_group(addr_or_group_id), opcode(op), index(index), name(name) { + : addr_or_group(addr_or_group_id), + opcode(op), + index(index), + num_of_indices(num_of_indices), + name(name) { /* Skip 0 on roll-over */ last_op_id_ += 1; if (last_op_id_ == 0) last_op_id_ = 1; diff --git a/system/bta/has/has_types.h b/system/bta/has/has_types.h index d726f07cf7..e7d691deab 100644 --- a/system/bta/has/has_types.h +++ b/system/bta/has/has_types.h @@ -70,15 +70,17 @@ union HasGattOpContext { static_assert(sizeof(HasGattOpContext) <= sizeof(void*)); /* Service UUIDs */ -/* FIXME: actually these were not yet assigned - using placeholders for now. */ static const bluetooth::Uuid kUuidHearingAccessService = bluetooth::Uuid::From16Bit(0x1854); static const bluetooth::Uuid kUuidHearingAidFeatures = - bluetooth::Uuid::From16Bit(0xEEED); + bluetooth::Uuid::From16Bit(0x2BDA); static const bluetooth::Uuid kUuidHearingAidPresetControlPoint = - bluetooth::Uuid::From16Bit(0xEEEC); + bluetooth::Uuid::From16Bit(0x2BDB); static const bluetooth::Uuid kUuidActivePresetIndex = - bluetooth::Uuid::From16Bit(0xEEEB); + bluetooth::Uuid::From16Bit(0x2BDC); + +static const uint8_t kStartPresetIndex = 1; +static const uint8_t kMaxNumOfPresets = 255; /* Base device class for the GATT-based service clients */ class GattServiceDevice { diff --git a/system/bta/include/bta_le_audio_broadcaster_api.h b/system/bta/include/bta_le_audio_broadcaster_api.h index 33022ef19b..e3ffa28d2d 100644 --- a/system/bta/include/bta_le_audio_broadcaster_api.h +++ b/system/bta/include/bta_le_audio_broadcaster_api.h @@ -49,17 +49,16 @@ class LeAudioBroadcaster { std::vector<uint8_t> metadata, AudioProfile profile, std::optional<bluetooth::le_audio::BroadcastCode> broadcast_code = std::nullopt) = 0; - virtual void SuspendAudioBroadcast(uint8_t instance_id) = 0; - virtual void StartAudioBroadcast(uint8_t instance_id) = 0; - virtual void StopAudioBroadcast(uint8_t instance_id) = 0; - virtual void DestroyAudioBroadcast(uint8_t instance_id) = 0; - virtual void GetBroadcastId(uint8_t instance_id) = 0; + virtual void SuspendAudioBroadcast(uint32_t broadcast_id) = 0; + virtual void StartAudioBroadcast(uint32_t broadcast_id) = 0; + virtual void StopAudioBroadcast(uint32_t broadcast_id) = 0; + virtual void DestroyAudioBroadcast(uint32_t broadcast_id) = 0; virtual void GetAllBroadcastStates(void) = 0; - virtual void UpdateMetadata(uint8_t instance_id, + virtual void UpdateMetadata(uint32_t broadcast_id, std::vector<uint8_t> metadata) = 0; virtual void IsValidBroadcast( - uint8_t instance_id, uint8_t addr_type, RawAddress addr, - base::Callback<void(uint8_t /* instance_id */, uint8_t /* addr_type */, + uint32_t broadcast_id, uint8_t addr_type, RawAddress addr, + base::Callback<void(uint8_t /* broadcast_id */, uint8_t /* addr_type */, RawAddress /* addr */, bool /* is_valid */)> cb) = 0; diff --git a/system/bta/le_audio/audio_set_configurations.fbs b/system/bta/le_audio/audio_set_configurations.fbs index 8afe72ea99..2aa7bab499 100644 --- a/system/bta/le_audio/audio_set_configurations.fbs +++ b/system/bta/le_audio/audio_set_configurations.fbs @@ -64,16 +64,28 @@ table AudioSetSubConfiguration { codec_id : CodecId (required); codec_configuration: [CodecSpecificConfiguration] (required); } +table CodecConfiguration { + name: string (key, required); + subconfigurations: [AudioSetSubConfiguration] (required); +} +table QosConfiguration { + name: string (key, required); + retransmission_number: ubyte; + max_transport_latency : ushort; +} /// Each set configration can contain multiple logical subconfigurations, which /// all must be configurable with the current set of audio devices. For example, /// one can define multiple output stream configurations with different /// qualities, or assign different configurations to each stream direction. table AudioSetConfiguration { name: string (key, required); - subconfigurations: [AudioSetSubConfiguration] (required); + codec_config_name: string (required); + qos_config_name: string (required); } table AudioSetConfigurations { _comments_: [string]; configurations: [AudioSetConfiguration] (required); + codec_configurations: [CodecConfiguration] (required); + qos_configurations: [QosConfiguration] (required); } root_type AudioSetConfigurations; diff --git a/system/bta/le_audio/audio_set_configurations.json b/system/bta/le_audio/audio_set_configurations.json index 08453307a1..81fdaf2661 100644 --- a/system/bta/le_audio/audio_set_configurations.json +++ b/system/bta/le_audio/audio_set_configurations.json @@ -1,6 +1,14 @@ { "_comments_": [ " == Audio Set Configurations == ", + " Contains: ", + " 1. configurations : ", + " Maps configuration name with codec and qos config to be used", + " 2. codec_configurations : ", + " Array of codec specific configurations", + " 3. qos_configurations : ", + " Array of QoS specific configurations", + " QoS configuration values are as per BAP spec 1.0", " Example values which can be used as 'codec_configuration.type'", " Codec Configuration parameter types:", " SUPPORTED_SAMPLING_FREQUENCY = 1", @@ -35,6 +43,338 @@ ], "configurations": [ { + "name": "DualDev_OneChanStereoSnk_16_1_Server_Preferred", + "codec_config_name": "DualDev_OneChanStereoSnk_16_1", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "DualDev_OneChanStereoSnk_16_1_1", + "codec_config_name": "DualDev_OneChanStereoSnk_16_1", + "qos_config_name": "QoS_Config_16_1_1" + }, + { + "name": "DualDev_OneChanStereoSnk_16_1_2", + "codec_config_name": "DualDev_OneChanStereoSnk_16_1", + "qos_config_name": "QoS_Config_16_1_2" + }, + { + "name": "DualDev_OneChanStereoSnk_16_2_Server_Preferred", + "codec_config_name": "DualDev_OneChanStereoSnk_16_2", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "DualDev_OneChanStereoSnk_16_2_1", + "codec_config_name": "DualDev_OneChanStereoSnk_16_2", + "qos_config_name": "QoS_Config_16_2_1" + }, + { + "name": "DualDev_OneChanStereoSnk_16_2_2", + "codec_config_name": "DualDev_OneChanStereoSnk_16_2", + "qos_config_name": "QoS_Config_16_2_2" + }, + { + "name": "SingleDev_OneChanStereoSnk_16_1_Server_Preferred", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_1", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_OneChanStereoSnk_16_1_1", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_1", + "qos_config_name": "QoS_Config_16_1_1" + }, + { + "name": "SingleDev_OneChanStereoSnk_16_1_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_1", + "qos_config_name": "QoS_Config_16_1_2" + }, + { + "name": "SingleDev_OneChanStereoSnk_16_2_Server_Preferred", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_2", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_OneChanStereoSnk_16_2_1", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_2", + "qos_config_name": "QoS_Config_16_2_1" + }, + { + "name": "SingleDev_OneChanStereoSnk_16_2_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_16_2", + "qos_config_name": "QoS_Config_16_2_2" + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_1_Server_Preferred", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_1_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1", + "qos_config_name": "QoS_Config_16_1_1" + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_1_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1", + "qos_config_name": "QoS_Config_16_1_2" + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_2_Server_Preferred", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_2_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2", + "qos_config_name": "QoS_Config_16_2_1" + }, + { + "name": "SingleDev_TwoChanStereoSnk_16_2_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2", + "qos_config_name": "QoS_Config_16_2_2" + }, + { + "name": "SingleDev_OneChanMonoSnk_16_1_Server_Preferred", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_1", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_OneChanMonoSnk_16_1_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_1", + "qos_config_name": "QoS_Config_16_1_1" + }, + { + "name": "SingleDev_OneChanMonoSnk_16_1_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_1", + "qos_config_name": "QoS_Config_16_1_2" + }, + { + "name": "SingleDev_OneChanMonoSnk_16_2_Server_Preferred", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_2", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_OneChanMonoSnk_16_2_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_2", + "qos_config_name": "QoS_Config_16_2_1" + }, + { + "name": "SingleDev_OneChanMonoSnk_16_2_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_16_2", + "qos_config_name": "QoS_Config_16_2_2" + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Server_Preferred", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_16_1_1" + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_2", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_16_1_2" + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Server_Preferred", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_16_2_1" + }, + { + "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_2", + "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_16_2_2" + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_Server_Preferred", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_1", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_16_1_1" + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_2", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_16_1_2" + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_Server_Preferred", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_1", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_16_2_1" + }, + { + "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_2", + "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_16_2_2" + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Server_Preferred", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_16_1_1" + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_16_1_2" + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Server_Preferred", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_16_2_1" + }, + { + "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_16_2_2" + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Server_Preferred", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_16_1_1" + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_16_1_2" + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Server_Preferred", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_16_2_1" + }, + { + "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_16_2_2" + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Server_Preferred", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_16_1_1" + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1", + "qos_config_name": "QoS_Config_16_1_2" + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Server_Preferred", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_16_2_1" + }, + { + "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2", + "qos_config_name": "QoS_Config_16_2_2" + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_Server_Preferred", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_1", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4", + "qos_config_name": "QoS_Config_48_4_1" + }, + { + "name": "DualDev_OneChanStereoSnk_48_4_2", + "codec_config_name": "DualDev_OneChanStereoSnk_48_4", + "qos_config_name": "QoS_Config_48_4_2" + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_Server_Preferred", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_4", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_1", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_4", + "qos_config_name": "QoS_Config_48_4_1" + }, + { + "name": "SingleDev_OneChanStereoSnk_48_4_2", + "codec_config_name": "SingleDev_OneChanStereoSnk_48_4", + "qos_config_name": "QoS_Config_48_4_2" + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_Server_Preferred", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_1", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4", + "qos_config_name": "QoS_Config_48_4_1" + }, + { + "name": "SingleDev_TwoChanStereoSnk_48_4_2", + "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4", + "qos_config_name": "QoS_Config_48_4_2" + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_Server_Preferred", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_4", + "qos_config_name": "QoS_Config_Server_Preferred" + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_1", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_4", + "qos_config_name": "QoS_Config_48_4_1" + }, + { + "name": "SingleDev_OneChanMonoSnk_48_4_2", + "codec_config_name": "SingleDev_OneChanMonoSnk_48_4", + "qos_config_name": "QoS_Config_48_4_2" + } + ], + "codec_configurations": [ + { "name": "DualDev_OneChanStereoSnk_16_2", "subconfigurations": [ { @@ -2114,5 +2454,42 @@ } ] } + ], + "qos_configurations": [ + { + "name": "QoS_Config_16_1_1", + "retransmission_number": 2, + "max_transport_latency": 8 + }, + { + "name": "QoS_Config_16_1_2", + "retransmission_number": 13, + "max_transport_latency": 75 + }, + { + "name": "QoS_Config_16_2_1", + "retransmission_number": 2, + "max_transport_latency": 10 + }, + { + "name": "QoS_Config_16_2_2", + "retransmission_number": 13, + "max_transport_latency": 95 + }, + { + "name": "QoS_Config_48_4_1", + "retransmission_number": 5, + "max_transport_latency": 20 + }, + { + "name": "QoS_Config_48_4_2", + "retransmission_number": 13, + "max_transport_latency": 100 + }, + { + "name": "QoS_Config_Server_Preferred", + "retransmission_number": 0, + "max_transport_latency": 0 + } ] -}
\ No newline at end of file +} diff --git a/system/bta/le_audio/audio_set_scenarios.json b/system/bta/le_audio/audio_set_scenarios.json index d9f7b8fc7a..d1314a4485 100644 --- a/system/bta/le_audio/audio_set_scenarios.json +++ b/system/bta/le_audio/audio_set_scenarios.json @@ -8,55 +8,89 @@ { "name": "Ringtone", "configurations": [ - "DualDev_OneChanStereoSnk_16_2", - "DualDev_OneChanStereoSnk_16_1", - "SingleDev_OneChanStereoSnk_16_2", - "SingleDev_OneChanStereoSnk_16_1", - "SingleDev_TwoChanStereoSnk_16_2", - "SingleDev_TwoChanStereoSnk_16_1", - "SingleDev_OneChanMonoSnk_16_2", - "SingleDev_OneChanMonoSnk_16_1" + "DualDev_OneChanStereoSnk_16_2_Server_Preferred", + "DualDev_OneChanStereoSnk_16_2_1", + "DualDev_OneChanStereoSnk_16_1_Server_Preferred", + "DualDev_OneChanStereoSnk_16_1_1", + "SingleDev_OneChanStereoSnk_16_2_Server_Preferred", + "SingleDev_OneChanStereoSnk_16_2_1", + "SingleDev_OneChanStereoSnk_16_1_Server_Preferred", + "SingleDev_OneChanStereoSnk_16_1_1", + "SingleDev_TwoChanStereoSnk_16_2_Server_Preferred", + "SingleDev_TwoChanStereoSnk_16_2_1", + "SingleDev_TwoChanStereoSnk_16_1_Server_Preferred", + "SingleDev_TwoChanStereoSnk_16_1_1", + "SingleDev_OneChanMonoSnk_16_2_Server_Preferred", + "SingleDev_OneChanMonoSnk_16_2_1", + "SingleDev_OneChanMonoSnk_16_1_Server_Preferred", + "SingleDev_OneChanMonoSnk_16_1_1" ] }, { "name": "Conversational", "configurations": [ - "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2", - "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1", - "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2", - "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1", - "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2", - "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1", - "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2", - "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1", - "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2", - "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1" + "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Server_Preferred", + "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", + "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Server_Preferred", + "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_Server_Preferred", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_1", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_Server_Preferred", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Server_Preferred", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Server_Preferred", + "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Server_Preferred", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Server_Preferred", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Server_Preferred", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Server_Preferred", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1" ] }, { "name": "Media", "configurations": [ - "DualDev_OneChanStereoSnk_48_4", - "DualDev_OneChanStereoSnk_16_2", - "DualDev_OneChanStereoSnk_16_1", - "SingleDev_OneChanStereoSnk_48_4", - "SingleDev_OneChanStereoSnk_16_2", - "SingleDev_OneChanStereoSnk_16_1", - "SingleDev_TwoChanStereoSnk_48_4", - "SingleDev_TwoChanStereoSnk_16_2", - "SingleDev_TwoChanStereoSnk_16_1", - "SingleDev_OneChanMonoSnk_48_4", - "SingleDev_OneChanMonoSnk_16_2", - "SingleDev_OneChanMonoSnk_16_1" + "DualDev_OneChanStereoSnk_48_4_Server_Preferred", + "DualDev_OneChanStereoSnk_48_4_2", + "DualDev_OneChanStereoSnk_16_2_Server_Preferred", + "DualDev_OneChanStereoSnk_16_2_2", + "DualDev_OneChanStereoSnk_16_1_Server_Preferred", + "DualDev_OneChanStereoSnk_16_1_2", + "SingleDev_OneChanStereoSnk_48_4_Server_Preferred", + "SingleDev_OneChanStereoSnk_48_4_2", + "SingleDev_OneChanStereoSnk_16_2_Server_Preferred", + "SingleDev_OneChanStereoSnk_16_2_2", + "SingleDev_OneChanStereoSnk_16_1_Server_Preferred", + "SingleDev_OneChanStereoSnk_16_1_2", + "SingleDev_TwoChanStereoSnk_48_4_Server_Preferred", + "SingleDev_TwoChanStereoSnk_48_4_2", + "SingleDev_TwoChanStereoSnk_16_2_Server_Preferred", + "SingleDev_TwoChanStereoSnk_16_2_2", + "SingleDev_TwoChanStereoSnk_16_1_Server_Preferred", + "SingleDev_TwoChanStereoSnk_16_1_2", + "SingleDev_OneChanMonoSnk_48_4_Server_Preferred", + "SingleDev_OneChanMonoSnk_48_4_2", + "SingleDev_OneChanMonoSnk_16_2_Server_Preferred", + "SingleDev_OneChanMonoSnk_16_2_2", + "SingleDev_OneChanMonoSnk_16_1_Server_Preferred", + "SingleDev_OneChanMonoSnk_16_1_2" ] }, { "name": "Default", "configurations": [ - "DualDev_OneChanStereoSnk_16_2", - "SingleDev_OneChanStereoSnk_16_2", - "SingleDev_TwoChanStereoSnk_16_2", - "SingleDev_OneChanMonoSnk_16_2" + "DualDev_OneChanStereoSnk_16_2_Server_Preferred", + "DualDev_OneChanStereoSnk_16_2_1", + "SingleDev_OneChanStereoSnk_16_2_Server_Preferred", + "SingleDev_OneChanStereoSnk_16_2_1", + "SingleDev_TwoChanStereoSnk_16_2_Server_Preferred", + "SingleDev_TwoChanStereoSnk_16_2_1", + "SingleDev_OneChanMonoSnk_16_2_Server_Preferred", + "SingleDev_OneChanMonoSnk_16_2_1" ] } ] diff --git a/system/bta/le_audio/broadcaster/broadcaster.cc b/system/bta/le_audio/broadcaster/broadcaster.cc index 43460e4ecb..a73b886e7d 100644 --- a/system/bta/le_audio/broadcaster/broadcaster.cc +++ b/system/bta/le_audio/broadcaster/broadcaster.cc @@ -23,10 +23,13 @@ #include "bta/le_audio/le_audio_types.h" #include "device/include/controller.h" #include "embdrv/lc3/include/lc3.h" +#include "gd/common/strings.h" +#include "osi/include/log.h" +#include "osi/include/properties.h" #include "stack/include/btm_api_types.h" #include "stack/include/btm_iso_api.h" -#include "osi/include/properties.h" +using bluetooth::common::ToString; using bluetooth::hci::IsoManager; using bluetooth::hci::iso_manager::big_create_cmpl_evt; using bluetooth::hci::iso_manager::big_terminate_cmpl_evt; @@ -67,7 +70,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { num_retransmit_(3), audio_data_path_state_(AudioDataPathState::INACTIVE), audio_instance_(nullptr) { - LOG(INFO) << __func__; + LOG_INFO(); /* Register State machine callbacks */ BroadcastStateMachine::Initialize(&state_machine_callbacks_); @@ -83,15 +86,22 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { /* LE Rand returns 8 octets. Lets' make 2 outstanding Broadcast Ids out * of it */ - for (int i = 0; i < 4; i += 3) { - BroadcastId b_id = {rand[i], rand[i + 1], rand[i + 2]}; - instance->available_broadcast_ids_.emplace_back(b_id); + for (int i = 0; i < 8; i += 4) { + BroadcastId broadcast_id = 0; + /* Broadcast ID should be 3 octets long (BAP v1.0 spec.) */ + STREAM_TO_UINT24(broadcast_id, rand); + if (broadcast_id == bluetooth::le_audio::kBroadcastIdInvalid) continue; + instance->available_broadcast_ids_.emplace_back(broadcast_id); + } + + if (instance->available_broadcast_ids_.empty()) { + LOG_ALWAYS_FATAL("Unable to generate proper broadcast identifiers."); } })); } void CleanUp() { - DLOG(INFO) << "Broadcaster " << __func__; + LOG_INFO("Broadcaster"); broadcasts_.clear(); callbacks_ = nullptr; @@ -103,7 +113,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { } void Stop() { - DLOG(INFO) << "Broadcaster " << __func__; + LOG_INFO("Broadcaster"); for (auto& sm_pair : broadcasts_) { StopAudioBroadcast(sm_pair.first); @@ -153,14 +163,14 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { return announcement; } - void UpdateMetadata(uint8_t instance_id, + void UpdateMetadata(uint32_t broadcast_id, std::vector<uint8_t> metadata) override { - if (broadcasts_.count(instance_id) == 0) { - LOG(ERROR) << __func__ << " no such instance_id=" << int{instance_id}; + if (broadcasts_.count(broadcast_id) == 0) { + LOG_ERROR("No such broadcast_id=%d", broadcast_id); return; } - DLOG(INFO) << __func__ << " for instance_id=" << int{instance_id}; + LOG_INFO("For broadcast_id=%d", broadcast_id); auto& codec_config = audio_receiver_.getCurrentCodecConfig(); @@ -168,7 +178,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { BasicAudioAnnouncementData announcement = prepareAnnouncement(codec_config, std::move(metadata)); - broadcasts_[instance_id]->UpdateBroadcastAnnouncement( + broadcasts_[broadcast_id]->UpdateBroadcastAnnouncement( std::move(announcement)); } @@ -176,7 +186,10 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { LeAudioBroadcaster::AudioProfile profile, std::optional<bluetooth::le_audio::BroadcastCode> broadcast_code) override { - DLOG(INFO) << __func__; + LOG_INFO("Audio profile: %s", + profile == LeAudioBroadcaster::AudioProfile::MEDIA + ? "Media" + : "Sonification"); auto& codec_wrapper = BroadcastCodecWrapper::getCodecConfigForProfile(profile); @@ -205,21 +218,22 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { // Notify the error instead just fail silently if (!pending_broadcasts_.back()->Initialize()) { pending_broadcasts_.pop_back(); - callbacks_->OnBroadcastCreated( - BroadcastStateMachine::kInstanceIdUndefined, false); + callbacks_->OnBroadcastCreated(bluetooth::le_audio::kBroadcastIdInvalid, + false); } } - void SuspendAudioBroadcast(uint8_t instance_id) override { - DLOG(INFO) << __func__ << " suspending instance_id=" << int{instance_id}; - if (broadcasts_.count(instance_id) != 0) { - DLOG(INFO) << __func__ << " Stopping LeAudioClientAudioSource"; + void SuspendAudioBroadcast(uint32_t broadcast_id) override { + LOG_INFO("broadcast_id=%d", broadcast_id); + + if (broadcasts_.count(broadcast_id) != 0) { + LOG_INFO("Stopping LeAudioClientAudioSource"); LeAudioClientAudioSource::Stop(); - broadcasts_[instance_id]->SetMuted(true); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->SetMuted(true); + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::SUSPEND, nullptr); } else { - LOG(ERROR) << __func__ << " no such instance_id=" << int{instance_id}; + LOG_ERROR("No such broadcast_id=%d", broadcast_id); } } @@ -235,94 +249,83 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { return (iter != instance->broadcasts_.cend()); } - void StartAudioBroadcast(uint8_t instance_id) override { - DLOG(INFO) << __func__ << " starting instance_id=" << int{instance_id}; + void StartAudioBroadcast(uint32_t broadcast_id) override { + LOG_INFO("Starting broadcast_id=%d", broadcast_id); if (IsAnyoneStreaming()) { - LOG(ERROR) << __func__ << ": Stop the other broadcast first!"; + LOG_ERROR("Stop the other broadcast first!"); return; } - if (broadcasts_.count(instance_id) != 0) { + if (broadcasts_.count(broadcast_id) != 0) { if (!audio_instance_) { audio_instance_ = LeAudioClientAudioSource::Acquire(); if (!audio_instance_) { - LOG(ERROR) << __func__ << " could not acquire le audio"; + LOG_ERROR("Could not acquire le audio"); return; } } - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START, nullptr); } else { - LOG(ERROR) << __func__ << " no such instance_id=" << int{instance_id}; + LOG_ERROR("No such broadcast_id=%d", broadcast_id); } } - void StopAudioBroadcast(uint8_t instance_id) override { - if (broadcasts_.count(instance_id) == 0) { - LOG(ERROR) << __func__ << " no such instance_id=" << int{instance_id}; + void StopAudioBroadcast(uint32_t broadcast_id) override { + if (broadcasts_.count(broadcast_id) == 0) { + LOG_ERROR("no such broadcast_id=%d", broadcast_id); return; } - DLOG(INFO) << __func__ << " stopping instance_id=" << int{instance_id}; - - DLOG(INFO) << __func__ << " Stopping LeAudioClientAudioSource"; + LOG_INFO("Stopping LeAudioClientAudioSource, broadcast_id=%d", + broadcast_id); LeAudioClientAudioSource::Stop(); - broadcasts_[instance_id]->SetMuted(true); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->SetMuted(true); + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::STOP, nullptr); } - void DestroyAudioBroadcast(uint8_t instance_id) override { - DLOG(INFO) << __func__ << " destroying instance_id=" << int{instance_id}; - broadcasts_.erase(instance_id); - } - - void GetBroadcastId(uint8_t instance_id) override { - if (broadcasts_.count(instance_id) == 0) { - LOG(ERROR) << __func__ << " no such instance_id=" << int{instance_id}; - return; - } - - auto broadcast_id = broadcasts_[instance_id]->GetBroadcastId(); - callbacks_->OnBroadcastId(instance_id, broadcast_id); + void DestroyAudioBroadcast(uint32_t broadcast_id) override { + LOG_INFO("Destroying broadcast_id=%d", broadcast_id); + broadcasts_.erase(broadcast_id); } void GetAllBroadcastStates(void) override { for (auto const& kv_it : broadcasts_) { callbacks_->OnBroadcastStateChanged( - kv_it.second->GetInstanceId(), + kv_it.second->GetBroadcastId(), static_cast<bluetooth::le_audio::BroadcastState>( kv_it.second->GetState())); } } void IsValidBroadcast( - uint8_t instance_id, uint8_t addr_type, RawAddress addr, - base::Callback<void(uint8_t /* instance_id */, uint8_t /* addr_type */, + uint32_t broadcast_id, uint8_t addr_type, RawAddress addr, + base::Callback<void(uint8_t /* broadcast_id */, uint8_t /* addr_type */, RawAddress /* addr */, bool /* is_local */)> cb) override { - if (broadcasts_.count(instance_id) == 0) { - LOG(ERROR) << __func__ << " no such instance_id=" << int{instance_id}; - std::move(cb).Run(instance_id, addr_type, addr, false); + if (broadcasts_.count(broadcast_id) == 0) { + LOG_ERROR("No such broadcast_id=%d", broadcast_id); + std::move(cb).Run(broadcast_id, addr_type, addr, false); return; } - broadcasts_[instance_id]->RequestOwnAddress(base::Bind( - [](uint8_t instance_id, uint8_t req_address_type, + broadcasts_[broadcast_id]->RequestOwnAddress(base::Bind( + [](uint32_t broadcast_id, uint8_t req_address_type, RawAddress req_address, - base::Callback<void(uint8_t /* instance_id */, + base::Callback<void(uint8_t /* broadcast_id */, uint8_t /* addr_type */, RawAddress /* addr */, bool /* is_local */)> cb, uint8_t rcv_address_type, RawAddress rcv_address) { bool is_local = (req_address_type == rcv_address_type) && (req_address == rcv_address); - std::move(cb).Run(instance_id, req_address_type, req_address, + std::move(cb).Run(broadcast_id, req_address_type, req_address, is_local); }, - instance_id, addr_type, addr, std::move(cb))); + broadcast_id, addr_type, addr, std::move(cb))); } void SetNumRetransmit(uint8_t count) override { num_retransmit_ = count; } @@ -333,36 +336,53 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { uint8_t GetStreamingPhy(void) const override { return current_phy_; } + BroadcastId BroadcastIdFromBigHandle(uint8_t big_handle) const { + auto pair_it = + std::find_if(broadcasts_.begin(), broadcasts_.end(), + [big_handle](auto const& entry) { + return entry.second->GetAdvertisingSid() == big_handle; + }); + if (pair_it != broadcasts_.end()) { + return pair_it->second->GetBroadcastId(); + } + return bluetooth::le_audio::kBroadcastIdInvalid; + } + void OnSetupIsoDataPath(uint8_t status, uint16_t conn_handle, - uint8_t big_id) override { - CHECK(broadcasts_.count(big_id) != 0); - broadcasts_[big_id]->OnSetupIsoDataPath(status, conn_handle); + uint8_t big_handle) override { + auto broadcast_id = BroadcastIdFromBigHandle(big_handle); + CHECK(broadcasts_.count(broadcast_id) != 0); + broadcasts_[broadcast_id]->OnSetupIsoDataPath(status, conn_handle); } void OnRemoveIsoDataPath(uint8_t status, uint16_t conn_handle, - uint8_t big_id) override { - CHECK(broadcasts_.count(big_id) != 0); - broadcasts_[big_id]->OnRemoveIsoDataPath(status, conn_handle); + uint8_t big_handle) override { + auto broadcast_id = BroadcastIdFromBigHandle(big_handle); + CHECK(broadcasts_.count(broadcast_id) != 0); + broadcasts_[broadcast_id]->OnRemoveIsoDataPath(status, conn_handle); } void OnBigEvent(uint8_t event, void* data) override { switch (event) { case bluetooth::hci::iso_manager::kIsoEventBigOnCreateCmpl: { auto* evt = static_cast<big_create_cmpl_evt*>(data); - CHECK(broadcasts_.count(evt->big_id) != 0); - broadcasts_[evt->big_id]->HandleHciEvent(HCI_BLE_CREATE_BIG_CPL_EVT, - evt); + auto broadcast_id = BroadcastIdFromBigHandle(evt->big_id); + CHECK(broadcasts_.count(broadcast_id) != 0); + broadcasts_[broadcast_id]->HandleHciEvent(HCI_BLE_CREATE_BIG_CPL_EVT, + evt); } break; case bluetooth::hci::iso_manager::kIsoEventBigOnTerminateCmpl: { auto* evt = static_cast<big_terminate_cmpl_evt*>(data); - CHECK(broadcasts_.count(evt->big_id) != 0); - broadcasts_[evt->big_id]->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT, evt); + auto broadcast_id = BroadcastIdFromBigHandle(evt->big_id); + CHECK(broadcasts_.count(broadcast_id) != 0); + broadcasts_[broadcast_id]->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT, + evt); LeAudioClientAudioSource::Release(audio_instance_); audio_instance_ = nullptr; } break; default: - LOG(ERROR) << __func__ << " Invalid event: " << int{event}; + LOG_ERROR("Invalid event=%d", event); } } @@ -379,19 +399,19 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { } private: - uint8_t GetNumRetransmit(uint8_t broadcaster_id) { + uint8_t GetNumRetransmit(uint32_t broadcast_id) { /* TODO: Should be based on QOS settings */ return GetNumRetransmit(); } - uint32_t GetSduItv(uint8_t broadcaster_id) { + uint32_t GetSduItv(uint32_t broadcast_id) { /* TODO: Should be based on QOS settings * currently tuned for media profile (music band) */ return 0x002710; } - uint16_t GetMaxTransportLatency(uint8_t broadcaster_id) { + uint16_t GetMaxTransportLatency(uint32_t broadcast_id) { /* TODO: Should be based on QOS settings * currently tuned for media profile (music band) */ @@ -400,53 +420,55 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { static class BroadcastStateMachineCallbacks : public IBroadcastStateMachineCallbacks { - void OnStateMachineCreateStatus(uint8_t instance_id, + void OnStateMachineCreateStatus(uint32_t broadcast_id, bool initialized) override { auto pending_broadcast = std::find_if( instance->pending_broadcasts_.begin(), - instance->pending_broadcasts_.end(), [instance_id](auto& sm) { - return (sm->GetInstanceId() == instance_id); + instance->pending_broadcasts_.end(), [broadcast_id](auto& sm) { + return (sm->GetBroadcastId() == broadcast_id); }); LOG_ASSERT(pending_broadcast != instance->pending_broadcasts_.end()); - LOG_ASSERT(instance->broadcasts_.count(instance_id) == 0); + LOG_ASSERT(instance->broadcasts_.count(broadcast_id) == 0); if (initialized) { - const uint8_t instance_id = (*pending_broadcast)->GetInstanceId(); - DLOG(INFO) << __func__ << " instance_id=" << int{instance_id} - << " state=" << (*pending_broadcast)->GetState(); + const uint32_t broadcast_id = (*pending_broadcast)->GetBroadcastId(); + LOG_INFO("broadcast_id=%d state=%s", broadcast_id, + ToString((*pending_broadcast)->GetState()).c_str()); - instance->broadcasts_[instance_id] = std::move(*pending_broadcast); + instance->broadcasts_[broadcast_id] = std::move(*pending_broadcast); } else { - LOG(ERROR) << "Failed creating broadcast!"; + LOG_ERROR("Failed creating broadcast!"); } instance->pending_broadcasts_.erase(pending_broadcast); - instance->callbacks_->OnBroadcastCreated(instance_id, initialized); + instance->callbacks_->OnBroadcastCreated(broadcast_id, initialized); } - void OnStateMachineDestroyed(uint8_t instance_id) override { + void OnStateMachineDestroyed(uint32_t broadcast_id) override { /* This is a special case when state machine destructor calls this * callback. It may happen during the Cleanup() call when all state * machines are erased and instance can already be set to null to avoid * unnecessary calls. */ - if (instance) instance->callbacks_->OnBroadcastDestroyed(instance_id); + if (instance) instance->callbacks_->OnBroadcastDestroyed(broadcast_id); } static int getStreamerCount() { return std::count_if(instance->broadcasts_.begin(), instance->broadcasts_.end(), [](auto const& sm) { - LOG(INFO) - << "\t<< state :" << sm.second->GetState(); + LOG_VERBOSE( + "broadcast_id=%d, state=%s", + sm.second->GetBroadcastId(), + ToString(sm.second->GetState()).c_str()); return sm.second->GetState() == BroadcastStateMachine::State::STREAMING; }); } - void OnStateMachineEvent(uint8_t instance_id, + void OnStateMachineEvent(uint32_t broadcast_id, BroadcastStateMachine::State state, const void* data) override { - DLOG(INFO) << __func__ << " instance_id=" << int{instance_id} - << " state=" << state; + LOG_INFO("broadcast_id=%d state=%s", broadcast_id, + ToString(state).c_str()); switch (state) { case BroadcastStateMachine::State::STOPPED: @@ -460,10 +482,10 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { break; case BroadcastStateMachine::State::STREAMING: if (getStreamerCount() == 1) { - DLOG(INFO) << __func__ << " Starting LeAudioClientAudioSource"; + LOG_INFO("Starting LeAudioClientAudioSource"); - if (instance->broadcasts_.count(instance_id) != 0) { - const auto& broadcast = instance->broadcasts_.at(instance_id); + if (instance->broadcasts_.count(broadcast_id) != 0) { + const auto& broadcast = instance->broadcasts_.at(broadcast_id); // Reconfigure encoder instance for the new stream requirements audio_receiver_.setCurrentCodecConfig( @@ -476,7 +498,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { LeAudioClientAudioSource::Start(*cfg, &audio_receiver_); if (!is_started) { /* Audio Source setup failed - stop the broadcast */ - instance->StopAudioBroadcast(instance_id); + instance->StopAudioBroadcast(broadcast_id); return; } @@ -487,24 +509,25 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { }; instance->callbacks_->OnBroadcastStateChanged( - instance_id, static_cast<bluetooth::le_audio::BroadcastState>(state)); + broadcast_id, + static_cast<bluetooth::le_audio::BroadcastState>(state)); } - void OnOwnAddressResponse(uint8_t instance_id, uint8_t addr_type, + void OnOwnAddressResponse(uint32_t broadcast_id, uint8_t addr_type, RawAddress addr) override { /* Not used currently */ } - uint8_t GetNumRetransmit(uint8_t instance_id) override { - return instance->GetNumRetransmit(instance_id); + uint8_t GetNumRetransmit(uint32_t broadcast_id) override { + return instance->GetNumRetransmit(broadcast_id); } - uint32_t GetSduItv(uint8_t instance_id) override { - return instance->GetSduItv(instance_id); + uint32_t GetSduItv(uint32_t broadcast_id) override { + return instance->GetSduItv(broadcast_id); } - uint16_t GetMaxTransportLatency(uint8_t instance_id) override { - return instance->GetMaxTransportLatency(instance_id); + uint16_t GetMaxTransportLatency(uint32_t broadcast_id) override { + return instance->GetMaxTransportLatency(broadcast_id); } } state_machine_callbacks_; @@ -518,10 +541,8 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { void CheckAndReconfigureEncoders() { auto const& codec_id = codec_wrapper_.GetLeAudioCodecId(); if (codec_id.coding_format != kLeAudioCodingFormatLC3) { - LOG(ERROR) << "Invalid codec ID: " - << "[" << +codec_id.coding_format << ":" - << +codec_id.vendor_company_id << ":" - << +codec_id.vendor_codec_id << "]"; + LOG_ERROR("Invalid codec ID: [%d:%d:%d]", codec_id.coding_format, + codec_id.vendor_company_id, codec_id.vendor_codec_id); return; } @@ -561,11 +582,11 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { int initial_channel_offset, int pitch_samples, int num_channels) { auto encoder_status = - lc3_encode(encoder, (int16_t*)(data.data() + initial_channel_offset), + lc3_encode(encoder, LC3_PCM_FORMAT_S16, + (int16_t*)(data.data() + initial_channel_offset), pitch_samples, out_buffer.size(), out_buffer.data()); if (encoder_status != 0) { - LOG(ERROR) << "Error while encoding" - << "\terror: " << encoder_status; + LOG_ERROR("Encoding error=%d", encoder_status); } } @@ -574,15 +595,16 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { std::vector<std::vector<uint8_t>>& encoded_channels) { auto const& config = broadcast->GetBigConfig(); if (config == std::nullopt) { - LOG(ERROR) << "Broadcast instance_id= " - << int{broadcast->GetInstanceId()} - << " has no valid BIS configurations in state= " - << broadcast->GetState(); + LOG_ERROR( + "Broadcast broadcast_id=%d has no valid BIS configurations in " + "state=%s", + broadcast->GetBroadcastId(), + ToString(broadcast->GetState()).c_str()); return; } if (config->connection_handles.size() < encoded_channels.size()) { - LOG(ERROR) << "Not enough BIS'es to broadcast all channels!"; + LOG_ERROR("Not enough BIS'es to broadcast all channels!"); return; } @@ -596,7 +618,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { virtual void OnAudioDataReady(const std::vector<uint8_t>& data) override { if (!instance) return; - DVLOG(INFO) << __func__ << ": " << data.size() << " bytes received."; + LOG_VERBOSE("Received %zu bytes.", data.size()); /* Constants for the channel data configuration */ const auto num_channels = codec_wrapper_.GetNumChannels(); @@ -620,12 +642,12 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { !broadcast->IsMuted()) sendBroadcastData(broadcast, enc_audio_buffers_); } - DVLOG(INFO) << __func__ << ": END"; + LOG_VERBOSE("All data sent."); } virtual void OnAudioSuspend( std::promise<void> do_suspend_promise) override { - LOG(INFO) << __func__; + LOG_INFO(); /* TODO: Should we suspend all broadcasts - remove BIGs? */ do_suspend_promise.set_value(); if (instance) @@ -633,7 +655,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { } virtual void OnAudioResume(void) override { - LOG(INFO) << __func__; + LOG_INFO(); /* TODO: Should we resume all broadcasts - recreate BIGs? */ if (instance) instance->audio_data_path_state_ = AudioDataPathState::ACTIVE; @@ -649,7 +671,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { virtual void OnAudioMetadataUpdate( std::promise<void> do_update_metadata_promise, const source_metadata_t& source_metadata) override { - LOG(INFO) << __func__; + LOG_INFO(); if (!instance) return; do_update_metadata_promise.set_value(); /* TODO: We probably don't want to change stream type or update the @@ -666,7 +688,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { } audio_receiver_; bluetooth::le_audio::LeAudioBroadcasterCallbacks* callbacks_; - std::map<uint8_t, std::unique_ptr<BroadcastStateMachine>> broadcasts_; + std::map<uint32_t, std::unique_ptr<BroadcastStateMachine>> broadcasts_; std::vector<std::unique_ptr<BroadcastStateMachine>> pending_broadcasts_; /* Some BIG params are set globally */ @@ -688,25 +710,24 @@ LeAudioBroadcasterImpl::LeAudioClientAudioSinkReceiverImpl void LeAudioBroadcaster::Initialize( bluetooth::le_audio::LeAudioBroadcasterCallbacks* callbacks, base::Callback<bool()> audio_hal_verifier) { - LOG(INFO) << "Broadcaster " << __func__; + LOG_INFO(); if (instance) { - LOG(ERROR) << "Already initialized"; + LOG_ERROR("Already initialized"); return; } if (!controller_get_interface()->supports_ble_isochronous_broadcaster() && !osi_property_get_bool("persist.bluetooth.fake_iso_support", false)) { - LOG(WARNING) << "Isochronous Broadcast not supported by the controller!"; + LOG_WARN("Isochronous Broadcast not supported by the controller!"); return; } - IsoManager::GetInstance()->Start(); - if (!std::move(audio_hal_verifier).Run()) { - LOG_ASSERT(false) << __func__ << ", HAL 2.1 not supported, Init aborted."; - return; + LOG_ALWAYS_FATAL("HAL requirements not met. Init aborted."); } + IsoManager::GetInstance()->Start(); + instance = new LeAudioBroadcasterImpl(callbacks); /* Register HCI event handlers */ IsoManager::GetInstance()->RegisterBigCallbacks(instance); @@ -715,13 +736,13 @@ void LeAudioBroadcaster::Initialize( bool LeAudioBroadcaster::IsLeAudioBroadcasterRunning() { return instance; } LeAudioBroadcaster* LeAudioBroadcaster::Get(void) { - LOG(INFO) << "Broadcaster " << __func__; + LOG_INFO(); CHECK(instance); return instance; } void LeAudioBroadcaster::Stop(void) { - LOG(INFO) << "Broadcaster " << __func__; + LOG_INFO(); if (instance) { instance->Stop(); @@ -729,7 +750,7 @@ void LeAudioBroadcaster::Stop(void) { } void LeAudioBroadcaster::Cleanup(void) { - LOG(INFO) << "Broadcaster " << __func__; + LOG_INFO(); if (instance == nullptr) return; diff --git a/system/bta/le_audio/broadcaster/broadcaster_test.cc b/system/bta/le_audio/broadcaster/broadcaster_test.cc index d028451105..69867245d0 100644 --- a/system/bta/le_audio/broadcaster/broadcaster_test.cc +++ b/system/bta/le_audio/broadcaster/broadcaster_test.cc @@ -20,13 +20,13 @@ #include <chrono> -#include "device/include/controller.h" #include "bta/include/bta_le_audio_api.h" #include "bta/include/bta_le_audio_broadcaster_api.h" -#include "bta/test/common/mock_controller.h" +#include "bta/le_audio/broadcaster/mock_state_machine.h" #include "bta/le_audio/mock_iso_manager.h" #include "bta/le_audio/mock_le_audio_client_audio.h" -#include "bta/le_audio/broadcaster/mock_state_machine.h" +#include "bta/test/common/mock_controller.h" +#include "device/include/controller.h" #include "stack/include/btm_iso_api.h" using testing::_; @@ -53,12 +53,6 @@ void btsnd_hcic_ble_rand(base::Callback<void(BT_OCTET8)> cb) { generator_cb = cb; } -std::ostream& operator<<( - std::ostream& os, - const le_audio::broadcaster::BroadcastStateMachine& machine) { - return os; -} - namespace le_audio { namespace broadcaster { namespace { @@ -72,15 +66,13 @@ static const std::vector<uint8_t> default_metadata = {0x03, 0x02, 0x01, 0x00}; class MockLeAudioBroadcasterCallbacks : public bluetooth::le_audio::LeAudioBroadcasterCallbacks { public: - MOCK_METHOD((void), OnBroadcastCreated, (uint8_t instance_id, bool success), + MOCK_METHOD((void), OnBroadcastCreated, (uint32_t broadcast_id, bool success), (override)); - MOCK_METHOD((void), OnBroadcastDestroyed, (uint8_t instance_id), (override)); - MOCK_METHOD((void), OnBroadcastStateChanged, - (uint8_t instance_id, bluetooth::le_audio::BroadcastState state), + MOCK_METHOD((void), OnBroadcastDestroyed, (uint32_t broadcast_id), (override)); - MOCK_METHOD((void), OnBroadcastId, - (uint8_t instance_id, - const bluetooth::le_audio::BroadcastId& broadcast_id), + MOCK_METHOD((void), OnBroadcastStateChanged, + (uint32_t broadcast_id, + bluetooth::le_audio::BroadcastState state), (override)); }; @@ -140,16 +132,16 @@ class BroadcasterTest : public Test { MockLeAudioClientAudioSource::SetMockInstanceForTesting(nullptr); } - uint8_t InstantiateBroadcast( + uint32_t InstantiateBroadcast( LeAudioBroadcaster::AudioProfile profile = default_profile, std::vector<uint8_t> metadata = default_metadata, BroadcastCode code = default_code) { - uint8_t instance_id = LeAudioBroadcaster::kInstanceIdUndefined; + uint32_t broadcast_id = LeAudioBroadcaster::kInstanceIdUndefined; EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastCreated(_, true)) - .WillOnce(SaveArg<0>(&instance_id)); + .WillOnce(SaveArg<0>(&broadcast_id)); LeAudioBroadcaster::Get()->CreateAudioBroadcast(metadata, profile, code); - return instance_id; + return broadcast_id; } protected: @@ -180,10 +172,10 @@ TEST_F(BroadcasterTest, GetStreamingPhy) { } TEST_F(BroadcasterTest, CreateAudioBroadcast) { - uint8_t instance_id = InstantiateBroadcast(); - ASSERT_NE(instance_id, LeAudioBroadcaster::kInstanceIdUndefined); - ASSERT_EQ(instance_id, - MockBroadcastStateMachine::GetLastInstance()->GetInstanceId()); + auto broadcast_id = InstantiateBroadcast(); + ASSERT_NE(broadcast_id, LeAudioBroadcaster::kInstanceIdUndefined); + ASSERT_EQ(broadcast_id, + MockBroadcastStateMachine::GetLastInstance()->GetBroadcastId()); auto& instance_config = MockBroadcastStateMachine::GetLastInstance()->cfg; ASSERT_EQ(instance_config.broadcast_code, default_code); @@ -194,30 +186,30 @@ TEST_F(BroadcasterTest, CreateAudioBroadcast) { } TEST_F(BroadcasterTest, SuspendAudioBroadcast) { - uint8_t instance_id = InstantiateBroadcast(); - LeAudioBroadcaster::Get()->StartAudioBroadcast(instance_id); + auto broadcast_id = InstantiateBroadcast(); + LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); EXPECT_CALL(mock_broadcaster_callbacks_, - OnBroadcastStateChanged(instance_id, BroadcastState::CONFIGURED)) + OnBroadcastStateChanged(broadcast_id, BroadcastState::CONFIGURED)) .Times(1); EXPECT_CALL(mock_audio_source_, Stop).Times(AtLeast(1)); - LeAudioBroadcaster::Get()->SuspendAudioBroadcast(instance_id); + LeAudioBroadcaster::Get()->SuspendAudioBroadcast(broadcast_id); } TEST_F(BroadcasterTest, StartAudioBroadcast) { - uint8_t instance_id = InstantiateBroadcast(); - LeAudioBroadcaster::Get()->StopAudioBroadcast(instance_id); + auto broadcast_id = InstantiateBroadcast(); + LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id); EXPECT_CALL(mock_broadcaster_callbacks_, - OnBroadcastStateChanged(instance_id, BroadcastState::STREAMING)) + OnBroadcastStateChanged(broadcast_id, BroadcastState::STREAMING)) .Times(1); LeAudioClientAudioSinkReceiver* audio_receiver; EXPECT_CALL(mock_audio_source_, Start) .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true))); - LeAudioBroadcaster::Get()->StartAudioBroadcast(instance_id); + LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); // NOTICE: This is really an implementation specific part, we fake the BIG @@ -226,7 +218,7 @@ TEST_F(BroadcasterTest, StartAudioBroadcast) { // a mocked one). BigConfig big_cfg; big_cfg.big_id = - MockBroadcastStateMachine::GetLastInstance()->GetInstanceId(); + MockBroadcastStateMachine::GetLastInstance()->GetAdvertisingSid(); big_cfg.connection_handles = {0x10, 0x12}; big_cfg.max_pdu = 128; MockBroadcastStateMachine::GetLastInstance()->SetExpectedBigConfig(big_cfg); @@ -238,19 +230,19 @@ TEST_F(BroadcasterTest, StartAudioBroadcast) { } TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { - uint8_t instance_id = + auto broadcast_id = InstantiateBroadcast(LeAudioBroadcaster::AudioProfile::MEDIA); - LeAudioBroadcaster::Get()->StopAudioBroadcast(instance_id); + LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id); EXPECT_CALL(mock_broadcaster_callbacks_, - OnBroadcastStateChanged(instance_id, BroadcastState::STREAMING)) + OnBroadcastStateChanged(broadcast_id, BroadcastState::STREAMING)) .Times(1); LeAudioClientAudioSinkReceiver* audio_receiver; EXPECT_CALL(mock_audio_source_, Start) .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true))); - LeAudioBroadcaster::Get()->StartAudioBroadcast(instance_id); + LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); // NOTICE: This is really an implementation specific part, we fake the BIG @@ -259,7 +251,7 @@ TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { // a mocked one). BigConfig big_cfg; big_cfg.big_id = - MockBroadcastStateMachine::GetLastInstance()->GetInstanceId(); + MockBroadcastStateMachine::GetLastInstance()->GetAdvertisingSid(); big_cfg.connection_handles = {0x10, 0x12}; big_cfg.max_pdu = 128; MockBroadcastStateMachine::GetLastInstance()->SetExpectedBigConfig(big_cfg); @@ -271,83 +263,75 @@ TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { } TEST_F(BroadcasterTest, StopAudioBroadcast) { - uint8_t instance_id = InstantiateBroadcast(); - LeAudioBroadcaster::Get()->StartAudioBroadcast(instance_id); + auto broadcast_id = InstantiateBroadcast(); + LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); EXPECT_CALL(mock_broadcaster_callbacks_, - OnBroadcastStateChanged(instance_id, BroadcastState::STOPPED)) + OnBroadcastStateChanged(broadcast_id, BroadcastState::STOPPED)) .Times(1); EXPECT_CALL(mock_audio_source_, Stop).Times(AtLeast(1)); - LeAudioBroadcaster::Get()->StopAudioBroadcast(instance_id); + LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id); } TEST_F(BroadcasterTest, DestroyAudioBroadcast) { - uint8_t instance_id = InstantiateBroadcast(); + auto broadcast_id = InstantiateBroadcast(); - EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastDestroyed(instance_id)) + EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastDestroyed(broadcast_id)) .Times(1); - LeAudioBroadcaster::Get()->DestroyAudioBroadcast(instance_id); + LeAudioBroadcaster::Get()->DestroyAudioBroadcast(broadcast_id); // Expect not being able to interact with this Broadcast EXPECT_CALL(mock_broadcaster_callbacks_, - OnBroadcastStateChanged(instance_id, _)) + OnBroadcastStateChanged(broadcast_id, _)) .Times(0); EXPECT_CALL(mock_audio_source_, Stop).Times(0); - LeAudioBroadcaster::Get()->StopAudioBroadcast(instance_id); + LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id); EXPECT_CALL(mock_audio_source_, Start).Times(0); - LeAudioBroadcaster::Get()->StartAudioBroadcast(instance_id); + LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); EXPECT_CALL(mock_audio_source_, Stop).Times(0); - LeAudioBroadcaster::Get()->SuspendAudioBroadcast(instance_id); -} - -TEST_F(BroadcasterTest, GetBroadcastId) { - uint8_t instance_id = InstantiateBroadcast(); - - EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastId(instance_id, _)) - .Times(1); - LeAudioBroadcaster::Get()->GetBroadcastId(instance_id); + LeAudioBroadcaster::Get()->SuspendAudioBroadcast(broadcast_id); } TEST_F(BroadcasterTest, GetBroadcastAllStates) { - uint8_t instance_id = InstantiateBroadcast(); - uint8_t instance_id2 = InstantiateBroadcast(); - ASSERT_NE(instance_id, LeAudioBroadcaster::kInstanceIdUndefined); - ASSERT_NE(instance_id2, LeAudioBroadcaster::kInstanceIdUndefined); - ASSERT_NE(instance_id, instance_id2); + auto broadcast_id = InstantiateBroadcast(); + auto broadcast_id2 = InstantiateBroadcast(); + ASSERT_NE(broadcast_id, LeAudioBroadcaster::kInstanceIdUndefined); + ASSERT_NE(broadcast_id2, LeAudioBroadcaster::kInstanceIdUndefined); + ASSERT_NE(broadcast_id, broadcast_id2); /* In the current implementation state machine switches to the correct state * on itself, therefore here when we use mocked state machine this is not * being verified. */ EXPECT_CALL(mock_broadcaster_callbacks_, - OnBroadcastStateChanged(instance_id, _)) + OnBroadcastStateChanged(broadcast_id, _)) .Times(1); EXPECT_CALL(mock_broadcaster_callbacks_, - OnBroadcastStateChanged(instance_id2, _)) + OnBroadcastStateChanged(broadcast_id2, _)) .Times(1); LeAudioBroadcaster::Get()->GetAllBroadcastStates(); } TEST_F(BroadcasterTest, UpdateMetadata) { - uint8_t instance_id = InstantiateBroadcast(); + auto broadcast_id = InstantiateBroadcast(); EXPECT_CALL(*MockBroadcastStateMachine::GetLastInstance(), UpdateBroadcastAnnouncement) .Times(1); - LeAudioBroadcaster::Get()->UpdateMetadata(instance_id, + LeAudioBroadcaster::Get()->UpdateMetadata(broadcast_id, std::vector<uint8_t>({0x02, 0x01})); } TEST_F(BroadcasterTest, SetNumRetransmit) { - uint8_t instance_id = InstantiateBroadcast(); + auto broadcast_id = InstantiateBroadcast(); LeAudioBroadcaster::Get()->SetNumRetransmit(9); ASSERT_EQ(MockBroadcastStateMachine::GetLastInstance()->cb->GetNumRetransmit( - instance_id), + broadcast_id), 9); ASSERT_EQ(LeAudioBroadcaster::Get()->GetNumRetransmit(), 9); } @@ -355,12 +339,12 @@ TEST_F(BroadcasterTest, SetNumRetransmit) { TEST_F(BroadcasterTest, SetStreamingPhy) { LeAudioBroadcaster::Get()->SetStreamingPhy(2); // From now on new streams should be using Phy = 2. - uint8_t instance_id = InstantiateBroadcast(); + InstantiateBroadcast(); ASSERT_EQ(MockBroadcastStateMachine::GetLastInstance()->cfg.streaming_phy, 2); // From now on new streams should be using Phy = 1. LeAudioBroadcaster::Get()->SetStreamingPhy(1); - instance_id = InstantiateBroadcast(); + InstantiateBroadcast(); ASSERT_EQ(MockBroadcastStateMachine::GetLastInstance()->cfg.streaming_phy, 1); ASSERT_EQ(LeAudioBroadcaster::Get()->GetStreamingPhy(), 1); } diff --git a/system/bta/le_audio/broadcaster/broadcaster_types.cc b/system/bta/le_audio/broadcaster/broadcaster_types.cc index 3cfbc6c122..fc3ee47faf 100644 --- a/system/bta/le_audio/broadcaster/broadcaster_types.cc +++ b/system/bta/le_audio/broadcaster/broadcaster_types.cc @@ -147,8 +147,7 @@ void PrepareAdvertisingData(bluetooth::le_audio::BroadcastId& broadcast_id, UINT8_TO_STREAM(data_ptr, 6); UINT8_TO_STREAM(data_ptr, BTM_BLE_AD_TYPE_SERVICE_DATA_TYPE); UINT16_TO_STREAM(data_ptr, kBroadcastAudioAnnouncementServiceUuid); - ARRAY_TO_STREAM(data_ptr, broadcast_id.data(), - bluetooth::le_audio::kBroadcastAnnouncementBroadcastIdSize); + UINT24_TO_STREAM(data_ptr, broadcast_id) }; void PreparePeriodicData(const BasicAudioAnnouncementData& announcement, @@ -272,9 +271,6 @@ std::vector<uint8_t> BroadcastCodecWrapper::GetCodecSpecData() const { return data; } -} /* namespace broadcaster */ -} /* namespace le_audio */ - std::ostream& operator<<( std::ostream& os, const le_audio::broadcaster::BroadcastCodecWrapper& config) { @@ -292,3 +288,6 @@ std::ostream& operator<<( os << "]"; return os; } + +} /* namespace broadcaster */ +} /* namespace le_audio */ diff --git a/system/bta/le_audio/broadcaster/broadcaster_types.h b/system/bta/le_audio/broadcaster/broadcaster_types.h index 8103fab979..7070424661 100644 --- a/system/bta/le_audio/broadcaster/broadcaster_types.h +++ b/system/bta/le_audio/broadcaster/broadcaster_types.h @@ -148,9 +148,10 @@ struct BroadcastCodecWrapper { uint32_t codec_frame_len; uint8_t blocks_per_sdu; }; -} // namespace broadcaster -} // namespace le_audio std::ostream& operator<<( std::ostream& os, const le_audio::broadcaster::BroadcastCodecWrapper& config); + +} // namespace broadcaster +} // namespace le_audio diff --git a/system/bta/le_audio/broadcaster/mock_state_machine.cc b/system/bta/le_audio/broadcaster/mock_state_machine.cc index 6af8c5ca9f..239ca0bb8e 100644 --- a/system/bta/le_audio/broadcaster/mock_state_machine.cc +++ b/system/bta/le_audio/broadcaster/mock_state_machine.cc @@ -32,6 +32,9 @@ std::unique_ptr<BroadcastStateMachine> BroadcastStateMachine::CreateInstance( return std::move(instance); } +namespace le_audio { +namespace broadcaster { + std::ostream& operator<<(std::ostream& os, const BroadcastStateMachine::Message& state) { static const char* char_value_[BroadcastStateMachine::MESSAGE_COUNT] = { @@ -48,5 +51,22 @@ std::ostream& operator<<(std::ostream& os, return os; } +std::ostream& operator<<(std::ostream& os, const BigConfig& config) { + return os; +} + +std::ostream& operator<<(std::ostream& os, + const BroadcastStateMachineConfig& config) { + return os; +} + +std::ostream& operator<<(std::ostream& os, + const BroadcastStateMachine& machine) { + return os; +} + +} // namespace broadcaster +} // namespace le_audio + uint8_t MockBroadcastStateMachine::instance_counter_ = 0; MockBroadcastStateMachine* MockBroadcastStateMachine::last_instance_ = nullptr; diff --git a/system/bta/le_audio/broadcaster/mock_state_machine.h b/system/bta/le_audio/broadcaster/mock_state_machine.h index 69480ab2d7..427f0128ee 100644 --- a/system/bta/le_audio/broadcaster/mock_state_machine.h +++ b/system/bta/le_audio/broadcaster/mock_state_machine.h @@ -28,10 +28,10 @@ class MockBroadcastStateMachine le_audio::broadcaster::BroadcastStateMachineConfig cfg, le_audio::broadcaster::IBroadcastStateMachineCallbacks* cb) : cfg(cfg), cb(cb) { - instance_id_ = ++instance_counter_; + advertising_sid_ = ++instance_counter_; ON_CALL(*this, Initialize).WillByDefault([this]() { - this->cb->OnStateMachineCreateStatus(GetInstanceId(), result_); + this->cb->OnStateMachineCreateStatus(this->cfg.broadcast_id, result_); return result_; }); @@ -53,14 +53,14 @@ class MockBroadcastStateMachine if (result_) SetState(State::CONFIGURED); break; }; - this->cb->OnStateMachineEvent(GetInstanceId(), GetState(), + this->cb->OnStateMachineEvent(this->cfg.broadcast_id, GetState(), sent_data); }); ON_CALL(*this, GetBigConfig).WillByDefault(testing::ReturnRef(big_config_)); ON_CALL(*this, RequestOwnAddress()).WillByDefault([this]() { - this->cb->OnOwnAddressResponse(GetInstanceId(), 0, RawAddress()); + this->cb->OnOwnAddressResponse(this->cfg.broadcast_id, 0, RawAddress()); }); ON_CALL(*this, GetCodecConfig()) @@ -70,9 +70,10 @@ class MockBroadcastStateMachine }); ON_CALL(*this, GetBroadcastId()) - .WillByDefault([this]() -> const bluetooth::le_audio::BroadcastId { + .WillByDefault([this]() -> bluetooth::le_audio::BroadcastId { return this->cfg.broadcast_id; }); + ON_CALL(*this, GetOwnAddress()).WillByDefault([this]() -> RawAddress { return this->addr_; }); @@ -82,13 +83,17 @@ class MockBroadcastStateMachine }); }; - ~MockBroadcastStateMachine() { cb->OnStateMachineDestroyed(instance_id_); } + ~MockBroadcastStateMachine() { + cb->OnStateMachineDestroyed(this->cfg.broadcast_id); + } MOCK_METHOD((bool), Initialize, (), (override)); MOCK_METHOD((const le_audio::broadcaster::BroadcastCodecWrapper&), GetCodecConfig, (), (const override)); MOCK_METHOD((std::optional<le_audio::broadcaster::BigConfig> const&), - GetBigConfig, (), (override)); + GetBigConfig, (), (const override)); + MOCK_METHOD((le_audio::broadcaster::BroadcastStateMachineConfig const&), + GetStateMachineConfig, (), (const override)); MOCK_METHOD( (void), RequestOwnAddress, (base::Callback<void(uint8_t /* address_type*/, RawAddress /*address*/)> @@ -99,7 +104,7 @@ class MockBroadcastStateMachine MOCK_METHOD((uint8_t), GetOwnAddressType, (), (override)); MOCK_METHOD((std::optional<bluetooth::le_audio::BroadcastCode>), GetBroadcastCode, (), (const override)); - MOCK_METHOD((bluetooth::le_audio::BroadcastId const&), GetBroadcastId, (), + MOCK_METHOD((bluetooth::le_audio::BroadcastId), GetBroadcastId, (), (const override)); MOCK_METHOD((void), UpdateBroadcastAnnouncement, (le_audio::broadcaster::BasicAudioAnnouncementData announcement), diff --git a/system/bta/le_audio/broadcaster/state_machine.cc b/system/bta/le_audio/broadcaster/state_machine.cc index 8b7b035626..bbf7a6c390 100644 --- a/system/bta/le_audio/broadcaster/state_machine.cc +++ b/system/bta/le_audio/broadcaster/state_machine.cc @@ -27,11 +27,14 @@ #include "base/logging.h" #include "bta/le_audio/broadcaster/broadcaster_types.h" #include "bta/le_audio/le_audio_types.h" +#include "gd/common/strings.h" +#include "osi/include/log.h" #include "service/common/bluetooth/low_energy_constants.h" #include "stack/include/ble_advertiser.h" #include "stack/include/btm_iso_api.h" #include "stack/include/btu.h" +using bluetooth::common::ToString; using bluetooth::hci::IsoManager; using bluetooth::hci::iso_manager::big_create_cmpl_evt; using bluetooth::hci::iso_manager::big_terminate_cmpl_evt; @@ -50,16 +53,17 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { ~BroadcastStateMachineImpl() { if (GetState() == State::STREAMING) TerminateBig(); DestroyBroadcastAnnouncement(); - if (callbacks_) callbacks_->OnStateMachineDestroyed(GetInstanceId()); + if (callbacks_) callbacks_->OnStateMachineDestroyed(GetBroadcastId()); } bool Initialize() override { static constexpr uint8_t sNumBisMax = 31; if (sm_config_.codec_wrapper.GetNumChannels() > sNumBisMax) { - DLOG(ERROR) << int{sm_config_.codec_wrapper.GetNumChannels()} - << " channel count exceeds " << int{sNumBisMax} - << " - the maximum number of possible BISes!"; + LOG_ERROR( + "Channel count of %d exceeds the maximum number of possible BISes, " + "which is %d", + sm_config_.codec_wrapper.GetNumChannels(), sNumBisMax); return false; } @@ -73,35 +77,39 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { return sm_config_.codec_wrapper; } - std::optional<BigConfig> const& GetBigConfig() override { + std::optional<BigConfig> const& GetBigConfig() const override { return active_config_; } + BroadcastStateMachineConfig const& GetStateMachineConfig() const override { + return sm_config_; + } + void RequestOwnAddress( base::Callback<void(uint8_t /* address_type*/, RawAddress /*address*/)> cb) override { - uint8_t instance_id = GetInstanceId(); - advertiser_if_->GetOwnAddress(instance_id, cb); + uint8_t advertising_sid = GetAdvertisingSid(); + advertiser_if_->GetOwnAddress(advertising_sid, cb); } void RequestOwnAddress(void) override { - uint8_t instance_id = GetInstanceId(); + auto broadcast_id = GetBroadcastId(); RequestOwnAddress( base::Bind(&IBroadcastStateMachineCallbacks::OnOwnAddressResponse, - base::Unretained(this->callbacks_), instance_id)); + base::Unretained(this->callbacks_), broadcast_id)); } RawAddress GetOwnAddress() override { - LOG(INFO) << __func__; + LOG_INFO(); return addr_; } uint8_t GetOwnAddressType() override { - LOG(INFO) << __func__; + LOG_INFO(); return addr_type_; } - bluetooth::le_audio::BroadcastId const& GetBroadcastId() const override { + bluetooth::le_audio::BroadcastId GetBroadcastId() const override { return sm_config_.broadcast_id; } @@ -116,13 +124,13 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { PreparePeriodicData(announcement, periodic_data); sm_config_.announcement = std::move(announcement); - advertiser_if_->SetPeriodicAdvertisingData(instance_id_, periodic_data, + advertiser_if_->SetPeriodicAdvertisingData(advertising_sid_, periodic_data, base::DoNothing()); } void ProcessMessage(Message msg, const void* data = nullptr) override { - DLOG(INFO) << __func__ << " instance_id=" << int{GetInstanceId()} - << " state=" << GetState() << " message=" << msg; + LOG_INFO("broadcast_id=%d, state=%s, message=%s", GetBroadcastId(), + ToString(GetState()).c_str(), ToString(msg).c_str()); switch (msg) { case Message::START: start_msg_handlers[StateMachine::GetState()](data); @@ -151,7 +159,7 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { /* in STOPPED state */ [this](const void*) { SetState(State::CONFIGURING); - callbacks_->OnStateMachineEvent(GetInstanceId(), GetState()); + callbacks_->OnStateMachineEvent(GetBroadcastId(), GetState()); EnableAnnouncement(); }, /* in CONFIGURING state */ @@ -172,7 +180,7 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { /* in CONFIGURED state */ [this](const void*) { SetState(State::STOPPING); - callbacks_->OnStateMachineEvent(GetInstanceId(), GetState()); + callbacks_->OnStateMachineEvent(GetBroadcastId(), GetState()); DisableAnnouncement(); }, /* in STOPPING state */ @@ -182,7 +190,7 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { if ((active_config_ != std::nullopt) && !suspending_) { suspending_ = false; SetState(State::STOPPING); - callbacks_->OnStateMachineEvent(GetInstanceId(), GetState()); + callbacks_->OnStateMachineEvent(GetBroadcastId(), GetState()); TriggerIsoDatapathTeardown(active_config_->connection_handles[0]); } }}; @@ -218,50 +226,49 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { [](const void*) { /* Already streaming */ }}; void OnAddressResponse(uint8_t addr_type, RawAddress addr) { - DLOG(INFO) << __func__ << " own address: " << addr - << " own address type: " << +addr_type; + LOG_INFO("own address=%s, type=%d", ToString(addr).c_str(), addr_type); addr_ = addr; addr_type_ = addr_type; } - void CreateAnnouncementCb(uint8_t instance_id, int8_t tx_power, + void CreateAnnouncementCb(uint8_t advertising_sid, int8_t tx_power, uint8_t status) { - DLOG(INFO) << __func__ << " instance_id=" << int{instance_id} - << " tx_power=" << int{tx_power} << " status=" << int{status}; + LOG_INFO("advertising_sid=%d tx_power=%d status=%d", advertising_sid, + tx_power, status); - /* If this callback gets called the instance_id is valid even though the - * status can be other than BTM_BLE_MULTI_ADV_SUCCESS. We must set it here - * to properly identify the instance when callback gets called. + /* If this callback gets called the advertising_sid is valid even though the + * status can be other than BTM_BLE_MULTI_ADV_SUCCESS. */ - instance_id_ = instance_id; + advertising_sid_ = advertising_sid; if (status != BTM_BLE_MULTI_ADV_SUCCESS) { - callbacks_->OnStateMachineCreateStatus(instance_id, false); + LOG_ERROR("Creating Announcement failed"); + callbacks_->OnStateMachineCreateStatus(GetBroadcastId(), false); return; } /* Ext. advertisings are already on */ SetState(State::CONFIGURED); - callbacks_->OnStateMachineCreateStatus(instance_id, true); - callbacks_->OnStateMachineEvent(instance_id, State::CONFIGURED); + callbacks_->OnStateMachineCreateStatus(GetBroadcastId(), true); + callbacks_->OnStateMachineEvent(GetBroadcastId(), State::CONFIGURED); advertiser_if_->GetOwnAddress( - instance_id, base::Bind(&BroadcastStateMachineImpl::OnAddressResponse, - base::Unretained(this))); + advertising_sid, + base::Bind(&BroadcastStateMachineImpl::OnAddressResponse, + base::Unretained(this))); } - void CreateAnnouncementTimeoutCb(uint8_t instance_id, uint8_t status) { - DLOG(INFO) << __func__ << " instance_id=" << int{instance_id} - << " status=" << int{status}; - instance_id_ = instance_id; - callbacks_->OnStateMachineCreateStatus(instance_id, false); + void CreateAnnouncementTimeoutCb(uint8_t advertising_sid, uint8_t status) { + LOG_INFO("advertising_sid=%d status=%d", advertising_sid, status); + advertising_sid_ = advertising_sid; + callbacks_->OnStateMachineCreateStatus(GetBroadcastId(), false); } void CreateBroadcastAnnouncement( bluetooth::le_audio::BroadcastId& broadcast_id, const BasicAudioAnnouncementData& announcement, uint8_t streaming_phy) { - DLOG(INFO) << __func__; + LOG_INFO(); if (advertiser_if_ != nullptr) { tBTM_BLE_ADV_PARAMS adv_params; tBLE_PERIODIC_ADV_PARAMS periodic_params; @@ -301,13 +308,12 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { void DestroyBroadcastAnnouncement() { if (BleAdvertisingManager::IsInitialized()) - advertiser_if_->Unregister(GetInstanceId()); + advertiser_if_->Unregister(GetAdvertisingSid()); } void EnableAnnouncementCb(bool enable, uint8_t status) { - DLOG(INFO) << __func__ << " operation=" << (enable ? "enable" : "disable") - << " instance_id=" << int{GetInstanceId()} - << " status=" << int{status}; + LOG_INFO("operation=%s, broadcast_id=%d, status=%d", + (enable ? "enable" : "disable"), GetBroadcastId(), status); if (status == BTM_BLE_MULTI_ADV_SUCCESS) { /* Periodic is enabled but without BIGInfo. Stream is suspended. */ @@ -318,14 +324,14 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { } else { /* User wanted to stop the announcement - report target state reached */ SetState(State::STOPPED); - callbacks_->OnStateMachineEvent(GetInstanceId(), GetState()); + callbacks_->OnStateMachineEvent(GetBroadcastId(), GetState()); } } } void EnableAnnouncementTimeoutCb(bool enable, uint8_t status) { - DLOG(INFO) << __func__ << " operation=" << (enable ? "enable" : "disable") - << " status=" << int{status}; + LOG_INFO("operation=%s, broadcast_id=%d, status=%d", + (enable ? "enable" : "disable"), GetBroadcastId(), status); if (enable) { /* Timeout on enabling */ SetState(State::STOPPED); @@ -333,13 +339,13 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { /* Timeout on disabling */ SetState(State::CONFIGURED); } - callbacks_->OnStateMachineEvent(GetInstanceId(), GetState()); + callbacks_->OnStateMachineEvent(GetBroadcastId(), GetState()); } void EnableAnnouncement() { - DLOG(INFO) << __func__ << "instance_id: " << int{GetInstanceId()}; + LOG_INFO("broadcast_id=%d", GetBroadcastId()); advertiser_if_->Enable( - GetInstanceId(), true, + GetAdvertisingSid(), true, base::Bind(&BroadcastStateMachineImpl::EnableAnnouncementCb, base::Unretained(this), true), 0, 0, /* Enable until stopped */ @@ -348,16 +354,16 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { } void CreateBig(void) { - DLOG(INFO) << __func__ << " instance_id=" << int{GetInstanceId()}; + LOG_INFO("broadcast_id=%d", GetBroadcastId()); /* TODO: Figure out how to decide on the currently hard-codded params. */ struct bluetooth::hci::iso_manager::big_create_params big_params = { - .adv_handle = GetInstanceId(), + .adv_handle = GetAdvertisingSid(), .num_bis = sm_config_.codec_wrapper.GetNumChannels(), - .sdu_itv = callbacks_->GetSduItv(GetInstanceId()), + .sdu_itv = callbacks_->GetSduItv(GetBroadcastId()), .max_sdu_size = sm_config_.codec_wrapper.GetMaxSduSize(), .max_transport_latency = - callbacks_->GetMaxTransportLatency(GetInstanceId()), - .rtn = callbacks_->GetNumRetransmit(GetInstanceId()), + callbacks_->GetMaxTransportLatency(GetBroadcastId()), + .rtn = callbacks_->GetNumRetransmit(GetBroadcastId()), .phy = sm_config_.streaming_phy, .packing = 0x00, /* Sequencial */ .framing = 0x00, /* Unframed */ @@ -366,14 +372,14 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { : std::array<uint8_t, 16>({0}), }; - IsoManager::GetInstance()->CreateBig(GetInstanceId(), + IsoManager::GetInstance()->CreateBig(GetAdvertisingSid(), std::move(big_params)); } void DisableAnnouncement(void) { - DLOG(INFO) << __func__ << "instance_id: " << int{instance_id_}; + LOG_INFO("broadcast_id=%d", GetBroadcastId()); advertiser_if_->Enable( - GetInstanceId(), false, + GetAdvertisingSid(), false, base::Bind(&BroadcastStateMachineImpl::EnableAnnouncementCb, base::Unretained(this), false), 0, 0, @@ -382,16 +388,16 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { } void TerminateBig() { - DLOG(INFO) << __func__ << "suspending: " << suspending_; + LOG_INFO("suspending=%d", suspending_); /* Terminate with reason: Connection Terminated By Local Host */ - IsoManager::GetInstance()->TerminateBig(GetInstanceId(), 0x16); + IsoManager::GetInstance()->TerminateBig(GetAdvertisingSid(), 0x16); } void OnSetupIsoDataPath(uint8_t status, uint16_t conn_hdl) override { LOG_ASSERT(active_config_ != std::nullopt); if (status != 0) { - DLOG(ERROR) << "Failure creating data path. Tearing down the BIG now."; + LOG_ERROR("Failure creating data path. Tearing down the BIG now."); suspending_ = true; TerminateBig(); return; @@ -409,11 +415,12 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { /* It was the last BIS to set up - change state to streaming */ SetState(State::STREAMING); callbacks_->OnStateMachineEvent( - GetInstanceId(), GetState(), + GetBroadcastId(), GetState(), &sm_config_.codec_wrapper.GetLeAudioCodecConfiguration()); } else { /* Note: We would feed a watchdog here if we had one */ /* There are more BISes to set up data path for */ + LOG_INFO("There is more data paths to set up."); TriggerIsoDatapathSetup(*handle_it); } } @@ -422,7 +429,7 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { LOG_ASSERT(active_config_ != std::nullopt); if (status != 0) { - DLOG(ERROR) << "Failure removing data path. Tearing down the BIG now."; + LOG_ERROR("Failure removing data path. Tearing down the BIG now."); TerminateBig(); return; } @@ -441,11 +448,13 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { } else { /* Note: We would feed a watchdog here if we had one */ /* There are more BISes to tear down data path for */ + LOG_INFO("There is more data paths to tear down."); TriggerIsoDatapathTeardown(*handle_it); } } void TriggerIsoDatapathSetup(uint16_t conn_handle) { + LOG_INFO("conn_hdl=%d", conn_handle); LOG_ASSERT(active_config_ != std::nullopt); /* Note: For the LC3 software encoding on the Host side, the coding format @@ -474,7 +483,7 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { } void TriggerIsoDatapathTeardown(uint16_t conn_handle) { - LOG(INFO) << __func__; + LOG_INFO("conn_hdl=%d", conn_handle); LOG_ASSERT(active_config_ != std::nullopt); SetMuted(true); @@ -487,16 +496,14 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { case HCI_BLE_CREATE_BIG_CPL_EVT: { auto* evt = static_cast<big_create_cmpl_evt*>(data); - if (evt->big_id != GetInstanceId()) { - LOG(ERROR) << __func__ << " State=" << GetState() - << " Event=" << +event - << " Unknown big, big_id= " << +evt->big_id; + if (evt->big_id != GetAdvertisingSid()) { + LOG_ERROR("State=%s, Event=%d, Unknown big, big_id=%d", + ToString(GetState()).c_str(), event, evt->big_id); break; } if (evt->status == 0x00) { - DLOG(INFO) << __func__ - << " BIG create BIG cmpl, big_id=" << +evt->big_id; + LOG_INFO("BIG create BIG complete, big_id=%d", evt->big_id); active_config_ = { .status = evt->status, .big_id = evt->big_id, @@ -513,23 +520,20 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { }; TriggerIsoDatapathSetup(evt->conn_handles[0]); } else { - LOG(ERROR) << __func__ << " State=" << GetState() - << " Event=" << +event - << ". Unable to create big, big_id= " << +evt->big_id - << ", status=" << +evt->status; + LOG_ERROR( + "State=%s Event=%d. Unable to create big, big_id=%d, status=%d", + ToString(GetState()).c_str(), event, evt->big_id, evt->status); } } break; case HCI_BLE_TERM_BIG_CPL_EVT: { auto* evt = static_cast<big_terminate_cmpl_evt*>(data); - DLOG(INFO) << __func__ - << " BIG terminate BIG cmpl, reason=" << int{evt->reason} - << " big_id=" << int{evt->big_id}; + LOG_INFO("BIG terminate BIG cmpl, reason=%d big_id=%d", evt->reason, + evt->big_id); - if (evt->big_id != GetInstanceId()) { - LOG(ERROR) << __func__ << " State=" << GetState() - << " Event=" << +event - << " Unknown instance= " << +evt->big_id; + if (evt->big_id != GetAdvertisingSid()) { + LOG_ERROR("State=%s Event=%d, unknown adv.sid=%d", + ToString(GetState()).c_str(), event, evt->big_id); break; } @@ -540,15 +544,15 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { /* Check if we got this HCI event due to STOP or SUSPEND message. */ if (suspending_) { - callbacks_->OnStateMachineEvent(GetInstanceId(), GetState(), evt); + callbacks_->OnStateMachineEvent(GetBroadcastId(), GetState(), evt); suspending_ = false; } else { DisableAnnouncement(); } } break; default: - LOG(ERROR) << __func__ << " State=" << GetState() - << " Unknown event= " << int{event}; + LOG_ERROR("State=%s Unknown event=%d", ToString(GetState()).c_str(), + event); break; } } @@ -569,19 +573,22 @@ void BroadcastStateMachine::Initialize( BroadcastStateMachineImpl::callbacks_ = callbacks; /* Get BLE advertiser interface */ if (BleAdvertisingManager::IsInitialized()) { - DLOG(INFO) << __func__ << " BleAdvertisingManager acquired"; + LOG_INFO("BleAdvertisingManager acquired"); BroadcastStateMachineImpl::advertiser_if_ = BleAdvertisingManager::Get(); } else { - LOG(ERROR) << __func__ << " Could not acquire BleAdvertisingManager!"; + LOG_INFO("Could not acquire BleAdvertisingManager!"); BroadcastStateMachineImpl::advertiser_if_ = nullptr; } } +namespace le_audio { +namespace broadcaster { + std::ostream& operator<<(std::ostream& os, - const BroadcastStateMachine::Message& state) { + const BroadcastStateMachine::Message& msg) { static const char* char_value_[BroadcastStateMachine::MESSAGE_COUNT] = { "START", "SUSPEND", "STOP"}; - os << char_value_[static_cast<uint8_t>(state)]; + os << char_value_[static_cast<uint8_t>(msg)]; return os; } @@ -593,17 +600,78 @@ std::ostream& operator<<(std::ostream& os, return os; } +std::ostream& operator<<(std::ostream& os, + const le_audio::broadcaster::BigConfig& config) { + os << "\n"; + os << " Status: 0x" << std::hex << +config.status << std::dec << "\n"; + os << " BIG ID: " << +config.big_id << "\n"; + os << " Sync delay: " << config.big_sync_delay << "\n"; + os << " Transport Latency: " << config.transport_latency_big << "\n"; + os << " Phy: " << +config.phy << "\n"; + os << " Nse: " << +config.nse << "\n"; + os << " Bn: " << +config.bn << "\n"; + os << " Pto: " << +config.pto << "\n"; + os << " Irc: " << +config.irc << "\n"; + os << " Max pdu: " << config.max_pdu << "\n"; + os << " Iso interval: " << config.iso_interval << "\n"; + os << " Connection handles (BISes): ["; + for (auto& el : config.connection_handles) { + os << std::hex << +el << std::dec << ":"; + } + os << "]"; + return os; +} + +std::ostream& operator<<( + std::ostream& os, + const le_audio::broadcaster::BroadcastStateMachineConfig& config) { + const char* const PHYS[] = {"NONE", "1M", "2M", "CODED"}; + + os << "\n"; + os << " Broadcast ID: " << config.broadcast_id << "\n"; + os << " Streaming PHY: " + << ((config.streaming_phy > 3) ? std::to_string(config.streaming_phy) + : PHYS[config.streaming_phy]) + << "\n"; + os << " Codec Wrapper: " << config.codec_wrapper << "\n"; + if (config.broadcast_code) { + os << " Broadcast Code: ["; + for (auto& el : *config.broadcast_code) { + os << std::hex << +el << ":"; + } + os << "]\n"; + } else { + os << " Broadcast Code: NONE\n"; + } + + std::vector<uint8_t> an_raw; + config.announcement.ToRawPacket(an_raw); + os << " Announcement RAW: ["; + for (auto& el : an_raw) { + os << std::hex << +el << ":"; + } + os << "]"; + + return os; +} + std::ostream& operator<<( std::ostream& os, const le_audio::broadcaster::BroadcastStateMachine& machine) { os << " Broadcast state machine: {" - << " State: " << machine.GetState() - << " Instance ID: " << +machine.GetInstanceId() << "\n" - << " Codec Config: " << machine.GetCodecConfig() << "\n"; - os << " Broadcast ID: ["; - for (auto& el : machine.GetBroadcastId()) { - os << std::hex << +el << ":"; + << " Advertising SID: " << +machine.GetAdvertisingSid() << "\n" + << " State: " << machine.GetState() << "\n"; + os << " State Machine Config: " << machine.GetStateMachineConfig() + << "\n"; + + if (machine.GetBigConfig()) { + os << " BigConfig: " << *machine.GetBigConfig() << "\n"; + } else { + os << " BigConfig: NONE\n"; } - os << "]}\n"; + os << " }\n"; return os; } + +} // namespace broadcaster +} // namespace le_audio diff --git a/system/bta/le_audio/broadcaster/state_machine.h b/system/bta/le_audio/broadcaster/state_machine.h index 5877a8c445..260f846305 100644 --- a/system/bta/le_audio/broadcaster/state_machine.h +++ b/system/bta/le_audio/broadcaster/state_machine.h @@ -103,7 +103,7 @@ struct BroadcastStateMachineConfig { class BroadcastStateMachine : public StateMachine<5> { public: - static constexpr uint8_t kInstanceIdUndefined = 0xFF; + static constexpr uint8_t kAdvSidUndefined = 0xFF; static constexpr uint8_t kPaIntervalMax = 0xA0; /* 160 * 0.625 = 100ms */ static constexpr uint8_t kPaIntervalMin = 0x50; /* 80 * 0.625 = 50ms */ @@ -133,11 +133,12 @@ class BroadcastStateMachine : public StateMachine<5> { return static_cast<State>(StateMachine::GetState()); } - inline uint8_t GetInstanceId() const { return instance_id_; } + inline uint8_t GetAdvertisingSid() const { return advertising_sid_; } virtual bool Initialize() = 0; virtual const BroadcastCodecWrapper& GetCodecConfig() const = 0; - virtual std::optional<BigConfig> const& GetBigConfig() = 0; + virtual std::optional<BigConfig> const& GetBigConfig() const = 0; + virtual BroadcastStateMachineConfig const& GetStateMachineConfig() const = 0; virtual void RequestOwnAddress( base::Callback<void(uint8_t /* address_type*/, RawAddress /*address*/)> cb) = 0; @@ -146,7 +147,7 @@ class BroadcastStateMachine : public StateMachine<5> { virtual uint8_t GetOwnAddressType() = 0; virtual std::optional<bluetooth::le_audio::BroadcastCode> GetBroadcastCode() const = 0; - virtual bluetooth::le_audio::BroadcastId const& GetBroadcastId() const = 0; + virtual bluetooth::le_audio::BroadcastId GetBroadcastId() const = 0; virtual void UpdateBroadcastAnnouncement( BasicAudioAnnouncementData announcement) = 0; void SetMuted(bool muted) { is_muted_ = muted; }; @@ -167,7 +168,7 @@ class BroadcastStateMachine : public StateMachine<5> { static_cast<std::underlying_type<State>::type>(state)); } - uint8_t instance_id_ = kInstanceIdUndefined; + uint8_t advertising_sid_ = kAdvSidUndefined; bool is_muted_ = false; RawAddress addr_ = RawAddress::kEmpty; @@ -178,22 +179,19 @@ class IBroadcastStateMachineCallbacks { public: IBroadcastStateMachineCallbacks() = default; virtual ~IBroadcastStateMachineCallbacks() = default; - virtual void OnStateMachineCreateStatus(uint8_t instance_id, + virtual void OnStateMachineCreateStatus(uint32_t broadcast_id, bool initialized) = 0; - virtual void OnStateMachineDestroyed(uint8_t instance_id) = 0; - virtual void OnStateMachineEvent(uint8_t instance_id, + virtual void OnStateMachineDestroyed(uint32_t broadcast_id) = 0; + virtual void OnStateMachineEvent(uint32_t broadcast_id, BroadcastStateMachine::State state, const void* data = nullptr) = 0; - virtual void OnOwnAddressResponse(uint8_t instance_id, uint8_t addr_type, + virtual void OnOwnAddressResponse(uint32_t broadcast_id, uint8_t addr_type, RawAddress address) = 0; - virtual uint8_t GetNumRetransmit(uint8_t instance_id) = 0; - virtual uint32_t GetSduItv(uint8_t instance_id) = 0; - virtual uint16_t GetMaxTransportLatency(uint8_t instance_id) = 0; + virtual uint8_t GetNumRetransmit(uint32_t broadcast_id) = 0; + virtual uint32_t GetSduItv(uint32_t broadcast_id) = 0; + virtual uint16_t GetMaxTransportLatency(uint32_t broadcast_id) = 0; }; -} /* namespace broadcaster */ -} /* namespace le_audio */ - std::ostream& operator<<( std::ostream& os, const le_audio::broadcaster::BroadcastStateMachine::Message& state); @@ -205,3 +203,13 @@ std::ostream& operator<<( std::ostream& operator<<( std::ostream& os, const le_audio::broadcaster::BroadcastStateMachine& machine); + +std::ostream& operator<<(std::ostream& os, + const le_audio::broadcaster::BigConfig& machine); + +std::ostream& operator<<( + std::ostream& os, + const le_audio::broadcaster::BroadcastStateMachineConfig& machine); + +} /* namespace broadcaster */ +} /* namespace le_audio */ diff --git a/system/bta/le_audio/broadcaster/state_machine_test.cc b/system/bta/le_audio/broadcaster/state_machine_test.cc index f6cf786e58..206487de0c 100644 --- a/system/bta/le_audio/broadcaster/state_machine_test.cc +++ b/system/bta/le_audio/broadcaster/state_machine_test.cc @@ -61,19 +61,19 @@ class MockBroadcastStatMachineCallbacks ~MockBroadcastStatMachineCallbacks() override = default; MOCK_METHOD((void), OnStateMachineCreateStatus, - (uint8_t instance_id, bool initialized), (override)); - MOCK_METHOD((void), OnStateMachineDestroyed, (uint8_t instance_id), + (uint32_t broadcast_id, bool initialized), (override)); + MOCK_METHOD((void), OnStateMachineDestroyed, (uint32_t broadcast_id), (override)); MOCK_METHOD((void), OnStateMachineEvent, - (uint8_t instance_id, BroadcastStateMachine::State state, + (uint32_t broadcast_id, BroadcastStateMachine::State state, const void* data), (override)); MOCK_METHOD((void), OnOwnAddressResponse, - (uint8_t instance_id, uint8_t addr_type, RawAddress addr), + (uint32_t broadcast_id, uint8_t addr_type, RawAddress addr), (override)); - MOCK_METHOD((uint8_t), GetNumRetransmit, (uint8_t instance_id), (override)); - MOCK_METHOD((uint32_t), GetSduItv, (uint8_t instance_id), (override)); - MOCK_METHOD((uint16_t), GetMaxTransportLatency, (uint8_t instance_id), + MOCK_METHOD((uint8_t), GetNumRetransmit, (uint32_t broadcast_id), (override)); + MOCK_METHOD((uint32_t), GetSduItv, (uint32_t broadcast_id), (override)); + MOCK_METHOD((uint16_t), GetMaxTransportLatency, (uint32_t broadcast_id), (override)); }; @@ -125,25 +125,25 @@ class StateMachineTest : public Test { }); ON_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus) - .WillByDefault([this](uint8_t instance_id, bool initialized) { + .WillByDefault([this](uint32_t broadcast_id, bool initialized) { auto instance_it = std::find_if(pending_broadcasts_.begin(), - pending_broadcasts_.end(), [instance_id](auto& up) { - return (up->GetInstanceId() == instance_id); + pending_broadcasts_.end(), [broadcast_id](auto& up) { + return (up->GetBroadcastId() == broadcast_id); }); if (instance_it != pending_broadcasts_.end()) { if (initialized) { - broadcasts_[instance_id] = std::move(*instance_it); + broadcasts_[broadcast_id] = std::move(*instance_it); } pending_broadcasts_.erase(instance_it); } - instance_creation_promise_.set_value(instance_id); + instance_creation_promise_.set_value(broadcast_id); }); ON_CALL(*(sm_callbacks_.get()), OnStateMachineDestroyed) - .WillByDefault([this](uint8_t instance_id) { - if (broadcasts_.count(instance_id)) { - instance_destruction_promise_.set_value(instance_id); + .WillByDefault([this](uint32_t broadcast_id) { + if (broadcasts_.count(broadcast_id)) { + instance_destruction_promise_.set_value(broadcast_id); } }); @@ -160,44 +160,69 @@ class StateMachineTest : public Test { ON_CALL(*mock_iso_manager_, CreateBig) .WillByDefault([this](uint8_t big_id, big_create_params p) { - if (!broadcasts_[big_id]) return; + auto bit = + std::find_if(broadcasts_.begin(), broadcasts_.end(), + [big_id](auto const& entry) { + return entry.second->GetAdvertisingSid() == big_id; + }); + if (bit == broadcasts_.end()) return; big_create_cmpl_evt evt; evt.big_id = big_id; - // For test convenience lets encode big_id into conn_hdl's - // MSB + // For test convenience lets encode big_id into conn_hdl MSB. + // NOTE: In current implementation big_id is equal to advertising SID. + // This is an important detail exploited by the IsoManager mock static uint8_t conn_lsb = 1; uint16_t conn_msb = ((uint16_t)big_id) << 8; for (auto i = 0; i < p.num_bis; ++i) { evt.conn_handles.push_back(conn_msb | conn_lsb++); } - broadcasts_[big_id]->HandleHciEvent(HCI_BLE_CREATE_BIG_CPL_EVT, &evt); + bit->second->HandleHciEvent(HCI_BLE_CREATE_BIG_CPL_EVT, &evt); }); ON_CALL(*mock_iso_manager_, SetupIsoDataPath) .WillByDefault([this](uint16_t conn_handle, iso_data_path_params p) { // Get the big_id encoded in conn_handle's MSB - if (!broadcasts_[conn_handle >> 8]) return; - broadcasts_[conn_handle >> 8]->OnSetupIsoDataPath(0, conn_handle); + uint8_t big_id = conn_handle >> 8; + auto bit = + std::find_if(broadcasts_.begin(), broadcasts_.end(), + [big_id](auto const& entry) { + return entry.second->GetAdvertisingSid() == big_id; + }); + if (bit == broadcasts_.end()) return; + bit->second->OnSetupIsoDataPath(0, conn_handle); }); ON_CALL(*mock_iso_manager_, RemoveIsoDataPath) .WillByDefault([this](uint16_t conn_handle, uint8_t iso_direction) { // Get the big_id encoded in conn_handle's MSB - if (!broadcasts_[conn_handle >> 8]) return; - broadcasts_[conn_handle >> 8]->OnRemoveIsoDataPath(0, conn_handle); + uint8_t big_id = conn_handle >> 8; + auto bit = + std::find_if(broadcasts_.begin(), broadcasts_.end(), + [big_id](auto const& entry) { + return entry.second->GetAdvertisingSid() == big_id; + }); + if (bit == broadcasts_.end()) return; + bit->second->OnRemoveIsoDataPath(0, conn_handle); }); ON_CALL(*mock_iso_manager_, TerminateBig) .WillByDefault([this](uint8_t big_id, uint8_t reason) { - if (!broadcasts_[big_id]) return; + // Get the big_id encoded in conn_handle's MSB + auto bit = + std::find_if(broadcasts_.begin(), broadcasts_.end(), + [big_id](auto const& entry) { + return entry.second->GetAdvertisingSid() == big_id; + }); + if (bit == broadcasts_.end()) return; + big_terminate_cmpl_evt evt; evt.big_id = big_id; evt.reason = reason; - broadcasts_[big_id]->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT, &evt); + bit->second->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT, &evt); }); } @@ -209,21 +234,22 @@ class StateMachineTest : public Test { sm_callbacks_.reset(); } - uint8_t InstantiateStateMachine( + uint32_t InstantiateStateMachine( LeAudioBroadcaster::AudioProfile profile = LeAudioBroadcaster::AudioProfile::SONIFICATION) { // We will get the state machine create status update in an async callback // so let's wait for it here. - instance_creation_promise_ = std::promise<uint8_t>(); - std::future<uint8_t> instance_future = + instance_creation_promise_ = std::promise<uint32_t>(); + std::future<uint32_t> instance_future = instance_creation_promise_.get_future(); static uint8_t broadcast_id_lsb = 1; auto codec_wrapper = BroadcastCodecWrapper::getCodecConfigForProfile(profile); + auto broadcast_id = broadcast_id_lsb++; pending_broadcasts_.push_back(BroadcastStateMachine::CreateInstance({ - .broadcast_id = {0, 0, broadcast_id_lsb++}, + .broadcast_id = broadcast_id, // .streaming_phy = , .codec_wrapper = std::move(codec_wrapper), // .announcement = , @@ -239,10 +265,10 @@ class StateMachineTest : public Test { IsoManager* iso_manager_; MockIsoManager* mock_iso_manager_; - std::map<uint8_t, std::unique_ptr<BroadcastStateMachine>> broadcasts_; + std::map<uint32_t, std::unique_ptr<BroadcastStateMachine>> broadcasts_; std::vector<std::unique_ptr<BroadcastStateMachine>> pending_broadcasts_; std::unique_ptr<MockBroadcastStatMachineCallbacks> sm_callbacks_; - std::promise<uint8_t> instance_creation_promise_; + std::promise<uint32_t> instance_creation_promise_; std::promise<uint8_t> instance_destruction_promise_; }; @@ -265,8 +291,8 @@ TEST_F(StateMachineTest, CreateInstanceFailed) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, false)) .Times(1); - uint8_t instance_id = InstantiateStateMachine(); - ASSERT_NE(instance_id, BroadcastStateMachine::kInstanceIdUndefined); + auto broadcast_id = InstantiateStateMachine(); + ASSERT_NE(broadcast_id, BroadcastStateMachine::kAdvSidUndefined); ASSERT_TRUE(pending_broadcasts_.empty()); ASSERT_TRUE(broadcasts_.empty()); } @@ -289,8 +315,8 @@ TEST_F(StateMachineTest, CreateInstanceTimeout) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, false)) .Times(1); - uint8_t instance_id = InstantiateStateMachine(); - ASSERT_NE(instance_id, BroadcastStateMachine::kInstanceIdUndefined); + auto broadcast_id = InstantiateStateMachine(); + ASSERT_NE(broadcast_id, BroadcastStateMachine::kAdvSidUndefined); ASSERT_TRUE(pending_broadcasts_.empty()); ASSERT_TRUE(broadcasts_.empty()); } @@ -299,12 +325,12 @@ TEST_F(StateMachineTest, CreateInstanceSuccess) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)) .Times(1); - uint8_t instance_id = InstantiateStateMachine(); - ASSERT_NE(instance_id, BroadcastStateMachine::kInstanceIdUndefined); + auto broadcast_id = InstantiateStateMachine(); + ASSERT_NE(broadcast_id, BroadcastStateMachine::kAdvSidUndefined); ASSERT_TRUE(pending_broadcasts_.empty()); ASSERT_FALSE(broadcasts_.empty()); - ASSERT_EQ(broadcasts_[instance_id]->GetInstanceId(), instance_id); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetBroadcastId(), broadcast_id); + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED); } @@ -312,8 +338,8 @@ TEST_F(StateMachineTest, DestroyInstanceSuccess) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)) .Times(1); - uint8_t instance_id = InstantiateStateMachine(); - ASSERT_NE(instance_id, BroadcastStateMachine::kInstanceIdUndefined); + auto broadcast_id = InstantiateStateMachine(); + ASSERT_NE(broadcast_id, BroadcastStateMachine::kAdvSidUndefined); ASSERT_FALSE(broadcasts_.empty()); instance_destruction_promise_ = std::promise<uint8_t>(); @@ -321,32 +347,32 @@ TEST_F(StateMachineTest, DestroyInstanceSuccess) { instance_destruction_promise_.get_future(); broadcasts_.clear(); - EXPECT_EQ(instance_future.get(), instance_id); + EXPECT_EQ(instance_future.get(), broadcast_id); } TEST_F(StateMachineTest, GetAdvertisingAddress) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)) .Times(1); - uint8_t instance_id = InstantiateStateMachine(); - EXPECT_CALL(*(sm_callbacks_.get()), OnOwnAddressResponse(instance_id, _, _)) + auto broadcast_id = InstantiateStateMachine(); + EXPECT_CALL(*(sm_callbacks_.get()), OnOwnAddressResponse(broadcast_id, _, _)) .Times(1); - broadcasts_[instance_id]->RequestOwnAddress(); + broadcasts_[broadcast_id]->RequestOwnAddress(); } TEST_F(StateMachineTest, Mute) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)) .Times(1); - uint8_t instance_id = InstantiateStateMachine(); + auto broadcast_id = InstantiateStateMachine(); ASSERT_TRUE(pending_broadcasts_.empty()); ASSERT_FALSE(broadcasts_.empty()); - ASSERT_FALSE(broadcasts_[instance_id]->IsMuted()); - broadcasts_[instance_id]->SetMuted(true); - ASSERT_TRUE(broadcasts_[instance_id]->IsMuted()); - broadcasts_[instance_id]->SetMuted(false); - ASSERT_FALSE(broadcasts_[instance_id]->IsMuted()); + ASSERT_FALSE(broadcasts_[broadcast_id]->IsMuted()); + broadcasts_[broadcast_id]->SetMuted(true); + ASSERT_TRUE(broadcasts_[broadcast_id]->IsMuted()); + broadcasts_[broadcast_id]->SetMuted(false); + ASSERT_FALSE(broadcasts_[broadcast_id]->IsMuted()); } static BasicAudioAnnouncementData prepareAnnouncement( @@ -381,7 +407,7 @@ TEST_F(StateMachineTest, UpdateAnnouncement) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)) .Times(1); - uint8_t instance_id = InstantiateStateMachine(); + auto broadcast_id = InstantiateStateMachine(); std::vector<uint8_t> metadata = {}; BroadcastCodecWrapper codec_config( {.coding_format = le_audio::types::kLeAudioCodingFormatLC3, @@ -394,12 +420,13 @@ TEST_F(StateMachineTest, UpdateAnnouncement) { 32000, 40); auto announcement = prepareAnnouncement(codec_config, metadata); + auto adv_sid = broadcasts_[broadcast_id]->GetAdvertisingSid(); std::vector<uint8_t> data; EXPECT_CALL(*mock_ble_advertising_manager_, - SetPeriodicAdvertisingData(instance_id, _, _)) + SetPeriodicAdvertisingData(adv_sid, _, _)) .Times(2) .WillRepeatedly(SaveArg<1>(&data)); - broadcasts_[instance_id]->UpdateBroadcastAnnouncement( + broadcasts_[broadcast_id]->UpdateBroadcastAnnouncement( std::move(announcement)); uint8_t first_len = data.size(); @@ -412,7 +439,7 @@ TEST_F(StateMachineTest, UpdateAnnouncement) { // Verify that changes in the announcement makes a difference metadata = {0x02, 0x01, 0x03}; announcement = prepareAnnouncement(codec_config, metadata); - broadcasts_[instance_id]->UpdateBroadcastAnnouncement( + broadcasts_[broadcast_id]->UpdateBroadcastAnnouncement( std::move(announcement)); uint8_t second_len = data.size(); @@ -427,14 +454,19 @@ TEST_F(StateMachineTest, ProcessMessageStartWhenConfigured) { auto sound_profile = LeAudioBroadcaster::AudioProfile::MEDIA; uint8_t num_channels = 2; - uint8_t instance_id = InstantiateStateMachine(sound_profile); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + auto broadcast_id = InstantiateStateMachine(sound_profile); + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED); uint8_t num_bises = 0; EXPECT_CALL(*mock_iso_manager_, CreateBig) .WillOnce([this, &num_bises](uint8_t big_id, big_create_params p) { - if (!broadcasts_[big_id]) return; + auto bit = + std::find_if(broadcasts_.begin(), broadcasts_.end(), + [big_id](auto const& entry) { + return entry.second->GetAdvertisingSid() == big_id; + }); + if (bit == broadcasts_.end()) return; num_bises = p.num_bis; @@ -449,21 +481,21 @@ TEST_F(StateMachineTest, ProcessMessageStartWhenConfigured) { evt.conn_handles.push_back(conn_msb | conn_lsb++); } - broadcasts_[big_id]->HandleHciEvent(HCI_BLE_CREATE_BIG_CPL_EVT, &evt); + bit->second->HandleHciEvent(HCI_BLE_CREATE_BIG_CPL_EVT, &evt); }); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(num_channels); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath).Times(0); EXPECT_CALL(*(sm_callbacks_.get()), - OnStateMachineEvent(instance_id, + OnStateMachineEvent(broadcast_id, BroadcastStateMachine::State::STREAMING, _)) .Times(1); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START); // Verify the right number of BISes in the BIG being created ASSERT_EQ(num_bises, num_channels); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STREAMING); } @@ -471,25 +503,25 @@ TEST_F(StateMachineTest, ProcessMessageStopWhenConfigured) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)) .Times(1); - uint8_t instance_id = + auto broadcast_id = InstantiateStateMachine(LeAudioBroadcaster::AudioProfile::MEDIA); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath).Times(0); EXPECT_CALL(*(sm_callbacks_.get()), - OnStateMachineEvent(instance_id, + OnStateMachineEvent(broadcast_id, BroadcastStateMachine::State::STOPPING, _)) .Times(1); EXPECT_CALL(*(sm_callbacks_.get()), - OnStateMachineEvent(instance_id, + OnStateMachineEvent(broadcast_id, BroadcastStateMachine::State::STOPPED, _)) .Times(1); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::STOP); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STOPPED); } @@ -497,156 +529,156 @@ TEST_F(StateMachineTest, ProcessMessageSuspendWhenConfigured) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)) .Times(1); - uint8_t instance_id = + auto broadcast_id = InstantiateStateMachine(LeAudioBroadcaster::AudioProfile::MEDIA); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath).Times(0); - EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineEvent(instance_id, _, _)) + EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineEvent(broadcast_id, _, _)) .Times(0); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::SUSPEND); // There shall be no change in state - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED); } TEST_F(StateMachineTest, ProcessMessageStartWhenStreaming) { - uint8_t instance_id = + auto broadcast_id = InstantiateStateMachine(LeAudioBroadcaster::AudioProfile::MEDIA); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STREAMING); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath).Times(0); - EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineEvent(instance_id, _, _)) + EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineEvent(broadcast_id, _, _)) .Times(0); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START); // There shall be no change in state - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STREAMING); } TEST_F(StateMachineTest, ProcessMessageStopWhenStreaming) { - uint8_t instance_id = + auto broadcast_id = InstantiateStateMachine(LeAudioBroadcaster::AudioProfile::MEDIA); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STREAMING); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath).Times(2); EXPECT_CALL(*(sm_callbacks_.get()), - OnStateMachineEvent(instance_id, + OnStateMachineEvent(broadcast_id, BroadcastStateMachine::State::STOPPING, _)) .Times(1); EXPECT_CALL(*(sm_callbacks_.get()), - OnStateMachineEvent(instance_id, + OnStateMachineEvent(broadcast_id, BroadcastStateMachine::State::STOPPED, _)) .Times(1); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::STOP); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STOPPED); } TEST_F(StateMachineTest, ProcessMessageSuspendWhenStreaming) { - uint8_t instance_id = + auto broadcast_id = InstantiateStateMachine(LeAudioBroadcaster::AudioProfile::MEDIA); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STREAMING); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath).Times(2); EXPECT_CALL(*(sm_callbacks_.get()), - OnStateMachineEvent(instance_id, + OnStateMachineEvent(broadcast_id, BroadcastStateMachine::State::CONFIGURED, _)) .Times(1); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::SUSPEND); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED); } TEST_F(StateMachineTest, ProcessMessageStartWhenStopped) { - uint8_t instance_id = + auto broadcast_id = InstantiateStateMachine(LeAudioBroadcaster::AudioProfile::MEDIA); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::STOP); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STOPPED); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(2); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath).Times(0); EXPECT_CALL(*(sm_callbacks_.get()), - OnStateMachineEvent(instance_id, + OnStateMachineEvent(broadcast_id, BroadcastStateMachine::State::CONFIGURING, _)) .Times(1); EXPECT_CALL(*(sm_callbacks_.get()), - OnStateMachineEvent(instance_id, + OnStateMachineEvent(broadcast_id, BroadcastStateMachine::State::STREAMING, _)) .Times(1); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STREAMING); } TEST_F(StateMachineTest, ProcessMessageStopWhenStopped) { - uint8_t instance_id = + auto broadcast_id = InstantiateStateMachine(LeAudioBroadcaster::AudioProfile::MEDIA); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::STOP); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STOPPED); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath).Times(0); - EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineEvent(instance_id, _, _)) + EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineEvent(broadcast_id, _, _)) .Times(0); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::STOP); // There shall be no change in state - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STOPPED); } TEST_F(StateMachineTest, ProcessMessageSuspendWhenStopped) { - uint8_t instance_id = + auto broadcast_id = InstantiateStateMachine(LeAudioBroadcaster::AudioProfile::MEDIA); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::STOP); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STOPPED); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath).Times(0); - EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineEvent(instance_id, _, _)) + EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineEvent(broadcast_id, _, _)) .Times(0); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::SUSPEND); // There shall be no change in state - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STOPPED); } @@ -654,79 +686,109 @@ TEST_F(StateMachineTest, OnSetupIsoDataPathError) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)) .Times(1); - uint8_t instance_id = + auto broadcast_id = InstantiateStateMachine(LeAudioBroadcaster::AudioProfile::MEDIA); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath) .WillOnce([this](uint16_t conn_handle, iso_data_path_params p) { // Get the big_id encoded in conn_handle's MSB - if (!broadcasts_[conn_handle >> 8]) return; - broadcasts_[conn_handle >> 8]->OnSetupIsoDataPath(0, conn_handle); + uint8_t big_id = conn_handle >> 8; + auto bit = + std::find_if(broadcasts_.begin(), broadcasts_.end(), + [big_id](auto const& entry) { + return entry.second->GetAdvertisingSid() == big_id; + }); + if (bit == broadcasts_.end()) return; + bit->second->OnSetupIsoDataPath(0, conn_handle); }) .WillOnce([this](uint16_t conn_handle, iso_data_path_params p) { // Get the big_id encoded in conn_handle's MSB - if (!broadcasts_[conn_handle >> 8]) return; - broadcasts_[conn_handle >> 8]->OnSetupIsoDataPath(1, conn_handle); + uint8_t big_id = conn_handle >> 8; + auto bit = + std::find_if(broadcasts_.begin(), broadcasts_.end(), + [big_id](auto const& entry) { + return entry.second->GetAdvertisingSid() == big_id; + }); + if (bit == broadcasts_.end()) return; + bit->second->OnSetupIsoDataPath(1, conn_handle); }) .RetiresOnSaturation(); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START); // On datapath setup failure we should go back to configured with BIG being // destroyed. Maybe it will work out next time for the new BIG. - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED); // And still be able to start again ON_CALL(*mock_iso_manager_, SetupIsoDataPath) .WillByDefault([this](uint16_t conn_handle, iso_data_path_params p) { // Get the big_id encoded in conn_handle's MSB - if (!broadcasts_[conn_handle >> 8]) return; - broadcasts_[conn_handle >> 8]->OnSetupIsoDataPath(0, conn_handle); + uint8_t big_id = conn_handle >> 8; + auto bit = + std::find_if(broadcasts_.begin(), broadcasts_.end(), + [big_id](auto const& entry) { + return entry.second->GetAdvertisingSid() == big_id; + }); + if (bit == broadcasts_.end()) return; + bit->second->OnSetupIsoDataPath(0, conn_handle); }); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(2); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STREAMING); } TEST_F(StateMachineTest, OnRemoveIsoDataPathError) { - uint8_t instance_id = + auto broadcast_id = InstantiateStateMachine(LeAudioBroadcaster::AudioProfile::MEDIA); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STREAMING); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath) .WillOnce([this](uint16_t conn_handle, uint8_t iso_direction) { // Get the big_id encoded in conn_handle's MSB - if (!broadcasts_[conn_handle >> 8]) return; - broadcasts_[conn_handle >> 8]->OnRemoveIsoDataPath(0, conn_handle); + uint8_t big_id = conn_handle >> 8; + auto bit = + std::find_if(broadcasts_.begin(), broadcasts_.end(), + [big_id](auto const& entry) { + return entry.second->GetAdvertisingSid() == big_id; + }); + if (bit == broadcasts_.end()) return; + bit->second->OnRemoveIsoDataPath(0, conn_handle); }) .WillOnce([this](uint16_t conn_handle, uint8_t iso_direction) { // Get the big_id encoded in conn_handle's MSB - if (!broadcasts_[conn_handle >> 8]) return; - broadcasts_[conn_handle >> 8]->OnRemoveIsoDataPath(1, conn_handle); + uint8_t big_id = conn_handle >> 8; + auto bit = + std::find_if(broadcasts_.begin(), broadcasts_.end(), + [big_id](auto const& entry) { + return entry.second->GetAdvertisingSid() == big_id; + }); + if (bit == broadcasts_.end()) return; + bit->second->OnRemoveIsoDataPath(1, conn_handle); }) .RetiresOnSaturation(); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::SUSPEND); // On datapath teardown failure we should stay in CONFIGURED with BIG being // destroyed. - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED); // And still be able to start again - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STREAMING); } @@ -737,22 +799,23 @@ TEST_F(StateMachineTest, GetConfig) { auto sound_profile = LeAudioBroadcaster::AudioProfile::MEDIA; uint8_t num_channels = 2; - uint8_t instance_id = InstantiateStateMachine(sound_profile); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + auto broadcast_id = InstantiateStateMachine(sound_profile); + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED); std::optional<BigConfig> const& big_cfg = - broadcasts_[instance_id]->GetBigConfig(); + broadcasts_[broadcast_id]->GetBigConfig(); ASSERT_FALSE(big_cfg.has_value()); - broadcasts_[instance_id]->ProcessMessage( + broadcasts_[broadcast_id]->ProcessMessage( BroadcastStateMachine::Message::START); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::STREAMING); ASSERT_TRUE(big_cfg.has_value()); ASSERT_EQ(big_cfg->status, 0); - ASSERT_EQ(big_cfg->big_id, instance_id); + // This is an implementation specific thing + ASSERT_EQ(big_cfg->big_id, broadcasts_[broadcast_id]->GetAdvertisingSid()); ASSERT_EQ(big_cfg->connection_handles.size(), num_channels); } @@ -760,13 +823,10 @@ TEST_F(StateMachineTest, GetBroadcastId) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)) .Times(1); - uint8_t instance_id = InstantiateStateMachine(); - ASSERT_EQ(broadcasts_[instance_id]->GetState(), + auto broadcast_id = InstantiateStateMachine(); + ASSERT_NE(bluetooth::le_audio::kBroadcastIdInvalid, broadcast_id); + ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED); - - bluetooth::le_audio::BroadcastId const& broadcast_id = - broadcasts_[instance_id]->GetBroadcastId(); - ASSERT_NE(bluetooth::le_audio::kBroadcastBroadcastIdInvalid, broadcast_id); } TEST_F(StateMachineTest, AnnouncementUUIDs) { @@ -798,8 +858,8 @@ TEST_F(StateMachineTest, AnnouncementUUIDs) { EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)) .Times(1); - uint8_t instance_id = InstantiateStateMachine(); - ASSERT_NE(instance_id, BroadcastStateMachine::kInstanceIdUndefined); + auto broadcast_id = InstantiateStateMachine(); + ASSERT_NE(broadcast_id, BroadcastStateMachine::kAdvSidUndefined); // Check ext. advertising data for Broadcast Announcement UUID ASSERT_NE(a_data[0], 0); // size diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc index 6dc3364be5..d3274ac39c 100644 --- a/system/bta/le_audio/client.cc +++ b/system/bta/le_audio/client.cc @@ -1909,25 +1909,27 @@ class LeAudioClientImpl : public LeAudioClient { bool mono = (left_cis_handle == 0) || (right_cis_handle == 0); - LOG(INFO) << __func__ << " data size: " << (int)data.size() - << " byte count: " << byte_count << " mono: " << mono; if (!mono) { - lc3_encode(lc3_encoder_left, (const int16_t*)data.data(), 2, - chan_left_enc.size(), chan_left_enc.data()); - lc3_encode(lc3_encoder_right, ((const int16_t*)data.data()) + 1, 2, - chan_right_enc.size(), chan_right_enc.data()); + lc3_encode(lc3_encoder_left, LC3_PCM_FORMAT_S16, + (const int16_t*)data.data(), 2, chan_left_enc.size(), + chan_left_enc.data()); + lc3_encode(lc3_encoder_right, LC3_PCM_FORMAT_S16, + ((const int16_t*)data.data()) + 1, 2, chan_right_enc.size(), + chan_right_enc.data()); } else { std::vector<int16_t> chan_mono; get_mono_stream(data, chan_mono); if (left_cis_handle) { - lc3_encode(lc3_encoder_left, (const int16_t*)chan_mono.data(), 1, - chan_left_enc.size(), chan_left_enc.data()); + lc3_encode(lc3_encoder_left, LC3_PCM_FORMAT_S16, + (const int16_t*)chan_mono.data(), 1, chan_left_enc.size(), + chan_left_enc.data()); } if (right_cis_handle) { - lc3_encode(lc3_encoder_right, (const int16_t*)chan_mono.data(), 1, - chan_right_enc.size(), chan_right_enc.data()); + lc3_encode(lc3_encoder_right, LC3_PCM_FORMAT_S16, + (const int16_t*)chan_mono.data(), 1, chan_right_enc.size(), + chan_right_enc.data()); } } @@ -1968,17 +1970,20 @@ class LeAudioClientImpl : public LeAudioClient { std::vector<int16_t> chan_mono; get_mono_stream(data, chan_mono); - auto err = lc3_encode(lc3_encoder_left, (const int16_t*)chan_mono.data(), - 1, byte_count, chan_encoded.data()); + auto err = lc3_encode(lc3_encoder_left, LC3_PCM_FORMAT_S16, + (const int16_t*)chan_mono.data(), 1, byte_count, + chan_encoded.data()); if (err < 0) { LOG(ERROR) << " error while encoding, error code: " << +err; } } else { - lc3_encode(lc3_encoder_left, (const int16_t*)data.data(), 2, byte_count, + lc3_encode(lc3_encoder_left, LC3_PCM_FORMAT_S16, + (const int16_t*)data.data(), 2, byte_count, chan_encoded.data()); - lc3_encode(lc3_encoder_right, (const int16_t*)data.data() + 1, 2, - byte_count, chan_encoded.data() + byte_count); + lc3_encode(lc3_encoder_right, LC3_PCM_FORMAT_S16, + (const int16_t*)data.data() + 1, 2, byte_count, + chan_encoded.data() + byte_count); } /* Send data to the controller */ @@ -2127,12 +2132,18 @@ class LeAudioClientImpl : public LeAudioClient { } } + void CleanCachedMicrophoneData() { + cached_channel_data_.clear(); + cached_channel_timestamp_ = 0; + cached_channel_is_left_ = false; + } + void SendAudioData(uint8_t* data, uint16_t size, uint16_t cis_conn_hdl, uint32_t timestamp) { /* Get only one channel for MONO microphone */ /* Gather data for channel */ if ((active_group_id_ == bluetooth::groups::kGroupUnknown) || - (audio_sender_state_ != AudioState::STARTED)) + (audio_receiver_state_ != AudioState::STARTED)) return; LeAudioDeviceGroup* group = aseGroups_.FindById(active_group_id_); @@ -2202,8 +2213,8 @@ class LeAudioClientImpl : public LeAudioClient { lc3_decoder_t decoder_to_use = is_left ? lc3_decoder_left : lc3_decoder_right; - err = lc3_decode(decoder_to_use, data, size, pcm_data_decoded.data(), - 1 /* pitch */); + err = lc3_decode(decoder_to_use, data, size, LC3_PCM_FORMAT_S16, + pcm_data_decoded.data(), 1 /* pitch */); if (err < 0) { LOG(ERROR) << " bad decoding parameters: " << static_cast<int>(err); @@ -2219,9 +2230,9 @@ class LeAudioClientImpl : public LeAudioClient { &pcm_data_decoded, nullptr); return; } - /* both devices are connected */ - if (cached_channel_timestamp_ == 0) { + + if (cached_channel_timestamp_ == 0 && cached_channel_data_.empty()) { /* First packet received, cache it. We need both channel data to send it * to AF. */ cached_channel_data_ = pcm_data_decoded; @@ -2245,7 +2256,7 @@ class LeAudioClientImpl : public LeAudioClient { &pcm_data_decoded, &cached_channel_data_); } - cached_channel_timestamp_ = 0; + CleanCachedMicrophoneData(); return; } @@ -2409,7 +2420,8 @@ class LeAudioClientImpl : public LeAudioClient { uint16_t remote_delay_ms = group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSource); - cached_channel_timestamp_ = 0; + CleanCachedMicrophoneData(); + if (CodecManager::GetInstance()->GetCodecLocation() == le_audio::types::CodecLocation::HOST) { if (lc3_decoder_left_mem) { diff --git a/system/bta/le_audio/devices.cc b/system/bta/le_audio/devices.cc index a147aea2fd..58ca4c46c4 100644 --- a/system/bta/le_audio/devices.cc +++ b/system/bta/le_audio/devices.cc @@ -958,6 +958,9 @@ bool LeAudioDevice::ConfigureAses( *ase->codec_config.octets_per_codec_frame * *ase->codec_config.codec_frames_blocks_per_sdu; + ase->retrans_nb = ent.qos.retransmission_number; + ase->max_transport_latency = ent.qos.max_transport_latency; + ase->metadata = GetMetadata(context_type); DLOG(INFO) << __func__ << " device=" << address_ diff --git a/system/bta/le_audio/le_audio_set_configuration_provider_json.cc b/system/bta/le_audio/le_audio_set_configuration_provider_json.cc index 354a81b395..b2fa48156f 100644 --- a/system/bta/le_audio/le_audio_set_configuration_provider_json.cc +++ b/system/bta/le_audio/le_audio_set_configuration_provider_json.cc @@ -27,6 +27,7 @@ using le_audio::set_configurations::AudioSetConfiguration; using le_audio::set_configurations::AudioSetConfigurations; using le_audio::set_configurations::CodecCapabilitySetting; using le_audio::set_configurations::LeAudioCodecIdLc3; +using le_audio::set_configurations::QosConfigSetting; using le_audio::set_configurations::SetConfiguration; using le_audio::types::LeAudioContextType; @@ -199,7 +200,8 @@ struct AudioSetConfigurationProviderJson { } SetConfiguration SetConfigurationFromFlatSubconfig( - const bluetooth::le_audio::AudioSetSubConfiguration* flat_subconfig) { + const bluetooth::le_audio::AudioSetSubConfiguration* flat_subconfig, + QosConfigSetting qos) { auto strategy_int = static_cast<int>(flat_subconfig->configuration_strategy()); @@ -228,21 +230,52 @@ struct AudioSetConfigurationProviderJson { flat_subconfig->ase_cnt(), target_latency, CodecCapabilitySettingFromFlat(flat_subconfig->codec_id(), flat_subconfig->codec_configuration()), - strategy); + qos, strategy); } AudioSetConfiguration AudioSetConfigurationFromFlat( - const bluetooth::le_audio::AudioSetConfiguration* flat_cfg) { + const bluetooth::le_audio::AudioSetConfiguration* flat_cfg, + std::vector<const bluetooth::le_audio::CodecConfiguration*>* codec_cfgs, + std::vector<const bluetooth::le_audio::QosConfiguration*>* qos_cfgs) { std::vector<SetConfiguration> subconfigs; - if (flat_cfg->subconfigurations()) { - /* Load subconfigurations */ - for (auto subconfig : *flat_cfg->subconfigurations()) { - subconfigs.push_back(SetConfigurationFromFlatSubconfig(subconfig)); + QosConfigSetting qos; + const bluetooth::le_audio::CodecConfiguration* codec_cfg = NULL; + const bluetooth::le_audio::QosConfiguration* qos_cfg = NULL; + + const char* codec_config_key = flat_cfg->codec_config_name()->c_str(); + const char* qos_config_key = flat_cfg->qos_config_name()->c_str(); + + for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) { + if (0 == strcmp((*i)->name()->c_str(), qos_config_key)) { + qos_cfg = *i; + break; } + } + if (qos_cfg != NULL) { + qos.retransmission_number = qos_cfg->retransmission_number(); + qos.max_transport_latency = qos_cfg->max_transport_latency(); + } else { + LOG_ERROR("No qos config matching key %s found", qos_config_key); + } + for (auto i = codec_cfgs->begin(); i != codec_cfgs->end(); ++i) { + if (0 == strcmp((*i)->name()->c_str(), codec_config_key)) { + codec_cfg = *i; + break; + } + } + if (codec_cfg != NULL && codec_cfg->subconfigurations()) { + /* Load subconfigurations */ + for (auto subconfig : *codec_cfg->subconfigurations()) { + subconfigs.push_back(SetConfigurationFromFlatSubconfig(subconfig, qos)); + } } else { - LOG_ERROR("Configuration '%s' has no valid subconfigurations.", - flat_cfg->name()->c_str()); + if (codec_cfg == NULL) { + LOG_ERROR("No codec config matching key %s found", codec_config_key); + } else { + LOG_ERROR("Configuration '%s' has no valid subconfigurations.", + flat_cfg->name()->c_str()); + } } return AudioSetConfiguration({flat_cfg->name()->c_str(), subconfigs}); @@ -277,13 +310,35 @@ struct AudioSetConfigurationProviderJson { configurations_parser_.builder_.GetBufferPointer()); if (!configurations_root) return false; + auto flat_qos_configs = configurations_root->qos_configurations(); + if ((flat_qos_configs == nullptr) || (flat_qos_configs->size() == 0)) + return false; + + LOG_DEBUG(": Updating %d qos config entries.", flat_qos_configs->size()); + std::vector<const bluetooth::le_audio::QosConfiguration*> qos_cfgs; + for (auto const& flat_qos_cfg : *flat_qos_configs) { + qos_cfgs.push_back(flat_qos_cfg); + } + + auto flat_codec_configs = configurations_root->codec_configurations(); + if ((flat_codec_configs == nullptr) || (flat_codec_configs->size() == 0)) + return false; + + LOG_DEBUG(": Updating %d codec config entries.", + flat_codec_configs->size()); + std::vector<const bluetooth::le_audio::CodecConfiguration*> codec_cfgs; + for (auto const& flat_codec_cfg : *flat_codec_configs) { + codec_cfgs.push_back(flat_codec_cfg); + } + auto flat_configs = configurations_root->configurations(); if ((flat_configs == nullptr) || (flat_configs->size() == 0)) return false; LOG_DEBUG(": Updating %d config entries.", flat_configs->size()); for (auto const& flat_cfg : *flat_configs) { configurations_.insert( - {flat_cfg->name()->str(), AudioSetConfigurationFromFlat(flat_cfg)}); + {flat_cfg->name()->str(), + AudioSetConfigurationFromFlat(flat_cfg, &codec_cfgs, &qos_cfgs)}); } return true; diff --git a/system/bta/le_audio/le_audio_types.h b/system/bta/le_audio/le_audio_types.h index 866dabbc05..ab1410a1bb 100644 --- a/system/bta/le_audio/le_audio_types.h +++ b/system/bta/le_audio/le_audio_types.h @@ -595,9 +595,16 @@ struct CodecCapabilitySetting { uint8_t GetConfigChannelCount() const; }; +struct QosConfigSetting { + uint8_t retransmission_number; + uint16_t max_transport_latency; +}; + struct SetConfiguration { SetConfiguration(uint8_t direction, uint8_t device_cnt, uint8_t ase_cnt, uint8_t target_latency, CodecCapabilitySetting codec, + QosConfigSetting qos = {.retransmission_number = 0, + .max_transport_latency = 0}, le_audio::types::LeAudioConfigurationStrategy strategy = le_audio::types::LeAudioConfigurationStrategy:: MONO_ONE_CIS_PER_DEVICE) @@ -606,6 +613,7 @@ struct SetConfiguration { ase_cnt(ase_cnt), target_latency(target_latency), codec(codec), + qos(qos), strategy(strategy) {} uint8_t direction; /* Direction of set */ @@ -613,6 +621,7 @@ struct SetConfiguration { uint8_t ase_cnt; /* How many ASE we need in configuration */ uint8_t target_latency; CodecCapabilitySetting codec; + QosConfigSetting qos; types::LeAudioConfigurationStrategy strategy; }; diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc index 86f7542327..97d8a47d76 100644 --- a/system/bta/le_audio/state_machine.cc +++ b/system/bta/le_audio/state_machine.cc @@ -860,7 +860,8 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { if (iter != cis_cfgs.end()) continue; auto ases_pair = leAudioDevice->GetAsesByCisId(cis); - EXT_CIS_CFG cis_cfg; + EXT_CIS_CFG cis_cfg = {0, 0, 0, 0, 0, 0, 0}; + cis_cfg.cis_id = ase->cis_id; cis_cfg.phy_mtos = group->GetPhyBitmask(le_audio::types::kLeAudioDirectionSink); @@ -1153,12 +1154,20 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } ase->framing = rsp.framing; ase->preferred_phy = rsp.preferred_phy; - ase->max_transport_latency = rsp.max_transport_latency; + /* Validate and update QoS settings to be consistent */ + if ((!ase->max_transport_latency || + ase->max_transport_latency > rsp.max_transport_latency) || + !ase->retrans_nb) { + ase->max_transport_latency = rsp.max_transport_latency; + ase->retrans_nb = rsp.preferred_retrans_nb; + LOG(INFO) << __func__ << " Using server preferred QoS settings." + << " Max Transport Latency: " << +ase->max_transport_latency + << ", Retransmission Number: " << +ase->retrans_nb; + } ase->pres_delay_min = rsp.pres_delay_min; ase->pres_delay_max = rsp.pres_delay_max; ase->preferred_pres_delay_min = rsp.preferred_pres_delay_min; ase->preferred_pres_delay_max = rsp.preferred_pres_delay_max; - ase->retrans_nb = rsp.preferred_retrans_nb; ase->state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; @@ -1222,12 +1231,20 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { ase->framing = rsp.framing; ase->preferred_phy = rsp.preferred_phy; - ase->max_transport_latency = rsp.max_transport_latency; + /* Validate and update QoS settings to be consistent */ + if ((!ase->max_transport_latency || + ase->max_transport_latency > rsp.max_transport_latency) || + !ase->retrans_nb) { + ase->max_transport_latency = rsp.max_transport_latency; + ase->retrans_nb = rsp.preferred_retrans_nb; + LOG(INFO) << __func__ << " Using server preferred QoS settings." + << " Max Transport Latency: " << +ase->max_transport_latency + << ", Retransmission Number: " << +ase->retrans_nb; + } ase->pres_delay_min = rsp.pres_delay_min; ase->pres_delay_max = rsp.pres_delay_max; ase->preferred_pres_delay_min = rsp.preferred_pres_delay_min; ase->preferred_pres_delay_max = rsp.preferred_pres_delay_max; - ase->retrans_nb = rsp.preferred_retrans_nb; /* This may be a notification from a re-configured ASE */ ase->reconfigure = false; diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc index bb12ed1ece..18c8d4bdd7 100644 --- a/system/btif/src/btif_dm.cc +++ b/system/btif/src/btif_dm.cc @@ -967,9 +967,14 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { bt_status_t ret; BTIF_TRACE_DEBUG("%s: Storing link key. key_type=0x%x, bond_type=%d", __func__, p_auth_cmpl->key_type, pairing_cb.bond_type); - ret = btif_storage_add_bonded_device(&bd_addr, p_auth_cmpl->key, - p_auth_cmpl->key_type, - pairing_cb.pin_code_len); + if (!bd_addr.IsEmpty()) { + ret = btif_storage_add_bonded_device(&bd_addr, p_auth_cmpl->key, + p_auth_cmpl->key_type, + pairing_cb.pin_code_len); + } else { + LOG_WARN("bd_addr is empty"); + ret = BT_STATUS_FAIL; + } ASSERTC(ret == BT_STATUS_SUCCESS, "storing link key failed", ret); } else { BTIF_TRACE_DEBUG( @@ -2775,6 +2780,11 @@ void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask, static void btif_dm_save_ble_bonding_keys(RawAddress& bd_addr) { BTIF_TRACE_DEBUG("%s", __func__); + if (bd_addr.IsEmpty()) { + LOG_WARN("bd_addr is empty"); + return; + } + if (pairing_cb.ble.is_penc_key_rcvd) { btif_storage_add_ble_bonding_key( &bd_addr, (uint8_t*)&pairing_cb.ble.penc_key, BTM_LE_KEY_PENC, diff --git a/system/btif/src/btif_le_audio_broadcaster.cc b/system/btif/src/btif_le_audio_broadcaster.cc index 57d14f93fc..342626f0dd 100644 --- a/system/btif/src/btif_le_audio_broadcaster.cc +++ b/system/btif/src/btif_le_audio_broadcaster.cc @@ -63,47 +63,40 @@ class LeAudioBroadcasterInterfaceImpl : public LeAudioBroadcasterInterface, broadcast_code)); } - void UpdateMetadata(uint8_t instance_id, + void UpdateMetadata(uint32_t broadcast_id, std::vector<uint8_t> metadata) override { DVLOG(2) << __func__; do_in_main_thread(FROM_HERE, Bind(&LeAudioBroadcaster::UpdateMetadata, Unretained(LeAudioBroadcaster::Get()), - instance_id, std::move(metadata))); + broadcast_id, std::move(metadata))); } - void StartBroadcast(uint8_t instance_id) override { + void StartBroadcast(uint32_t broadcast_id) override { DVLOG(2) << __func__; - do_in_main_thread(FROM_HERE, - Bind(&LeAudioBroadcaster::StartAudioBroadcast, - Unretained(LeAudioBroadcaster::Get()), instance_id)); - } - - void StopBroadcast(uint8_t instance_id) override { - DVLOG(2) << __func__; - do_in_main_thread(FROM_HERE, - Bind(&LeAudioBroadcaster::StopAudioBroadcast, - Unretained(LeAudioBroadcaster::Get()), instance_id)); + do_in_main_thread( + FROM_HERE, Bind(&LeAudioBroadcaster::StartAudioBroadcast, + Unretained(LeAudioBroadcaster::Get()), broadcast_id)); } - void PauseBroadcast(uint8_t instance_id) override { + void StopBroadcast(uint32_t broadcast_id) override { DVLOG(2) << __func__; - do_in_main_thread(FROM_HERE, - Bind(&LeAudioBroadcaster::SuspendAudioBroadcast, - Unretained(LeAudioBroadcaster::Get()), instance_id)); + do_in_main_thread( + FROM_HERE, Bind(&LeAudioBroadcaster::StopAudioBroadcast, + Unretained(LeAudioBroadcaster::Get()), broadcast_id)); } - void DestroyBroadcast(uint8_t instance_id) override { + void PauseBroadcast(uint32_t broadcast_id) override { DVLOG(2) << __func__; - do_in_main_thread(FROM_HERE, - Bind(&LeAudioBroadcaster::DestroyAudioBroadcast, - Unretained(LeAudioBroadcaster::Get()), instance_id)); + do_in_main_thread( + FROM_HERE, Bind(&LeAudioBroadcaster::SuspendAudioBroadcast, + Unretained(LeAudioBroadcaster::Get()), broadcast_id)); } - void GetBroadcastId(uint8_t instance_id) override { + void DestroyBroadcast(uint32_t broadcast_id) override { DVLOG(2) << __func__; - do_in_main_thread(FROM_HERE, - Bind(&LeAudioBroadcaster::GetBroadcastId, - Unretained(LeAudioBroadcaster::Get()), instance_id)); + do_in_main_thread( + FROM_HERE, Bind(&LeAudioBroadcaster::DestroyAudioBroadcast, + Unretained(LeAudioBroadcaster::Get()), broadcast_id)); } void GetAllBroadcastStates(void) override { @@ -113,34 +106,26 @@ class LeAudioBroadcasterInterfaceImpl : public LeAudioBroadcasterInterface, Unretained(LeAudioBroadcaster::Get()))); } - void OnBroadcastCreated(uint8_t instance_id, bool success) override { + void OnBroadcastCreated(uint32_t broadcast_id, bool success) override { DVLOG(2) << __func__; do_in_jni_thread(FROM_HERE, Bind(&LeAudioBroadcasterCallbacks::OnBroadcastCreated, - Unretained(callbacks_), instance_id, success)); + Unretained(callbacks_), broadcast_id, success)); } - void OnBroadcastDestroyed(uint8_t instance_id) override { + void OnBroadcastDestroyed(uint32_t broadcast_id) override { DVLOG(2) << __func__; do_in_jni_thread(FROM_HERE, Bind(&LeAudioBroadcasterCallbacks::OnBroadcastDestroyed, - Unretained(callbacks_), instance_id)); + Unretained(callbacks_), broadcast_id)); } - void OnBroadcastStateChanged(uint8_t instance_id, + void OnBroadcastStateChanged(uint32_t broadcast_id, BroadcastState state) override { DVLOG(2) << __func__; do_in_jni_thread(FROM_HERE, Bind(&LeAudioBroadcasterCallbacks::OnBroadcastStateChanged, - Unretained(callbacks_), instance_id, state)); - } - - void OnBroadcastId(uint8_t instance_id, - const BroadcastId& broadcast_id) override { - DVLOG(2) << __func__; - do_in_jni_thread(FROM_HERE, - Bind(&LeAudioBroadcasterCallbacks::OnBroadcastId, - Unretained(callbacks_), instance_id, broadcast_id)); + Unretained(callbacks_), broadcast_id, state)); } void Stop(void) override { diff --git a/system/embdrv/lc3/fuzzer/liblc3_fuzzer.cpp b/system/embdrv/lc3/fuzzer/liblc3_fuzzer.cpp index a5a7ae7f29..00ff5a2e74 100644 --- a/system/embdrv/lc3/fuzzer/liblc3_fuzzer.cpp +++ b/system/embdrv/lc3/fuzzer/liblc3_fuzzer.cpp @@ -18,6 +18,8 @@ #include "include/lc3.h" void TestEncoder(FuzzedDataProvider& fdp) { + enum lc3_pcm_format pcm_format = + fdp.PickValueInArray({LC3_PCM_FORMAT_S16, LC3_PCM_FORMAT_S24}); int dt_us = fdp.PickValueInArray({10000, 7500}); int sr_hz = fdp.PickValueInArray({8000, 16000, 24000, 32000, /*44100,*/ 48000}); @@ -39,8 +41,8 @@ void TestEncoder(FuzzedDataProvider& fdp) { lc3_setup_encoder(dt_us, sr_hz, 0, lc3_encoder_mem); std::vector<uint8_t> output(output_byte_count); - lc3_encode(lc3_encoder, (const int16_t*)input_frames.data(), 1, output.size(), - output.data()); + lc3_encode(lc3_encoder, pcm_format, (const int16_t*)input_frames.data(), 1, + output.size(), output.data()); free(lc3_encoder_mem); lc3_encoder_mem = nullptr; @@ -48,6 +50,8 @@ void TestEncoder(FuzzedDataProvider& fdp) { } void TestDecoder(FuzzedDataProvider& fdp) { + enum lc3_pcm_format pcm_format = + fdp.PickValueInArray({LC3_PCM_FORMAT_S16, LC3_PCM_FORMAT_S24}); int dt_us = fdp.PickValueInArray({10000, 7500}); int sr_hz = fdp.PickValueInArray({8000, 16000, 24000, 32000, /*44100,*/ 48000}); @@ -68,11 +72,11 @@ void TestDecoder(FuzzedDataProvider& fdp) { lc3_setup_decoder(dt_us, sr_hz, 0, lc3_decoder_mem); std::vector<uint16_t> output(num_frames); - lc3_decode(lc3_decoder, input.data(), input.size(), (int16_t*)output.data(), - 1); + lc3_decode(lc3_decoder, input.data(), input.size(), pcm_format, + (int16_t*)output.data(), 1); /* Empty input performs PLC (packet loss concealment) */ - lc3_decode(lc3_decoder, nullptr, 0, (int16_t*)output.data(), 1); + lc3_decode(lc3_decoder, nullptr, 0, pcm_format, (int16_t*)output.data(), 1); free(lc3_decoder_mem); lc3_decoder_mem = nullptr; diff --git a/system/embdrv/lc3/include/lc3.h b/system/embdrv/lc3/include/lc3.h index f8dc8b3492..652d694697 100644 --- a/system/embdrv/lc3/include/lc3.h +++ b/system/embdrv/lc3/include/lc3.h @@ -145,6 +145,19 @@ extern "C" { /** + * PCM Sample Format + * S16 Signed 16 bits, in 16 bits words (int16_t) + * S24 Signed 24 bits, using low three bytes of 32 bits words (int32_t). + * The high byte sign extends the sample value (bits 31..24 set to b23). + */ + +enum lc3_pcm_format { + LC3_PCM_FORMAT_S16, + LC3_PCM_FORMAT_S24, +}; + + +/** * Handle */ @@ -231,13 +244,14 @@ lc3_encoder_t lc3_setup_encoder( /** * Encode a frame * encoder Handle of the encoder - * pcm, pitch Input PCM samples, and count between two consecutives + * fmt PCM input format + * pcm, stride Input PCM samples, and count between two consecutives * nbytes Target size, in bytes, of the frame (20 to 400) * out Output buffer of `nbytes` size * return 0: On success -1: Wrong parameters */ -int lc3_encode(lc3_encoder_t encoder, - const int16_t *pcm, int pitch, int nbytes, void *out); +int lc3_encode(lc3_encoder_t encoder, enum lc3_pcm_format fmt, + const void *pcm, int stride, int nbytes, void *out); /** * Return size needed for an decoder @@ -271,11 +285,12 @@ lc3_decoder_t lc3_setup_decoder( * Decode a frame * decoder Handle of the decoder * in, nbytes Input bitstream, and size in bytes, NULL performs PLC - * pcm, pitch Output PCM samples, and count between two consecutives + * fmt PCM output format + * pcm, stride Output PCM samples, and count between two consecutives * return 0: On success 1: PLC operated -1: Wrong parameters */ -int lc3_decode(lc3_decoder_t decoder, - const void *in, int nbytes, int16_t *pcm, int pitch); +int lc3_decode(lc3_decoder_t decoder, const void *in, int nbytes, + enum lc3_pcm_format fmt, void *pcm, int stride); #ifdef __cplusplus diff --git a/system/embdrv/lc3/src/bits.h b/system/embdrv/lc3/src/bits.h index 475fc26ca6..faef3370bd 100644 --- a/system/embdrv/lc3/src/bits.h +++ b/system/embdrv/lc3/src/bits.h @@ -286,9 +286,9 @@ static inline unsigned lc3_get_symbol( const struct lc3_ac_symbol *symbols = model->s; struct lc3_bits_ac *ac = &bits->ac; - uint16_t range = ac->range >> 10; + unsigned range = (ac->range >> 10) & 0xffff; - ac->error |= (ac->low >= ((unsigned)range << 10)); + ac->error |= (ac->low >= (range << 10)); if (ac->error) ac->low = 0; diff --git a/system/embdrv/lc3/src/lc3.c b/system/embdrv/lc3/src/lc3.c index 6fd7575014..69774422dd 100644 --- a/system/embdrv/lc3/src/lc3.c +++ b/system/embdrv/lc3/src/lc3.c @@ -147,18 +147,39 @@ int lc3_delay_samples(int dt_us, int sr_hz) /** * Input PCM Samples from signed 16 bits * encoder Encoder state - * pcm, pitch Input PCM samples, and count between two consecutives + * pcm, stride Input PCM samples, and count between two consecutives */ static void load_s16( - struct lc3_encoder *encoder, const int16_t *pcm, int pitch) + struct lc3_encoder *encoder, const void *_pcm, int stride) { + const int16_t *pcm = _pcm; + + enum lc3_dt dt = encoder->dt; + enum lc3_srate sr = encoder->sr_pcm; + float *xs = encoder->xs; + int ns = LC3_NS(dt, sr); + + for (int i = 0; i < ns; i++) + xs[i] = pcm[i*stride]; +} + +/** + * Input PCM Samples from signed 24 bits + * encoder Encoder state + * pcm, stride Input PCM samples, and count between two consecutives + */ +static void load_s24( + struct lc3_encoder *encoder, const void *_pcm, int stride) +{ + const int32_t *pcm = _pcm; + enum lc3_dt dt = encoder->dt; enum lc3_srate sr = encoder->sr_pcm; float *xs = encoder->xs; int ns = LC3_NS(dt, sr); for (int i = 0; i < ns; i++) - xs[i] = pcm[i*pitch]; + xs[i] = ldexpf(pcm[i*stride], -8); } /** @@ -295,9 +316,14 @@ struct lc3_encoder *lc3_setup_encoder( /** * Encode a frame */ -int lc3_encode(struct lc3_encoder *encoder, - const int16_t *pcm, int pitch, int nbytes, void *out) +int lc3_encode(struct lc3_encoder *encoder, enum lc3_pcm_format fmt, + const void *pcm, int stride, int nbytes, void *out) { + static void (* const load[])(struct lc3_encoder *, const void *, int) = { + [LC3_PCM_FORMAT_S16] = load_s16, + [LC3_PCM_FORMAT_S24] = load_s24, + }; + /* --- Check parameters --- */ if (!encoder || nbytes < LC3_MIN_FRAME_BYTES @@ -309,7 +335,7 @@ int lc3_encode(struct lc3_encoder *encoder, struct side_data side; int16_t xq[LC3_NE(encoder->dt, encoder->sr)]; - load_s16(encoder, pcm, pitch); + load[fmt](encoder, pcm, stride); analyze(encoder, nbytes, &side, xq); @@ -326,23 +352,49 @@ int lc3_encode(struct lc3_encoder *encoder, /** * Output PCM Samples to signed 16 bits * decoder Decoder state - * pcm, pitch Output PCM samples, and count between two consecutives + * pcm, stride Output PCM samples, and count between two consecutives */ static void store_s16( - struct lc3_decoder *decoder, int16_t *pcm, int pitch) + struct lc3_decoder *decoder, void *_pcm, int stride) { + int16_t *pcm = _pcm; + enum lc3_dt dt = decoder->dt; enum lc3_srate sr = decoder->sr_pcm; float *xs = decoder->xs; int ns = LC3_NS(dt, sr); - for ( ; ns > 0; ns--, xs++, pcm += pitch) { + for ( ; ns > 0; ns--, xs++, pcm += stride) { int s = *xs >= 0 ? (int)(*xs + 0.5f) : (int)(*xs - 0.5f); *pcm = LC3_CLIP(s, INT16_MIN, INT16_MAX); } } /** + * Output PCM Samples to signed 24 bits + * decoder Decoder state + * pcm, stride Output PCM samples, and count between two consecutives + */ +static void store_s24( + struct lc3_decoder *decoder, void *_pcm, int stride) +{ + int32_t *pcm = _pcm; + const int32_t int24_max = (1 << 23) - 1; + const int32_t int24_min = -(1 << 23); + + enum lc3_dt dt = decoder->dt; + enum lc3_srate sr = decoder->sr_pcm; + float *xs = decoder->xs; + int ns = LC3_NS(dt, sr); + + for ( ; ns > 0; ns--, xs++, pcm += stride) { + int32_t s = *xs >= 0 ? (int32_t)(ldexpf(*xs, 8) + 0.5f) + : (int32_t)(ldexpf(*xs, 8) - 0.5f); + *pcm = LC3_CLIP(s, int24_min, int24_max); + } +} + +/** * Decode bitstream * decoder Decoder state * data, nbytes Input bitstream buffer @@ -484,9 +536,14 @@ struct lc3_decoder *lc3_setup_decoder( /** * Decode a frame */ -int lc3_decode(struct lc3_decoder *decoder, - const void *in, int nbytes, int16_t *pcm, int pitch) +int lc3_decode(struct lc3_decoder *decoder, const void *in, int nbytes, + enum lc3_pcm_format fmt, void *pcm, int stride) { + static void (* const store[])(struct lc3_decoder *, void *, int) = { + [LC3_PCM_FORMAT_S16] = store_s16, + [LC3_PCM_FORMAT_S24] = store_s24, + }; + /* --- Check parameters --- */ if (!decoder) @@ -504,7 +561,7 @@ int lc3_decode(struct lc3_decoder *decoder, synthesize(decoder, ret ? NULL : &side, nbytes); - store_s16(decoder, pcm, pitch); + store[fmt](decoder, pcm, stride); return ret; } diff --git a/system/embdrv/lc3/src/tns.c b/system/embdrv/lc3/src/tns.c index 8545d78380..7c6d1e81ed 100644 --- a/system/embdrv/lc3/src/tns.c +++ b/system/embdrv/lc3/src/tns.c @@ -375,7 +375,7 @@ void lc3_tns_analyze(enum lc3_dt dt, enum lc3_bandwidth bw, void lc3_tns_synthesize(enum lc3_dt dt, enum lc3_bandwidth bw, const struct lc3_tns_data *data, float *x) { - float rc[2][8] = { 0 }; + float rc[2][8] = { }; for (int f = 0; f < data->nfilters; f++) if (data->rc_order[f]) diff --git a/system/gd/common/strings.h b/system/gd/common/strings.h index 3c0d314ccf..01944f55eb 100644 --- a/system/gd/common/strings.h +++ b/system/gd/common/strings.h @@ -36,6 +36,13 @@ namespace bluetooth { namespace common { +template <typename T> +inline std::string ToString(const T& value) { + std::stringstream tmp; + tmp << value; + return tmp.str(); +} + // Convert number into a hex string prefixed with 0x template <typename T> std::string ToHexString(T x) { diff --git a/system/gd/common/strings_test.cc b/system/gd/common/strings_test.cc index 7da1ccd087..64f2142973 100644 --- a/system/gd/common/strings_test.cc +++ b/system/gd/common/strings_test.cc @@ -256,4 +256,15 @@ TEST(StringsTest, string_format_time_with_ms_test) { ASSERT_THAT(StringFormatTimeWithMilliseconds(format, time_point2, gmtime), StrEq("2009-02-13 23:31:30.001")); } +class ExampleClass {}; +std::ostream& operator<<(std::ostream& os, const ExampleClass& obj) { + os << "ExampleClass"; + return os; +} + +TEST(StringsTest, example_class_to_string_test) { + ExampleClass obj; + ASSERT_THAT(ToString(obj), StrEq("ExampleClass")); +} + } // namespace testing diff --git a/system/gd/hci/acl_manager/le_impl.h b/system/gd/hci/acl_manager/le_impl.h index c1c5ff732b..a9c2ac98c3 100644 --- a/system/gd/hci/acl_manager/le_impl.h +++ b/system/gd/hci/acl_manager/le_impl.h @@ -16,6 +16,8 @@ #pragma once +#include <base/strings/stringprintf.h> + #include <atomic> #include <memory> @@ -46,6 +48,29 @@ constexpr uint8_t PHY_LE_1M = 0x01; constexpr uint8_t PHY_LE_2M = 0x02; constexpr uint8_t PHY_LE_CODED = 0x04; +enum class ConnectabilityState { + DISARMED = 0, + ARMING = 1, + ARMED = 2, + DISARMING = 3, +}; + +#define CASE_RETURN_TEXT(code) \ + case code: \ + return #code + +inline std::string connectability_state_machine_text(const ConnectabilityState& state) { + switch (state) { + CASE_RETURN_TEXT(ConnectabilityState::DISARMED); + CASE_RETURN_TEXT(ConnectabilityState::ARMING); + CASE_RETURN_TEXT(ConnectabilityState::ARMED); + CASE_RETURN_TEXT(ConnectabilityState::DISARMING); + default: + return base::StringPrintf("UNKNOWN[%d]", state); + } +} +#undef CASE_RETURN_TEXT + struct le_acl_connection { le_acl_connection(AddressWithType remote_address, AclConnection::QueueDownEnd* queue_down_end, os::Handler* handler) : remote_address_(remote_address), @@ -201,6 +226,16 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { AddressWithType empty(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS); return empty; } + + bool alreadyConnected(AddressWithType address_with_type) { + for (auto it = le_acl_connections_.begin(); it != le_acl_connections_.end(); it++) { + if (it->second.remote_address_ == address_with_type) { + return true; + } + } + return false; + } + } connections; public: @@ -233,6 +268,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { auto status = connection_complete.GetStatus(); auto address = connection_complete.GetPeerAddress(); auto peer_address_type = connection_complete.GetPeerAddressType(); + connectability_state_ = ConnectabilityState::DISARMED; if (status == ErrorCode::UNKNOWN_CONNECTION && pause_connection) { // connection canceled by LeAddressManager.OnPause(), will auto reconnect by LeAddressManager.OnResume() return; @@ -299,6 +335,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { auto address = connection_complete.GetPeerAddress(); auto peer_address_type = connection_complete.GetPeerAddressType(); auto peer_resolvable_address = connection_complete.GetPeerResolvablePrivateAddress(); + connectability_state_ = ConnectabilityState::DISARMED; if (status == ErrorCode::UNKNOWN_CONNECTION && pause_connection) { // connection canceled by LeAddressManager.OnPause(), will auto reconnect by LeAddressManager.OnResume() return; @@ -370,10 +407,6 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { static constexpr bool kRemoveConnectionAfterwards = true; void on_le_disconnect(uint16_t handle, ErrorCode reason) { AddressWithType remote_address = connections.getAddressWithType(handle); - if (background_connections_.count(remote_address) == 1) { - LOG_INFO("re-add device to connect list"); - add_device_to_connect_list(remote_address); - } bool event_also_routes_to_other_receivers = connections.crash_on_unknown_handle_; connections.crash_on_unknown_handle_ = false; connections.execute( @@ -384,10 +417,14 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { }, kRemoveConnectionAfterwards); connections.crash_on_unknown_handle_ = event_also_routes_to_other_receivers; - if (!connect_list.empty()) { + + if (background_connections_.count(remote_address) == 1) { + LOG_INFO("re-add device to connect list"); + add_device_to_connect_list(remote_address); + } + if (!connect_list.empty() && connectability_state_ == ConnectabilityState::DISARMED) { LOG_INFO("connect_list is not empty, send a new connection request"); - AddressWithType empty(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS); - create_le_connection(empty, false, false); + arm_connectability(); } } @@ -477,6 +514,11 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { } void add_device_to_connect_list(AddressWithType address_with_type) { + if (connections.alreadyConnected(address_with_type)) { + LOG_INFO("Device already connected, return"); + return; + } + connect_list.insert(address_with_type); register_with_address_manager(); le_address_manager_->AddDeviceToConnectList( @@ -515,11 +557,50 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { void on_extended_create_connection(CommandStatusView status) { ASSERT(status.IsValid()); ASSERT(status.GetCommandOpCode() == OpCode::LE_EXTENDED_CREATE_CONNECTION); + if (connectability_state_ != ConnectabilityState::ARMING) { + LOG_ERROR( + "Received connectability arm notification for unexpected state:%s", + connectability_state_machine_text(connectability_state_).c_str()); + } + connectability_state_ = + (status.GetStatus() == ErrorCode::SUCCESS) ? ConnectabilityState::ARMED : ConnectabilityState::DISARMED; } void on_create_connection(CommandStatusView status) { ASSERT(status.IsValid()); ASSERT(status.GetCommandOpCode() == OpCode::LE_CREATE_CONNECTION); + if (connectability_state_ != ConnectabilityState::ARMING) { + LOG_ERROR( + "Received connectability arm notification for unexpected state:%s", + connectability_state_machine_text(connectability_state_).c_str()); + } + connectability_state_ = + (status.GetStatus() == ErrorCode::SUCCESS) ? ConnectabilityState::ARMED : ConnectabilityState::DISARMED; + } + + void arm_connectability() { + if (connectability_state_ != ConnectabilityState::DISARMED) { + LOG_ERROR( + "Attempting to re-arm le connection state machine in unexpected state:%s", + connectability_state_machine_text(connectability_state_).c_str()); + return; + } + connectability_state_ = ConnectabilityState::ARMING; + AddressWithType empty(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS); + create_le_connection(empty, false, false); + } + + void disarm_connectability() { + if (connectability_state_ != ConnectabilityState::ARMED) { + LOG_ERROR( + "Attempting to re-arm le connection state machine in unexpected state:%s", + connectability_state_machine_text(connectability_state_).c_str()); + return; + } + connectability_state_ = ConnectabilityState::DISARMING; + le_acl_connection_interface_->EnqueueCommand( + LeCreateConnectionCancelBuilder::Create(), + handler_->BindOnce(&le_impl::on_create_connection_cancel_complete, common::Unretained(this))); } void create_le_connection(AddressWithType address_with_type, bool add_to_connect_list, bool is_direct) { @@ -528,6 +609,11 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { return; } + if (connections.alreadyConnected(address_with_type)) { + LOG_INFO("Device already connected, return"); + return; + } + // TODO: Configure default LE connection parameters? if (add_to_connect_list) { add_device_to_connect_list(address_with_type); @@ -664,9 +750,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { create_connection_timeout_alarms_.erase(address_with_type); if (background_connections_.find(address_with_type) != background_connections_.end()) { direct_connections_.erase(address_with_type); - le_acl_connection_interface_->EnqueueCommand( - LeCreateConnectionCancelBuilder::Create(), - handler_->BindOnce(&le_impl::on_create_connection_cancel_complete, common::Unretained(this))); + disarm_connectability(); } else { cancel_connect(address_with_type); } @@ -765,21 +849,18 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { void OnPause() override { pause_connection = true; - if (connecting_le_.empty()) { + if (connectability_state_ == ConnectabilityState::DISARMED) { le_address_manager_->AckPause(this); return; } canceled_connections_ = connecting_le_; - le_acl_connection_interface_->EnqueueCommand( - LeCreateConnectionCancelBuilder::Create(), - handler_->BindOnce(&le_impl::on_create_connection_cancel_complete, common::Unretained(this))); - le_address_manager_->AckPause(this); + disarm_connectability(); } void OnResume() override { pause_connection = false; if (!canceled_connections_.empty()) { - create_le_connection(*canceled_connections_.begin(), false, false); + arm_connectability(); } canceled_connections_.clear(); le_address_manager_->AckResume(this); @@ -794,6 +875,15 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { std::string error_code = ErrorCodeText(status); LOG_WARN("Received on_create_connection_cancel_complete with error code %s", error_code.c_str()); } + if (connectability_state_ != ConnectabilityState::DISARMING) { + LOG_ERROR( + "Attempting to disarm le connection state machine in unexpected state:%s", + connectability_state_machine_text(connectability_state_).c_str()); + } + connectability_state_ = ConnectabilityState::DISARMED; + if (pause_connection) { + le_address_manager_->AckPause(this); + } } void register_with_address_manager() { @@ -832,6 +922,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { bool address_manager_registered = false; bool ready_to_unregister = false; bool pause_connection = false; + ConnectabilityState connectability_state_{ConnectabilityState::DISARMED}; std::map<AddressWithType, os::Alarm> create_connection_timeout_alarms_; }; diff --git a/system/gd/hci/le_address_manager.cc b/system/gd/hci/le_address_manager.cc index c3c11ceb5d..68bfeccd71 100644 --- a/system/gd/hci/le_address_manager.cc +++ b/system/gd/hci/le_address_manager.cc @@ -411,7 +411,11 @@ void LeAddressManager::AddDeviceToResolvingList( Command enable = {CommandType::SET_ADDRESS_RESOLUTION_ENABLE, std::move(enable_builder)}; cached_commands_.push(std::move(enable)); - pause_registered_clients(); + if (registered_clients_.empty()) { + handle_next_command(); + } else { + pause_registered_clients(); + } } void LeAddressManager::RemoveDeviceFromConnectList( @@ -438,7 +442,11 @@ void LeAddressManager::RemoveDeviceFromResolvingList( Command enable = {CommandType::SET_ADDRESS_RESOLUTION_ENABLE, std::move(enable_builder)}; cached_commands_.push(std::move(enable)); - pause_registered_clients(); + if (registered_clients_.empty()) { + handle_next_command(); + } else { + pause_registered_clients(); + } } void LeAddressManager::ClearConnectList() { @@ -496,7 +504,8 @@ void LeAddressManager::OnCommandComplete(bluetooth::hci::CommandCompleteView vie void LeAddressManager::check_cached_commands() { for (auto client : registered_clients_) { - if (client.second != ClientState::PAUSED) { + if (client.second != ClientState::PAUSED && !cached_commands_.empty()) { + pause_registered_clients(); return; } } diff --git a/system/gd/hci/le_advertising_manager.cc b/system/gd/hci/le_advertising_manager.cc index 03a001833d..afc874c592 100644 --- a/system/gd/hci/le_advertising_manager.cc +++ b/system/gd/hci/le_advertising_manager.cc @@ -33,6 +33,7 @@ namespace bluetooth { namespace hci { const ModuleFactory LeAdvertisingManager::Factory = ModuleFactory([]() { return new LeAdvertisingManager(); }); +constexpr int kIdLocal = 0xff; // Id for advertiser not register from Java layer enum class AdvertisingApiType { LEGACY = 1, @@ -51,6 +52,8 @@ enum class AdvertisingFlag : uint8_t { struct Advertiser { os::Handler* handler; AddressWithType current_address; + base::Callback<void(uint8_t /* status */)> status_callback; + base::Callback<void(uint8_t /* status */)> timeout_callback; common::Callback<void(Address, AddressType)> scan_callback; common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback; int8_t tx_power; @@ -186,7 +189,14 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb auto status = event_view.GetStatus(); acl_manager_->OnAdvertisingSetTerminated(status, event_view.GetConnectionHandle(), advertiser_address); if (status == ErrorCode::LIMIT_REACHED || status == ErrorCode::ADVERTISING_TIMEOUT) { - advertising_callbacks_->OnAdvertisingEnabled(advertiser_id, false, (uint8_t)status); + if (id_map_[advertiser_id] == kIdLocal) { + if (!advertising_sets_[advertiser_id].timeout_callback.is_null()) { + advertising_sets_[advertiser_id].timeout_callback.Run((uint8_t)status); + advertising_sets_[advertiser_id].timeout_callback.Reset(); + } + } else { + advertising_callbacks_->OnAdvertisingEnabled(advertiser_id, false, (uint8_t)status); + } return; } @@ -304,6 +314,21 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb } } + void start_advertising( + AdvertiserId id, + const ExtendedAdvertisingConfig config, + uint16_t duration, + const base::Callback<void(uint8_t /* status */)>& status_callback, + const base::Callback<void(uint8_t /* status */)>& timeout_callback, + const common::Callback<void(Address, AddressType)>& scan_callback, + const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, + os::Handler* handler) { + advertising_sets_[id].status_callback = status_callback; + advertising_sets_[id].timeout_callback = timeout_callback; + + create_extended_advertiser(kIdLocal, id, config, scan_callback, set_terminated_callback, duration, 0, handler); + } + void create_extended_advertiser( int reg_id, AdvertiserId id, @@ -975,6 +1000,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb std::mutex id_mutex_; size_t num_instances_; std::vector<hci::EnabledSet> enabled_sets_; + // map to mapping the id from java layer and advertier id std::map<uint8_t, int> id_map_; AdvertisingApiType advertising_api_type_{0}; @@ -1016,6 +1042,14 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb continue; } + if (id_map_[id] == kIdLocal) { + if (!advertising_sets_[enabled_set.advertising_handle_].status_callback.is_null()) { + advertising_sets_[enabled_set.advertising_handle_].status_callback.Run(advertising_status); + advertising_sets_[enabled_set.advertising_handle_].status_callback.Reset(); + } + continue; + } + if (started) { advertising_callbacks_->OnAdvertisingEnabled(id, enable, advertising_status); } else { @@ -1050,6 +1084,14 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb continue; } + if (id_map_[id] == kIdLocal) { + if (!advertising_sets_[enabled_set.advertising_handle_].status_callback.is_null()) { + advertising_sets_[enabled_set.advertising_handle_].status_callback.Run(advertising_status); + advertising_sets_[enabled_set.advertising_handle_].status_callback.Reset(); + } + continue; + } + if (started) { advertising_callbacks_->OnAdvertisingEnabled(id, enable, advertising_status); } else { @@ -1072,7 +1114,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb } advertising_sets_[id].tx_power = complete_view.GetSelectedTxPower(); - if (advertising_sets_[id].started) { + if (advertising_sets_[id].started && id_map_[id] != kIdLocal) { advertising_callbacks_->OnAdvertisingParametersUpdated(id, advertising_sets_[id].tx_power, advertising_status); } } @@ -1088,7 +1130,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb advertising_status = AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR; } - if (advertising_callbacks_ == nullptr || !advertising_sets_[id].started) { + if (advertising_callbacks_ == nullptr || !advertising_sets_[id].started || id_map_[id] == kIdLocal) { return; } @@ -1129,8 +1171,9 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb advertising_status = AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR; } - // Do not trigger callback if the advertiser not stated yet - if (advertising_callbacks_ == nullptr || !advertising_sets_[id].started) { + // Do not trigger callback if the advertiser not stated yet, or the advertiser is not register + // from Java layer + if (advertising_callbacks_ == nullptr || !advertising_sets_[id].started || id_map_[id] == kIdLocal) { return; } @@ -1300,6 +1343,38 @@ AdvertiserId LeAdvertisingManager::ExtendedCreateAdvertiser( return id; } +void LeAdvertisingManager::StartAdvertising( + AdvertiserId advertiser_id, + const ExtendedAdvertisingConfig config, + uint16_t duration, + const base::Callback<void(uint8_t /* status */)>& status_callback, + const base::Callback<void(uint8_t /* status */)>& timeout_callback, + const common::Callback<void(Address, AddressType)>& scan_callback, + const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, + os::Handler* handler) { + CallOn( + pimpl_.get(), + &impl::start_advertising, + advertiser_id, + config, + duration, + status_callback, + timeout_callback, + scan_callback, + set_terminated_callback, + handler); +} + +void LeAdvertisingManager::RegisterAdvertiser( + base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)> callback) { + AdvertiserId id = pimpl_->allocate_advertiser(); + if (id == kInvalidId) { + callback.Run(kInvalidId, AdvertisingCallback::AdvertisingStatus::TOO_MANY_ADVERTISERS); + } else { + callback.Run(id, AdvertisingCallback::AdvertisingStatus::SUCCESS); + } +} + void LeAdvertisingManager::GetOwnAddress(uint8_t advertiser_id) { CallOn(pimpl_.get(), &impl::get_own_address, advertiser_id); } diff --git a/system/gd/hci/le_advertising_manager.h b/system/gd/hci/le_advertising_manager.h index 557b110d8d..3ef4de6396 100644 --- a/system/gd/hci/le_advertising_manager.h +++ b/system/gd/hci/le_advertising_manager.h @@ -116,8 +116,20 @@ class LeAdvertisingManager : public bluetooth::Module { uint8_t max_extended_advertising_events, os::Handler* handler); + void StartAdvertising( + AdvertiserId advertiser_id, + const ExtendedAdvertisingConfig config, + uint16_t duration, + const base::Callback<void(uint8_t /* status */)>& status_callback, + const base::Callback<void(uint8_t /* status */)>& timeout_callback, + const common::Callback<void(Address, AddressType)>& scan_callback, + const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, + os::Handler* handler); + void GetOwnAddress(uint8_t advertiser_id); + void RegisterAdvertiser(base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)> callback); + void SetParameters(AdvertiserId advertiser_id, ExtendedAdvertisingConfig config); void SetData(AdvertiserId advertiser_id, bool set_scan_rsp, std::vector<GapData> data); diff --git a/system/gd/hci/le_scanning_callback.h b/system/gd/hci/le_scanning_callback.h index d0ef782a7c..5f91208a45 100644 --- a/system/gd/hci/le_scanning_callback.h +++ b/system/gd/hci/le_scanning_callback.h @@ -89,6 +89,7 @@ class AdvertisingPacketContentFilterCommand { uint16_t company_mask; std::vector<uint8_t> data; std::vector<uint8_t> data_mask; + std::array<uint8_t, 16> irk; }; class AdvertisingFilterParameter { diff --git a/system/gd/hci/le_scanning_manager.cc b/system/gd/hci/le_scanning_manager.cc index 857d2495e5..3bd8f8cbce 100644 --- a/system/gd/hci/le_scanning_manager.cc +++ b/system/gd/hci/le_scanning_manager.cc @@ -712,7 +712,7 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback switch (filter.filter_type) { case ApcfFilterType::BROADCASTER_ADDRESS: { - update_address_filter(apcf_action, filter_index, filter.address, filter.application_address_type); + update_address_filter(apcf_action, filter_index, filter.address, filter.application_address_type, filter.irk); break; } case ApcfFilterType::SERVICE_UUID: @@ -741,11 +741,36 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback } void update_address_filter( - ApcfAction action, uint8_t filter_index, Address address, ApcfApplicationAddressType address_type) { + ApcfAction action, + uint8_t filter_index, + Address address, + ApcfApplicationAddressType address_type, + std::array<uint8_t, 16> irk) { if (action != ApcfAction::CLEAR) { + /* + * The vendor command (APCF Filtering 0x0157) takes Public (0) or Random (1) + * or Addresses type not applicable (2). + * + * Advertising results have four types: + *  - Public = 0 + *  - Random = 1 + *  - Public ID = 2 + *  - Random ID = 3 + * + * e.g. specifying PUBLIC (0) will only return results with a public + * address. It will ignore resolved addresses, since they return PUBLIC + * IDENTITY (2). For this, Addresses type not applicable (0x02) must be specified. + * This should also cover if the RPA is derived from RANDOM STATIC. + */ le_scanning_interface_->EnqueueCommand( - LeAdvFilterBroadcasterAddressBuilder::Create(action, filter_index, address, address_type), + LeAdvFilterBroadcasterAddressBuilder::Create( + action, filter_index, address, ApcfApplicationAddressType::NOT_APPLICABLE), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); + if (!is_empty_128bit(irk)) { + std::array<uint8_t, 16> empty_irk; + le_address_manager_->AddDeviceToResolvingList( + static_cast<PeerAddressType>(address_type), address, irk, empty_irk); + } } else { le_scanning_interface_->EnqueueCommand( LeAdvFilterClearBroadcasterAddressBuilder::Create(filter_index), @@ -753,6 +778,15 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback } } + bool is_empty_128bit(const std::array<uint8_t, 16> data) { + for (int i = 0; i < 16; i++) { + if (data[i] != (uint8_t)0) { + return false; + } + } + return true; + } + void update_uuid_filter( ApcfAction action, uint8_t filter_index, ApcfFilterType filter_type, Uuid uuid, Uuid uuid_mask) { std::vector<uint8_t> combined_data = {}; diff --git a/system/gd/os/fuzz/fake_timerfd.cc b/system/gd/os/fuzz/fake_timerfd.cc index 5b7389beba..8154e44edc 100644 --- a/system/gd/os/fuzz/fake_timerfd.cc +++ b/system/gd/os/fuzz/fake_timerfd.cc @@ -122,7 +122,7 @@ static bool fire_next_event(uint64_t new_clock) { void fake_timerfd_advance(uint64_t ms) { uint64_t new_clock = clock + ms; - if (new_clock > max_clock) { + if (new_clock < clock) { new_clock = max_clock; } while (fire_next_event(new_clock)) { diff --git a/system/gd/os/linux_generic/alarm.cc b/system/gd/os/linux_generic/alarm.cc index cd859b5fe7..22bd3b2282 100644 --- a/system/gd/os/linux_generic/alarm.cc +++ b/system/gd/os/linux_generic/alarm.cc @@ -77,7 +77,11 @@ void Alarm::on_fire() { lock.unlock(); std::move(task).Run(); ASSERT(bytes_read == static_cast<ssize_t>(sizeof(uint64_t))); - ASSERT(times_invoked == static_cast<uint64_t>(1)); + ASSERT_LOG( + times_invoked == static_cast<uint64_t>(1), + "Invoked number of times:%lu fd:%d", + (unsigned long)times_invoked, + fd_); } } // namespace os diff --git a/system/gd/packet/parser/fields/array_field.cc b/system/gd/packet/parser/fields/array_field.cc index c856e5b712..c95734d098 100644 --- a/system/gd/packet/parser/fields/array_field.cc +++ b/system/gd/packet/parser/fields/array_field.cc @@ -200,10 +200,11 @@ std::string ArrayField::GetRustDataType() const { return "[" + element_field_->GetRustDataType() + "; " + std::to_string(array_size_) + "]"; } -void ArrayField::GenRustGetter(std::ostream& s, Size start_offset, Size) const { +void ArrayField::GenRustGetter(std::ostream& s, Size start_offset, Size, std::string) const { s << "let " << GetName() << " = "; s << "bytes[" << start_offset.bytes() << ".."; - s << start_offset.bytes() + GetSize().bytes() << "].try_into().unwrap();"; + s << start_offset.bytes() + GetSize().bytes() << "].try_into()"; + s << ".map_err(|_| Error::InvalidPacketError)?;"; } void ArrayField::GenRustWriter(std::ostream& s, Size start_offset, Size) const { diff --git a/system/gd/packet/parser/fields/array_field.h b/system/gd/packet/parser/fields/array_field.h index 0bd487d397..d19a069edb 100644 --- a/system/gd/packet/parser/fields/array_field.h +++ b/system/gd/packet/parser/fields/array_field.h @@ -66,7 +66,7 @@ class ArrayField : public PacketField { virtual std::string GetRustDataType() const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string parent_name) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/body_field.cc b/system/gd/packet/parser/fields/body_field.cc index 557f184161..d0d61dd52f 100644 --- a/system/gd/packet/parser/fields/body_field.cc +++ b/system/gd/packet/parser/fields/body_field.cc @@ -80,7 +80,6 @@ std::string BodyField::GetRustDataType() const { return GetDataType(); } -void BodyField::GenRustGetter(std::ostream&, Size, Size) const { -} +void BodyField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} void BodyField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/body_field.h b/system/gd/packet/parser/fields/body_field.h index c31af7414c..2712bf0522 100644 --- a/system/gd/packet/parser/fields/body_field.h +++ b/system/gd/packet/parser/fields/body_field.h @@ -54,7 +54,7 @@ class BodyField : public PacketField { virtual std::string GetRustDataType() const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/checksum_field.cc b/system/gd/packet/parser/fields/checksum_field.cc index bcbcac2fab..6344450563 100644 --- a/system/gd/packet/parser/fields/checksum_field.cc +++ b/system/gd/packet/parser/fields/checksum_field.cc @@ -64,7 +64,6 @@ void ChecksumField::GenStringRepresentation(std::ostream& s, std::string) const s << "\"CHECKSUM\""; } -void ChecksumField::GenRustGetter(std::ostream&, Size, Size) const { -} +void ChecksumField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} void ChecksumField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/checksum_field.h b/system/gd/packet/parser/fields/checksum_field.h index 2b5b221479..3a6908e98d 100644 --- a/system/gd/packet/parser/fields/checksum_field.h +++ b/system/gd/packet/parser/fields/checksum_field.h @@ -48,7 +48,7 @@ class ChecksumField : public ScalarField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/checksum_start_field.cc b/system/gd/packet/parser/fields/checksum_start_field.cc index e0c03b828a..22b2891679 100644 --- a/system/gd/packet/parser/fields/checksum_start_field.cc +++ b/system/gd/packet/parser/fields/checksum_start_field.cc @@ -70,7 +70,6 @@ std::string ChecksumStartField::GetRustDataType() const { return GetDataType(); } -void ChecksumStartField::GenRustGetter(std::ostream&, Size, Size) const { -} +void ChecksumStartField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} void ChecksumStartField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/checksum_start_field.h b/system/gd/packet/parser/fields/checksum_start_field.h index 82e71ba8c4..67ddc9568f 100644 --- a/system/gd/packet/parser/fields/checksum_start_field.h +++ b/system/gd/packet/parser/fields/checksum_start_field.h @@ -55,7 +55,7 @@ class ChecksumStartField : public PacketField { virtual std::string GetRustDataType() const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/custom_field.cc b/system/gd/packet/parser/fields/custom_field.cc index e4761abc98..295fbf5ca5 100644 --- a/system/gd/packet/parser/fields/custom_field.cc +++ b/system/gd/packet/parser/fields/custom_field.cc @@ -104,7 +104,6 @@ std::string CustomField::GetRustDataType() const { return type_name_; } -void CustomField::GenRustGetter(std::ostream&, Size, Size) const { -} +void CustomField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} void CustomField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/custom_field.h b/system/gd/packet/parser/fields/custom_field.h index 55642c9c58..25e196d2bb 100644 --- a/system/gd/packet/parser/fields/custom_field.h +++ b/system/gd/packet/parser/fields/custom_field.h @@ -55,7 +55,7 @@ class CustomField : public PacketField { virtual std::string GetRustDataType() const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/custom_field_fixed_size.cc b/system/gd/packet/parser/fields/custom_field_fixed_size.cc index 8dc27fa3e1..a603259d30 100644 --- a/system/gd/packet/parser/fields/custom_field_fixed_size.cc +++ b/system/gd/packet/parser/fields/custom_field_fixed_size.cc @@ -77,7 +77,7 @@ std::string CustomFieldFixedSize::GetRustParseDataType() const { return "[u8; " + std::to_string(GetSize().bytes()) + "]"; } -void CustomFieldFixedSize::GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const { +void CustomFieldFixedSize::GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const { Size size = GetSize(); int num_leading_bits = GetRustBitOffset(s, start_offset, end_offset, GetSize()); if (num_leading_bits != 0) { @@ -88,7 +88,8 @@ void CustomFieldFixedSize::GenRustGetter(std::ostream& s, Size start_offset, Siz } s << "let " << GetName() << " = bytes[" << start_offset.bytes() << ".."; - s << start_offset.bytes() + size.bytes() << "].try_into().unwrap();"; + s << start_offset.bytes() + size.bytes() << "].try_into()"; + s << ".map_err(|_| Error::InvalidPacketError)?;"; } void CustomFieldFixedSize::GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const { diff --git a/system/gd/packet/parser/fields/custom_field_fixed_size.h b/system/gd/packet/parser/fields/custom_field_fixed_size.h index 8423f803b0..b21c5d8065 100644 --- a/system/gd/packet/parser/fields/custom_field_fixed_size.h +++ b/system/gd/packet/parser/fields/custom_field_fixed_size.h @@ -43,7 +43,7 @@ class CustomFieldFixedSize : public ScalarField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/fixed_scalar_field.cc b/system/gd/packet/parser/fields/fixed_scalar_field.cc index c745b12069..3a5b760733 100644 --- a/system/gd/packet/parser/fields/fixed_scalar_field.cc +++ b/system/gd/packet/parser/fields/fixed_scalar_field.cc @@ -43,6 +43,7 @@ void FixedScalarField::GenRustWriter(std::ostream& s, Size start_offset, Size en FixedField::GenRustWriter(s, start_offset, end_offset); } -void FixedScalarField::GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const { - FixedField::GenRustGetter(s, start_offset, end_offset); +void FixedScalarField::GenRustGetter( + std::ostream& s, Size start_offset, Size end_offset, std::string parent_name) const { + FixedField::GenRustGetter(s, start_offset, end_offset, parent_name); } diff --git a/system/gd/packet/parser/fields/fixed_scalar_field.h b/system/gd/packet/parser/fields/fixed_scalar_field.h index 2304ba4a0d..595c96df71 100644 --- a/system/gd/packet/parser/fields/fixed_scalar_field.h +++ b/system/gd/packet/parser/fields/fixed_scalar_field.h @@ -39,7 +39,7 @@ class FixedScalarField : public FixedField { static const std::string field_type; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/group_field.cc b/system/gd/packet/parser/fields/group_field.cc index f2e3b95f8e..1de8fb75f7 100644 --- a/system/gd/packet/parser/fields/group_field.cc +++ b/system/gd/packet/parser/fields/group_field.cc @@ -87,7 +87,6 @@ std::string GroupField::GetRustDataType() const { return GetDataType(); } -void GroupField::GenRustGetter(std::ostream&, Size, Size) const { -} +void GroupField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} void GroupField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/group_field.h b/system/gd/packet/parser/fields/group_field.h index 691fb229f1..f058f986f7 100644 --- a/system/gd/packet/parser/fields/group_field.h +++ b/system/gd/packet/parser/fields/group_field.h @@ -57,7 +57,7 @@ class GroupField : public PacketField { virtual std::string GetRustDataType() const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/packet_field.cc b/system/gd/packet/parser/fields/packet_field.cc index 4ce02e22e5..608fb28bfb 100644 --- a/system/gd/packet/parser/fields/packet_field.cc +++ b/system/gd/packet/parser/fields/packet_field.cc @@ -131,14 +131,14 @@ bool PacketField::GenRustNameAndType(std::ostream& s) const { return true; } -void PacketField::GenBoundsCheck(std::ostream& s, Size start_offset, Size, std::string context) const { +void PacketField::GenBoundsCheck(std::ostream& s, Size start_offset, Size, std::string parent_name) const { Size size = GetSize(); if (size.bits() < 8) { return; } s << "if bytes.len() < " << start_offset.bytes() + size.bytes() << " {"; s << " return Err(Error::InvalidLengthError{"; - s << " obj: \"" << context << "\".to_string(),"; + s << " obj: \"" << parent_name << "\".to_string(),"; s << " field: \"" << GetName() << "\".to_string(),"; s << " wanted: " << start_offset.bytes() + size.bytes() << ","; s << " got: bytes.len()});"; diff --git a/system/gd/packet/parser/fields/packet_field.h b/system/gd/packet/parser/fields/packet_field.h index 128536223b..c3df79b912 100644 --- a/system/gd/packet/parser/fields/packet_field.h +++ b/system/gd/packet/parser/fields/packet_field.h @@ -124,7 +124,7 @@ class PacketField : public Loggable { virtual int GetRustBitOffset( std::ostream& s, Size start_offset, Size end_offset, Size size) const; - virtual void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const = 0; + virtual void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const = 0; virtual void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const = 0; diff --git a/system/gd/packet/parser/fields/padding_field.cc b/system/gd/packet/parser/fields/padding_field.cc index e6a2c366bd..155bed6622 100644 --- a/system/gd/packet/parser/fields/padding_field.cc +++ b/system/gd/packet/parser/fields/padding_field.cc @@ -66,7 +66,6 @@ std::string PaddingField::GetRustDataType() const { return "There's no type for Padding fields"; } -void PaddingField::GenRustGetter(std::ostream&, Size, Size) const { -} +void PaddingField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} void PaddingField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/padding_field.h b/system/gd/packet/parser/fields/padding_field.h index ea40ccded7..ca9664f4b5 100644 --- a/system/gd/packet/parser/fields/padding_field.h +++ b/system/gd/packet/parser/fields/padding_field.h @@ -53,7 +53,7 @@ class PaddingField : public PacketField { virtual std::string GetRustDataType() const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/payload_field.cc b/system/gd/packet/parser/fields/payload_field.cc index 844488242e..93491a1476 100644 --- a/system/gd/packet/parser/fields/payload_field.cc +++ b/system/gd/packet/parser/fields/payload_field.cc @@ -117,7 +117,29 @@ std::string PayloadField::GetRustDataType() const { return "Vec::<u8>"; } -void PayloadField::GenRustGetter(std::ostream& s, Size start_offset, Size) const { +void PayloadField::GenBoundsCheck(std::ostream& s, Size start_offset, Size, std::string parent_name) const { + if (size_field_ != nullptr) { + s << "let want_ = " << start_offset.bytes() << " + (" << size_field_->GetName() << " as usize)"; + if (!size_modifier_.empty()) { + s << " - ((" << size_modifier_.substr(1) << ") / 8)"; + } + s << ";"; + s << "if bytes.len() < want_ {"; + s << " return Err(Error::InvalidLengthError{"; + s << " obj: \"" << parent_name << "\".to_string(),"; + s << " field: \"" << GetName() << "\".to_string(),"; + s << " wanted: want_,"; + s << " got: bytes.len()});"; + s << "}"; + if (!size_modifier_.empty()) { + s << "if ((" << size_field_->GetName() << " as usize) < ((" << size_modifier_.substr(1) << ") / 8)) {"; + s << " return Err(Error::ImpossibleStructError);"; + s << "}"; + } + } +} + +void PayloadField::GenRustGetter(std::ostream& s, Size start_offset, Size, std::string) const { s << "let " << GetName() << ": " << GetRustDataType() << " = "; if (size_field_ == nullptr) { s << "bytes[" << start_offset.bytes() << "..].into();"; diff --git a/system/gd/packet/parser/fields/payload_field.h b/system/gd/packet/parser/fields/payload_field.h index f86f27522b..aae05fb843 100644 --- a/system/gd/packet/parser/fields/payload_field.h +++ b/system/gd/packet/parser/fields/payload_field.h @@ -58,11 +58,11 @@ class PayloadField : public PacketField { virtual std::string GetRustDataType() const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - void GenBoundsCheck(std::ostream&, Size, Size, std::string) const override{}; + void GenBoundsCheck(std::ostream&, Size, Size, std::string) const override; // Payload fields can only be dynamically sized. const SizeField* size_field_; diff --git a/system/gd/packet/parser/fields/reserved_field.cc b/system/gd/packet/parser/fields/reserved_field.cc index ac05338310..76fdf631fb 100644 --- a/system/gd/packet/parser/fields/reserved_field.cc +++ b/system/gd/packet/parser/fields/reserved_field.cc @@ -72,7 +72,6 @@ std::string ReservedField::GetRustDataType() const { return util::GetRustTypeForSize(size_); } -void ReservedField::GenRustGetter(std::ostream&, Size, Size) const { -} +void ReservedField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} void ReservedField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/reserved_field.h b/system/gd/packet/parser/fields/reserved_field.h index 7fabe499a1..f17418167b 100644 --- a/system/gd/packet/parser/fields/reserved_field.h +++ b/system/gd/packet/parser/fields/reserved_field.h @@ -49,7 +49,7 @@ class ReservedField : public PacketField { virtual std::string GetRustDataType() const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/scalar_field.cc b/system/gd/packet/parser/fields/scalar_field.cc index de5e31c9b2..10c85284c7 100644 --- a/system/gd/packet/parser/fields/scalar_field.cc +++ b/system/gd/packet/parser/fields/scalar_field.cc @@ -160,7 +160,7 @@ int ScalarField::GetRustBitOffset( return num_leading_bits; } -void ScalarField::GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const { +void ScalarField::GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string parent_name) const { Size size = GetSize(); int num_leading_bits = GetRustBitOffset(s, start_offset, end_offset, GetSize()); @@ -207,7 +207,13 @@ void ScalarField::GenRustGetter(std::ostream& s, Size start_offset, Size end_off // needs casting from primitive if (GetRustParseDataType() != GetRustDataType()) { s << "let " << GetName() << " = "; - s << GetRustDataType() << "::from_" << GetRustParseDataType() << "(" << GetName() << ").unwrap();"; + s << GetRustDataType() << "::from_" << GetRustParseDataType() << "(" << GetName() << ").ok_or_else(||"; + s << "Error::InvalidEnumValueError {"; + s << " obj: \"" << parent_name << "\".to_string(),"; + s << " field: \"" << GetName() << "\".to_string(),"; + s << " value: " << GetName() << " as u64,"; + s << " type_: \"" << GetRustDataType() << "\".to_string(),"; + s << "})?;"; } } diff --git a/system/gd/packet/parser/fields/scalar_field.h b/system/gd/packet/parser/fields/scalar_field.h index 81616cee78..09fd16e236 100644 --- a/system/gd/packet/parser/fields/scalar_field.h +++ b/system/gd/packet/parser/fields/scalar_field.h @@ -58,7 +58,7 @@ class ScalarField : public PacketField { virtual int GetRustBitOffset(std::ostream& s, Size start_offset, Size end_offset, Size size) const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/struct_field.cc b/system/gd/packet/parser/fields/struct_field.cc index 75ad1abb05..6555e60bb2 100644 --- a/system/gd/packet/parser/fields/struct_field.cc +++ b/system/gd/packet/parser/fields/struct_field.cc @@ -96,10 +96,10 @@ void StructField::GenBoundsCheck(std::ostream&, Size, Size, std::string) const { // implicitly checked by the struct parser } -void StructField::GenRustGetter(std::ostream& s, Size start_offset, Size) const { +void StructField::GenRustGetter(std::ostream& s, Size start_offset, Size, std::string) const { s << "let " << GetName() << " = "; s << GetRustDataType() << "::parse(&bytes[" << start_offset.bytes() << ".."; - s << start_offset.bytes() + GetSize().bytes() << "]).unwrap();"; + s << start_offset.bytes() + GetSize().bytes() << "])?;"; } void StructField::GenRustWriter(std::ostream& s, Size start_offset, Size) const { diff --git a/system/gd/packet/parser/fields/struct_field.h b/system/gd/packet/parser/fields/struct_field.h index acc5fb459c..051b9ef2d2 100644 --- a/system/gd/packet/parser/fields/struct_field.h +++ b/system/gd/packet/parser/fields/struct_field.h @@ -53,7 +53,7 @@ class StructField : public PacketField { virtual std::string GetRustDataType() const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/variable_length_struct_field.cc b/system/gd/packet/parser/fields/variable_length_struct_field.cc index 628b43ad34..6506d8f298 100644 --- a/system/gd/packet/parser/fields/variable_length_struct_field.cc +++ b/system/gd/packet/parser/fields/variable_length_struct_field.cc @@ -96,7 +96,6 @@ std::string VariableLengthStructField::GetRustDataType() const { return ret; } -void VariableLengthStructField::GenRustGetter(std::ostream&, Size, Size) const { -} +void VariableLengthStructField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} void VariableLengthStructField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/variable_length_struct_field.h b/system/gd/packet/parser/fields/variable_length_struct_field.h index 2774d4e7a5..a6c66d69ee 100644 --- a/system/gd/packet/parser/fields/variable_length_struct_field.h +++ b/system/gd/packet/parser/fields/variable_length_struct_field.h @@ -53,7 +53,7 @@ class VariableLengthStructField : public PacketField { virtual std::string GetRustDataType() const override; - void GenRustGetter(std::ostream&, Size, Size) const override; + void GenRustGetter(std::ostream&, Size, Size, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; diff --git a/system/gd/packet/parser/fields/vector_field.cc b/system/gd/packet/parser/fields/vector_field.cc index 9c8ca0715f..7678d99794 100644 --- a/system/gd/packet/parser/fields/vector_field.cc +++ b/system/gd/packet/parser/fields/vector_field.cc @@ -254,54 +254,54 @@ std::string VectorField::GetRustDataType() const { return "Vec::<" + element_field_->GetRustDataType() + ">"; } -void VectorField::GenBoundsCheck(std::ostream& s, Size start_offset, Size, std::string context) const { +void VectorField::GenBoundsCheck(std::ostream& s, Size start_offset, Size, std::string parent_name) const { auto element_field_type = GetElementField()->GetFieldType(); auto element_field = GetElementField(); - auto element_size = element_field->GetSize().bytes(); + auto element_size = element_field->GetSize(); - if (element_field_type == ScalarField::kFieldType) { - if (size_field_ == nullptr) { - s << "let rem_ = (bytes.len() - " << start_offset.bytes() << ") % " << element_size << ";"; - s << "if rem_ != 0 {"; - s << " return Err(Error::InvalidLengthError{"; - s << " obj: \"" << context << "\".to_string(),"; - s << " field: \"" << GetName() << "\".to_string(),"; - s << " wanted: bytes.len() + rem_,"; - s << " got: bytes.len()});"; - s << "}"; - } else if (size_field_->GetFieldType() == CountField::kFieldType) { - s << "let want_ = " << start_offset.bytes() << " + ((" << size_field_->GetName() << " as usize) * " - << element_size << ");"; - s << "if bytes.len() < want_ {"; - s << " return Err(Error::InvalidLengthError{"; - s << " obj: \"" << context << "\".to_string(),"; - s << " field: \"" << GetName() << "\".to_string(),"; - s << " wanted: want_,"; - s << " got: bytes.len()});"; - s << "}"; - } else { - s << "let want_ = " << start_offset.bytes() << " + (" << size_field_->GetName() << " as usize)"; - if (GetSizeModifier() != "") { - s << " - ((" << GetSizeModifier().substr(1) << ") / 8)"; - } - s << ";"; - s << "if bytes.len() < want_ {"; - s << " return Err(Error::InvalidLengthError{"; - s << " obj: \"" << context << "\".to_string(),"; - s << " field: \"" << GetName() << "\".to_string(),"; - s << " wanted: want_,"; - s << " got: bytes.len()});"; + if (size_field_ != nullptr && size_field_->GetFieldType() == SizeField::kFieldType) { + s << "let want_ = " << start_offset.bytes() << " + (" << size_field_->GetName() << " as usize)"; + if (GetSizeModifier() != "") { + s << " - ((" << GetSizeModifier().substr(1) << ") / 8)"; + } + s << ";"; + s << "if bytes.len() < want_ {"; + s << " return Err(Error::InvalidLengthError{"; + s << " obj: \"" << parent_name << "\".to_string(),"; + s << " field: \"" << GetName() << "\".to_string(),"; + s << " wanted: want_,"; + s << " got: bytes.len()});"; + s << "}"; + if (GetSizeModifier() != "") { + s << "if ((" << size_field_->GetName() << " as usize) < ((" << GetSizeModifier().substr(1) << ") / 8)) {"; + s << " return Err(Error::ImpossibleStructError);"; s << "}"; - if (GetSizeModifier() != "") { - s << "if ((" << size_field_->GetName() << " as usize) < ((" << GetSizeModifier().substr(1) << ") / 8)) {"; - s << " return Err(Error::ImpossibleStructError);"; - s << "}"; - } } + } else if ( + size_field_ != nullptr && size_field_->GetFieldType() == CountField::kFieldType && !element_size.empty() && + !element_size.has_dynamic()) { + s << "let want_ = " << start_offset.bytes() << " + ((" << size_field_->GetName() << " as usize) * " + << element_size.bytes() << ");"; + s << "if bytes.len() < want_ {"; + s << " return Err(Error::InvalidLengthError{"; + s << " obj: \"" << parent_name << "\".to_string(),"; + s << " field: \"" << GetName() << "\".to_string(),"; + s << " wanted: want_,"; + s << " got: bytes.len()});"; + s << "}"; + } else if (size_field_ == nullptr && element_field_type == ScalarField::kFieldType) { + s << "let rem_ = (bytes.len() - " << start_offset.bytes() << ") % " << element_size.bytes() << ";"; + s << "if rem_ != 0 {"; + s << " return Err(Error::InvalidLengthError{"; + s << " obj: \"" << parent_name << "\".to_string(),"; + s << " field: \"" << GetName() << "\".to_string(),"; + s << " wanted: bytes.len() + rem_,"; + s << " got: bytes.len()});"; + s << "}"; } } -void VectorField::GenRustGetter(std::ostream& s, Size start_offset, Size) const { +void VectorField::GenRustGetter(std::ostream& s, Size start_offset, Size, std::string) const { auto element_field_type = GetElementField()->GetFieldType(); auto element_field = GetElementField(); auto element_size = element_field->GetSize().bytes(); diff --git a/system/gd/packet/parser/fields/vector_field.h b/system/gd/packet/parser/fields/vector_field.h index e6b5330393..aa53eb4991 100644 --- a/system/gd/packet/parser/fields/vector_field.h +++ b/system/gd/packet/parser/fields/vector_field.h @@ -71,11 +71,11 @@ class VectorField : public PacketField { virtual std::string GetRustDataType() const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset) const override; + void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - void GenBoundsCheck(std::ostream& s, Size start_offset, Size end_offset, std::string context) const override; + void GenBoundsCheck(std::ostream& s, Size start_offset, Size end_offset, std::string parent_name) const override; const std::string name_; diff --git a/system/gd/packet/parser/gen_rust.cc b/system/gd/packet/parser/gen_rust.cc index 75e814a578..1097083941 100644 --- a/system/gd/packet/parser/gen_rust.cc +++ b/system/gd/packet/parser/gen_rust.cc @@ -50,6 +50,13 @@ pub enum Error { }, #[error("Due to size restrictions a struct could not be parsed.")] ImpossibleStructError, + #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] + InvalidEnumValueError { + obj: String, + field: String, + value: u64, + type_: String, + }, } #[derive(Debug, Error)] diff --git a/system/gd/packet/parser/packet_def.cc b/system/gd/packet/parser/packet_def.cc index d30be830d3..3fe2218c9a 100644 --- a/system/gd/packet/parser/packet_def.cc +++ b/system/gd/packet/parser/packet_def.cc @@ -929,7 +929,7 @@ void PacketDef::GenRustStructImpls(std::ostream& s) const { } field->GenBoundsCheck(s, start_field_offset, end_field_offset, name_); - field->GenRustGetter(s, start_field_offset, end_field_offset); + field->GenRustGetter(s, start_field_offset, end_field_offset, name_); } auto payload_field = fields_.GetFieldsWithTypes({ diff --git a/system/gd/packet/parser/parent_def.cc b/system/gd/packet/parser/parent_def.cc index e4b7353cb3..0df4a5d3cd 100644 --- a/system/gd/packet/parser/parent_def.cc +++ b/system/gd/packet/parser/parent_def.cc @@ -618,7 +618,7 @@ void ParentDef::GenRustConformanceCheck(std::ostream& s) const { auto end_offset = GetOffsetForField(field->GetName(), true); auto f = (FixedScalarField*)field; - f->GenRustGetter(s, start_offset, end_offset); + f->GenRustGetter(s, start_offset, end_offset, name_); s << "if " << f->GetName() << " != "; f->GenValue(s); s << " { return false; } "; diff --git a/system/gd/packet/parser/struct_def.cc b/system/gd/packet/parser/struct_def.cc index d602e25e9e..4f6e981e58 100644 --- a/system/gd/packet/parser/struct_def.cc +++ b/system/gd/packet/parser/struct_def.cc @@ -384,7 +384,7 @@ void StructDef::GenRustImpls(std::ostream& s) const { } field->GenBoundsCheck(s, start_field_offset, end_field_offset, name_); - field->GenRustGetter(s, start_field_offset, end_field_offset); + field->GenRustGetter(s, start_field_offset, end_field_offset, name_); } fields = fields_.GetFieldsWithoutTypes({ diff --git a/system/gd/packet/parser/test/rust_test_packets.pdl b/system/gd/packet/parser/test/rust_test_packets.pdl index 387a553778..d791979f3d 100644 --- a/system/gd/packet/parser/test/rust_test_packets.pdl +++ b/system/gd/packet/parser/test/rust_test_packets.pdl @@ -1,5 +1,45 @@ little_endian_packets +custom_field Boolean: 8 "Boolean" +enum Enum : 8 { + // Keep 0x0 as invalid value + ONE = 1, + TWO = 2, +} + +struct Struct { + v: Enum, + u: 8, +} + +packet TestEnum { + v: Enum, +} + +packet TestCustomField { + v: Boolean, +} + +packet TestArraySize { + _size_(array) : 8, + array : Struct[], +} + +packet TestArrayCount { + _count_(array) : 8, + array : Struct[], +} + +packet TestPayloadSize { + _size_(_payload_) : 8, + _payload_, +} + +packet TestBodySize { + _size_(_body_) : 8, + _body_, +} + // Test Packets #1 enum OpCode: 8 { ADD_ERR = 0, @@ -122,5 +162,3 @@ test ChildThree { test GrandChildThreeFive { "\x01\x02\x03\x01", } - - diff --git a/system/gd/rust/linux/client/src/dbus_iface.rs b/system/gd/rust/linux/client/src/dbus_iface.rs index 5a93233bba..20b11329f9 100644 --- a/system/gd/rust/linux/client/src/dbus_iface.rs +++ b/system/gd/rust/linux/client/src/dbus_iface.rs @@ -237,8 +237,6 @@ impl BluetoothDBus { } } -trait DBusExportable {} - #[generate_dbus_interface_client] impl IBluetooth for BluetoothDBus { #[dbus_method("RegisterCallback")] diff --git a/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager.rs b/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager.rs index 8daf0b7efb..706fb11113 100644 --- a/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager.rs +++ b/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager.rs @@ -61,6 +61,11 @@ impl BluetoothManager { pub(crate) fn callback_disconnected(&mut self, id: u32) { self.callbacks.remove(&id); } + + pub(crate) fn get_floss_enabled_internal(&mut self) -> bool { + let enabled = self.manager_context.floss_enabled.load(Ordering::Relaxed); + enabled + } } impl IBluetoothManager for BluetoothManager { @@ -115,8 +120,7 @@ impl IBluetoothManager for BluetoothManager { } fn get_floss_enabled(&mut self) -> bool { - let enabled = self.manager_context.floss_enabled.load(Ordering::Relaxed); - enabled + self.get_floss_enabled_internal() } fn set_floss_enabled(&mut self, enabled: bool) { diff --git a/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs b/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs index 9ff9cea800..ee8373d402 100644 --- a/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs +++ b/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs @@ -1,7 +1,7 @@ use dbus::arg::RefArg; use dbus::strings::Path; use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter}; -use dbus_projection::DisconnectWatcher; +use dbus_projection::{dbus_generated, DisconnectWatcher}; use manager_service::iface_bluetooth_manager::{ AdapterWithEnabled, IBluetoothManager, IBluetoothManagerCallback, @@ -22,30 +22,38 @@ struct BluetoothManagerDBus {} #[generate_dbus_exporter(export_bluetooth_manager_dbus_obj, "org.chromium.bluetooth.Manager")] impl IBluetoothManager for BluetoothManagerDBus { #[dbus_method("Start")] - fn start(&mut self, _hci_interface: i32) {} + fn start(&mut self, hci_interface: i32) { + dbus_generated!() + } #[dbus_method("Stop")] - fn stop(&mut self, _hci_interface: i32) {} + fn stop(&mut self, hci_interface: i32) { + dbus_generated!() + } #[dbus_method("GetAdapterEnabled")] - fn get_adapter_enabled(&mut self, _hci_interface: i32) -> bool { - false + fn get_adapter_enabled(&mut self, hci_interface: i32) -> bool { + dbus_generated!() } #[dbus_method("RegisterCallback")] - fn register_callback(&mut self, _callback: Box<dyn IBluetoothManagerCallback + Send>) {} + fn register_callback(&mut self, callback: Box<dyn IBluetoothManagerCallback + Send>) { + dbus_generated!() + } #[dbus_method("GetFlossEnabled")] fn get_floss_enabled(&mut self) -> bool { - false + dbus_generated!() } #[dbus_method("SetFlossEnabled")] - fn set_floss_enabled(&mut self, _enabled: bool) {} + fn set_floss_enabled(&mut self, enabled: bool) { + dbus_generated!() + } #[dbus_method("GetAvailableAdapters")] fn get_available_adapters(&mut self) -> Vec<AdapterWithEnabled> { - vec![] + dbus_generated!() } } diff --git a/system/gd/rust/linux/mgmt/src/bin/btmanagerd/state_machine.rs b/system/gd/rust/linux/mgmt/src/bin/btmanagerd/state_machine.rs index 52b5ff0ed0..aa17c6d27d 100644 --- a/system/gd/rust/linux/mgmt/src/bin/btmanagerd/state_machine.rs +++ b/system/gd/rust/linux/mgmt/src/bin/btmanagerd/state_machine.rs @@ -5,11 +5,12 @@ use log::{debug, error, info, warn}; use nix::sys::signal::{self, Signal}; use nix::unistd::Pid; use regex::Regex; +use std::cmp; use std::process::{Child, Command, Stdio}; use std::sync::Arc; -use std::time::Duration; use tokio::io::unix::AsyncFd; use tokio::sync::mpsc; +use tokio::time::{sleep, Duration}; // Directory for Bluetooth pid file pub const PID_DIR: &str = "/var/run/bluetooth"; @@ -84,6 +85,10 @@ pub struct StateMachineProxy { const TX_SEND_TIMEOUT_DURATION: Duration = Duration::from_secs(3); const COMMAND_TIMEOUT_DURATION: Duration = Duration::from_secs(3); +/// Maximum amount of time (in seconds) we should wait before polling for +/// /sys/class/bluetooth to become available. +const HCI_DEVICE_SLEEP_MAX_SECONDS: u64 = 64; + impl StateMachineProxy { pub fn start_bluetooth(&self, hci_interface: i32) { let tx = self.tx.clone(); @@ -122,8 +127,8 @@ fn pid_inotify_async_fd() -> AsyncFd<inotify::Inotify> { let mut pid_detector = inotify::Inotify::init().expect("cannot use inotify"); pid_detector .add_watch(PID_DIR, inotify::WatchMask::CREATE | inotify::WatchMask::DELETE) - .expect("failed to add watch"); - AsyncFd::new(pid_detector).expect("failed to add async fd") + .expect("failed to add watch on pid directory"); + AsyncFd::new(pid_detector).expect("failed to add async fd for pid detector") } /// Given an pid path, returns the adapter index for that pid path. @@ -132,15 +137,29 @@ fn get_hci_index_from_pid_path(path: &str) -> Option<i32> { re.captures(path)?.get(1)?.as_str().parse().ok() } -fn hci_devices_inotify_async_fd() -> AsyncFd<inotify::Inotify> { - let mut detector = inotify::Inotify::init().expect("cannot use inotify"); - detector - .add_watch( +fn hci_devices_inotify_async_fd() -> Option<AsyncFd<inotify::Inotify>> { + let detector = inotify::Inotify::init().and_then(|mut detector| { + match detector.add_watch( config_util::HCI_DEVICES_DIR, inotify::WatchMask::CREATE | inotify::WatchMask::DELETE, - ) - .expect("failed to add watch"); - AsyncFd::new(detector).expect("failed to add async fd") + ) { + Ok(_) => Ok(detector), + Err(e) => Err(e), + } + }); + match detector { + Ok(d) => match AsyncFd::new(d) { + Ok(afd) => Some(afd), + Err(_) => { + warn!("Could not init asyncfd for {}", config_util::HCI_DEVICES_DIR); + None + } + }, + Err(_) => { + warn!("Could not init inotify: {}", config_util::HCI_DEVICES_DIR); + None + } + } } /// On startup, get and cache all hci devices by emitting the callback @@ -190,6 +209,8 @@ pub async fn mainloop( }); let init_tx = context.tx.clone(); + let floss_enabled = bluetooth_manager.lock().unwrap().get_floss_enabled_internal(); + tokio::spawn(async move { // Get a list of active pid files to determine initial adapter status let files = config_util::list_pid_files(PID_DIR); @@ -203,18 +224,22 @@ pub async fn mainloop( .unwrap(); } - // Initialize adapter states based on saved config - let hci_devices = config_util::list_hci_devices(); - for device in hci_devices.iter() { - let is_enabled = config_util::is_hci_n_enabled(*device); - if is_enabled { - let _ = init_tx - .send_timeout( - Message::AdapterStateChange(AdapterStateActions::StartBluetooth(*device)), - TX_SEND_TIMEOUT_DURATION, - ) - .await - .unwrap(); + // Initialize adapter states based on saved config only if floss is enabled. + if floss_enabled { + let hci_devices = config_util::list_hci_devices(); + for device in hci_devices.iter() { + let is_enabled = config_util::is_hci_n_enabled(*device); + if is_enabled { + let _ = init_tx + .send_timeout( + Message::AdapterStateChange(AdapterStateActions::StartBluetooth( + *device, + )), + TX_SEND_TIMEOUT_DURATION, + ) + .await + .unwrap(); + } } } }); @@ -244,7 +269,7 @@ pub async fn mainloop( .unwrap(); } } - Err(_) | Ok(Err(_)) => panic!("why can't we read while the asyncfd is ready?"), + Err(_) | Ok(Err(_)) => panic!("Inotify watcher on {} failed.", PID_DIR), } fd_ready.clear_ready(); drop(fd_ready); @@ -252,35 +277,67 @@ pub async fn mainloop( }); // Set up an HCI device listener to emit HCI device inotify messages - let mut hci_devices_async_fd = hci_devices_inotify_async_fd(); let hci_tx = context.tx.clone(); tokio::spawn(async move { debug!("Spawned hci notify task"); + + // Try to create an inotify on /sys/class/bluetooth and listen for any + // changes. If we fail to create the inotify, we go into a polling mode + // which will do exponential backoff waiting for Bluetooth to become + // available. + // + // TODO(b/226644782) - Eventually we need to replace this inotify + // listener with something that talks to MGMT via socket(AF_BLUETOOTH). + // We should poll on INDEX_ADDED/INDEX_REMOVED rather than inotify the + // /sys/class/bluetooth directory. + let mut sleep_duration = 1; loop { - let r = hci_devices_async_fd.readable_mut(); - let mut fd_ready = r.await.unwrap(); - let mut buffer: [u8; 1024] = [0; 1024]; - debug!("Found new hci device entries. Reading them."); - match fd_ready.try_io(|inner| inner.get_mut().read_events(&mut buffer)) { - Ok(Ok(events)) => { - for event in events { - let _ = hci_tx - .send_timeout( - Message::HciDeviceChange( - event.mask, - event_name_to_string(event.name), - ), - TX_SEND_TIMEOUT_DURATION, - ) - .await - .unwrap(); + match hci_devices_inotify_async_fd() { + Some(mut hci_inotify) => { + sleep_duration = 1; + + // This inner loop runs successfully as long as the hci inotify is valid. + loop { + let r = hci_inotify.readable_mut(); + let mut fd_ready = r.await.unwrap(); + let mut buffer: [u8; 1024] = [0; 1024]; + debug!("Found new hci device entries. Reading them."); + match fd_ready.try_io(|inner| inner.get_mut().read_events(&mut buffer)) { + Ok(Ok(events)) => { + for event in events { + let _ = hci_tx + .send_timeout( + Message::HciDeviceChange( + event.mask, + event_name_to_string(event.name), + ), + TX_SEND_TIMEOUT_DURATION, + ) + .await + .unwrap(); + } + } + // In the case where inotify fails, we want to reconfigure the inotify + // again. + Err(_) | Ok(Err(_)) => { + warn!( + "Inotify watcher on {} failed.", + config_util::HCI_DEVICES_DIR + ); + break; + } + } + fd_ready.clear_ready(); + drop(fd_ready); } } - Err(_) | Ok(Err(_)) => panic!("why can't we read while the asyncfd is ready?"), + None => { + // Exponential backoff until we succeed. + sleep_duration = cmp::min(sleep_duration * 2, HCI_DEVICE_SLEEP_MAX_SECONDS); + sleep(Duration::from_secs(sleep_duration)).await; + } } - fd_ready.clear_ready(); - drop(fd_ready); } }); @@ -337,7 +394,7 @@ pub async fn mainloop( true => { command_timeout.cancel(); } - false => error!("unexpected BluetoothStarted pid{} hci{}", pid, hci), + false => warn!("unexpected BluetoothStarted pid{} hci{}", pid, hci), } } AdapterStateActions::BluetoothStopped(i) => { @@ -387,9 +444,7 @@ pub async fn mainloop( .await .unwrap(); } - (hci, s) => { - warn!("invalid file hci={:?} pid_file={:?}", hci, s) - } + _ => debug!("Invalid pid path: {}", fname), } } (inotify::EventMask::DELETE, Some(fname)) => { diff --git a/system/gd/rust/linux/service/src/iface_bluetooth.rs b/system/gd/rust/linux/service/src/iface_bluetooth.rs index 9d84b1d3c5..37769b67b1 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth.rs @@ -194,17 +194,17 @@ impl IBluetooth for IBluetoothDBus { } #[dbus_method("CreateBond")] - fn create_bond(&self, _device: BluetoothDevice, _transport: BtTransport) -> bool { + fn create_bond(&self, device: BluetoothDevice, transport: BtTransport) -> bool { dbus_generated!() } #[dbus_method("CancelBondProcess")] - fn cancel_bond_process(&self, _device: BluetoothDevice) -> bool { + fn cancel_bond_process(&self, device: BluetoothDevice) -> bool { dbus_generated!() } #[dbus_method("RemoveBond")] - fn remove_bond(&self, _device: BluetoothDevice) -> bool { + fn remove_bond(&self, device: BluetoothDevice) -> bool { dbus_generated!() } @@ -214,22 +214,22 @@ impl IBluetooth for IBluetoothDBus { } #[dbus_method("GetBondState")] - fn get_bond_state(&self, _device: BluetoothDevice) -> u32 { + fn get_bond_state(&self, device: BluetoothDevice) -> u32 { dbus_generated!() } #[dbus_method("SetPin")] - fn set_pin(&self, _device: BluetoothDevice, _accept: bool, _pin_code: Vec<u8>) -> bool { + fn set_pin(&self, device: BluetoothDevice, accept: bool, pin_code: Vec<u8>) -> bool { dbus_generated!() } #[dbus_method("SetPasskey")] - fn set_passkey(&self, _device: BluetoothDevice, _accept: bool, _passkey: Vec<u8>) -> bool { + fn set_passkey(&self, device: BluetoothDevice, accept: bool, passkey: Vec<u8>) -> bool { dbus_generated!() } #[dbus_method("SetPairingConfirmation")] - fn set_pairing_confirmation(&self, _device: BluetoothDevice, _accept: bool) -> bool { + fn set_pairing_confirmation(&self, device: BluetoothDevice, accept: bool) -> bool { dbus_generated!() } @@ -254,37 +254,37 @@ impl IBluetooth for IBluetoothDBus { } #[dbus_method("GetConnectionState")] - fn get_connection_state(&self, _device: BluetoothDevice) -> u32 { + fn get_connection_state(&self, device: BluetoothDevice) -> u32 { dbus_generated!() } #[dbus_method("GetProfileConnectionState")] - fn get_profile_connection_state(&self, _profile: Profile) -> u32 { + fn get_profile_connection_state(&self, profile: Profile) -> u32 { dbus_generated!() } #[dbus_method("GetRemoteUuids")] - fn get_remote_uuids(&self, _device: BluetoothDevice) -> Vec<Uuid128Bit> { + fn get_remote_uuids(&self, device: BluetoothDevice) -> Vec<Uuid128Bit> { dbus_generated!() } #[dbus_method("FetchRemoteUuids")] - fn fetch_remote_uuids(&self, _device: BluetoothDevice) -> bool { + fn fetch_remote_uuids(&self, device: BluetoothDevice) -> bool { dbus_generated!() } #[dbus_method("SdpSearch")] - fn sdp_search(&self, _device: BluetoothDevice, _uuid: Uuid128Bit) -> bool { + fn sdp_search(&self, device: BluetoothDevice, uuid: Uuid128Bit) -> bool { dbus_generated!() } #[dbus_method("ConnectAllEnabledProfiles")] - fn connect_all_enabled_profiles(&self, _device: BluetoothDevice) -> bool { + fn connect_all_enabled_profiles(&self, device: BluetoothDevice) -> bool { dbus_generated!() } #[dbus_method("DisconnectAllEnabledProfiles")] - fn disconnect_all_enabled_profiles(&self, _device: BluetoothDevice) -> bool { + fn disconnect_all_enabled_profiles(&self, device: BluetoothDevice) -> bool { dbus_generated!() } } diff --git a/system/gd/rust/linux/service/src/iface_bluetooth_gatt.rs b/system/gd/rust/linux/service/src/iface_bluetooth_gatt.rs index 8adf3e71a3..c595fa0749 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth_gatt.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth_gatt.rs @@ -30,7 +30,7 @@ struct BluetoothGattCallbackDBus {} #[dbus_proxy_obj(BluetoothGattCallback, "org.chromium.bluetooth.BluetoothGattCallback")] impl IBluetoothGattCallback for BluetoothGattCallbackDBus { #[dbus_method("OnClientRegistered")] - fn on_client_registered(&self, _status: i32, _scanner_id: i32) { + fn on_client_registered(&self, status: i32, scanner_id: i32) { dbus_generated!() } @@ -142,7 +142,7 @@ struct ScannerCallbackDBus {} #[dbus_proxy_obj(ScannerCallback, "org.chromium.bluetooth.ScannerCallback")] impl IScannerCallback for ScannerCallbackDBus { #[dbus_method("OnScannerRegistered")] - fn on_scanner_registered(&self, _status: i32, _scanner_id: i32) { + fn on_scanner_registered(&self, status: i32, scanner_id: i32) { dbus_generated!() } } diff --git a/system/gd/rust/linux/stack/src/bluetooth_gatt.rs b/system/gd/rust/linux/stack/src/bluetooth_gatt.rs index 92d6cc7e8c..6f2653eb14 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_gatt.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_gatt.rs @@ -1458,6 +1458,8 @@ mod tests { fn unregister(&mut self, _id: u32) -> bool { false } + + fn export_for_rpc(self: Box<Self>) {} } use super::*; diff --git a/system/gd/rust/linux/stack/src/bluetooth_media.rs b/system/gd/rust/linux/stack/src/bluetooth_media.rs index 0f2488aa10..5b7d820460 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_media.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_media.rs @@ -22,9 +22,13 @@ use std::sync::Arc; use std::sync::Mutex; use tokio::sync::mpsc::Sender; +use tokio::task::JoinHandle; +use tokio::time::{sleep, Duration}; use crate::Message; +const DEFAULT_PROFILE_DISCOVERY_TIMEOUT_SEC: u64 = 5; + pub trait IBluetoothMedia { /// fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool; @@ -86,7 +90,7 @@ pub enum MediaActions { pub struct BluetoothMedia { intf: Arc<Mutex<BluetoothInterface>>, initialized: bool, - callbacks: Vec<(u32, Box<dyn IBluetoothMediaCallback + Send>)>, + callbacks: Arc<Mutex<Vec<(u32, Box<dyn IBluetoothMediaCallback + Send>)>>>, callback_last_id: u32, tx: Sender<Message>, a2dp: Option<A2dp>, @@ -95,6 +99,8 @@ pub struct BluetoothMedia { hfp: Option<Hfp>, hfp_states: HashMap<RawAddress, BthfConnectionState>, selectable_caps: HashMap<RawAddress, Vec<A2dpCodecConfig>>, + hfp_caps: HashMap<RawAddress, HfpCodecCapability>, + device_added_tasks: Arc<Mutex<HashMap<RawAddress, Option<JoinHandle<()>>>>>, } impl BluetoothMedia { @@ -102,7 +108,7 @@ impl BluetoothMedia { BluetoothMedia { intf, initialized: false, - callbacks: vec![], + callbacks: Arc::new(Mutex::new(vec![])), callback_last_id: 0, tx, a2dp: None, @@ -111,6 +117,8 @@ impl BluetoothMedia { hfp: None, hfp_states: HashMap::new(), selectable_caps: HashMap::new(), + hfp_caps: HashMap::new(), + device_added_tasks: Arc::new(Mutex::new(HashMap::new())), } } @@ -124,36 +132,20 @@ impl BluetoothMedia { } match state { BtavConnectionState::Connected => { - if let Some(caps) = self.selectable_caps.get(&addr) { - for cap in caps { - // TODO: support codecs other than SBC. - if A2dpCodecIndex::SrcSbc != A2dpCodecIndex::from(cap.codec_type) { - continue; - } - - // TODO: Coordinate with HFP. Should only trigger once. - self.for_all_callbacks(|callback| { - callback.on_bluetooth_audio_device_added( - addr.to_string(), - cap.sample_rate, - cap.bits_per_sample, - cap.channel_mode, - HfpCodecCapability::UNSUPPORTED.bits(), - ); - }); - return; - } - } + info!("[{}]: a2dp connected.", addr.to_string()); + self.notify_media_capability_added(addr); + self.a2dp_states.insert(addr, state); } - BtavConnectionState::Connecting => {} - BtavConnectionState::Disconnected => { - self.for_all_callbacks(|callback| { - callback.on_bluetooth_audio_device_removed(addr.to_string()); - }); + BtavConnectionState::Disconnected => match self.a2dp_states.remove(&addr) { + Some(_) => self.notify_media_capability_removed(addr), + None => { + warn!("[{}]: Unknown address a2dp disconnected.", addr.to_string()); + } + }, + _ => { + self.a2dp_states.insert(addr, state); } - BtavConnectionState::Disconnecting => {} - }; - self.a2dp_states.insert(addr, state); + } } A2dpCallbacks::AudioState(_addr, _state) => {} A2dpCallbacks::AudioConfig(addr, _config, _local_caps, selectable_caps) => { @@ -195,29 +187,29 @@ impl BluetoothMedia { } match state { BthfConnectionState::Connected => { - info!("{} HFP connected.", addr.to_string()); + info!("[{}]: hfp connected.", addr.to_string()); } BthfConnectionState::SlcConnected => { - info!("{} HFP SLC connected.", addr.to_string()); - // TODO: Coordinate with A2DP. Should only trigger once. - self.for_all_callbacks(|callback| { - callback.on_bluetooth_audio_device_added( - addr.to_string(), - 0, - 0, - 0, - HfpCodecCapability::CVSD.bits(), - ); - }); + info!("[{}]: hfp slc connected.", addr.to_string()); + // TODO(b/214148074): Support WBS + self.hfp_caps.insert(addr, HfpCodecCapability::CVSD); + self.notify_media_capability_added(addr); } BthfConnectionState::Disconnected => { - info!("{} HFP disconnected.", addr.to_string()); + info!("[{}]: hfp disconnected.", addr.to_string()); + match self.hfp_states.remove(&addr) { + Some(_) => self.notify_media_capability_removed(addr), + None => { + warn!("[{}] Unknown address hfp disconnected.", addr.to_string()) + } + } + return; } BthfConnectionState::Connecting => { - info!("{} HFP connecting.", addr.to_string()); + info!("[{}]: hfp connecting.", addr.to_string()); } BthfConnectionState::Disconnecting => { - info!("{} HFP disconnecting.", addr.to_string()); + info!("[{}]: hfp disconnecting.", addr.to_string()); } } @@ -227,29 +219,141 @@ impl BluetoothMedia { if self.hfp_states.get(&addr).is_none() || BthfConnectionState::SlcConnected != *self.hfp_states.get(&addr).unwrap() { - warn!("{} not connected or SLC not ready", addr.to_string()); + warn!("[{}]: Unknown address hfp or slc not ready", addr.to_string()); return; } match state { BthfAudioState::Connected => { - info!("{} HFP audio connected.", addr.to_string()); + info!("[{}]: hfp audio connected.", addr.to_string()); } BthfAudioState::Disconnected => { - info!("{} HFP audio disconnected.", addr.to_string()); + info!("[{}]: hfp audio disconnected.", addr.to_string()); } BthfAudioState::Connecting => { - info!("{} HFP audio connecting.", addr.to_string()); + info!("[{}]: hfp audio connecting.", addr.to_string()); } BthfAudioState::Disconnecting => { - info!("{} HFP audio disconnecting.", addr.to_string()); + info!("[{}]: hfp audio disconnecting.", addr.to_string()); + } + } + } + } + } + + fn notify_media_capability_added(&self, addr: RawAddress) { + // Return true if the device added message is sent by the call. + fn dedup_added_cb( + device_added_tasks: Arc<Mutex<HashMap<RawAddress, Option<JoinHandle<()>>>>>, + addr: RawAddress, + callbacks: Arc<Mutex<Vec<(u32, Box<dyn IBluetoothMediaCallback + Send>)>>>, + cap: A2dpCodecConfig, + hfp_cap: HfpCodecCapability, + is_delayed: bool, + ) -> bool { + // Closure used to lock and trigger the device added callbacks. + let trigger_device_added = || { + for callback in &*callbacks.lock().unwrap() { + callback.1.on_bluetooth_audio_device_added( + addr.to_string(), + cap.sample_rate, + cap.bits_per_sample, + cap.channel_mode, + hfp_cap.bits(), + ); + } + }; + let mut guard = device_added_tasks.lock().unwrap(); + let task = guard.insert(addr, None); + match task { + // None handler means the device has just been added + Some(handler) if handler.is_none() => { + warn!("[{}]: A device with the same address has been added.", addr.to_string()); + false + } + // Not None handler means there is a pending task. + Some(handler) => { + trigger_device_added(); + + // Abort the delayed callback if the caller is not delayed. + // Otherwise, it is the delayed callback task itself. + // The abort call can be out of the critical section as we + // have updated the device_added_tasks and send the message. + drop(guard); + if !is_delayed { + handler.unwrap().abort(); } + true } + // The delayed callback task has been removed and couldn't be found. + None if is_delayed => false, + // No delayed callback and the device hasn't been added. + None => { + trigger_device_added(); + true + } + } + } + + let cur_a2dp_cap = self.selectable_caps.get(&addr).and_then(|a2dp_caps| { + a2dp_caps + .iter() + .find(|cap| A2dpCodecIndex::SrcSbc == A2dpCodecIndex::from(cap.codec_type)) + }); + let cur_hfp_cap = self.hfp_caps.get(&addr); + match (cur_a2dp_cap, cur_hfp_cap) { + (None, None) => warn!( + "[{}]: Try to add a device without a2dp and hfp capability.", + addr.to_string() + ), + (Some(cap), Some(hfp_cap)) => { + dedup_added_cb( + self.device_added_tasks.clone(), + addr, + self.callbacks.clone(), + *cap, + *hfp_cap, + false, + ); } + (_, _) => { + let mut guard = self.device_added_tasks.lock().unwrap(); + if guard.get(&addr).is_none() { + let callbacks = self.callbacks.clone(); + let device_added_tasks = self.device_added_tasks.clone(); + let cap = cur_a2dp_cap.unwrap_or(&A2dpCodecConfig::default()).clone(); + let hfp_cap = cur_hfp_cap.unwrap_or(&HfpCodecCapability::UNSUPPORTED).clone(); + let task = topstack::get_runtime().spawn(async move { + sleep(Duration::from_secs(DEFAULT_PROFILE_DISCOVERY_TIMEOUT_SEC)).await; + if dedup_added_cb(device_added_tasks, addr, callbacks, cap, hfp_cap, true) { + warn!( + "[{}]: Add a device with only hfp or a2dp capability after timeout.", + addr.to_string() + ); + } + }); + guard.insert(addr, Some(task)); + } + } + } + } + + fn notify_media_capability_removed(&self, addr: RawAddress) { + if let Some(task) = self.device_added_tasks.lock().unwrap().remove(&addr) { + match task { + // Abort what is pending + Some(handler) => handler.abort(), + // This addr has been added so tell audio server to remove it + None => self.for_all_callbacks(|callback| { + callback.on_bluetooth_audio_device_removed(addr.to_string()); + }), + } + } else { + warn!("[{}]: Device hasn't been added yet.", addr.to_string()); } } fn for_all_callbacks<F: Fn(&Box<dyn IBluetoothMediaCallback + Send>)>(&self, f: F) { - for callback in &self.callbacks { + for callback in &*self.callbacks.lock().unwrap() { f(&callback.1); } } @@ -305,7 +409,7 @@ fn get_hfp_dispatcher(tx: Sender<Message>) -> HfpCallbacksDispatcher { impl IBluetoothMedia for BluetoothMedia { fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool { self.callback_last_id += 1; - self.callbacks.push((self.callback_last_id, callback)); + self.callbacks.lock().unwrap().push((self.callback_last_id, callback)); true } diff --git a/system/gd/rust/packets/test_lib.rs b/system/gd/rust/packets/test_lib.rs index d689572c30..960178c81d 100644 --- a/system/gd/rust/packets/test_lib.rs +++ b/system/gd/rust/packets/test_lib.rs @@ -4,10 +4,98 @@ #![allow(unused)] #![allow(missing_docs)] -pub mod custom_types; +use std::convert::TryFrom; +use std::fmt; -pub mod hci { - use crate::custom_types::*; +pub mod test_packets { + + // Custom boolean type + #[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)] + pub struct Boolean { + pub value: u8, + } + + impl fmt::Display for Boolean { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:02x}", self.value) + } + } + + #[derive(Debug, Clone)] + pub struct InvalidBooleanError; + + impl TryFrom<&[u8]> for Boolean { + type Error = InvalidBooleanError; + + fn try_from(slice: &[u8]) -> std::result::Result<Self, Self::Error> { + if slice.len() != 1 || slice[0] > 1 { + Err(InvalidBooleanError) + } else { + Ok(Boolean { value: slice[0] }) + } + } + } + + impl From<Boolean> for [u8; 1] { + fn from(b: Boolean) -> [u8; 1] { + [b.value] + } + } include!(concat!(env!("OUT_DIR"), "/rust_test_packets.rs")); } + +#[cfg(test)] +pub mod test { + use crate::test_packets::*; + + #[test] + fn test_invalid_enum_field_value() { + // 0x0 is not a recognized Enum value. + let input = [0x0]; + let res = TestEnumPacket::parse(&input); + assert!(res.is_err()); + } + + #[test] + fn test_invalid_custom_field_value() { + // 0x2 is not a recognized Boolean value. + let input = [0x2]; + let res = TestCustomFieldPacket::parse(&input); + assert!(res.is_err()); + } + + #[test] + fn test_invalid_array_size() { + // Size 4, have 2. + let input = [0x4, 0x0, 0x0]; + let res = TestArraySizePacket::parse(&input); + assert!(res.is_err()); + } + + #[test] + fn test_invalid_array_count() { + // Count 2, have 1. + let input = [0x2, 0x0, 0x0]; + let res = TestArrayCountPacket::parse(&input); + assert!(res.is_err()); + } + + #[test] + fn test_invalid_payload_size() { + // Size 2, have 1. + let input = [0x2, 0x0]; + let res = TestPayloadSizePacket::parse(&input); + assert!(res.is_err()); + } + + #[test] + fn test_invalid_body_size() { + // Size 2, have 1. + // Body does not have a concrete representation, + // the size and payload are both discarded. + let input = [0x2, 0x0]; + let res = TestBodySizePacket::parse(&input); + assert!(res.is_ok()); + } +} diff --git a/system/gd/rust/topshim/src/profiles/a2dp.rs b/system/gd/rust/topshim/src/profiles/a2dp.rs index d2c31a5589..96764454bd 100644 --- a/system/gd/rust/topshim/src/profiles/a2dp.rs +++ b/system/gd/rust/topshim/src/profiles/a2dp.rs @@ -133,7 +133,7 @@ pub mod ffi { address: [u8; 6], } - #[derive(Debug)] + #[derive(Debug, Copy, Clone)] pub struct A2dpCodecConfig { codec_type: i32, codec_priority: i32, diff --git a/system/include/hardware/bt_le_audio.h b/system/include/hardware/bt_le_audio.h index 3b61399f9d..8276986d48 100644 --- a/system/include/hardware/bt_le_audio.h +++ b/system/include/hardware/bt_le_audio.h @@ -145,8 +145,6 @@ class LeAudioClientInterface { btle_audio_codec_config_t output_codec_config) = 0; }; -static constexpr uint8_t INSTANCE_ID_UNDEFINED = 0xFF; - /* Represents the broadcast source state. */ enum class BroadcastState { STOPPED = 0, @@ -162,25 +160,21 @@ enum class BroadcastAudioProfile { MEDIA, }; -constexpr uint8_t kBroadcastAnnouncementBroadcastIdSize = 3; -using BroadcastId = std::array<uint8_t, kBroadcastAnnouncementBroadcastIdSize>; -constexpr BroadcastId kBroadcastBroadcastIdInvalid = {0, 0, 0}; +using BroadcastId = uint32_t; +static constexpr BroadcastId kBroadcastIdInvalid = 0x00000000; using BroadcastCode = std::array<uint8_t, 16>; class LeAudioBroadcasterCallbacks { public: virtual ~LeAudioBroadcasterCallbacks() = default; /* Callback for the newly created broadcast event. */ - virtual void OnBroadcastCreated(uint8_t instance_id, bool success) = 0; + virtual void OnBroadcastCreated(uint32_t broadcast_id, bool success) = 0; /* Callback for the destroyed broadcast event. */ - virtual void OnBroadcastDestroyed(uint8_t instance_id) = 0; + virtual void OnBroadcastDestroyed(uint32_t broadcast_id) = 0; /* Callback for the broadcast source state event. */ - virtual void OnBroadcastStateChanged(uint8_t instance_id, + virtual void OnBroadcastStateChanged(uint32_t broadcast_id, BroadcastState state) = 0; - /* Callback for the broadcaster identifier. */ - virtual void OnBroadcastId(uint8_t instance_id, - const BroadcastId& broadcast_id) = 0; }; class LeAudioBroadcasterInterface { @@ -197,19 +191,17 @@ class LeAudioBroadcasterInterface { BroadcastAudioProfile profile, std::optional<BroadcastCode> broadcast_code) = 0; /* Update the ongoing Broadcast metadata */ - virtual void UpdateMetadata(uint8_t instance_id, + virtual void UpdateMetadata(uint32_t broadcast_id, std::vector<uint8_t> metadata) = 0; /* Start the existing Broadcast stream */ - virtual void StartBroadcast(uint8_t instance_id) = 0; + virtual void StartBroadcast(uint32_t broadcast_id) = 0; /* Pause the ongoing Broadcast stream */ - virtual void PauseBroadcast(uint8_t instance_id) = 0; + virtual void PauseBroadcast(uint32_t broadcast_id) = 0; /* Stop the Broadcast (no stream, no periodic advertisements */ - virtual void StopBroadcast(uint8_t instance_id) = 0; + virtual void StopBroadcast(uint32_t broadcast_id) = 0; /* Destroy the existing Broadcast instance */ - virtual void DestroyBroadcast(uint8_t instance_id) = 0; - /* Get Broadcasts identifier */ - virtual void GetBroadcastId(uint8_t instance_id) = 0; + virtual void DestroyBroadcast(uint32_t broadcast_id) = 0; /* Get all broadcast states */ virtual void GetAllBroadcastStates(void) = 0; diff --git a/system/main/shim/acl.cc b/system/main/shim/acl.cc index b635424ac8..613bf70122 100644 --- a/system/main/shim/acl.cc +++ b/system/main/shim/acl.cc @@ -1505,7 +1505,7 @@ void shim::legacy::Acl::OnLeConnectSuccess( RawAddress local_rpa = RawAddress::kEmpty; /* TODO enhanced */ RawAddress peer_rpa = RawAddress::kEmpty; /* TODO enhanced */ - uint8_t peer_addr_type = 0; /* TODO public */ + tBLE_ADDR_TYPE peer_addr_type = BLE_ADDR_PUBLIC; /* TODO public */ // Once an le connection has successfully been established // the device address is removed from the controller accept list. diff --git a/system/main/shim/acl_api.cc b/system/main/shim/acl_api.cc index 878d47002b..09b1823f2c 100644 --- a/system/main/shim/acl_api.cc +++ b/system/main/shim/acl_api.cc @@ -102,11 +102,11 @@ void bluetooth::shim::ACL_IgnoreAllLeConnections() { void bluetooth::shim::ACL_ReadConnectionAddress(const RawAddress& pseudo_addr, RawAddress& conn_addr, - uint8_t* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type) { auto local_address = Stack::GetInstance()->GetAcl()->GetConnectionLocalAddress(pseudo_addr); conn_addr = ToRawAddress(local_address.GetAddress()); - *p_addr_type = static_cast<uint8_t>(local_address.GetAddressType()); + *p_addr_type = static_cast<tBLE_ADDR_TYPE>(local_address.GetAddressType()); } void bluetooth::shim::ACL_AddToAddressResolution( diff --git a/system/main/shim/acl_api.h b/system/main/shim/acl_api.h index 42f7808ca1..b7688b9b4a 100644 --- a/system/main/shim/acl_api.h +++ b/system/main/shim/acl_api.h @@ -39,7 +39,8 @@ void ACL_Shutdown(); void ACL_IgnoreAllLeConnections(); void ACL_ReadConnectionAddress(const RawAddress& pseudo_addr, - RawAddress& conn_addr, uint8_t* p_addr_type); + RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type); void ACL_AddToAddressResolution(const tBLE_BD_ADDR& legacy_address_with_type, const Octet16& peer_irk, diff --git a/system/main/shim/acl_legacy_interface.h b/system/main/shim/acl_legacy_interface.h index 226b00e8f7..040f013341 100644 --- a/system/main/shim/acl_legacy_interface.h +++ b/system/main/shim/acl_legacy_interface.h @@ -45,7 +45,7 @@ typedef struct { tHCI_ROLE role, uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout, const RawAddress& local_rpa, const RawAddress& peer_rpa, - uint8_t peer_addr_type); + tBLE_ADDR_TYPE peer_addr_type); void (*on_failed)(const tBLE_BD_ADDR& address_with_type, uint16_t handle, bool enhanced, tHCI_STATUS status); void (*on_disconnected)(tHCI_STATUS status, uint16_t handle, diff --git a/system/main/shim/btm.cc b/system/main/shim/btm.cc index 29827208d3..422c1a2dff 100644 --- a/system/main/shim/btm.cc +++ b/system/main/shim/btm.cc @@ -18,6 +18,8 @@ #include "main/shim/btm.h" +#include <base/logging.h> + #include <algorithm> #include <chrono> #include <cstddef> @@ -40,12 +42,11 @@ #include "main/shim/shim.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_int_types.h" +#include "types/ble_address_with_type.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" -#include <base/logging.h> - extern tBTM_CB btm_cb; static constexpr size_t kRemoteDeviceNameLength = 248; @@ -60,10 +61,11 @@ extern void btm_process_inq_complete(tHCI_STATUS status, uint8_t result_type); extern void btm_ble_process_adv_addr(RawAddress& raw_address, tBLE_ADDR_TYPE* address_type); extern void btm_ble_process_adv_pkt_cont( - uint16_t event_type, uint8_t address_type, const RawAddress& raw_address, - uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, - int8_t tx_power, int8_t rssi, uint16_t periodic_adv_int, uint8_t data_len, - const uint8_t* data, const RawAddress& original_bda); + uint16_t event_type, tBLE_ADDR_TYPE address_type, + const RawAddress& raw_address, uint8_t primary_phy, uint8_t secondary_phy, + uint8_t advertising_sid, int8_t tx_power, int8_t rssi, + uint16_t periodic_adv_int, uint8_t data_len, const uint8_t* data, + const RawAddress& original_bda); extern void btm_api_process_inquiry_result(const RawAddress& raw_address, uint8_t page_scan_rep_mode, @@ -676,7 +678,7 @@ hci::AddressWithType Btm::GetAddressAndType(const RawAddress& bd_addr) { p_dev_rec->ble.identity_address_with_type.type); } else { return ToAddressWithType(p_dev_rec->ble.pseudo_addr, - p_dev_rec->ble.ble_addr_type); + p_dev_rec->ble.AddressType()); } } LOG(ERROR) << "Unknown bd_addr. Use public address"; diff --git a/system/main/shim/btm_api.cc b/system/main/shim/btm_api.cc index 646a67cab0..6e799313f3 100644 --- a/system/main/shim/btm_api.cc +++ b/system/main/shim/btm_api.cc @@ -40,6 +40,7 @@ #include "stack/btm/btm_int_types.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_octets.h" +#include "types/ble_address_with_type.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -897,12 +898,6 @@ void bluetooth::shim::BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16) { CHECK(p_eir_uuid != nullptr); } -void bluetooth::shim::BTM_RemoveEirService(uint32_t* p_eir_uuid, - uint16_t uuid16) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - CHECK(p_eir_uuid != nullptr); -} - void bluetooth::shim::BTM_SecAddBleDevice(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type) { @@ -1236,8 +1231,8 @@ void bluetooth::shim::BTM_ConfirmReqReply(tBTM_STATUS res, const RawAddress& bd_addr) { // Send for both Classic and LE until we can determine the type bool accept = res == BTM_SUCCESS; - hci::AddressWithType address = ToAddressWithType(bd_addr, 0); - hci::AddressWithType address2 = ToAddressWithType(bd_addr, 1); + hci::AddressWithType address = ToAddressWithType(bd_addr, BLE_ADDR_PUBLIC); + hci::AddressWithType address2 = ToAddressWithType(bd_addr, BLE_ADDR_RANDOM); auto security_manager = bluetooth::shim::GetSecurityModule()->GetSecurityManager(); if (ShimUi::GetInstance()->waiting_for_pairing_prompt_) { diff --git a/system/main/shim/btm_api.h b/system/main/shim/btm_api.h index 3117c42351..91dc6b6f14 100644 --- a/system/main/shim/btm_api.h +++ b/system/main/shim/btm_api.h @@ -336,21 +336,6 @@ void BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16); /******************************************************************************* * - * Function BTM_RemoveEirService - * - * Description This function is called to remove a service from the bit map - * UUID list. - * - * Parameters p_eir_uuid - bit mask of UUID list for EIR - * uuid16 - UUID 16-bit - * - * Returns None - * - ******************************************************************************/ -void BTM_RemoveEirService(uint32_t* p_eir_uuid, uint16_t uuid16); - -/******************************************************************************* - * * Function BTM_SecAddBleDevice * * Description Add/modify device. This function will be normally called diff --git a/system/main/shim/l2c_api.cc b/system/main/shim/l2c_api.cc index 42115cd0b6..ecbe502b83 100644 --- a/system/main/shim/l2c_api.cc +++ b/system/main/shim/l2c_api.cc @@ -18,6 +18,8 @@ #include "main/shim/l2c_api.h" +#include <base/logging.h> + #include <future> #include <unordered_map> #include <unordered_set> @@ -42,10 +44,9 @@ #include "stack/include/btu.h" #include "stack/include/gatt_api.h" #include "stack/include/sco_hci_link_interface.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" -#include <base/logging.h> - extern void gatt_notify_conn_update(const RawAddress& remote, uint16_t interval, uint16_t latency, uint16_t timeout, tHCI_STATUS status); @@ -1200,7 +1201,8 @@ bool L2CA_IsLeLink(uint16_t acl_handle) { } void L2CA_ReadConnectionAddr(const RawAddress& pseudo_addr, - RawAddress& conn_addr, uint8_t* p_addr_type) { + RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type) { auto* helper = &le_fixed_channel_helper_.find(kSmpCid)->second; auto channel = helper->channels_.find(ToGdAddress(pseudo_addr)); if (channel == helper->channels_.end() || channel->second == nullptr) { @@ -1209,12 +1211,12 @@ void L2CA_ReadConnectionAddr(const RawAddress& pseudo_addr, } auto local = channel->second->GetLinkOptions()->GetLocalAddress(); conn_addr = ToRawAddress(local.GetAddress()); - *p_addr_type = static_cast<uint8_t>(local.GetAddressType()); + *p_addr_type = static_cast<tBLE_ADDR_TYPE>(local.GetAddressType()); } bool L2CA_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr, RawAddress& conn_addr, - uint8_t* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type) { auto remote = ToGdAddress(pseudo_addr); if (le_link_property_listener_shim_.info_.count(remote) == 0) { LOG(ERROR) << __func__ << ": Unknown address"; diff --git a/system/main/shim/l2c_api.h b/system/main/shim/l2c_api.h index a100cea862..0fe3fbd1ed 100644 --- a/system/main/shim/l2c_api.h +++ b/system/main/shim/l2c_api.h @@ -22,6 +22,7 @@ #include "stack/include/bt_hdr.h" #include "stack/include/l2c_api.h" +#include "types/ble_address_with_type.h" #include "types/hci_role.h" #include "types/raw_address.h" @@ -484,10 +485,12 @@ uint16_t L2CA_GetNumLinks(); bool L2CA_IsLeLink(uint16_t acl_handle); void L2CA_ReadConnectionAddr(const RawAddress& pseudo_addr, - RawAddress& conn_addr, uint8_t* p_addr_type); + RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type); bool L2CA_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr, - RawAddress& conn_addr, uint8_t* p_addr_type); + RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type); } // namespace shim } // namespace bluetooth diff --git a/system/main/shim/le_advertising_manager.cc b/system/main/shim/le_advertising_manager.cc index e0bccabdf3..54508f6e48 100644 --- a/system/main/shim/le_advertising_manager.cc +++ b/system/main/shim/le_advertising_manager.cc @@ -59,9 +59,9 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, bluetooth::shim::GetAdvertising()->RegisterAdvertisingCallback(this); } - // nobody use this function void RegisterAdvertiser(IdStatusCallback cb) override { LOG(INFO) << __func__ << " in shim layer"; + bluetooth::shim::GetAdvertising()->RegisterAdvertiser(cb); } void Unregister(uint8_t advertiser_id) override { @@ -73,6 +73,7 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, void GetOwnAddress(uint8_t advertiser_id, GetAddressCallback cb) override { LOG(INFO) << __func__ << " in shim layer"; + address_callbacks_[advertiser_id] = cb; bluetooth::shim::GetAdvertising()->GetOwnAddress(advertiser_id); } @@ -123,6 +124,41 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, std::vector<uint8_t> scan_response_data, int timeout_s, MultiAdvCb timeout_cb) override { LOG(INFO) << __func__ << " in shim layer"; + + bluetooth::hci::ExtendedAdvertisingConfig config{}; + parse_parameter(config, params); + + size_t offset = 0; + while (offset < advertise_data.size()) { + GapData gap_data; + uint8_t len = advertise_data[offset]; + auto begin = advertise_data.begin() + offset; + auto end = begin + len + 1; // 1 byte for len + auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end); + bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet( + data_copy); + GapData::Parse(&gap_data, packet.begin()); + config.advertisement.push_back(gap_data); + offset += len + 1; // 1 byte for len + } + + offset = 0; + while (offset < scan_response_data.size()) { + GapData gap_data; + uint8_t len = scan_response_data[offset]; + auto begin = scan_response_data.begin() + offset; + auto end = begin + len + 1; // 1 byte for len + auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end); + bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet( + data_copy); + GapData::Parse(&gap_data, packet.begin()); + config.scan_response.push_back(gap_data); + offset += len + 1; // 1 byte for len + } + + bluetooth::shim::GetAdvertising()->StartAdvertising( + advertiser_id, config, timeout_s * 100, cb, timeout_cb, scan_callback, + set_terminated_callback, bluetooth::shim::GetGdShimHandler()); } void StartAdvertisingSet(int reg_id, IdTxPowerStatusCallback register_cb, @@ -331,6 +367,11 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, void OnOwnAddressRead(uint8_t advertiser_id, uint8_t address_type, bluetooth::hci::Address address) { RawAddress raw_address = bluetooth::ToRawAddress(address); + if (address_callbacks_.find(advertiser_id) != address_callbacks_.end()) { + address_callbacks_[advertiser_id].Run(address_type, raw_address); + address_callbacks_.erase(advertiser_id); + return; + } do_in_jni_thread(FROM_HERE, base::Bind(&AdvertisingCallbacks::OnOwnAddressRead, base::Unretained(advertising_callbacks_), @@ -368,6 +409,7 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, // TODO set own_address_type based on address policy config.own_address_type = OwnAddressType::RANDOM_DEVICE_ADDRESS; } + std::map<uint8_t, GetAddressCallback> address_callbacks_; }; BleAdvertiserInterfaceImpl* bt_le_advertiser_instance = nullptr; diff --git a/system/main/shim/le_scanning_manager.cc b/system/main/shim/le_scanning_manager.cc index 7bd81e30bc..c4b957129b 100644 --- a/system/main/shim/le_scanning_manager.cc +++ b/system/main/shim/le_scanning_manager.cc @@ -42,6 +42,7 @@ #include "storage/device.h" #include "storage/le_device.h" #include "storage/storage_module.h" +#include "types/ble_address_with_type.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -92,10 +93,10 @@ class DefaultScanningCallback : public ::ScanningCallbacks { extern ::ScanningCallbacks* bluetooth::shim::default_scanning_callback; extern void btm_ble_process_adv_pkt_cont_for_inquiry( - uint16_t event_type, uint8_t address_type, const RawAddress& raw_address, - uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, - int8_t tx_power, int8_t rssi, uint16_t periodic_adv_int, - std::vector<uint8_t> advertising_data); + uint16_t event_type, tBLE_ADDR_TYPE address_type, + const RawAddress& raw_address, uint8_t primary_phy, uint8_t secondary_phy, + uint8_t advertising_sid, int8_t tx_power, int8_t rssi, + uint16_t periodic_adv_int, std::vector<uint8_t> advertising_data); extern void btif_dm_update_ble_remote_properties(const RawAddress& bd_addr, BD_NAME bd_name, @@ -492,6 +493,7 @@ bool BleScannerInterfaceImpl::parse_filter_command( apcf_command.data.begin(), apcf_command.data.end()); advertising_packet_content_filter_command.data_mask.assign( apcf_command.data_mask.begin(), apcf_command.data_mask.end()); + advertising_packet_content_filter_command.irk = apcf_command.irk; return true; } diff --git a/system/main/test/main_shim_test.cc b/system/main/test/main_shim_test.cc index 602a559ac7..039254ecc8 100644 --- a/system/main/test/main_shim_test.cc +++ b/system/main/test/main_shim_test.cc @@ -118,7 +118,7 @@ void mock_connection_le_on_connected( const tBLE_BD_ADDR& address_with_type, uint16_t handle, tHCI_ROLE role, uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout, const RawAddress& local_rpa, const RawAddress& peer_rpa, - uint8_t peer_addr_type) { + tBLE_ADDR_TYPE peer_addr_type) { mock_function_count_map[__func__]++; } void mock_connection_le_on_failed(const tBLE_BD_ADDR& address_with_type, diff --git a/system/osi/src/config.cc b/system/osi/src/config.cc index bdc695cd65..9ebe076e8e 100644 --- a/system/osi/src/config.cc +++ b/system/osi/src/config.cc @@ -495,8 +495,8 @@ static bool config_parse(FILE* fp, config_t* config) { CHECK(config != nullptr); int line_num = 0; - char line[1024]; - char section[1024]; + char line[4096]; + char section[4096]; strcpy(section, CONFIG_DEFAULT_SECTION); while (fgets(line, sizeof(line), fp)) { @@ -513,7 +513,7 @@ static bool config_parse(FILE* fp, config_t* config) { << line_num; return false; } - strncpy(section, line_ptr + 1, len - 2); // NOLINT (len < 1024) + strncpy(section, line_ptr + 1, len - 2); // NOLINT (len < 4096) section[len - 2] = '\0'; } else { char* split = strchr(line_ptr, '='); diff --git a/system/stack/Android.bp b/system/stack/Android.bp index 744a342ce1..8ab335ba74 100644 --- a/system/stack/Android.bp +++ b/system/stack/Android.bp @@ -293,6 +293,7 @@ cc_test { srcs: [ ":TestCommonMockFunctions", ":TestMockHci", + ":TestMockStackMetrics", "rfcomm/port_api.cc", "rfcomm/port_rfc.cc", "rfcomm/port_utils.cc", diff --git a/system/stack/a2dp/a2dp_vendor.cc b/system/stack/a2dp/a2dp_vendor.cc index b1bd5f65e7..d6bc28ad59 100644 --- a/system/stack/a2dp/a2dp_vendor.cc +++ b/system/stack/a2dp/a2dp_vendor.cc @@ -22,6 +22,8 @@ #include "a2dp_vendor.h" +#include <dlfcn.h> + #include "a2dp_vendor_aptx.h" #include "a2dp_vendor_aptx_hd.h" #include "a2dp_vendor_ldac.h" @@ -664,3 +666,23 @@ std::string A2DP_VendorCodecInfoString(const uint8_t* p_codec_info) { return "Unsupported codec vendor_id: " + loghex(vendor_id) + " codec_id: " + loghex(codec_id); } + +void* A2DP_VendorCodecLoadExternalLib(const std::vector<std::string>& lib_paths, + const std::string& friendly_name) { + std::string lib_path_error_list = ""; + for (auto lib_path : lib_paths) { + void* lib_handle = dlopen(lib_path.c_str(), RTLD_NOW); + if (lib_handle != NULL) { + LOG(INFO) << __func__ << "Library found: " << friendly_name << " with [" + << lib_path << "]." + << " (Tested libs: " << lib_path_error_list << ")"; + return lib_handle; + } + lib_path_error_list += "[ Err: "; + lib_path_error_list += dlerror(); + lib_path_error_list += " ], "; + } + LOG(ERROR) << __func__ << "Failed to open library: " << friendly_name + << ". (Tested libs: " << lib_path_error_list << ")"; + return nullptr; +} diff --git a/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc index 32929c2f09..4305d6cd01 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc @@ -38,7 +38,8 @@ // // The aptX encoder shared library, and the functions to use // -static const char* APTX_ENCODER_LIB_NAME = "libaptX_encoder.so"; +static const std::string APTX_ENCODER_LIB_NAME = "libaptX_encoder.so"; + static void* aptx_encoder_lib_handle = NULL; static const char* APTX_ENCODER_INIT_NAME = "aptxbtenc_init"; @@ -111,14 +112,22 @@ static size_t aptx_encode_16bit(tAPTX_FRAMING_PARAMS* framing_params, size_t* data_out_index, uint16_t* data16_in, uint8_t* data_out); +static const std::vector<std::string> APTX_ENCODER_LIB_PATHS = { + APTX_ENCODER_LIB_NAME, +#ifdef __LP64__ + "/system_ext/lib64/" + APTX_ENCODER_LIB_NAME, +#else + "/system_ext/lib/" + APTX_ENCODER_LIB_NAME, +#endif +}; + bool A2DP_VendorLoadEncoderAptx(void) { if (aptx_encoder_lib_handle != NULL) return true; // Already loaded // Open the encoder library - aptx_encoder_lib_handle = dlopen(APTX_ENCODER_LIB_NAME, RTLD_NOW); - if (aptx_encoder_lib_handle == NULL) { - LOG_ERROR("%s: cannot open aptX encoder library %s: %s", __func__, - APTX_ENCODER_LIB_NAME, dlerror()); + aptx_encoder_lib_handle = + A2DP_VendorCodecLoadExternalLib(APTX_ENCODER_LIB_PATHS, "aptX encoder"); + if (!aptx_encoder_lib_handle) { return false; } diff --git a/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc index 3396b12345..562ae74ab2 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc @@ -38,7 +38,7 @@ // // The aptX-HD encoder shared library, and the functions to use // -static const char* APTX_HD_ENCODER_LIB_NAME = "libaptXHD_encoder.so"; +static const std::string APTX_HD_ENCODER_LIB_NAME = "libaptXHD_encoder.so"; static void* aptx_hd_encoder_lib_handle = NULL; static const char* APTX_HD_ENCODER_INIT_NAME = "aptxhdbtenc_init"; @@ -112,14 +112,22 @@ static size_t aptx_hd_encode_24bit(tAPTX_HD_FRAMING_PARAMS* framing_params, size_t* data_out_index, uint32_t* data32_in, uint8_t* data_out); +static const std::vector<std::string> APTX_HD_ENCODER_LIB_PATHS = { + APTX_HD_ENCODER_LIB_NAME, +#ifdef __LP64__ + "/system_ext/lib64/" + APTX_HD_ENCODER_LIB_NAME, +#else + "/system_ext/lib/" + APTX_HD_ENCODER_LIB_NAME, +#endif +}; + bool A2DP_VendorLoadEncoderAptxHd(void) { if (aptx_hd_encoder_lib_handle != NULL) return true; // Already loaded // Open the encoder library - aptx_hd_encoder_lib_handle = dlopen(APTX_HD_ENCODER_LIB_NAME, RTLD_NOW); - if (aptx_hd_encoder_lib_handle == NULL) { - LOG_ERROR("%s: cannot open aptX-HD encoder library %s: %s", __func__, - APTX_HD_ENCODER_LIB_NAME, dlerror()); + aptx_hd_encoder_lib_handle = A2DP_VendorCodecLoadExternalLib( + APTX_HD_ENCODER_LIB_PATHS, "aptX-HD encoder"); + if (!aptx_hd_encoder_lib_handle) { return false; } diff --git a/system/stack/a2dp/a2dp_vendor_ldac_abr.cc b/system/stack/a2dp/a2dp_vendor_ldac_abr.cc index 635c6eea0e..3f91f3d68c 100644 --- a/system/stack/a2dp/a2dp_vendor_ldac_abr.cc +++ b/system/stack/a2dp/a2dp_vendor_ldac_abr.cc @@ -23,6 +23,7 @@ #include <stdio.h> #include <string.h> +#include "a2dp_vendor.h" #include "osi/include/log.h" // @@ -32,7 +33,7 @@ // // The LDAC ABR shared library, and the functions to use // -static const char* LDAC_ABR_LIB_NAME = "libldacBT_abr.so"; +static const std::string LDAC_ABR_LIB_NAME = "libldacBT_abr.so"; static void* ldac_abr_lib_handle = NULL; static const char* LDAC_ABR_GET_HANDLE_NAME = "ldac_ABR_get_handle"; @@ -62,15 +63,22 @@ static tLDAC_ABR_INIT ldac_abr_init_func; static tLDAC_ABR_SET_THRESHOLDS ldac_abr_set_thresholds_func; static tLDAC_ABR_PROC ldac_abr_proc_func; +static const std::vector<std::string> LDAC_ABR_LIB_PATHS = { + LDAC_ABR_LIB_NAME, +#ifdef __LP64__ + "/system/lib64/" + LDAC_ABR_LIB_NAME, +#else + "/system/lib/" + LDAC_ABR_LIB_NAME, +#endif +}; + bool A2DP_VendorLoadLdacAbr(void) { if (ldac_abr_lib_handle != NULL) return true; // Already loaded // Open the LDAC ABR library - ldac_abr_lib_handle = dlopen(LDAC_ABR_LIB_NAME, RTLD_NOW); - if (ldac_abr_lib_handle == NULL) { - LOG_ERROR("%s: cannot open LDAC ABR library %s: %s", __func__, - LDAC_ABR_LIB_NAME, dlerror()); - A2DP_VendorUnloadLdacAbr(); + ldac_abr_lib_handle = + A2DP_VendorCodecLoadExternalLib(LDAC_ABR_LIB_PATHS, "LDAC ABR"); + if (!ldac_abr_lib_handle) { return false; } diff --git a/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc b/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc index 2f87c52522..942b010609 100644 --- a/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc @@ -44,7 +44,7 @@ // // The LDAC encoder shared library, and the functions to use // -static const char* LDAC_ENCODER_LIB_NAME = "libldacBT_enc.so"; +static const std::string LDAC_ENCODER_LIB_NAME = "libldacBT_enc.so"; static void* ldac_encoder_lib_handle = NULL; static const char* LDAC_GET_HANDLE_NAME = "ldacBT_get_handle"; @@ -194,6 +194,15 @@ static void* load_func(const char* func_name) { return func_ptr; } +static const std::vector<std::string> LDAC_ENCODER_LIB_PATHS = { + LDAC_ENCODER_LIB_NAME, +#ifdef __LP64__ + "/system/lib64/" + LDAC_ENCODER_LIB_NAME, +#else + "/system/lib/" + LDAC_ENCODER_LIB_NAME, +#endif +}; + bool A2DP_VendorLoadEncoderLdac(void) { if (ldac_encoder_lib_handle != NULL) return true; // Already loaded @@ -201,10 +210,9 @@ bool A2DP_VendorLoadEncoderLdac(void) { memset(&a2dp_ldac_encoder_cb, 0, sizeof(a2dp_ldac_encoder_cb)); // Open the encoder library - ldac_encoder_lib_handle = dlopen(LDAC_ENCODER_LIB_NAME, RTLD_NOW); - if (ldac_encoder_lib_handle == NULL) { - LOG_ERROR("%s: cannot open LDAC encoder library %s: %s", __func__, - LDAC_ENCODER_LIB_NAME, dlerror()); + ldac_encoder_lib_handle = + A2DP_VendorCodecLoadExternalLib(LDAC_ENCODER_LIB_PATHS, "LDAC encoder"); + if (!ldac_encoder_lib_handle) { return false; } diff --git a/system/stack/acl/btm_ble_connection_establishment.cc b/system/stack/acl/btm_ble_connection_establishment.cc index fefd71a14c..f68dd73306 100644 --- a/system/stack/acl/btm_ble_connection_establishment.cc +++ b/system/stack/acl/btm_ble_connection_establishment.cc @@ -88,7 +88,7 @@ bool maybe_resolve_address(RawAddress* bda, tBLE_ADDR_TYPE* bda_type) { if (!btm_ble_init_pseudo_addr(match_rec, *bda)) { /* assign the original address to be the current report address */ *bda = match_rec->ble.pseudo_addr; - *bda_type = match_rec->ble.ble_addr_type; + *bda_type = match_rec->ble.AddressType(); } else { *bda = match_rec->bd_addr; } diff --git a/system/stack/btm/btm_ble.cc b/system/stack/btm/btm_ble.cc index b0976d0256..5e1ab22e7b 100644 --- a/system/stack/btm/btm_ble.cc +++ b/system/stack/btm/btm_ble.cc @@ -89,12 +89,12 @@ void BTM_SecAddBleDevice(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type, memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME)); p_dev_rec->device_type |= dev_type; - p_dev_rec->ble.ble_addr_type = addr_type; + p_dev_rec->ble.SetAddressType(addr_type); /* sync up with the Inq Data base*/ tBTM_INQ_INFO* p_info = BTM_InqDbRead(bd_addr); if (p_info) { - p_info->results.ble_addr_type = p_dev_rec->ble.ble_addr_type; + p_info->results.ble_addr_type = p_dev_rec->ble.AddressType(); p_info->results.device_type = p_dev_rec->device_type; BTM_TRACE_DEBUG("InqDb device_type =0x%x addr_type=0x%x", p_info->results.device_type, p_info->results.ble_addr_type); @@ -364,7 +364,7 @@ void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr, oob.peer_oob_data.present = true; memcpy(&oob.peer_oob_data.randomizer, p_r, OCTET16_LEN); memcpy(&oob.peer_oob_data.commitment, p_c, OCTET16_LEN); - oob.peer_oob_data.addr_rcvd_from.type = p_dev_rec->ble.ble_addr_type; + oob.peer_oob_data.addr_rcvd_from.type = p_dev_rec->ble.AddressType(); oob.peer_oob_data.addr_rcvd_from.bda = bd_addr; SMP_SecureConnectionOobDataReply((uint8_t*)&oob); @@ -481,16 +481,16 @@ void BTM_ReadDevInfo(const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type, /* new inquiry result, overwrite device type in security device record */ if (p_inq_info) { p_dev_rec->device_type = p_inq_info->results.device_type; - p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type; + p_dev_rec->ble.SetAddressType(p_inq_info->results.ble_addr_type); } if (p_dev_rec->bd_addr == remote_bda && p_dev_rec->ble.pseudo_addr == remote_bda) { *p_dev_type = p_dev_rec->device_type; - *p_addr_type = p_dev_rec->ble.ble_addr_type; + *p_addr_type = p_dev_rec->ble.AddressType(); } else if (p_dev_rec->ble.pseudo_addr == remote_bda) { *p_dev_type = BT_DEVICE_TYPE_BLE; - *p_addr_type = p_dev_rec->ble.ble_addr_type; + *p_addr_type = p_dev_rec->ble.AddressType(); } else /* matching static adddress only */ { if (p_dev_rec->device_type != BT_DEVICE_TYPE_UNKNOWN) { *p_dev_type = p_dev_rec->device_type; @@ -1713,7 +1713,7 @@ void btm_ble_connected(const RawAddress& bda, uint16_t handle, uint8_t enc_mode, p_dev_rec->timestamp = btm_cb.dev_rec_count++; } - p_dev_rec->ble.ble_addr_type = addr_type; + p_dev_rec->ble.SetAddressType(addr_type); p_dev_rec->ble.pseudo_addr = bda; p_dev_rec->ble_hci_handle = handle; p_dev_rec->device_type |= BT_DEVICE_TYPE_BLE; @@ -1721,7 +1721,7 @@ void btm_ble_connected(const RawAddress& bda, uint16_t handle, uint8_t enc_mode, if (!addr_matched) { p_dev_rec->ble.active_addr_type = tBTM_SEC_BLE::BTM_BLE_ADDR_PSEUDO; - if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_RANDOM) { + if (p_dev_rec->ble.AddressType() == BLE_ADDR_RANDOM) { p_dev_rec->ble.cur_rand_addr = bda; } } @@ -2097,7 +2097,7 @@ bool btm_ble_get_acl_remote_addr(uint16_t hci_handle, RawAddress& conn_addr, switch (p_dev_rec->ble.active_addr_type) { case tBTM_SEC_BLE::BTM_BLE_ADDR_PSEUDO: conn_addr = p_dev_rec->bd_addr; - *p_addr_type = p_dev_rec->ble.ble_addr_type; + *p_addr_type = p_dev_rec->ble.AddressType(); break; case tBTM_SEC_BLE::BTM_BLE_ADDR_RRA: diff --git a/system/stack/btm/btm_ble_addr.cc b/system/stack/btm/btm_ble_addr.cc index c2b472acf7..93a4011558 100644 --- a/system/stack/btm/btm_ble_addr.cc +++ b/system/stack/btm/btm_ble_addr.cc @@ -34,6 +34,7 @@ #include "stack/crypto_toolbox/crypto_toolbox.h" #include "stack/include/acl_api.h" #include "stack/include/bt_octets.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" extern tBTM_CB btm_cb; @@ -226,7 +227,8 @@ static tBTM_SEC_DEV_REC* btm_find_dev_by_identity_addr( * ******************************************************************************/ bool btm_identity_addr_to_random_pseudo(RawAddress* bd_addr, - uint8_t* p_addr_type, bool refresh) { + tBLE_ADDR_TYPE* p_addr_type, + bool refresh) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_identity_addr(*bd_addr, *p_addr_type); if (p_dev_rec == nullptr) { @@ -245,7 +247,7 @@ bool btm_identity_addr_to_random_pseudo(RawAddress* bd_addr, *bd_addr = p_dev_rec->ble.pseudo_addr; } - *p_addr_type = p_dev_rec->ble.ble_addr_type; + *p_addr_type = p_dev_rec->ble.AddressType(); return true; } @@ -264,7 +266,7 @@ bool btm_identity_addr_to_random_pseudo_from_address_with_type( * ******************************************************************************/ bool btm_random_pseudo_to_identity_addr(RawAddress* random_pseudo, - uint8_t* p_identity_addr_type) { + tBLE_ADDR_TYPE* p_identity_addr_type) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(*random_pseudo); if (p_dev_rec != NULL) { diff --git a/system/stack/btm/btm_ble_bgconn.cc b/system/stack/btm/btm_ble_bgconn.cc index f725351191..249f9ed7f4 100644 --- a/system/stack/btm/btm_ble_bgconn.cc +++ b/system/stack/btm/btm_ble_bgconn.cc @@ -97,7 +97,7 @@ const tBLE_BD_ADDR convert_to_address_with_type( if (p_dev_rec->ble.identity_address_with_type.bda.IsEmpty()) { return { - .type = p_dev_rec->ble.ble_addr_type, + .type = p_dev_rec->ble.AddressType(), .bda = bd_addr, }; } else { @@ -203,7 +203,7 @@ bool BTM_BackgroundConnectAddressKnown(const RawAddress& address) { } // Public address, Random Static, or Random Non-Resolvable Address known - if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC || + if (p_dev_rec->ble.AddressType() == BLE_ADDR_PUBLIC || !BTM_BLE_IS_RESOLVE_BDA(address)) { return true; } diff --git a/system/stack/btm/btm_ble_gap.cc b/system/stack/btm/btm_ble_gap.cc index a5683c3fee..e72177bce3 100644 --- a/system/stack/btm/btm_ble_gap.cc +++ b/system/stack/btm/btm_ble_gap.cc @@ -55,6 +55,7 @@ #include "stack/include/gap_api.h" #include "stack/include/hci_error_code.h" #include "stack/include/inq_hci_link_interface.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" extern tBTM_CB btm_cb; @@ -63,7 +64,7 @@ extern void btm_inq_remote_name_timer_timeout(void* data); extern bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, const RawAddress& new_pseudo_addr); extern bool btm_identity_addr_to_random_pseudo(RawAddress* bd_addr, - uint8_t* p_addr_type, + tBLE_ADDR_TYPE* p_addr_type, bool refresh); extern void btm_ble_batchscan_init(void); extern void btm_ble_adv_filter_init(void); @@ -243,7 +244,7 @@ static void btm_ble_start_sync_timeout(void* data); * Local functions ******************************************************************************/ static void btm_ble_update_adv_flag(uint8_t flag); -void btm_ble_process_adv_pkt_cont(uint16_t evt_type, uint8_t addr_type, +void btm_ble_process_adv_pkt_cont(uint16_t evt_type, tBLE_ADDR_TYPE addr_type, const RawAddress& bda, uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, int8_t tx_power, @@ -909,7 +910,7 @@ static void sync_queue_cleanup(remove_sync_node_t* p_param) { void btm_ble_start_sync_request(uint8_t sid, RawAddress addr, uint16_t skip, uint16_t timeout) { - uint8_t address_type = BLE_ADDR_RANDOM; + tBLE_ADDR_TYPE address_type = BLE_ADDR_RANDOM; tINQ_DB_ENT* p_i = btm_inq_db_find(addr); if (p_i) { address_type = p_i->inq_info.results.ble_addr_type; // Random @@ -1939,7 +1940,8 @@ static void btm_send_hci_scan_enable(uint8_t enable, } void btm_send_hci_set_scan_params(uint8_t scan_type, uint16_t scan_int, - uint16_t scan_win, uint8_t addr_type_own, + uint16_t scan_win, + tBLE_ADDR_TYPE addr_type_own, uint8_t scan_filter_policy) { if (controller_get_interface()->supports_ble_extended_advertising()) { scanning_phy_cfg phy_cfg; @@ -2476,7 +2478,7 @@ void btm_clear_all_pending_le_entry(void) { } } -void btm_ble_process_adv_addr(RawAddress& bda, uint8_t* addr_type) { +void btm_ble_process_adv_addr(RawAddress& bda, tBLE_ADDR_TYPE* addr_type) { /* map address to security record */ bool match = btm_identity_addr_to_random_pseudo(&bda, addr_type, false); @@ -2493,7 +2495,7 @@ void btm_ble_process_adv_addr(RawAddress& bda, uint8_t* addr_type) { } else { // Assign the original address to be the current report address bda = match_rec->ble.pseudo_addr; - *addr_type = match_rec->ble.ble_addr_type; + *addr_type = match_rec->ble.AddressType(); } } } @@ -2656,7 +2658,7 @@ void btm_ble_process_adv_pkt(uint8_t data_len, const uint8_t* data) { * This function is called after random address resolution is done, and proceed * to process adv packet. */ -void btm_ble_process_adv_pkt_cont(uint16_t evt_type, uint8_t addr_type, +void btm_ble_process_adv_pkt_cont(uint16_t evt_type, tBLE_ADDR_TYPE addr_type, const RawAddress& bda, uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, int8_t tx_power, @@ -2804,7 +2806,7 @@ void btm_ble_process_adv_pkt_cont(uint16_t evt_type, uint8_t addr_type, * from gd scanning module to handle inquiry result callback. */ void btm_ble_process_adv_pkt_cont_for_inquiry( - uint16_t evt_type, uint8_t addr_type, const RawAddress& bda, + uint16_t evt_type, tBLE_ADDR_TYPE addr_type, const RawAddress& bda, uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, int8_t tx_power, int8_t rssi, uint16_t periodic_adv_int, std::vector<uint8_t> advertising_data) { diff --git a/system/stack/btm/btm_ble_int.h b/system/stack/btm/btm_ble_int.h index dfb9f2277b..d92b9537aa 100644 --- a/system/stack/btm/btm_ble_int.h +++ b/system/stack/btm/btm_ble_int.h @@ -32,6 +32,7 @@ #include "btm_int_types.h" #include "smp_api.h" #include "stack/include/hci_error_code.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" extern void btm_ble_process_periodic_adv_sync_est_evt(uint8_t len, @@ -111,8 +112,8 @@ extern uint64_t btm_get_next_private_addrress_interval_ms(); /* privacy function */ /* BLE address mapping with CS feature */ -extern bool btm_random_pseudo_to_identity_addr(RawAddress* random_pseudo, - uint8_t* p_identity_addr_type); +extern bool btm_random_pseudo_to_identity_addr( + RawAddress* random_pseudo, tBLE_ADDR_TYPE* p_identity_addr_type); extern void btm_ble_refresh_peer_resolvable_private_addr( const RawAddress& pseudo_bda, const RawAddress& rra, tBTM_SEC_BLE::tADDRESS_TYPE type); diff --git a/system/stack/btm/btm_ble_privacy.cc b/system/stack/btm/btm_ble_privacy.cc index 76dbc4b10e..78e981c41b 100644 --- a/system/stack/btm/btm_ble_privacy.cc +++ b/system/stack/btm/btm_ble_privacy.cc @@ -585,7 +585,7 @@ bool btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC* p_dev_rec) { if (p_dev_rec->ble.identity_address_with_type.bda.IsEmpty()) { p_dev_rec->ble.identity_address_with_type.bda = p_dev_rec->bd_addr; p_dev_rec->ble.identity_address_with_type.type = - p_dev_rec->ble.ble_addr_type; + p_dev_rec->ble.AddressType(); } BTM_TRACE_DEBUG( @@ -686,7 +686,7 @@ void btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC& dev_rec) { if (dev_rec.ble.identity_address_with_type.bda.IsEmpty()) { dev_rec.ble.identity_address_with_type = { .bda = dev_rec.bd_addr, - .type = dev_rec.ble.ble_addr_type, + .type = dev_rec.ble.AddressType(), }; } diff --git a/system/stack/btm/btm_dev.cc b/system/stack/btm/btm_dev.cc index 18f05a29c7..d887e93c2d 100644 --- a/system/stack/btm/btm_dev.cc +++ b/system/stack/btm/btm_dev.cc @@ -237,7 +237,7 @@ tBTM_SEC_DEV_REC* btm_sec_alloc_dev(const RawAddress& bd_addr) { memcpy(p_dev_rec->dev_class, p_inq_info->results.dev_class, DEV_CLASS_LEN); p_dev_rec->device_type = p_inq_info->results.device_type; - p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type; + p_dev_rec->ble.SetAddressType(p_inq_info->results.ble_addr_type); } else if (bd_addr == btm_cb.connecting_bda) memcpy(p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN); @@ -405,7 +405,7 @@ void btm_consolidate_dev(tBTM_SEC_DEV_REC* p_target_rec) { /* an RPA device entry is a duplicate of the target record */ if (btm_ble_addr_resolvable(p_dev_rec->bd_addr, p_target_rec)) { if (p_target_rec->ble.pseudo_addr == p_dev_rec->bd_addr) { - p_target_rec->ble.ble_addr_type = p_dev_rec->ble.ble_addr_type; + p_target_rec->ble.SetAddressType(p_dev_rec->ble.AddressType()); p_target_rec->device_type |= p_dev_rec->device_type; /* remove the combined record */ diff --git a/system/stack/btm/security_device_record.h b/system/stack/btm/security_device_record.h index 5b076ae2ed..360c7fb793 100644 --- a/system/stack/btm/security_device_record.h +++ b/system/stack/btm/security_device_record.h @@ -95,7 +95,14 @@ typedef struct { typedef struct { RawAddress pseudo_addr; /* LE pseudo address of the device if different from device address */ - tBLE_ADDR_TYPE ble_addr_type; /* LE device type: public or random address */ + private: + tBLE_ADDR_TYPE ble_addr_type_; /* LE device type: public or random address */ + + public: + tBLE_ADDR_TYPE AddressType() const { return ble_addr_type_; } + void SetAddressType(tBLE_ADDR_TYPE ble_addr_type) { + if (is_ble_addr_type_known(ble_addr_type)) ble_addr_type_ = ble_addr_type; + } tBLE_BD_ADDR identity_address_with_type; diff --git a/system/stack/gatt/gatt_main.cc b/system/stack/gatt/gatt_main.cc index 2ce057db87..c4e1039a95 100644 --- a/system/stack/gatt/gatt_main.cc +++ b/system/stack/gatt/gatt_main.cc @@ -189,7 +189,7 @@ void gatt_find_in_device_record(const RawAddress& bd_addr, if (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) { if (p_dev_rec->ble.identity_address_with_type.bda.IsEmpty()) { - *address_with_type = {.type = p_dev_rec->ble.ble_addr_type, + *address_with_type = {.type = p_dev_rec->ble.AddressType(), .bda = bd_addr}; return; } diff --git a/system/stack/include/a2dp_vendor.h b/system/stack/include/a2dp_vendor.h index 39e1086ce9..6f4d16512b 100644 --- a/system/stack/include/a2dp_vendor.h +++ b/system/stack/include/a2dp_vendor.h @@ -25,6 +25,8 @@ #include <stddef.h> #include <stdint.h> +#include <vector> + #include "a2dp_codec_api.h" #include "stack/include/bt_hdr.h" @@ -211,4 +213,12 @@ bool A2DP_VendorInitCodecConfig(btav_a2dp_codec_index_t codec_index, // Returns a string describing the codec information. std::string A2DP_VendorCodecInfoString(const uint8_t* p_codec_info); +// Try to dlopen external codec library +// Will iterate over |lib_paths| to return the first successfully dlopen library +// |friendly_name| is only use for logging purpose +// Return pointer to the handle if the library is successfully dlopen, +// nullptr otherwise +void* A2DP_VendorCodecLoadExternalLib(const std::vector<std::string>& lib_paths, + const std::string& friendly_name); + #endif // A2DP_VENDOR_H diff --git a/system/stack/include/ble_hci_link_interface.h b/system/stack/include/ble_hci_link_interface.h index 19766fd2de..d4f6d35169 100644 --- a/system/stack/include/ble_hci_link_interface.h +++ b/system/stack/include/ble_hci_link_interface.h @@ -20,6 +20,7 @@ #include <cstdint> #include "osi/include/osi.h" // UNUSED_ATTR +#include "types/ble_address_with_type.h" #include "types/raw_address.h" // This header contains functions for HCI-ble to invoke @@ -36,7 +37,7 @@ extern void btm_ble_test_command_complete(uint8_t* p); extern void btm_ble_rand_enc_complete(uint8_t* p, uint16_t op_code, tBTM_RAND_ENC_CB* p_enc_cplt_cback); extern bool btm_identity_addr_to_random_pseudo(RawAddress* bd_addr, - uint8_t* p_addr_type, + tBLE_ADDR_TYPE* p_addr_type, bool refresh); extern bool btm_identity_addr_to_random_pseudo_from_address_with_type( tBLE_BD_ADDR* address_with_type, bool refresh); diff --git a/system/stack/include/rfcdefs.h b/system/stack/include/rfcdefs.h index ca9b3ce520..f5c952b034 100644 --- a/system/stack/include/rfcdefs.h +++ b/system/stack/include/rfcdefs.h @@ -35,11 +35,12 @@ /* * Define used by RFCOMM TS frame types */ -#define RFCOMM_SABME 0x2F -#define RFCOMM_UA 0x63 -#define RFCOMM_DM 0x0F -#define RFCOMM_DISC 0x43 -#define RFCOMM_UIH 0xEF +#define RFCOMM_SABME 0x2F // Start Asynchronous Balanced Mode (startup command) +#define RFCOMM_UA 0x63 // Unnumbered Acknowledgement (response when connected) +#define RFCOMM_DM \ + 0x0F // Disconnected Mode (response to a command when disconnected) +#define RFCOMM_DISC 0x43 // Disconnect (disconnect command) +#define RFCOMM_UIH 0xEF // Unnumbered Information with Header check /* * Defenitions for the TS control frames diff --git a/system/stack/include/stack_metrics_logging.h b/system/stack/include/stack_metrics_logging.h index 1705f307ee..56921ddbdf 100644 --- a/system/stack/include/stack_metrics_logging.h +++ b/system/stack/include/stack_metrics_logging.h @@ -49,3 +49,6 @@ void log_manufacturer_info(const RawAddress& address, const std::string& model, const std::string& hardware_version, const std::string& software_version); + +void log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum key, + int64_t value); diff --git a/system/stack/metrics/stack_metrics_logging.cc b/system/stack/metrics/stack_metrics_logging.cc index bd801ca03b..50f029f803 100644 --- a/system/stack/metrics/stack_metrics_logging.cc +++ b/system/stack/metrics/stack_metrics_logging.cc @@ -67,3 +67,8 @@ void log_manufacturer_info(const RawAddress& address, address, source_type, source_name, manufacturer, model, hardware_version, software_version); } + +void log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum key, + int64_t value) { + bluetooth::shim::CountCounterMetrics(key, value); +} diff --git a/system/stack/rfcomm/port_api.cc b/system/stack/rfcomm/port_api.cc index 862b731624..f49129d197 100644 --- a/system/stack/rfcomm/port_api.cc +++ b/system/stack/rfcomm/port_api.cc @@ -711,11 +711,18 @@ int PORT_ReadData(uint16_t handle, char* p_data, uint16_t max_len, return (PORT_NOT_OPENED); } + if (p_port->state == PORT_STATE_OPENING) { + LOG_WARN("Trying to read a port in PORT_STATE_OPENING state"); + } + if (p_port->line_status) { return (PORT_LINE_ERR); } - if (fixed_queue_is_empty(p_port->rx.queue)) return (PORT_SUCCESS); + if (fixed_queue_is_empty(p_port->rx.queue)) { + LOG_WARN("Read on empty input queue"); + return (PORT_SUCCESS); + } count = 0; @@ -1024,6 +1031,10 @@ int PORT_WriteData(uint16_t handle, const char* p_data, uint16_t max_len, return (PORT_NOT_OPENED); } + if (p_port->state == PORT_STATE_OPENING) { + LOG_WARN("Write data received but port is in OPENING state"); + } + if (!max_len || !p_port->peer_mtu) { RFCOMM_TRACE_ERROR("PORT_WriteData() peer_mtu:%d", p_port->peer_mtu); return (PORT_UNKNOWN_ERROR); diff --git a/system/stack/rfcomm/port_rfc.cc b/system/stack/rfcomm/port_rfc.cc index 647e6af357..111284a120 100644 --- a/system/stack/rfcomm/port_rfc.cc +++ b/system/stack/rfcomm/port_rfc.cc @@ -24,6 +24,7 @@ ******************************************************************************/ #include <base/logging.h> +#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h> #include <cstdint> #include <string> @@ -35,6 +36,7 @@ #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" #include "stack/include/sdpdefs.h" +#include "stack/include/stack_metrics_logging.h" #include "stack/rfcomm/port_int.h" #include "stack/rfcomm/rfc_int.h" @@ -165,8 +167,12 @@ void port_start_close(tPORT* p_port) { if ((p_mcb == NULL) || (p_port->rfc.state == RFC_STATE_CLOSED)) { /* Call management callback function before calling port_release_port() to * clear tPort */ - if (p_port->p_mgmt_callback) + if (p_port->p_mgmt_callback) { p_port->p_mgmt_callback(PORT_CLOSED, p_port->handle); + log_counter_metrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_START_CLOSE, + 1); + } port_release_port(p_port); } else { @@ -217,8 +223,10 @@ void PORT_StartCnf(tRFC_MCB* p_mcb, uint16_t result) { if (p_port->p_mgmt_callback) { p_port->p_mgmt_callback(PORT_START_FAILED, p_port->handle); + log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: + RFCOMM_PORT_START_CNF_FAILED, + 1); } - port_release_port(p_port); } } @@ -449,8 +457,12 @@ void PORT_DlcEstablishInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) { if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED)) (p_port->p_callback)(PORT_EV_CONNECTED, p_port->handle); - if (p_port->p_mgmt_callback) + if (p_port->p_mgmt_callback) { p_port->p_mgmt_callback(PORT_SUCCESS, p_port->handle); + log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: + RFCOMM_CONNECTION_SUCCESS_IND, + 1); + } p_port->state = PORT_STATE_OPENED; } @@ -477,6 +489,9 @@ void PORT_DlcEstablishCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, if (result != RFCOMM_SUCCESS) { p_port->error = PORT_START_FAILED; port_rfc_closed(p_port, PORT_START_FAILED); + log_counter_metrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_START_FAILED, + 1); return; } @@ -489,9 +504,12 @@ void PORT_DlcEstablishCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED)) (p_port->p_callback)(PORT_EV_CONNECTED, p_port->handle); - if (p_port->p_mgmt_callback) + if (p_port->p_mgmt_callback) { p_port->p_mgmt_callback(PORT_SUCCESS, p_port->handle); - + log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: + RFCOMM_CONNECTION_SUCCESS_CNF, + 1); + } p_port->state = PORT_STATE_OPENED; /* RPN is required only if we want to tell DTE how the port should be opened @@ -561,6 +579,8 @@ void PORT_PortNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, RFCOMM_DlcReleaseReq(p_mcb, p_port->dlci); port_rfc_closed(p_port, PORT_PORT_NEG_FAILED); + log_counter_metrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_NEG_FAILED, 1); return; } @@ -698,6 +718,8 @@ void PORT_DlcReleaseInd(tRFC_MCB* p_mcb, uint8_t dlci) { tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); if (!p_port) return; port_rfc_closed(p_port, PORT_CLOSED); + log_counter_metrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_CLOSED, 1); } /******************************************************************************* @@ -718,6 +740,9 @@ void PORT_CloseInd(tRFC_MCB* p_mcb) { for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) { if (p_port->rfc.p_mcb == p_mcb) { port_rfc_closed(p_port, PORT_PEER_CONNECTION_FAILED); + log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: + RFCOMM_PORT_PEER_CONNECTION_FAILED, + 1); } } rfc_release_multiplexer_channel(p_mcb); @@ -741,6 +766,9 @@ void Port_TimeOutCloseMux(tRFC_MCB* p_mcb) { for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) { if (p_port->rfc.p_mcb == p_mcb) { port_rfc_closed(p_port, PORT_PEER_TIMEOUT); + log_counter_metrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_PEER_TIMEOUT, + 1); } } } diff --git a/system/stack/rfcomm/rfc_event.h b/system/stack/rfcomm/rfc_event.h index 98d24000d3..c950a4fcf2 100644 --- a/system/stack/rfcomm/rfc_event.h +++ b/system/stack/rfcomm/rfc_event.h @@ -21,47 +21,122 @@ /* * Events that can be received by multiplexer as well as port state machines */ -typedef uint8_t tRFC_EVENT; -#define RFC_EVENT_SABME 0 -#define RFC_EVENT_UA 1 -#define RFC_EVENT_DM 2 -#define RFC_EVENT_DISC 3 -#define RFC_EVENT_UIH 4 -#define RFC_EVENT_TIMEOUT 5 -#define RFC_EVENT_BAD_FRAME 50 +enum tRFC_EVENT : uint16_t { + /* + * Events that can be received by multiplexer as well as port state machines + */ + RFC_EVENT_SABME = 0, + RFC_EVENT_UA = 1, + RFC_EVENT_DM = 2, + RFC_EVENT_DISC = 3, + RFC_EVENT_UIH = 4, + RFC_EVENT_TIMEOUT = 5, + RFC_EVENT_BAD_FRAME = 50, +}; + /* * Multiplexer events */ -typedef uint8_t tRFC_MX_EVENT; -#define RFC_MX_EVENT_SABME RFC_EVENT_SABME -#define RFC_MX_EVENT_UA RFC_EVENT_UA -#define RFC_MX_EVENT_DM RFC_EVENT_DM -#define RFC_MX_EVENT_DISC RFC_EVENT_DISC -#define RFC_MX_EVENT_UIH RFC_EVENT_UIH -#define RFC_MX_EVENT_TIMEOUT RFC_EVENT_TIMEOUT -#define RFC_MX_EVENT_START_REQ 6 -#define RFC_MX_EVENT_START_RSP 7 -#define RFC_MX_EVENT_CLOSE_REQ 8 -#define RFC_MX_EVENT_CONN_CNF 9 -#define RFC_MX_EVENT_CONN_IND 10 -#define RFC_MX_EVENT_CONF_CNF 11 -#define RFC_MX_EVENT_CONF_IND 12 -#define RFC_MX_EVENT_QOS_VIOLATION_IND 13 -#define RFC_MX_EVENT_DISC_IND 14 +enum tRFC_MX_EVENT : uint16_t { + /* + * Multiplexer events + */ + RFC_MX_EVENT_SABME = RFC_EVENT_SABME, + RFC_MX_EVENT_UA = RFC_EVENT_UA, + RFC_MX_EVENT_DM = RFC_EVENT_DM, + RFC_MX_EVENT_DISC = RFC_EVENT_DISC, + RFC_MX_EVENT_UIH = RFC_EVENT_UIH, + RFC_MX_EVENT_TIMEOUT = RFC_EVENT_TIMEOUT, + RFC_MX_EVENT_START_REQ = 6, + RFC_MX_EVENT_START_RSP = 7, + RFC_MX_EVENT_CLOSE_REQ = 8, + RFC_MX_EVENT_CONN_CNF = 9, + RFC_MX_EVENT_CONN_IND = 10, + RFC_MX_EVENT_CONF_CNF = 11, + RFC_MX_EVENT_CONF_IND = 12, + RFC_MX_EVENT_QOS_VIOLATION_IND = 13, + RFC_MX_EVENT_DISC_IND = 14, +}; /* * Port events */ -typedef uint8_t tRFC_PORT_EVENT; -#define RFC_PORT_EVENT_SABME RFC_EVENT_SABME -#define RFC_PORT_EVENT_UA RFC_EVENT_UA -#define RFC_PORT_EVENT_DM RFC_EVENT_DM -#define RFC_PORT_EVENT_DISC RFC_EVENT_DISC -#define RFC_PORT_EVENT_UIH RFC_EVENT_UIH -#define RFC_PORT_EVENT_TIMEOUT RFC_EVENT_TIMEOUT -#define RFC_PORT_EVENT_OPEN 9 -#define RFC_PORT_EVENT_ESTABLISH_RSP 11 -#define RFC_PORT_EVENT_CLOSE 12 -#define RFC_PORT_EVENT_CLEAR 13 -#define RFC_PORT_EVENT_DATA 14 -#define RFC_PORT_EVENT_SEC_COMPLETE 15 +enum tRFC_PORT_EVENT : uint16_t { + /* + * Port events + */ + RFC_PORT_EVENT_SABME = RFC_EVENT_SABME, + RFC_PORT_EVENT_UA = RFC_EVENT_UA, + RFC_PORT_EVENT_DM = RFC_EVENT_DM, + RFC_PORT_EVENT_DISC = RFC_EVENT_DISC, + RFC_PORT_EVENT_UIH = RFC_EVENT_UIH, + RFC_PORT_EVENT_TIMEOUT = RFC_EVENT_TIMEOUT, + RFC_PORT_EVENT_OPEN = 9, + RFC_PORT_EVENT_ESTABLISH_RSP = 11, + RFC_PORT_EVENT_CLOSE = 12, + RFC_PORT_EVENT_CLEAR = 13, + RFC_PORT_EVENT_DATA = 14, + RFC_PORT_EVENT_SEC_COMPLETE = 15, +}; + +#define CASE_RETURN_TEXT(code) \ + case code: \ + return #code + +// Common events for both port and mux +inline std::string rfcomm_event_text(const tRFC_EVENT& event) { + switch (event) { + CASE_RETURN_TEXT(RFC_EVENT_SABME); + CASE_RETURN_TEXT(RFC_EVENT_UA); + CASE_RETURN_TEXT(RFC_EVENT_DM); + CASE_RETURN_TEXT(RFC_EVENT_DISC); + CASE_RETURN_TEXT(RFC_EVENT_UIH); + CASE_RETURN_TEXT(RFC_EVENT_TIMEOUT); + CASE_RETURN_TEXT(RFC_EVENT_BAD_FRAME); + default: + return std::string("UNKNOWN[") + std::to_string(event) + std::string("]"); + } +} + +inline std::string rfcomm_mx_event_text(const tRFC_MX_EVENT& event) { + switch (event) { + CASE_RETURN_TEXT(RFC_MX_EVENT_SABME); + CASE_RETURN_TEXT(RFC_MX_EVENT_UA); + CASE_RETURN_TEXT(RFC_MX_EVENT_DM); + CASE_RETURN_TEXT(RFC_MX_EVENT_DISC); + CASE_RETURN_TEXT(RFC_MX_EVENT_UIH); + CASE_RETURN_TEXT(RFC_MX_EVENT_TIMEOUT); + CASE_RETURN_TEXT(RFC_MX_EVENT_START_REQ); + CASE_RETURN_TEXT(RFC_MX_EVENT_START_RSP); + CASE_RETURN_TEXT(RFC_MX_EVENT_CLOSE_REQ); + CASE_RETURN_TEXT(RFC_MX_EVENT_CONN_CNF); + CASE_RETURN_TEXT(RFC_MX_EVENT_CONN_IND); + CASE_RETURN_TEXT(RFC_MX_EVENT_CONF_CNF); + CASE_RETURN_TEXT(RFC_MX_EVENT_CONF_IND); + CASE_RETURN_TEXT(RFC_MX_EVENT_QOS_VIOLATION_IND); + CASE_RETURN_TEXT(RFC_MX_EVENT_DISC_IND); + default: + return std::string("UNKNOWN[") + std::to_string(event) + std::string("]"); + } +} + +inline std::string rfcomm_port_event_text(const tRFC_PORT_EVENT& event) { + switch (event) { + CASE_RETURN_TEXT(RFC_PORT_EVENT_SABME); + CASE_RETURN_TEXT(RFC_PORT_EVENT_UA); + CASE_RETURN_TEXT(RFC_PORT_EVENT_DM); + CASE_RETURN_TEXT(RFC_PORT_EVENT_DISC); + CASE_RETURN_TEXT(RFC_PORT_EVENT_UIH); + CASE_RETURN_TEXT(RFC_PORT_EVENT_TIMEOUT); + CASE_RETURN_TEXT(RFC_PORT_EVENT_OPEN); + CASE_RETURN_TEXT(RFC_PORT_EVENT_ESTABLISH_RSP); + CASE_RETURN_TEXT(RFC_PORT_EVENT_CLOSE); + CASE_RETURN_TEXT(RFC_PORT_EVENT_CLEAR); + CASE_RETURN_TEXT(RFC_PORT_EVENT_DATA); + CASE_RETURN_TEXT(RFC_PORT_EVENT_SEC_COMPLETE); + default: + return std::string("UNKNOWN[") + std::to_string(event) + std::string("]"); + } +} + +#undef CASE_RETURN_TEXT diff --git a/system/stack/rfcomm/rfc_int.h b/system/stack/rfcomm/rfc_int.h index 9b9c96b5a8..61706a2946 100644 --- a/system/stack/rfcomm/rfc_int.h +++ b/system/stack/rfcomm/rfc_int.h @@ -34,6 +34,7 @@ #include "stack/include/l2c_api.h" #include "stack/rfcomm/port_int.h" #include "stack/rfcomm/rfc_event.h" +#include "stack/rfcomm/rfc_state.h" #include "types/raw_address.h" /* @@ -146,50 +147,6 @@ typedef struct { #define LINE_STATUS_FRAME 0x08 /* Receive Framing error */ #define LINE_STATUS_FAILED 0x10 /* Connection Failed */ -/* - * Define states and events for the RFC multiplexer state machine -*/ -typedef enum : uint16_t { - RFC_MX_STATE_IDLE = 0, - RFC_MX_STATE_WAIT_CONN_CNF = 1, - RFC_MX_STATE_CONFIGURE = 2, - RFC_MX_STATE_SABME_WAIT_UA = 3, - RFC_MX_STATE_WAIT_SABME = 4, - RFC_MX_STATE_CONNECTED = 5, - RFC_MX_STATE_DISC_WAIT_UA = 6, -} tRFC_MX_STATE; - -inline std::string rfcomm_mx_state_text(tRFC_MX_STATE state) { - switch (state) { - case RFC_MX_STATE_IDLE: - return std::string("idle"); - case RFC_MX_STATE_WAIT_CONN_CNF: - return std::string("wait_config"); - case RFC_MX_STATE_CONFIGURE: - return std::string("configure"); - case RFC_MX_STATE_SABME_WAIT_UA: - return std::string("sabme_wait_ua"); - case RFC_MX_STATE_WAIT_SABME: - return std::string("wait_sabme"); - case RFC_MX_STATE_CONNECTED: - return std::string("connected"); - case RFC_MX_STATE_DISC_WAIT_UA: - return std::string("disconnect_wait_ua"); - default: - return std::string("UNKNOWN"); - } -} - -/* - * Define port states - */ -#define RFC_STATE_CLOSED 0 -#define RFC_STATE_SABME_WAIT_UA 1 -#define RFC_STATE_ORIG_WAIT_SEC_CHECK 2 -#define RFC_STATE_TERM_WAIT_SEC_CHECK 3 -#define RFC_STATE_OPENED 4 -#define RFC_STATE_DISC_WAIT_UA 5 - /* seconds to wait for reply with Poll bit */ #define RFC_T1_TIMEOUT 20 /* seconds to wait for reply with Poll bit other than MX */ diff --git a/system/stack/rfcomm/rfc_l2cap_if.cc b/system/stack/rfcomm/rfc_l2cap_if.cc index bf6fd6eafe..d5a80d26a3 100644 --- a/system/stack/rfcomm/rfc_l2cap_if.cc +++ b/system/stack/rfcomm/rfc_l2cap_if.cc @@ -22,12 +22,15 @@ * ******************************************************************************/ +#include <base/logging.h> + #include <cstddef> #include <cstdint> #include "bt_target.h" #include "common/time_util.h" #include "osi/include/allocator.h" +#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" @@ -36,8 +39,6 @@ #include "stack/rfcomm/rfc_int.h" #include "types/raw_address.h" -#include <base/logging.h> - /* * Define Callback functions to be called by L2CAP */ @@ -177,6 +178,11 @@ void RFCOMM_ConnectCnf(uint16_t lcid, uint16_t result) { * ******************************************************************************/ void RFCOMM_ConfigInd(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { + if (p_cfg == nullptr) { + LOG_ERROR("Received l2cap configuration info with nullptr"); + return; + } + tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); if (!p_mcb) { diff --git a/system/stack/rfcomm/rfc_state.h b/system/stack/rfcomm/rfc_state.h new file mode 100644 index 0000000000..b725a3503a --- /dev/null +++ b/system/stack/rfcomm/rfc_state.h @@ -0,0 +1,75 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/* + * Define states and events for the RFC multiplexer state machine + */ +typedef enum : uint16_t { + RFC_MX_STATE_IDLE = 0, + RFC_MX_STATE_WAIT_CONN_CNF = 1, + RFC_MX_STATE_CONFIGURE = 2, + RFC_MX_STATE_SABME_WAIT_UA = 3, + RFC_MX_STATE_WAIT_SABME = 4, + RFC_MX_STATE_CONNECTED = 5, + RFC_MX_STATE_DISC_WAIT_UA = 6, +} tRFC_MX_STATE; + +/* + * Define port states + */ +typedef enum : uint8_t { + RFC_STATE_CLOSED = 0, + RFC_STATE_SABME_WAIT_UA = 1, + RFC_STATE_ORIG_WAIT_SEC_CHECK = 2, + RFC_STATE_TERM_WAIT_SEC_CHECK = 3, + RFC_STATE_OPENED = 4, + RFC_STATE_DISC_WAIT_UA = 5, +} tRFC_PORT_STATE; + +#define CASE_RETURN_TEXT(code) \ + case code: \ + return #code + +inline std::string rfcomm_mx_state_text(const tRFC_MX_STATE& state) { + switch (state) { + CASE_RETURN_TEXT(RFC_MX_STATE_IDLE); + CASE_RETURN_TEXT(RFC_MX_STATE_WAIT_CONN_CNF); + CASE_RETURN_TEXT(RFC_MX_STATE_CONFIGURE); + CASE_RETURN_TEXT(RFC_MX_STATE_SABME_WAIT_UA); + CASE_RETURN_TEXT(RFC_MX_STATE_WAIT_SABME); + CASE_RETURN_TEXT(RFC_MX_STATE_CONNECTED); + CASE_RETURN_TEXT(RFC_MX_STATE_DISC_WAIT_UA); + default: + return std::string("UNKNOWN[") + std::to_string(state) + std::string("]"); + } +} + +inline std::string rfcomm_port_state_text(const tRFC_PORT_STATE& state) { + switch (state) { + CASE_RETURN_TEXT(RFC_STATE_CLOSED); + CASE_RETURN_TEXT(RFC_STATE_SABME_WAIT_UA); + CASE_RETURN_TEXT(RFC_STATE_ORIG_WAIT_SEC_CHECK); + CASE_RETURN_TEXT(RFC_STATE_TERM_WAIT_SEC_CHECK); + CASE_RETURN_TEXT(RFC_STATE_OPENED); + CASE_RETURN_TEXT(RFC_STATE_DISC_WAIT_UA); + default: + return std::string("UNKNOWN[") + std::to_string(state) + std::string("]"); + } +} + +#undef CASE_RETURN_TEXT diff --git a/system/stack/rfcomm/rfc_utils.cc b/system/stack/rfcomm/rfc_utils.cc index e1eb71b90f..ae3708def4 100644 --- a/system/stack/rfcomm/rfc_utils.cc +++ b/system/stack/rfcomm/rfc_utils.cc @@ -320,6 +320,7 @@ void rfcomm_mcb_timer_timeout(void* data) { void rfc_sec_check_complete(UNUSED_ATTR const RawAddress* bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void* p_ref_data, tBTM_STATUS res) { + CHECK(p_ref_data != nullptr); tPORT* p_port = (tPORT*)p_ref_data; /* Verify that PORT is still waiting for Security to complete */ diff --git a/system/test/mock/mock_main_shim_acl_api.cc b/system/test/mock/mock_main_shim_acl_api.cc index 04709d7866..55ffd4cbe9 100644 --- a/system/test/mock/mock_main_shim_acl_api.cc +++ b/system/test/mock/mock_main_shim_acl_api.cc @@ -69,7 +69,7 @@ void bluetooth::shim::ACL_IgnoreAllLeConnections() { } void bluetooth::shim::ACL_ReadConnectionAddress(const RawAddress& pseudo_addr, RawAddress& conn_addr, - uint8_t* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type) { mock_function_count_map[__func__]++; } diff --git a/system/test/mock/mock_main_shim_btm_api.cc b/system/test/mock/mock_main_shim_btm_api.cc index 975374d009..d799c2027b 100644 --- a/system/test/mock/mock_main_shim_btm_api.cc +++ b/system/test/mock/mock_main_shim_btm_api.cc @@ -383,10 +383,6 @@ void bluetooth::shim::BTM_RemoteOobDataReply(tBTM_STATUS res, const Octet16& r) { mock_function_count_map[__func__]++; } -void bluetooth::shim::BTM_RemoveEirService(uint32_t* p_eir_uuid, - uint16_t uuid16) { - mock_function_count_map[__func__]++; -} void bluetooth::shim::BTM_SecAddBleDevice(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type) { diff --git a/system/test/mock/mock_main_shim_l2cap_api.cc b/system/test/mock/mock_main_shim_l2cap_api.cc index e2ed0048dc..0cf413c3c7 100644 --- a/system/test/mock/mock_main_shim_l2cap_api.cc +++ b/system/test/mock/mock_main_shim_l2cap_api.cc @@ -257,14 +257,14 @@ bool bluetooth::shim::L2CA_IsLeLink(uint16_t acl_handle) { } void bluetooth::shim::L2CA_ReadConnectionAddr(const RawAddress& pseudo_addr, RawAddress& conn_addr, - uint8_t* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type) { mock_function_count_map[__func__]++; test::mock::main_shim_l2cap_api::L2CA_ReadConnectionAddr( pseudo_addr, conn_addr, p_addr_type); } bool bluetooth::shim::L2CA_ReadRemoteConnectionAddr( const RawAddress& pseudo_addr, RawAddress& conn_addr, - uint8_t* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type) { mock_function_count_map[__func__]++; return test::mock::main_shim_l2cap_api::L2CA_ReadRemoteConnectionAddr( pseudo_addr, conn_addr, p_addr_type); diff --git a/system/test/mock/mock_main_shim_l2cap_api.h b/system/test/mock/mock_main_shim_l2cap_api.h index 1d8d37c74a..3916c05b6e 100644 --- a/system/test/mock/mock_main_shim_l2cap_api.h +++ b/system/test/mock/mock_main_shim_l2cap_api.h @@ -54,6 +54,7 @@ extern std::map<std::string, int> mock_function_count_map; #include "stack/include/btm_api.h" #include "stack/include/gatt_api.h" #include "stack/include/sco_hci_link_interface.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" // Mocked compile conditionals, if any @@ -418,11 +419,11 @@ extern struct L2CA_IsLeLink L2CA_IsLeLink; // p_addr_type Returns: void struct L2CA_ReadConnectionAddr { std::function<void(const RawAddress& pseudo_addr, RawAddress& conn_addr, - uint8_t* p_addr_type)> + tBLE_ADDR_TYPE* p_addr_type)> body{[](const RawAddress& pseudo_addr, RawAddress& conn_addr, - uint8_t* p_addr_type) {}}; + tBLE_ADDR_TYPE* p_addr_type) {}}; void operator()(const RawAddress& pseudo_addr, RawAddress& conn_addr, - uint8_t* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type) { body(pseudo_addr, conn_addr, p_addr_type); }; }; @@ -432,11 +433,11 @@ extern struct L2CA_ReadConnectionAddr L2CA_ReadConnectionAddr; // p_addr_type Returns: bool struct L2CA_ReadRemoteConnectionAddr { std::function<bool(const RawAddress& pseudo_addr, RawAddress& conn_addr, - uint8_t* p_addr_type)> + tBLE_ADDR_TYPE* p_addr_type)> body{[](const RawAddress& pseudo_addr, RawAddress& conn_addr, - uint8_t* p_addr_type) { return false; }}; + tBLE_ADDR_TYPE* p_addr_type) { return false; }}; bool operator()(const RawAddress& pseudo_addr, RawAddress& conn_addr, - uint8_t* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type) { return body(pseudo_addr, conn_addr, p_addr_type); }; }; diff --git a/system/test/mock/mock_osi_mutex.cc b/system/test/mock/mock_osi_mutex.cc new file mode 100644 index 0000000000..0f9bc8599d --- /dev/null +++ b/system/test/mock/mock_osi_mutex.cc @@ -0,0 +1,65 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Generated mock file from original source file + * Functions generated:2 + * + * mockcify.pl ver 0.3.0 + */ + +#include <cstdint> +#include <functional> +#include <map> +#include <string> + +extern std::map<std::string, int> mock_function_count_map; + +// Mock include file to share data between tests and mock +#include "test/mock/mock_osi_mutex.h" + +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace osi_mutex { + +// Function state capture and return values, if needed +struct mutex_global_lock mutex_global_lock; +struct mutex_global_unlock mutex_global_unlock; + +} // namespace osi_mutex +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace osi_mutex {} // namespace osi_mutex +} // namespace mock +} // namespace test + +// Mocked functions, if any +void mutex_global_lock(void) { + mock_function_count_map[__func__]++; + test::mock::osi_mutex::mutex_global_lock(); +} +void mutex_global_unlock(void) { + mock_function_count_map[__func__]++; + test::mock::osi_mutex::mutex_global_unlock(); +} +// Mocked functions complete +// END mockcify generation diff --git a/system/test/mock/mock_osi_mutex.h b/system/test/mock/mock_osi_mutex.h new file mode 100644 index 0000000000..8870c878fb --- /dev/null +++ b/system/test/mock/mock_osi_mutex.h @@ -0,0 +1,72 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:2 + * + * mockcify.pl ver 0.3.0 + */ + +#include <cstdint> +#include <functional> +#include <map> +#include <string> + +extern std::map<std::string, int> mock_function_count_map; + +// Original included files, if any +// NOTE: Since this is a mock file with mock definitions some number of +// include files may not be required. The include-what-you-use +// still applies, but crafting proper inclusion is out of scope +// for this effort. This compilation unit may compile as-is, or +// may need attention to prune from (or add to ) the inclusion set. +#include <mutex> + +#include "osi/include/mutex.h" + +// Mocked compile conditionals, if any + +namespace test { +namespace mock { +namespace osi_mutex { + +// Shared state between mocked functions and tests +// Name: mutex_global_lock +// Params: void +// Return: void +struct mutex_global_lock { + std::function<void(void)> body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct mutex_global_lock mutex_global_lock; + +// Name: mutex_global_unlock +// Params: void +// Return: void +struct mutex_global_unlock { + std::function<void(void)> body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct mutex_global_unlock mutex_global_unlock; + +} // namespace osi_mutex +} // namespace mock +} // namespace test + +// END mockcify generation
\ No newline at end of file diff --git a/system/test/mock/mock_stack_acl_ble.cc b/system/test/mock/mock_stack_acl_ble.cc index b9b7794e87..33b3c99805 100644 --- a/system/test/mock/mock_stack_acl_ble.cc +++ b/system/test/mock/mock_stack_acl_ble.cc @@ -63,7 +63,7 @@ void acl_ble_enhanced_connection_complete_from_shim( const tBLE_BD_ADDR& address_with_type, uint16_t handle, tHCI_ROLE role, uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout, const RawAddress& local_rpa, const RawAddress& peer_rpa, - uint8_t peer_addr_type) { + tBLE_ADDR_TYPE peer_addr_type) { mock_function_count_map[__func__]++; } diff --git a/system/test/mock/mock_stack_btm_ble_addr.cc b/system/test/mock/mock_stack_btm_ble_addr.cc index 157ebe8fb7..80507b99cd 100644 --- a/system/test/mock/mock_stack_btm_ble_addr.cc +++ b/system/test/mock/mock_stack_btm_ble_addr.cc @@ -35,6 +35,7 @@ extern std::map<std::string, int> mock_function_count_map; // Mock include file to share data between tests and mock #include "test/mock/mock_stack_btm_ble_addr.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" // Mocked compile conditionals, if any @@ -100,7 +101,8 @@ tBTM_SEC_DEV_REC* btm_ble_resolve_random_addr(const RawAddress& random_bda) { random_bda); } bool btm_identity_addr_to_random_pseudo(RawAddress* bd_addr, - uint8_t* p_addr_type, bool refresh) { + tBLE_ADDR_TYPE* p_addr_type, + bool refresh) { mock_function_count_map[__func__]++; return test::mock::stack_btm_ble_addr::btm_identity_addr_to_random_pseudo( bd_addr, p_addr_type, refresh); @@ -113,7 +115,7 @@ bool btm_identity_addr_to_random_pseudo_from_address_with_type( address_with_type, refresh); } bool btm_random_pseudo_to_identity_addr(RawAddress* random_pseudo, - uint8_t* p_identity_addr_type) { + tBLE_ADDR_TYPE* p_identity_addr_type) { mock_function_count_map[__func__]++; return test::mock::stack_btm_ble_addr::btm_random_pseudo_to_identity_addr( random_pseudo, p_identity_addr_type); diff --git a/system/test/mock/mock_stack_btm_ble_addr.h b/system/test/mock/mock_stack_btm_ble_addr.h index e620953385..6f9a93737a 100644 --- a/system/test/mock/mock_stack_btm_ble_addr.h +++ b/system/test/mock/mock_stack_btm_ble_addr.h @@ -118,11 +118,13 @@ extern struct btm_ble_resolve_random_addr btm_ble_resolve_random_addr; // Params: RawAddress* bd_addr, uint8_t* p_addr_type, bool refresh // Returns: bool struct btm_identity_addr_to_random_pseudo { - std::function<bool(RawAddress* bd_addr, uint8_t* p_addr_type, bool refresh)> - body{[](RawAddress* bd_addr, uint8_t* p_addr_type, bool refresh) { + std::function<bool(RawAddress* bd_addr, tBLE_ADDR_TYPE* p_addr_type, + bool refresh)> + body{[](RawAddress* bd_addr, tBLE_ADDR_TYPE* p_addr_type, bool refresh) { return false; }}; - bool operator()(RawAddress* bd_addr, uint8_t* p_addr_type, bool refresh) { + bool operator()(RawAddress* bd_addr, tBLE_ADDR_TYPE* p_addr_type, + bool refresh) { return body(bd_addr, p_addr_type, refresh); }; }; diff --git a/system/test/mock/mock_stack_btm_ble_gap.cc b/system/test/mock/mock_stack_btm_ble_gap.cc index ef913db823..c3c8d0942d 100644 --- a/system/test/mock/mock_stack_btm_ble_gap.cc +++ b/system/test/mock/mock_stack_btm_ble_gap.cc @@ -26,10 +26,12 @@ extern std::map<std::string, int> mock_function_count_map; #include <base/bind.h> #include <base/strings/string_number_conversions.h> + #include <cstdint> #include <list> #include <memory> #include <vector> + #include "common/time_util.h" #include "device/include/controller.h" #include "main/shim/acl_api.h" @@ -47,6 +49,7 @@ extern std::map<std::string, int> mock_function_count_map; #include "stack/include/gap_api.h" #include "stack/include/hci_error_code.h" #include "stack/include/inq_hci_link_interface.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" #ifndef UNUSED_ATTR @@ -155,13 +158,13 @@ void btm_ble_increment_link_topology_mask(uint8_t link_role) { mock_function_count_map[__func__]++; } void btm_ble_init(void) { mock_function_count_map[__func__]++; } -void btm_ble_process_adv_addr(RawAddress& bda, uint8_t* addr_type) { +void btm_ble_process_adv_addr(RawAddress& bda, tBLE_ADDR_TYPE* addr_type) { mock_function_count_map[__func__]++; } void btm_ble_process_adv_pkt(uint8_t data_len, const uint8_t* data) { mock_function_count_map[__func__]++; } -void btm_ble_process_adv_pkt_cont(uint16_t evt_type, uint8_t addr_type, +void btm_ble_process_adv_pkt_cont(uint16_t evt_type, tBLE_ADDR_TYPE addr_type, const RawAddress& bda, uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, int8_t tx_power, @@ -171,7 +174,7 @@ void btm_ble_process_adv_pkt_cont(uint16_t evt_type, uint8_t addr_type, mock_function_count_map[__func__]++; } void btm_ble_process_adv_pkt_cont_for_inquiry( - uint16_t evt_type, uint8_t addr_type, const RawAddress& bda, + uint16_t evt_type, tBLE_ADDR_TYPE addr_type, const RawAddress& bda, uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, int8_t tx_power, int8_t rssi, uint16_t periodic_adv_int, std::vector<uint8_t> advertising_data) { @@ -220,7 +223,8 @@ void btm_clear_all_pending_le_entry(void) { mock_function_count_map[__func__]++; } void btm_send_hci_set_scan_params(uint8_t scan_type, uint16_t scan_int, - uint16_t scan_win, uint8_t addr_type_own, + uint16_t scan_win, + tBLE_ADDR_TYPE addr_type_own, uint8_t scan_filter_policy) { mock_function_count_map[__func__]++; } @@ -254,4 +258,4 @@ void btm_ble_periodic_adv_sync_tx_rcvd(uint8_t* p, uint16_t param_len) { } void btm_ble_biginfo_adv_report_rcvd(uint8_t* p, uint16_t param_len) { mock_function_count_map[__func__]++; -}
\ No newline at end of file +} diff --git a/system/test/mock/mock_stack_btm_inq.cc b/system/test/mock/mock_stack_btm_inq.cc index c068026118..356fe6d765 100644 --- a/system/test/mock/mock_stack_btm_inq.cc +++ b/system/test/mock/mock_stack_btm_inq.cc @@ -144,9 +144,6 @@ void BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16) { void BTM_CancelInquiry(void) { mock_function_count_map[__func__]++; } void BTM_EnableInterlacedInquiryScan() { mock_function_count_map[__func__]++; } void BTM_EnableInterlacedPageScan() { mock_function_count_map[__func__]++; } -void BTM_RemoveEirService(uint32_t* p_eir_uuid, uint16_t uuid16) { - mock_function_count_map[__func__]++; -} void btm_clr_inq_db(const RawAddress* p_bda) { mock_function_count_map[__func__]++; } diff --git a/system/test/mock/mock_stack_metrics_logging.cc b/system/test/mock/mock_stack_metrics_logging.cc index 3485c351a6..befaade97c 100644 --- a/system/test/mock/mock_stack_metrics_logging.cc +++ b/system/test/mock/mock_stack_metrics_logging.cc @@ -60,6 +60,7 @@ struct log_link_layer_connection_event log_link_layer_connection_event; struct log_smp_pairing_event log_smp_pairing_event; struct log_sdp_attribute log_sdp_attribute; struct log_manufacturer_info log_manufacturer_info; +struct log_counter_metrics log_counter_metrics; } // namespace stack_metrics_logging } // namespace mock @@ -112,4 +113,10 @@ void log_manufacturer_info(const RawAddress& address, software_version); } +void log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum key, + int64_t value) { + mock_function_count_map[__func__]++; + test::mock::stack_metrics_logging::log_counter_metrics(key, value); +} + // END mockcify generation diff --git a/system/test/mock/mock_stack_metrics_logging.h b/system/test/mock/mock_stack_metrics_logging.h index f923859c3a..354ee37c90 100644 --- a/system/test/mock/mock_stack_metrics_logging.h +++ b/system/test/mock/mock_stack_metrics_logging.h @@ -159,6 +159,18 @@ struct log_manufacturer_info { }; extern struct log_manufacturer_info log_manufacturer_info; +// Name: log_counter_metrics +struct log_counter_metrics { + std::function<void(android::bluetooth::CodePathCounterKeyEnum key, + int64_t value)> + body{ + [](android::bluetooth::CodePathCounterKeyEnum key, int64_t value) {}}; + void operator()(android::bluetooth::CodePathCounterKeyEnum key, + int64_t value) { + body(key, value); + }; +}; +extern struct log_counter_metrics log_counter_metrics; } // namespace stack_metrics_logging } // namespace mock } // namespace test diff --git a/system/types/Android.bp b/system/types/Android.bp index 7beb94028d..059c8e501e 100644 --- a/system/types/Android.bp +++ b/system/types/Android.bp @@ -48,11 +48,15 @@ cc_test { name: "net_test_types", test_suites: ["device-tests"], defaults: ["fluoride_defaults"], + include_dirs: [ + "packages/modules/Bluetooth/system", + ], host_supported: true, srcs: [ + "test/ble_address_with_type_unittest.cc", + "test/bluetooth/uuid_unittest.cc", "test/class_of_device_unittest.cc", "test/raw_address_unittest.cc", - "test/bluetooth/uuid_unittest.cc", ], shared_libs: [ "android.hardware.bluetooth@1.0", diff --git a/system/types/ble_address_with_type.h b/system/types/ble_address_with_type.h index 850abb900c..ecd62a85fb 100644 --- a/system/types/ble_address_with_type.h +++ b/system/types/ble_address_with_type.h @@ -45,8 +45,38 @@ inline std::string AddressTypeText(tBLE_ADDR_TYPE type) { } #endif // __cplusplus +inline bool is_ble_addr_type_valid(uint8_t raw_type) { return raw_type < 4; } + +inline bool is_ble_addr_type_known(tBLE_ADDR_TYPE type) { + switch (type) { + case BLE_ADDR_PUBLIC: + case BLE_ADDR_PUBLIC_ID: + case BLE_ADDR_RANDOM: + case BLE_ADDR_RANDOM_ID: + return true; + default: + return false; + } +} + +inline tBLE_ADDR_TYPE to_ble_addr_type(uint8_t raw_type) { + return (tBLE_ADDR_TYPE)raw_type; +} +inline uint8_t from_ble_addr_type(tBLE_ADDR_TYPE type) { return (uint8_t)type; } + /* BLE ADDR type ID bit */ #define BLE_ADDR_TYPE_ID_BIT 0x02 +inline bool is_identity_type(const tBLE_ADDR_TYPE& type) { + return type & BLE_ADDR_TYPE_ID_BIT; +} + +#define STREAM_TO_BLE_ADDR_TYPE(type, p) \ + { \ + (type) = (tBLE_ADDR_TYPE)(*(p)); \ + (p) += sizeof(tBLE_ADDR_TYPE); \ + } +#define BLE_ADDR_TYPE_TO_STREAM(p, type) \ + { *(p)++ = (tBLE_ADDR_TYPE)(type); } #ifdef __cplusplus constexpr uint8_t kBleAddressPublicDevice = BLE_ADDR_PUBLIC; diff --git a/system/types/test/ble_address_with_type_unittest.cc b/system/types/test/ble_address_with_type_unittest.cc new file mode 100644 index 0000000000..5332d99e28 --- /dev/null +++ b/system/types/test/ble_address_with_type_unittest.cc @@ -0,0 +1,113 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "types/ble_address_with_type.h" + +#include <gtest/gtest.h> + +TEST(BleAddressWithTypeTest, to_ble_addr_type) { + for (unsigned i = 0; i < 0xff + 1; i++) { + switch (to_ble_addr_type((uint8_t)i)) { + case BLE_ADDR_PUBLIC: + ASSERT_TRUE(i == 0); + break; + case BLE_ADDR_RANDOM: + ASSERT_TRUE(i == 1); + break; + case BLE_ADDR_PUBLIC_ID: + ASSERT_TRUE(i == 2); + break; + case BLE_ADDR_RANDOM_ID: + ASSERT_TRUE(i == 3); + break; + case BLE_ADDR_ANONYMOUS: + ASSERT_TRUE(i == 0xff); + break; + default: + ASSERT_TRUE(i > 3 && i != 0xff); + break; + } + } +} + +TEST(BleAddressWithTypeTest, from_ble_addr_type) { + struct type_table_t { + tBLE_ADDR_TYPE type; + uint8_t value; + } type_table[] = { + {BLE_ADDR_PUBLIC, 0}, {BLE_ADDR_RANDOM, 1}, + {BLE_ADDR_PUBLIC_ID, 2}, {BLE_ADDR_RANDOM_ID, 3}, + {BLE_ADDR_ANONYMOUS, 0xff}, + }; + + for (unsigned i = 0; i < sizeof(type_table) / sizeof(type_table[0]); i++) { + ASSERT_TRUE(from_ble_addr_type(type_table[i].type) == type_table[i].value); + } +} + +TEST(BleAddressWithTypeTest, STREAM_TO_BLE_ADDR_TYPE) { + uint8_t buf[256] = {0x00, 0x01, 0x02, 0x03}; + buf[10] = 0x01; + buf[20] = 0x02; + buf[30] = 0x03; + buf[127] = 0xff; + buf[255] = 0xff; + + uint8_t* p = buf; + for (unsigned i = 0; i < sizeof(buf); i++) { + tBLE_ADDR_TYPE type; + STREAM_TO_BLE_ADDR_TYPE(type, p); + switch (i) { + case 0: + ASSERT_TRUE(type == BLE_ADDR_PUBLIC); + break; + case 1: + case 10: + ASSERT_TRUE(type == BLE_ADDR_RANDOM); + break; + case 2: + case 20: + ASSERT_TRUE(type == BLE_ADDR_PUBLIC_ID); + break; + case 3: + case 30: + ASSERT_TRUE(type == BLE_ADDR_RANDOM_ID); + break; + case 127: + case 255: + ASSERT_TRUE(type == BLE_ADDR_ANONYMOUS); + break; + default: + ASSERT_TRUE(type == BLE_ADDR_PUBLIC); + break; + } + } +} + +TEST(BleAddressWithTypeTest, BLE_ADDR_TYPE_TO_STREAM) { + uint8_t buf[256] = {0}; + uint8_t* p = buf; + + BLE_ADDR_TYPE_TO_STREAM(p, BLE_ADDR_PUBLIC); + BLE_ADDR_TYPE_TO_STREAM(p, BLE_ADDR_RANDOM); + BLE_ADDR_TYPE_TO_STREAM(p, BLE_ADDR_PUBLIC_ID); + BLE_ADDR_TYPE_TO_STREAM(p, BLE_ADDR_RANDOM_ID); + BLE_ADDR_TYPE_TO_STREAM(p, BLE_ADDR_ANONYMOUS); + + const uint8_t exp[] = {0x0, 0x1, 0x2, 0x3, 0xff}; + ASSERT_EQ(*exp, *buf); + ASSERT_EQ(5, p - buf); +} diff --git a/tools/rootcanal/model/controller/link_layer_controller.cc b/tools/rootcanal/model/controller/link_layer_controller.cc index e3cf441147..871a595dd2 100644 --- a/tools/rootcanal/model/controller/link_layer_controller.cc +++ b/tools/rootcanal/model/controller/link_layer_controller.cc @@ -38,8 +38,6 @@ namespace rootcanal { constexpr uint16_t kNumCommandPackets = 0x01; constexpr milliseconds kNoDelayMs(0); -constexpr milliseconds kShortDelayMs(5); -constexpr milliseconds kLongDelayMs(200); // TODO: Model Rssi? static uint8_t GetRssi() { @@ -923,7 +921,7 @@ void LinkLayerController::IncomingIoCapabilityRequestPacket( if (pairing_started) { PairingType pairing_type = security_manager_.GetSimplePairingType(); if (pairing_type != PairingType::INVALID) { - ScheduleTask(kShortDelayMs, [this, peer, pairing_type]() { + ScheduleTask(kNoDelayMs, [this, peer, pairing_type]() { AuthenticateRemoteStage1(peer, pairing_type); }); } else { @@ -965,7 +963,7 @@ void LinkLayerController::IncomingIoCapabilityResponsePacket( PairingType pairing_type = security_manager_.GetSimplePairingType(); if (pairing_type != PairingType::INVALID) { - ScheduleTask(kShortDelayMs, [this, peer, pairing_type]() { + ScheduleTask(kNoDelayMs, [this, peer, pairing_type]() { AuthenticateRemoteStage1(peer, pairing_type); }); } else { @@ -1878,7 +1876,7 @@ void LinkLayerController::IncomingPasskeyFailedPacket( ASSERT(failed.IsValid()); auto current_peer = incoming.GetSourceAddress(); security_manager_.AuthenticationRequestFinished(); - ScheduleTask(kShortDelayMs, [this, current_peer]() { + ScheduleTask(kNoDelayMs, [this, current_peer]() { if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( ErrorCode::AUTHENTICATION_FAILURE, current_peer)); @@ -1927,7 +1925,7 @@ void LinkLayerController::IncomingPinRequestPacket( SaveKeyAndAuthenticate('L', peer); // Legacy } else { security_manager_.AuthenticationRequestFinished(); - ScheduleTask(kShortDelayMs, [this, peer]() { + ScheduleTask(kNoDelayMs, [this, peer]() { if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( ErrorCode::AUTHENTICATION_FAILURE, peer)); @@ -1937,7 +1935,7 @@ void LinkLayerController::IncomingPinRequestPacket( } } else { LOG_INFO("PIN pairing %s", properties_.GetAddress().ToString().c_str()); - ScheduleTask(kShortDelayMs, [this, peer]() { + ScheduleTask(kNoDelayMs, [this, peer]() { security_manager_.SetPinRequested(peer); if (properties_.IsUnmasked(EventCode::PIN_CODE_REQUEST)) { send_event_(bluetooth::hci::PinCodeRequestBuilder::Create(peer)); @@ -1980,7 +1978,7 @@ void LinkLayerController::IncomingPinResponsePacket( SaveKeyAndAuthenticate('L', peer); // Legacy } else { security_manager_.AuthenticationRequestFinished(); - ScheduleTask(kShortDelayMs, [this, peer]() { + ScheduleTask(kNoDelayMs, [this, peer]() { if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( ErrorCode::AUTHENTICATION_FAILURE, peer)); @@ -1990,7 +1988,7 @@ void LinkLayerController::IncomingPinResponsePacket( } } else { LOG_INFO("PIN pairing %s", properties_.GetAddress().ToString().c_str()); - ScheduleTask(kShortDelayMs, [this, peer]() { + ScheduleTask(kNoDelayMs, [this, peer]() { security_manager_.SetPinRequested(peer); if (properties_.IsUnmasked(EventCode::PIN_CODE_REQUEST)) { send_event_(bluetooth::hci::PinCodeRequestBuilder::Create(peer)); @@ -2055,7 +2053,7 @@ void LinkLayerController::IncomingPageResponsePacket( } if (awaiting_authentication) { - ScheduleTask(kShortDelayMs, [this, peer, handle]() { + ScheduleTask(kNoDelayMs, [this, peer, handle]() { HandleAuthenticationRequest(peer, handle); }); } @@ -2230,8 +2228,7 @@ ErrorCode LinkLayerController::LinkKeyRequestReply( security_manager_.WriteKey(peer, key); security_manager_.AuthenticationRequestFinished(); - ScheduleTask(kShortDelayMs, - [this, peer]() { AuthenticateRemoteStage2(peer); }); + ScheduleTask(kNoDelayMs, [this, peer]() { AuthenticateRemoteStage2(peer); }); return ErrorCode::SUCCESS; } @@ -2251,11 +2248,11 @@ ErrorCode LinkLayerController::LinkKeyRequestNegativeReply( security_manager_.AuthenticationRequest(address, handle, false); } - ScheduleTask(kShortDelayMs, + ScheduleTask(kNoDelayMs, [this, address]() { StartSimplePairing(address); }); } else { LOG_INFO("PIN pairing %s", properties_.GetAddress().ToString().c_str()); - ScheduleTask(kShortDelayMs, [this, address]() { + ScheduleTask(kNoDelayMs, [this, address]() { security_manager_.SetPinRequested(address); if (properties_.IsUnmasked(EventCode::PIN_CODE_REQUEST)) { send_event_(bluetooth::hci::PinCodeRequestBuilder::Create(address)); @@ -2274,7 +2271,7 @@ ErrorCode LinkLayerController::IoCapabilityRequestReply( PairingType pairing_type = security_manager_.GetSimplePairingType(); if (pairing_type != PairingType::INVALID) { - ScheduleTask(kShortDelayMs, [this, peer, pairing_type]() { + ScheduleTask(kNoDelayMs, [this, peer, pairing_type]() { AuthenticateRemoteStage1(peer, pairing_type); }); SendLinkLayerPacket(model::packets::IoCapabilityResponseBuilder::Create( @@ -2331,21 +2328,21 @@ void LinkLayerController::SaveKeyAndAuthenticate(uint8_t key_type, if (key_type == 'L') { // Legacy - ScheduleTask(kShortDelayMs, [this, peer, key_vec]() { + ScheduleTask(kNoDelayMs, [this, peer, key_vec]() { if (properties_.IsUnmasked(EventCode::LINK_KEY_NOTIFICATION)) { send_event_(bluetooth::hci::LinkKeyNotificationBuilder::Create( peer, key_vec, bluetooth::hci::KeyType::AUTHENTICATED_P192)); } }); } else { - ScheduleTask(kShortDelayMs, [this, peer]() { + ScheduleTask(kNoDelayMs, [this, peer]() { if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( ErrorCode::SUCCESS, peer)); } }); - ScheduleTask(kShortDelayMs, [this, peer, key_vec]() { + ScheduleTask(kNoDelayMs, [this, peer, key_vec]() { if (properties_.IsUnmasked(EventCode::LINK_KEY_NOTIFICATION)) { send_event_(bluetooth::hci::LinkKeyNotificationBuilder::Create( peer, key_vec, bluetooth::hci::KeyType::AUTHENTICATED_P256)); @@ -2353,8 +2350,7 @@ void LinkLayerController::SaveKeyAndAuthenticate(uint8_t key_type, }); } - ScheduleTask(kShortDelayMs, - [this, peer]() { AuthenticateRemoteStage2(peer); }); + ScheduleTask(kNoDelayMs, [this, peer]() { AuthenticateRemoteStage2(peer); }); } ErrorCode LinkLayerController::PinCodeRequestReply(const Address& peer, @@ -2365,7 +2361,7 @@ ErrorCode LinkLayerController::PinCodeRequestReply(const Address& peer, LOG_INFO("%s: %s != %s", properties_.GetAddress().ToString().c_str(), peer.ToString().c_str(), current_peer.ToString().c_str()); security_manager_.AuthenticationRequestFinished(); - ScheduleTask(kShortDelayMs, [this, current_peer]() { + ScheduleTask(kNoDelayMs, [this, current_peer]() { if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( ErrorCode::AUTHENTICATION_FAILURE, current_peer)); @@ -2384,7 +2380,7 @@ ErrorCode LinkLayerController::PinCodeRequestReply(const Address& peer, SaveKeyAndAuthenticate('L', peer); // Legacy } else { security_manager_.AuthenticationRequestFinished(); - ScheduleTask(kShortDelayMs, [this, peer]() { + ScheduleTask(kNoDelayMs, [this, peer]() { if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( ErrorCode::AUTHENTICATION_FAILURE, peer)); @@ -2402,7 +2398,7 @@ ErrorCode LinkLayerController::PinCodeRequestNegativeReply( const Address& peer) { auto current_peer = security_manager_.GetAuthenticationAddress(); security_manager_.AuthenticationRequestFinished(); - ScheduleTask(kShortDelayMs, [this, current_peer]() { + ScheduleTask(kNoDelayMs, [this, current_peer]() { if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( ErrorCode::AUTHENTICATION_FAILURE, current_peer)); @@ -2431,7 +2427,7 @@ ErrorCode LinkLayerController::UserConfirmationRequestNegativeReply( const Address& peer) { auto current_peer = security_manager_.GetAuthenticationAddress(); security_manager_.AuthenticationRequestFinished(); - ScheduleTask(kShortDelayMs, [this, current_peer]() { + ScheduleTask(kNoDelayMs, [this, current_peer]() { if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( ErrorCode::AUTHENTICATION_FAILURE, current_peer)); @@ -2459,7 +2455,7 @@ ErrorCode LinkLayerController::UserPasskeyRequestNegativeReply( const Address& peer) { auto current_peer = security_manager_.GetAuthenticationAddress(); security_manager_.AuthenticationRequestFinished(); - ScheduleTask(kShortDelayMs, [this, current_peer]() { + ScheduleTask(kNoDelayMs, [this, current_peer]() { if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( ErrorCode::AUTHENTICATION_FAILURE, current_peer)); @@ -2487,7 +2483,7 @@ ErrorCode LinkLayerController::RemoteOobDataRequestNegativeReply( const Address& peer) { auto current_peer = security_manager_.GetAuthenticationAddress(); security_manager_.AuthenticationRequestFinished(); - ScheduleTask(kShortDelayMs, [this, current_peer]() { + ScheduleTask(kNoDelayMs, [this, current_peer]() { if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( ErrorCode::AUTHENTICATION_FAILURE, current_peer)); @@ -2544,7 +2540,7 @@ ErrorCode LinkLayerController::AuthenticationRequested(uint16_t handle) { AddressWithType remote = connections_.GetAddress(handle); - ScheduleTask(kShortDelayMs, [this, remote, handle]() { + ScheduleTask(kNoDelayMs, [this, remote, handle]() { HandleAuthenticationRequest(remote.GetAddress(), handle); }); @@ -2591,7 +2587,7 @@ ErrorCode LinkLayerController::SetConnectionEncryption( return ErrorCode::PIN_OR_KEY_MISSING; } - ScheduleTask(kShortDelayMs, [this, remote, handle, encryption_enable]() { + ScheduleTask(kNoDelayMs, [this, remote, handle, encryption_enable]() { HandleSetConnectionEncryption(remote.GetAddress(), handle, encryption_enable); }); @@ -2603,7 +2599,7 @@ ErrorCode LinkLayerController::AcceptConnectionRequest(const Address& bd_addr, if (connections_.HasPendingConnection(bd_addr)) { LOG_INFO("Accepting connection request from %s", bd_addr.ToString().c_str()); - ScheduleTask(kLongDelayMs, [this, bd_addr, try_role_switch]() { + ScheduleTask(kNoDelayMs, [this, bd_addr, try_role_switch]() { LOG_INFO("Accepted connection from %s", bd_addr.ToString().c_str()); MakePeripheralConnection(bd_addr, try_role_switch); }); @@ -2638,7 +2634,7 @@ ErrorCode LinkLayerController::AcceptConnectionRequest(const Address& bd_addr, link_parameters.extended)); // Schedule HCI Connection Complete event. - ScheduleTask(kShortDelayMs, [this, status, sco_handle, bd_addr]() { + ScheduleTask(kNoDelayMs, [this, status, sco_handle, bd_addr]() { send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( ErrorCode(status), sco_handle, bd_addr, bluetooth::hci::LinkType::SCO, bluetooth::hci::Enable::DISABLED)); @@ -2678,7 +2674,7 @@ ErrorCode LinkLayerController::RejectConnectionRequest(const Address& addr, return ErrorCode::UNKNOWN_CONNECTION; } - ScheduleTask(kLongDelayMs, [this, addr, reason]() { + ScheduleTask(kNoDelayMs, [this, addr, reason]() { RejectPeripheralConnection(addr, reason); }); @@ -2723,7 +2719,7 @@ ErrorCode LinkLayerController::CreateConnectionCancel(const Address& addr) { void LinkLayerController::SendDisconnectionCompleteEvent(uint16_t handle, uint8_t reason) { if (properties_.IsUnmasked(EventCode::DISCONNECTION_COMPLETE)) { - ScheduleTask(kShortDelayMs, [this, handle, reason]() { + ScheduleTask(kNoDelayMs, [this, handle, reason]() { send_event_(bluetooth::hci::DisconnectionCompleteBuilder::Create( ErrorCode::SUCCESS, handle, ErrorCode(reason))); }); @@ -2784,7 +2780,7 @@ ErrorCode LinkLayerController::ChangeConnectionPacketType(uint16_t handle, return ErrorCode::UNKNOWN_CONNECTION; } - ScheduleTask(kShortDelayMs, [this, handle, types]() { + ScheduleTask(kNoDelayMs, [this, handle, types]() { if (properties_.IsUnmasked(EventCode::CONNECTION_PACKET_TYPE_CHANGED)) { send_event_(bluetooth::hci::ConnectionPacketTypeChangedBuilder::Create( ErrorCode::SUCCESS, handle, types)); @@ -3156,8 +3152,8 @@ ErrorCode LinkLayerController::LeRemoteConnectionParameterRequestReply( return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } - ScheduleTask(kShortDelayMs, [this, connection_handle, interval_min, - interval_max, latency, timeout]() { + ScheduleTask(kNoDelayMs, [this, connection_handle, interval_min, interval_max, + latency, timeout]() { LeConnectionUpdateComplete(connection_handle, interval_min, interval_max, latency, timeout); }); @@ -3423,7 +3419,7 @@ ErrorCode LinkLayerController::LeEnableEncryption(uint16_t handle, return ErrorCode::UNKNOWN_CONNECTION; } - ScheduleTask(kShortDelayMs, [this, handle, rand, ediv, ltk]() { + ScheduleTask(kNoDelayMs, [this, handle, rand, ediv, ltk]() { HandleLeEnableEncryption(handle, rand, ediv, ltk); }); return ErrorCode::SUCCESS; @@ -3823,8 +3819,8 @@ ErrorCode LinkLayerController::AcceptSynchronousConnection( link_parameters.extended)); // Schedule HCI Synchronous Connection Complete event. - ScheduleTask(kShortDelayMs, [this, status, sco_handle, bd_addr, - link_parameters]() { + ScheduleTask(kNoDelayMs, [this, status, sco_handle, bd_addr, + link_parameters]() { send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( ErrorCode(status), sco_handle, bd_addr, link_parameters.extended ? bluetooth::hci::ScoLinkType::ESCO @@ -3858,7 +3854,7 @@ ErrorCode LinkLayerController::RejectSynchronousConnection(Address bd_addr, properties_.GetAddress(), bd_addr, reason, 0, 0, 0, 0, 0, 0)); // Schedule HCI Synchronous Connection Complete event. - ScheduleTask(kShortDelayMs, [this, reason, bd_addr]() { + ScheduleTask(kNoDelayMs, [this, reason, bd_addr]() { send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( ErrorCode(reason), 0, bd_addr, bluetooth::hci::ScoLinkType::ESCO, 0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT)); |